类型兼容性
函数
1.函数参数个数
左边的个数大于右边
如果对函数 y 进行赋值,那么要求 x 中的每个参数都应在 y 中有对应,也就是 x 的参数个数小于等于 y 的参数个数
let x = (a: number) => 0;
let y = (b: number, c: string) => 0;
2.函数参数类型
let x = (a: number) => 0; let y = (b: string) => 0; let z = (c: string) => false; x = y; // error 不能将类型“(b: string) => number”分配给类型“(a: number) => number”。 x = z; // error 不能将类型“(c: string) => boolean”分配给类型“(a: number) => number”。
3.剩余参数和可选参数
const getNum = ( arr: number[], callback: (arg1: number, arg2?: number) => number // 这里指定第二个参数callback是一个函数,函数的第二个参数为可选参数 ): number => { return callback(...arr); // error 应有 1-2 个参数,但获得的数量大于等于 0 };
4.函数参数双向协变
函数参数双向协变即参数类型无需绝对相同
他们的联合类型相同即可
5.函数返回值类型
函数返回值应该是同种类型,不同就会报错的
6.函数重载
function merge(arg1: number, arg2: number): number; // 这是merge函数重载的一部分 function merge(arg1: string, arg2: string): string; // 这也是merge函数重载的一部分 function merge(arg1: any, arg2: any) { // 这是merge函数实体 return arg1 + arg2; } function sum(arg1: number, arg2: number): number; // 这是sum函数重载的一部分 function sum(arg1: any, arg2: any): any { // 这是sum函数实体 return arg1 + arg2; } let func = merge; func = sum; // error 不能将类型“(arg1: number, arg2: number) => number”分配给类型“{ (arg1: number, arg2: number): number; (arg1: string, arg2: string): string; }”
上面例子中,sum函数的重载缺少参数都为string返回值为string的情况,与merge函数不兼容,所以赋值时会报错。
类
1.比较两个类类型的值的兼容性时,只比较实例的成员,类的静态成员和构造函数不进行比较
类类型比较兼容性时,只比较实例的成员
class Animal {
//成员
static age: number;
constructor(public name: string) {}
}
class People {
//成员
static age: string; constructor(public name: string) {} }
2.类的私有成员和受保护成员
类的私有成员和受保护成员会影响兼容性。当检查类的实例兼容性时,如果目标(也就是要被赋值的那个值)类型(这里实例类型就是创建它的类)包含一个私有成员,那么源(也就是用来赋值的值)类型必须包含来自同一个类的这个私有成员,这就允许子类赋值给父类。
泛型
泛型包含类型参数,这个类型参数可能是任意类型,使用时类型参数会被指定为特定的类型,而这个类型只影响使用了类型参数的部分。来看例子:
interface Data<T> {}
let data1: Data<number>;
let data2: Data<string>;
data1 = data2;
在这个例子中,data1 和 data2 都是 Data 接口的实现,但是指定的泛型参数的类型不同,TS 是结构性类型系统,所以上面将 data2 赋值给 data1 是兼容的,因为 data2 指定了类型参数为 string 类型,但是接口里没有用到参数 T,所以传入 string 类型还是传入 number 类型并没有影响
越努力越幸运