我有一个环境,其中具有id
属性的某些对象会在每个“滴答”中过期,并且需要使用getObjectById
进行调用。我想实现一个setter方法,以通过映射thing.property => getObjectById(thing.property.id)
刷新某些属性。理想情况下,我希望此方法采用事物T
和键K
,其中T[K]
可以是具有id(HasID
)或它们的数组的对象(HasID[]
。
我相信我已经接近解决方案,但还不太正确。下面列出了我目前所拥有的(在名为$
的类上的静态方法):
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]
的类型吗?
答案 0 :(得分:2)
您亲近了,问题在于,并非T
的每个键都必须是HasID
或HasID[]
,只有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
我也可以使用{ [P in K]: HasID }
而不是Record<K, HasId>
,而是保留了原始版本,以便更轻松地跟踪差异。使用记录的标志将是:
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 {
}
}