我正在尝试通过提供字段名称来转换对象的某些字段,目前我写了如下内容:
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
typescript “知道”这一点, Foo[T]
和Parameters<Bar[T]>
应该是一样的吧?
最佳答案
也许编译器应该知道这一点,但它不知道。我倾向于将这个问题称为“相关类型”或“相关记录”。编译器将 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]);
我通常选择类型断言。好的,希望有帮助;祝你好运!
关于typescript - 泛型函数中的属性类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59077562/