我正在尝试通过提供字段名称来转换对象的某些字段,目前我写了如下内容:
interface Foo {
a: number[],
b: string[],
}
type Bar = { [T in keyof Foo] : (arg : Foo[T]) => Foo[T] }
function test<T extends keyof Foo>(field: T) {
const foo : Foo = {
a: [],
b: [],
};
const bar: Bar = {
a: arg => /* some code */ [],
b: arg => /* some code */ [],
};
foo[field] = bar[field](foo[field]);
}
但是我最终在bar[field](foo[field])
上看到以下错误消息:
Argument of type 'Foo[T]' is not assignable to parameter of type 'number[] & string[]'.
Type 'number[] | string[]' is not assignable to type 'number[] & string[]'.
Type 'number[]' is not assignable to type 'number[] & string[]'.
Type 'number[]' is not assignable to type 'string[]'.
Type 'number' is not assignable to type 'string'.
Type 'Foo[T]' is not assignable to type 'number[]'.
Type 'number[] | string[]' is not assignable to type 'number[]'.
Type 'string[]' is not assignable to type 'number[]'.
Type 'string' is not assignable to type 'number'
但是应该不应该打字稿“知道”具有相同的T
,Foo[T]
和Parameters<Bar[T]>
的文字?
答案 0 :(得分:2)
也许编译器应该知道,但事实并非如此。我倾向于将此问题称为“相关类型”或“相关记录”。编译器将foo[field]
和bar[field]
视为联合类型的东西,这确实是正确的。但是它将它们的类型视为独立的,这意味着,据我们所知,foo[field]
可能是number[]
,而bar[field]
可能是一个占用string[]
的函数。它没有发现foo[field]
的类型与bar[field]
的类型相关,以至于知道一个可以修复另一个。有一个未解决的问题,microsoft/TypeScript#30581(我提起,fwiw)表明对关联类型有一些支持,但尚不清楚这是否会发生或如何发生。
我们现在所拥有的只是解决方法。该问题中提到的两种解决方法:要么使用冗余代码来迫使编译器解决各种可能性并保证类型安全,要么使用type assertions放弃某种类型安全性但保持简洁。对于您的代码,它看起来像这样:
// redundant code
const f: keyof Foo = field;
switch (f) {
case "a":
foo[f] = bar[f](foo[f]);
break;
case "b":
foo[f] = bar[f](foo[f]);
break;
}
// type assertion
foo[field] = (bar[field] as <T>(arg: T) => T)(foo[field]);
我通常选择类型断言。好的,希望能有所帮助;祝你好运!