類型兼容性用于確定一個類型是否能賦值給其他類型婚惫,TypeScript 結構化類型系統(tǒng)的基本規(guī)則是氛赐,如果 x 要兼容 y,那么 y 至少具有與 x 相同的屬性先舷。
示例
interface INamed {
name: string;
}
let x: INamed;
let y = {
name: 'funlee',
age: 18
};
x = y;
函數的兼容性
在考慮函數的兼容性的時候艰管,需要考慮一些額外的東西。
參數數量
要查看 x 是否能賦值給 y蒋川,首先看它們的參數列表牲芋,x 的每個參數必須能在 y 里找到對應類型的參數,注意的是參數的名字相同與否無所謂捺球,只看它們的類型缸浦。
let x = (a: number) => 0;
let y = (b: number, s: string) => 0;
y = x; // OK
x = y; // Error
返回類型
類型系統(tǒng)強制源函數的返回值類型必須是目標函數返回值類型的子類型。
interface Point2D {
x: number;
y: number;
}
interface Point3D {
x: number;
y: number;
z: number;
}
let iMakePoint2D = (): Point2D => ({ x: 0, y: 0 });
let iMakePoint3D = (): Point3D => ({ x: 0, y: 0, z: 0 });
iMakePoint2D = iMakePoint3D;
iMakePoint3D = iMakePoint2D; // ERROR: Point2D 不能賦值給 Point3D
可選的和 rest 參數
可選的(預先確定的)和 Rest 參數(任何數量的參數)都是兼容的:
let foo = (x: number, y: number) => {};
let bar = (x?: number, y?: number) => {};
let bas = (...args: number[]) => {};
foo = bar = bas;
bas = bar = foo;
枚舉的兼容性
枚舉與數字類型相互兼容氮兵。
enum Person {
name,
age,
love
}
let age = Person.age;
let num = 18;
age = num;
num = age;
來自于不同枚舉的枚舉變量裂逐,被認為是不兼容的。
enum Person {
name,
age,
love
}
enum Colors {
red,
blue,
green
}
let age = Person.age;
let blue = Colors.blue;
// age = blue; // error
類的兼容性
僅僅只有實例成員和方法會相比較泣栈,構造函數和靜態(tài)成員不會被檢查卜高。
class Animal {
feet: number;
constructor(name: string, numFeet: number) {}
}
class Size {
feet: number;
constructor(meters: number) {}
}
let a: Animal;
let s: Size;
a = s; // OK
s = a; // OK
私有的和受保護的成員必須來自于相同的類。
class Animal {
protected feet: number;
}
class Cat extends Animal {}
let animal: Animal;
let cat: Cat;
animal = cat; // ok
cat = animal; // ok
class Size {
protected feet: number;
}
let size: Size;
animal = size; // ERROR
size = animal; // ERROR
泛型的兼容性
TypeScript 類型系統(tǒng)基于變量的結構南片,僅當類型參數在被一個成員使用時掺涛,才會影響兼容性。如下例子中疼进,T 對兼容性沒有影響:
interface Empty<T> {}
let x: Empty<number>;
let y: Empty<string>;
x = y; // ok
當 T 被成員使用時薪缆,它將在實例化泛型后影響兼容性:
interface Empty<T> {
data: T;
}
let x: Empty<number>;
let y: Empty<string>;
x = y; // Error
如果尚未實例化泛型參數,則在檢查兼容性之前將其替換為 any:
let identity = function<T>(x: T): T {
// ...
};
let reverse = function<U>(y: U): U {
// ...
};
identity = reverse; // ok, 因為 `(x: any) => any` 匹配 `(y: any) => any`
類中的泛型兼容性與類的兼容性所提及一致:
class List<T> {
add(val: T) {}
}
class Animal {
name: string;
}
class Cat extends Animal {
meow() {
// ..
}
}
const animals = new List<Animal>();
animals.add(new Animal()); // ok
animals.add(new Cat()); // ok
const cats = new List<Cat>();
cats.add(new Animal()); // Error
cats.add(new Cat()); // ok