打字稿泛型:给定键K和对象T,限制T [K]的类型 [英] Typescript generics: given key K and object T, constrain the type of T[K]

查看:34
本文介绍了打字稿泛型:给定键K和对象T,限制T [K]的类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个环境,其中某些具有 id 属性的对象会在每个滴答"中过期,并且需要使用 getObjectById 进行调用.我想实现一个setter方法,通过映射 thing.property =>来刷新某物的属性.getObjectById(thing.property.id).理想情况下,我希望此方法采用事物 T 和键 K ,其中 T [K] 可以是具有id的对象( HasID )或它们的数组( HasID [] ).

I have an environment where certain objects which have an id property expire every "tick" and need to be recalled using getObjectById. I would like to implement a setter method to refresh a property of something by mapping thing.property => getObjectById(thing.property.id). Ideally, I would like this method to take a thing T and a key K, where T[K] can be an object with an id (HasID) or and array of them (HasID[]).

我相信我已经接近解决方案,但这还不是很正确.下面列出了我目前所拥有的(在名为 $ 的类上的静态方法):

I believe I'm close to a solution, but it's not quite correct yet. What I currently have is listed below (a static method on a class called $):

static refresh<T extends {[K in keyof T]: HasID}, K extends keyof T>(thing: T, key: K): void;
static refresh<T extends {[K in keyof T]: HasID[]}, K extends keyof T>(thing: T, key: K): void;
static refresh<T extends {[K in keyof T]: HasID | HasID[]}, K extends keyof T>(thing: T, key: K): void {
    if (_.isArray(thing[key])) {
        thing[key] = _.map(thing[key] as HasID[], s => getObjectById(s.id)) as HasID[];
    } else {
        thing[key] = getObjectById(thing[key].id) as HasID;
    }
}

例如, foo:{bar:HasID,baz:HasID [],biz:string []} 的期望行为是:

$.refresh(foo, 'bar') // foo.bar = getObjectById(foo.bar.id)
$.refresh(foo, 'baz') // foo.baz = _.map(foo.baz, x=>getObjectById(x.id))
$.refresh(foo, 'biz') // error: foo.biz is not HasID or HasID[]
$.refresh(foo, 'boo') // error: 'boo' is not a key of foo

有人可以指出正确的方向来正确限制 T [K] 的类型吗?

Could someone point me in the right direction to correctly constrain the type of T[K]?

推荐答案

您很亲密,问题在于,并非 T 的每个键都必须是 HasID HasID [] ,仅由 K

You are close, the problem is that not every key of T has to be HasID or HasID[], only the one specified by K

class $ {
  static refresh<T extends { [P in K]: HasID }, K extends string>(thing: T, key: K): void;
  static refresh<T extends { [P in K]: HasID[] }, K extends string>(thing: T, key: K): void;
  static refresh<T extends { [P in K]: HasID | HasID[] }, K extends string>(thing: T, key: K): void {

  }
}

let foo: { bar: HasID, baz: HasID[], biz: string[] };
$.refresh(foo, 'bar') // foo.bar = getObjectById(foo.bar.id)
$.refresh(foo, 'baz') // foo.baz = _.map(foo.baz, x=>getObjectById(x.id))
$.refresh(foo, 'biz') // error: foo.biz is not HasID or HasID[]
$.refresh(foo, 'boo') // error: 'boo' is not a key of foo

也可以使用 Record< K,HasId> 代替 {[K中的P]:HasID} ,我保留了原始版本,以便于跟踪差异.使用记录的标志将是:

Also instead of { [P in K]: HasID } you can use Record<K, HasId>, I left your original version to make it easier to track the differences. Using record the sigantures would be:

class $ {
  static refresh<T extends Record<K, HasID>, K extends string>(thing: T, key: K): void;
  static refresh<T extends Record<K, HasID>[], K extends string>(thing: T, key: K): void;
  static refresh<T extends Record<K, HasID | HasID[]>, K extends string>(thing: T, key: K): void {

  }
}

这篇关于打字稿泛型:给定键K和对象T,限制T [K]的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆