只有当缺少非可选接口属性和额外属性时,TypeScript才会失败

时间:2018-02-22 11:06:31

标签: typescript object interface casting

我在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; }'.

2 个答案:

答案 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中解决。