2015-11-09 40 views
4

我最近偶然发现了TypeScript中这种奇怪的(imo)行为。 在编译过程中,只有当接口没有必填字段时,期望变量的类型是一个接口,它才会抱怨超额属性。链接打字稿游乐场#1:http://goo.gl/rnsLjdTypeScript在接口和类中处理多余属性的区别

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接口,并在动物类会开始抱怨“巴”是为机器人过量财产实现它接口和类。链接打字稿游乐场#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

回答

2

以下三个要点阐明在TS 1.6新严格行为,其在游乐场中使用的比特的光的:

  • 每个对象文字最初认为是“新鲜”。
  • 当新鲜对象文字分配给一个变量或通过了的参数的非空目标类型 [添加强调],它是用于文字对象指定没有在存在属性的错误目标类型。
  • 新鲜度在类型断言中消失或当对象文字的类型变宽时消失。

我已经在源代码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 === 0isKnownProperty函数中为true)。另一方面,IAnimal具有定义的属性。

我可能已经在技术上描述了这种行为,但是......希望我明确地说,希望我在路上没有犯错。

+0

关于该功能的深入信息:https://gitter.im/Microsoft/TypeScript?at=56419a856420c33467a0fbb7(来自微软贡献者)。 –