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

时间:2015-11-09 17:05:29

标签: 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?

现在,如果你添加一个强制性的&#39; IAnimal接口的字段并在Animal类中实现它将开始抱怨&#39; bar&#39;是机器人接口和类的多余属性。链接到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'

如果有人对于为什么会这样有效,请做一些见解 我很好奇为什么会这样。

1 个答案:

答案 0 :(得分:3)

来自pull request的以下三个要点阐明了在操场上使用的TS 1.6中新的严格行为:

  
      
  • 每个对象文字最初都被视为&#34;新鲜&#34;。
  •   
  • 当一个新的对象文字分配给一个变量或为一个非空目标类型的参数 [强调添加]传递时,对象文字指定的属性是错误的#39; t存在于目标类型中。
  •   
  • 新鲜度在类型断言中消失,或者当对象文字的类型变宽时消失。
  •   

我在源代码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;
 }

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

我可能在技术上有点描述了这种行为但是...希望,我明确表示并且希望,我没有在路上犯错误。