我最近在 TypeScript 中偶然发现了这种奇怪的 (imo) 行为。 在编译期间,只有当预期变量的类型是接口(interface)且接口(interface)没有必填字段时,它才会提示过多的属性。链接到 TypeScript Playground #1:http://goo.gl/rnsLjd
interface IAnimal {
name?: string;
}
class Animal implements IAnimal {
}
var x : IAnimal = { bar: true }; // Object literal may only specify known properties, and 'bar' does not exist in type 'IAnimal'
var y : Animal = { bar: true }; // Just fine.. why?
function foo<T>(t: T) {
}
foo<IAnimal>({ bar: true }); // Object literal may only specify known properties, and 'bar' does not exist in type 'IAnimal'
foo<Animal>({ bar: true }); // Just fine.. why?
现在,如果您向 IAnimal 接口(interface)添加一个“强制”字段并在 Animal 类中实现它,它将开始提示“bar”是机器人接口(interface)和类的多余属性。链接到 TypeScript Playground #2:http://goo.gl/9wEKvp
interface IAnimal {
name?: string;
mandatory: number;
}
class Animal implements IAnimal {
mandatory: number;
}
var x : IAnimal = { mandatory: 0, bar: true }; // Object literal may only specify known properties, and 'bar' does not exist in type 'IAnimal'
var y : Animal = { mandatory: 0, bar: true }; // Not fine anymore.. why? Object literal may only specify known properties, and 'bar' does not exist in type 'Animal'
function foo<T>(t: T) {
}
foo<IAnimal>({ mandatory: 0, bar: true }); // Object literal may only specify known properties, and 'bar' does not exist in type 'IAnimal'
foo<Animal>({ mandatory: 0,bar: true }); // Not fine anymore.. why? Object literal may only specify known properties, and 'bar' does not exist in type 'Animal'
如果有人对它的工作原理有一些见解,请这样做。
我很好奇这是为什么。
最佳答案
以下三个要点来自 pull request阐明了在 playground 中使用的 TS 1.6 中新的严格行为:
- Every object literal is initially considered "fresh".
- When a fresh object literal is assigned to a variable or passed for a parameter of a non-empty target type [emphasis added], it is an error for the object literal to specify properties that don't exist in the target type.
- Freshness disappears in a type assertion or when the type of an object literal is widened.
我在源码里找到了function hasExcessProperties
和 function isKnownProperty
评论:
// Check if a property with the given name is known anywhere in the given type. In an object type, a property // is considered known if the object type is empty and the check is for assignability, if the object type has // index signatures, or if the property is actually declared in the object type. In a union or intersection // type, a property is considered known if it is known in any constituent type. function isKnownProperty(type: Type, name: string): boolean { if (type.flags & TypeFlags.ObjectType) { const resolved = resolveStructuredTypeMembers(type); if (relation === assignableRelation && (type === globalObjectType || resolved.properties.length === 0) || resolved.stringIndexType || resolved.numberIndexType || getPropertyOfType(type, name)) { return true; } } else if (type.flags & TypeFlags.UnionOrIntersection) { for (const t of (<UnionOrIntersectionType>type).types) { if (isKnownProperty(t, name)) { return true; } } } return false; }
所以第一个示例中的目标类型 Animal
(类)是一个空类型 - 它没有属性,因为您没有在类中实现 name
属性(因此resolved.properties.length === 0
在 isKnownProperty
函数中为真)。另一方面,IAnimal
定义了属性。
我可能已经从技术上描述了这种行为,但是......希望我说清楚了,希望我在整个过程中没有犯错。
关于javascript - TypeScript 处理接口(interface)和类中多余属性的方式不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33614328/