2015-11-09 38 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(來自微軟貢獻者)。 –