javascript - TypeScript 处理接口(interface)和类中多余属性的方式不同

标签 javascript typescript typescript1.7

我最近在 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 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 函数中为真)。另一方面,IAnimal 定义了属性。

我可能已经从技术上描述了这种行为,但是......希望我说清楚了,希望我在整个过程中没有犯错。

关于javascript - TypeScript 处理接口(interface)和类中多余属性的方式不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33614328/

相关文章:

node.js - 由于以下错误,无法安装 tsd 软件包

javascript - 与模块相比,使用具有静态函数的类有什么优势吗?

javascript - 将模块导入到命名空间类

javascript - 更改 Google Maps JavaScript API v3 圈外的 map 不透明度

javascript - 在导航中 react native 多颜色标题

javascript - 编译 Typescript 时如何导出模块类型

angular - 如何在 Angular 2 中对数据进行分组?

typescript - 无法在 typescript 1.7.3 中更改 Number.prototype

javascript - 使用日历在产品页面上的 magento 中出现 "TypeError: triggerElement is null "错误

javascript - WordPress jQuery 将值发送到数据库