如何使用泛型来强制实现某种特定类型的值?
// An example array
const testArr = [
{
id: 3,
name: 'Spaghetto', // NOTE: Type 'string' here
shouldNotWork: 3.14, // NOTE: Type 'number' here
},
{
id: 5,
name: 'Bread',
shouldNotWork: 3.14,
},
];
这就是我试图成为我的映射函数,但我必须附加as V2
以使TS不要抱怨:/
type Mapping<T, U> = (val: T, i: number, arr: T[]) => U;
interface Option<T> {
value: T;
label: string; // <- NOTE: Type string is required
}
const typeToOption = <
T,
K1 extends keyof T,
K2 extends keyof T,
V2 extends T[K2] & string // <- NOTE: 'string' union here to match
>(
valueK: K1,
labelK: K2,
): Mapping<T, Option<T[K1]>> => (item: T): Option<T[K1]> => ({
value: item[valueK],
label: item[labelK] as V2,
});
我希望TS允许我这个
const result = testArr.map(typeToOption('id', 'name'));
......但不是这个
const result = testArr.map(typeToOption('id', 'shouldNotWork'));
我如何让TS抱怨后者?
答案 0 :(得分:0)
我想你想这样输入typeToOption()
:
const typeToOption = <
T extends Record<K2, string>,
K1 extends keyof T,
K2 extends keyof T,
>(
valueK: K1,
labelK: K2,
): Mapping<T, Option<T[K1]>> => (item: T): Option<T[K1]> => ({
value: item[valueK],
label: item[labelK],
});
TypeScript允许您在通用参数中执行一些“循环”类型约束。因此,在这种情况下,我们不需要指定V2
(因为它没有做任何工作),我们只需要T extends Record<K2, string>
,这意味着类型T
必须有{ {1}}键string
处的有价值属性。这足以为您提供您所要求的行为:
K2
虽然错误有点令人困惑,但至少这是一个错误。 (如果重要:类型推断失败会导致有趣的事情发生。const result = testArr.map(typeToOption('id', 'name')); // okay
const result = testArr.map(typeToOption('id', 'shouldNotWork')); // error
// [ts] Argument of type '"id"' is not assignable to
// parameter of type '"shouldNotWork"'.
会回退到T
,相当于Record<'shouldNotWork', string>
,而{shouldNotWork: string}
只会keyof T
,因此'shouldNotWork'
'shouldNotWork'`。哦,好吧。)
希望有所帮助;祝你好运!