在TypeScript中没有内置的存在类型,因此您不能说“我不关心key
是哪个键,但它需要是T
的某个键。”
唯一的方法是使Type
在T
和K extends keyof T
中都是泛型,像这样:
type Type<T, K extends keyof T> = {
key: K,
doStuff: (value: T[K]) => void
};
然后,您可以像这样指定
Test
:
const Test: Type<{ var1: string, var2: number }, "var1"> = {
key: 'var1',
doStuff: (value) => { }
}
这个方法可行,但也许您不喜欢必须在类型和key属性中手动指定"var1"。 不幸的是,您不能只指定T并使K被推断出来,
至少目前还不行。 最终应该会有一种方式可以实现
部分类型参数推断, 可能会在
2018年8月,TypeScript 3.1尽快实现。
目前,您可以通过
柯里化的方法进行变通,其中一个泛型函数返回另一个泛型函数,您指定一个并让另一个被推断出来。 就像这样:
const typeFor = <T>() => <K extends keyof T>(type: Type<T, K>) => type;
const typeForVar1StringVar2Number = typeFor<{ var1: string, var2: number }>();
const Test2 = typeForVar1StringVar2Number({
key: 'var1',
doStuff: (value) => { }
});
这需要更多的操作,但它可以避免您为 K
写出 'var1'
。
好的,希望这有所帮助。祝你好运!
编辑:我看到你确实需要存在类型,因为你需要一个这些东西的数组。当你有文字联合(比如
T
没有字符串索引时的
keyof T
)时,获取类似存在类型的一种方法是使用
distributive conditional types。
type PossibleTypes<T> = keyof T extends infer K ?
K extends any ? Type<T, K> : never : never;
PossibleTypes<T>
将成为每个K
(来自T
的所有键)对应的Type<T, K>
的联合类型。让我们用它来创建该数组:
type ArrayOfPossibleTypes<T> = Array<PossibleTypes<T>>
const asArrayOfPossibleTypes = <T>(arr: ArrayOfPossibleTypes<T>) => arr;
const testArray = asArrayOfPossibleTypes<{ var1: string, var2: number }>([
{
key: 'var1', doStuff(value) { }
}, {
key: 'var2', doStuff(value) { }
}
]);
推断看起来很不错。如果你不太害怕分布式条件类型,我想这可能适合你。
如果其他方法都失败了,在TypeScript中有一种存在类型的实现,但它涉及到
延续传递,可能对您的用例来说过于复杂。以下是一个完整的示例:
type ExistentialType<T> = <R>(f: <K extends keyof T>(x: Type<T, K>) => R) => R;
与其说“我是某个 K
类型的 Type<T, K>
”,不如说“如果你给我一个可以操作任何 Type<T, K>
的函数,我可以为你调用该函数并返回结果”。让我们创建一个:
const exType: ExistentialType<{ var1: string, var2: number }> =
(f) => f({ key: 'var1', doStuff(value) { } });
然后使用它:
const obj = {var1: "hey", var2: 123};
exType(function (t) { if (t.doStuff) t.doStuff(obj[t.key]) });
这种内外颠倒的方式很古怪有趣,有时也很实用...但在这里可能过于浪费。
好的,希望那有所帮助。再次祝你好运。
Type
在T
和K extends keyof T
中都是泛型。 - jcalz