如何在不使用@ ts-ignore的情况下解决此错误?
class Test {
public field1!: Date;
public field2?: Date;
public field3?: string;
public field4?: number;
}
const t = {field1: new Date(), field2: new Date()} as Test;
for(const field of ["field1", "field2"] as Array<keyof Test>) {
// error is in the next line: TS2322: Type 'Date' is not assignable to type 'never'.
t[field] = new Date();
}
我了解为什么会出现此问题,但不了解如何在这种情况下通过一些类型提示来解决它。
答案 0 :(得分:1)
这是因为在进行["field1", "field2"] as Array<keyof Test>
时不会自动进行类型缩小,例如,["field1", "field2", "field3"]
也是Array<keyof Test>
的有效子类型。
如果要缩小类型,则必须在for循环内执行该操作:
for (const field of Object.keys(t) as Array<keyof Test>) {
// From here, TypeScript is able to narrow to type of `t[field]` to `Date`
if (field === 'field1' || field === 'field2') {
t[field] = new Date();
}
}
答案 1 :(得分:1)
您可能已经意识到,["field1", "field2"]
被推断为string[]
,对于编译器来说,它太宽了以至于不能保证循环内的安全性。 t
可能没有与任何给定string
对应的字段。通过断言它是Array<keyof Test>
,您已将其范围缩小了一点,但仍然不足以保证安全;毕竟,我们知道t
的字段类型为keyof Test
,但是其中某些属性必须为string
类型,而不是Date
类型,因此您不能安全地分配一个Date
。
自TypeScript 3.4发布以来,到目前为止,最简单的方法是使用const
assertion并编写["field1", "field2"] as const
。这实际上要求编译器将数组文字的类型推断为它可以推断的最窄类型,即readonly ["field1", "field2"]
;由两个条目组成的readonly
tuple,该条目必须恰好是字符串文字"field1"
和"field2
“,该顺序比您需要要窄循环中的安全性:Array<"field1" | "field2">
就足够了;但这不是太窄之类的东西,所以您最好使用它:
for (const field of ["field1", "field2"] as const) {
t[field] = new Date(); // okay
}
看起来不错。希望能有所帮助;祝你好运!