我在tsc
本地运行example.ts
我希望onePropMissing
出现警告或错误,因为c
不是界面上的可选属性,onePropMissing
c
属性丢失,我没有收到任何错误。
之后,我添加了一个示例oneExtraProp
,我也预计会失败,因为还有一个属性。
在这两个例子之后,我很确定extraAndOneMissing
也没问题,但令我惊讶的是,TSC在这里抱怨。
interface InterfaceEverythingRequired {
a: string;
b: string;
c: number;
}
// Expected to be OK, it's OK
const allPropsPresent = { a: 'a', b: 'b', c: 1 } as InterfaceEverythingRequired;
// Expected warning as c is missing, but TSC says it's OK
const onePropMissing = { a: 'a', b: 'b' } as InterfaceEverythingRequired;
// Expected warning as extraProp is present, but TSC says it's OK
const oneExtraProp = { a: 'a', b: 'b', c: 3, extraProp: 'no-issues' } as InterfaceEverythingRequired;
// After the last two examples, I expected to have no warnings, as
// there were no warnings for the extra property, nor the missing property
// but TSC complained
const extraAndOneMissing = { a: 'a', b: 'b', extraProp: 'what?' } as InterfaceEverythingRequired;
这里发生了什么以及错误为何如此有趣?
我得到的错误:
Type '{ a: string; b: string; extraProp: string; }' cannot be
converted to type 'InterfaceEverythingRequired'.
Property 'c' is missing in type '{ a: string; b: string;
extraProp: string; }'.
答案 0 :(得分:1)
如果您编写如下示例,您将收到更好的错误消息:
const allPropsPresent: InterfaceEverythingRequired = { a: 'a', b: 'b', c: 1 };
// Ok
const onePropMissing: InterfaceEverythingRequired = { a: 'a', b: 'b' }
// Property 'c' is missing
const oneExtraProp: InterfaceEverythingRequired = { a: 'a', b: 'b', c: 3, extraProp: 'no-issues' }
// Object literals may only specify known properties
const extraAndOneMissing: InterfaceEverythingRequired = { a: 'a', b: 'b', extraProp: 'what?' };
// Object literals may only specify known properties
现在问题,为什么类型断言适用于除最后一个之外的所有情况,你需要考虑TypeScript中的结构类型:
{ a: 'a', b: 'b', c: 1 }
是{ a: 'a', b: 'b' }
的子类型,因为它具有超类型的所有属性。
let x: { a: 'a', b: 'b', c: 1 };
let y: { a: 'a', b: 'b' };
x = y; // error
y = x; // OK
但是你可以在向下转发x = y as { a: 'a', b: 'b', c: 1 }
时写y
,错误就会消失。
对于您的第三个示例,{ a: 'a', b: 'b', c: 3, extraProp: 'no-issues' }
是InterfaceEverythingRequired
的子类型,因此类型断言(向下转换)有效。在您的第四个示例中,{ a: 'a', b: 'b', extraProp: 'what?' }
和InterfaceEverythingRequired
是不相关的类型(它们没有子类型超类型关系),TypeScript在这种情况下不允许向下转换。您的第四个示例与以下情况类似:
let x: string;
let y: number;
x = y as string; // Type 'number' cannot be converted to type 'string'
答案 1 :(得分:0)
您不应该使用as
来输入变量。直接输入
const onePropMissing: InterfaceEverythingRequired = { a: 'a', b: 'b' }; // error
TypeScript中的类型转换实际上只是类型断言,而TypeScript的结构类型系统在来自名义类型语言时会导致许多意外结果。
许多典型的陷阱都在TypeScript FAQ中解决。