类型兼容性用于确定一个类型是否能赋值给其他类型。
any
任何类型都能被赋值给any
let foo: any = 123;
foo = 'hello';
结构化
TypeScript 对象是一种结构类型,因此只要结构匹配就是兼容的
interface Point1 {
x: number;
y: number;
}
class Point2D {
constructor(public x: number, public y: number) {}
}
// OK Point2D: {x: 1, y: 2}
let p1: Point1 = new Point2D(1,2)
结构化数据如果包含原数据,也是可行的
interface Point2D {
x: number;
y: number;
}
interface Point3D {
x: number;
y: number;
z: number;
}
const point2D: Point2D = { x: 0, y: 10 };
const point3D: Point3D = { x: 0, y: 10, z: 20 };
function PointFn(point: Point2D) {
/* do something */
}
// 额外的信息,没关系
PointFn(point3D)
// 缺少信息,不行
PointFn({x: 1})
函数
返回类型如果包含更多的数据,函数是兼容的
interface Point2D {
x: number;
y: number;
}
interface Point3D {
x: number;
y: number;
z: number;
}
let f1 = (): Point2D => ({x: 1, y: 2})
let f2 = (): Point3D => ({x: 1, y: 2, z: 3})
// OK, f2包含更多的数据
f1 = f2
// ERROR
f2 = f1
函数的参数如果少于定义的类型,函数参数是兼容的
// f1接受一个callback函数,callback函数接收两个参数,无返回值
const f1 = (x: (err: any, data: any) => void) => {}
// OK
f1((err) => null)
// OK
f1(() => null)
// ERROR
f1((err, data, more) => null)
可选参数、确定参数和rest参数互相兼容
let f1 = (x: number, y: number) => {}
let f2 = (...args: number[]) => {}
let f3 = (x?: number, y?: number) => {}
f1 = f2 = f3
f3 = f2 = f1
f1 = f3 = f2
枚举
枚举与数字类型相互兼容
enum Status {
Ready,
Waiting
}
let status = Status.Ready;
let num = 0;
status = num;
num = status;
不同枚举的枚举变量是不兼容的
enum Status {
Ready,
Waiting
}
enum Color {
Red,
Blue,
Green
}
let status = Status.Ready;
let color = Color.Red;
status = color; // Error
类
构造函数和静态成员不会被检查
class Animal {
feet: number;
constructor(name: string, numFeet: number) {}
}
class Size {
feet: number;
constructor(meters: number) {}
}
let a: Animal = new Animal('wmui', 18);
let s: Size = new Size(18);
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
泛型
当类型参数被内部成员使用时,会影响兼容性
interface Empty<T> {
data: T;
}
let x: Empty<number>;
let y: Empty<string>;
x = y; // Error
当类型参数没有被内部使用时,不存在兼容性问题
interface Empty<T> {}
let x: Empty<number>;
let y: Empty<string>;
x = y; // ok
如果尚未实例化泛型参数,则在检查兼容性之前将其替换为 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