我不明白为什么这段代码在使用省略实用程序类型时可以工作:
type Foo = {
prop1: string;
prop2: string;
}
const foo: Foo = {
prop1: 'prop1',
prop2: 'prop2'
}
console.log(foo) // {"prop1": "prop1", "prop2": "prop2"}
type Bar = Omit<Foo, 'prop2'> & {
prop3: string;
}
const bar: Bar = {
...foo,
prop3: 'prop3'
}
console.log(bar) // {"prop1": "prop1", "prop2": "prop2", "prop3": "prop3"}
同时,直接使用Bar
如预期的那样失败:
const qux: Bar = {
prop1: "prop1",
prop2: "prop2", // '{ prop1: string; prop2: string; prop3: string; }' is not assignable to type 'Bar'
prop3: "prop3"
}
这是因为过多的属性检查只发生在对象字面量中的属性上,而且只在某些情况下发生。多余的属性实际上不是类型安全问题;编译器只有在认为代码可能会立即忘记它们时才会发出警告。像const x: {a: string} = {a: "", b: ""}
这样的东西是一个问题,因为没有什么能安全地访问b
属性。但const y = {a: "", b: ""}; const x: {a: string} = y;
是好的,因为y
记得b
,即使x
忘记了。
同样,一般来说,额外的属性不是类型安全问题。你希望编译器允许额外的属性,否则接口扩展将无法工作(如果interface Foo {a: string}
和interface Bar extends Foo {b: string}
,那么禁止额外的属性将意味着Bar
与Foo
不兼容,并且TypeScript的结构类型系统将被击败)。TypeScript并没有真正的"精确类型"。就像《Flow》一样。有一个开放的请求在微软/打印稿# 12936支持的类型,但是现在我们没有他们。我们所拥有的只是结构子类型,其中{a: string, b: string}
可分配给{a: string}
,以及在非常特殊的情况下有时会发出警告的多余属性检查。
在bar
的初始化项中,您正在传播foo
,一个已经存在的变量。它不是对象字面量,因此没有多余的属性检查。这是按照ms/TS#41237的预期工作。
另一方面,qux
的初始化器直接在对象字面量中添加了多余的属性,这会发出警告,因为没有人会记住qux
有prop2
属性。