文章转载自:https://github.com/zhongsp

介绍

TypeScript 里的类型兼容性基于结构子类型的。结构类型是只使用其成员来描述类型的方式,它正好与名义类型形成对比:

interface Named {
    name: string;
}

class Person {
    name: string;
}

var p: Named;
p = new Person();  // OK,因为结构类型兼容

在使用名义类型的语言(比如 C# 或 Java)中,这段代码会报错,因为 Person 类没有明确说明其实现了 Named 接口。

开始

TypeScript 结构化类型系统的基本规则是,如果 x 要兼容 y,那么 y 至少具有与 x 相同的属性:

interface Named { name: string; }

var x: Named;
var y = { name: 'Alice', location: 'Seattle' };
x = y;  // OK,y 包含 name 属性

比较两个函数

var x = (a: number) => 0;
var y = (b: number, s: string) => 0;

y = x;  // OK,x 的参数在 y 中都能找到
x = y;  // Error,y 有必需的第二个参数,x 没有

JavaScript 里忽略额外的参数是很常见的(如 Array#forEach 的回调),TypeScript 允许这种行为。

返回值类型:

var x = () => ({name: 'Alice'});
var y = () => ({name: 'Alice', location: 'Seattle'});

x = y;  // OK
y = x;  // Error,x() 缺少 location 属性

枚举

枚举类型与数字类型兼容,并且数字类型与枚举类型兼容。不同枚举类型之间是不兼容的:

enum Status { Ready, Waiting };
enum Color { Red, Blue, Green };

var status = Status.Ready;
status = Color.Green;  // Error

类与对象字面量和接口差不多,但有一点不同:类有静态部分和实例部分的类型。比较两个类类型的对象时,只有实例的成员会被比较,静态成员和构造函数不在比较的范围内:

class Animal {
    feet: number;
    constructor(name: string, numFeet: number) { }
}

class Size {
    feet: number;
    constructor(numFeet: number) { }
}

var a: Animal;
var s: Size;

a = s;  // OK
s = a;  // OK

私有成员会影响兼容性判断:如果目标类型包含一个私有成员,那么源类型必须包含来自同一个类的这个私有成员。

泛型

因为 TypeScript 是结构性的类型系统,类型参数只影响使用其做为类型一部分的结果类型:

interface Empty<T> { }
var x: Empty<number>;
var y: Empty<string>;
x = y;  // OK,结构相同

interface NotEmpty<T> { data: T; }
var x: NotEmpty<number>;
var y: NotEmpty<string>;
x = y;  // Error,结构不同

<
Previous Post
转载:《TypeScript 中文入门教程》 16、Symbols
>
Next Post
转载:《TypeScript 中文入门教程》 12、类型推导