TypeScript如何处理接口和类中的多余属性的区别

Den*_*stu 6 javascript typescript typescript1.7

我最近偶然发现了TypeScript中这种奇怪的(imo)行为.在编译期间,只有当接口没有必填字段时,如果预期变量的类型是接口,它才会抱怨多余的属性.链接到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?
Run Code Online (Sandbox Code Playgroud)

现在,如果你向IAnimal接口添加一个'强制'字段并在Animal类中实现它,它将开始抱怨'bar'是bot接口和类的多余属性.链接到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'
Run Code Online (Sandbox Code Playgroud)

如果有人有一些见解,为什么它的工作原理,请做.
我很好奇为什么会这样.

Mar*_*cka 4

以下来自拉取请求的三个要点揭示了 TS 1.6 中在 Playground 中使用的新严格行为:

  • 每个对象字面量最初都被认为是“新鲜的”。
  • 当将新的对象字面量分配给变量或传递给非空目标类型的参数时[强调],对象字面量指定目标类型中不存在的属性是错误的。
  • 当类型断言或对象字面量的类型被扩展时,新鲜感就会消失。

我在源代码function hasExcessPropertiesfunction 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;
 }
Run Code Online (Sandbox Code Playgroud)

因此,第一个示例中的目标类型Animal(类)是一个空类型 - 它没有属性,因为您没有name在类中实现属性(因此resolved.properties.length === 0在函数中为 true isKnownProperty)。另一方面IAnimal已定义属性。

我可能从技术上描述了这种行为,但是……希望我说得很清楚,希望我在路上没有犯错误。