类型兼容性就是看一个类型能赋值给其他类型。Typescript 的兼容性是基于结构类型的。如果x要兼容y,那么y至少具有与x相同的属性。
基本类型
// 基本类型兼容性let num:string | number;let str: string = 'str'num = strlet num2:{ // 有个 toString方法,并且返回stringtoString():string}let str2:string = 'll' // 字符串也有个toString 方法num2=str2str2 = num2 // 不能将类型“{ toString(): string; }”分配给类型“string” num2 至少要具有与str2 相同的的属性
接口兼容
interface Animal{name: string;age: number}interface Person1{name: stringage: number;gender: string}function getName(a: Animal):string{return a.name}let a1: Animal = {name: '',age: 10}getName(a1)let p: Person1 = {name: '',age: 10,gender: 'man'}getName(p) // 因为Animal里的属性,Person里都有let p2 = {name: '',}getName(p2) // Property 'age' is missing in type '{ name: string; }' but required in type 'Animal'.ts(2345)
类类型兼容性
类类型的兼容性,只比较实例成员和方法,类的静态成员和构造函数不进行比较:
class Animal {static age: number;constructor(public name: string) {}}class People {static age: string;constructor(public name: string) {}}class Food {constructor(public name: number) {}}let a: Animal;let p: People;let f: Food;a = p; // oka = f; // error Type 'Food' is not assignable to type 'Animal'
函数类型兼容性
1.参数
(1)参数类型
let x = (a: number) => 0;let y = (b: number, s: string) => 0;y = x; // OK x是否能赋值给y, 就看x的每个参数必须能在y里找到对应类型的参数。x = y; // Error y有个必需的第二个参数类型string,但是x并没有,所以不允许赋值。
(2)参数个数
参数个数只能少不能多
let x = (a: number) => 0;let y = (b: number, s: string) => 0;y = x; // OK x 赋值给y,y有两个参数,x的参数个数只能小于等于y的参数个数。x = y; // Error y参数个数只能少于等于 x 的参数个数
为什么允许忽略参数,像例子y = x中那样。 原因是忽略额外的参数在JavaScript里是很常见的。 例如,Array#forEach给回调函数传3个参数:数组元素,索引和整个数组。 尽管如此,传入一个只使用第一个参数的回调函数也是很有用的。
(3)剩余参数和可选参数
const getNum = ( // 这里定义一个getNum函数,他有两个参数arr: number[], // 第一个参数是一个数组callback: (...args: number[]) => number // 第二个参数是一个函数,这个函数的类型要求可以传入任意多个参数,但是类型必须是数值类型,返回值必须是数值类型): number => {return callback(...arr); // 这个getNum函数直接返回调用传入的第二个参数这个函数,以第一个参数这个数组作为参数的函数返回值};getNum([1, 2],(...args: number[]): number => args.length // 这里传入一个函数,逻辑是返回参数的个数);
const getNum = (arr: number[],callback: (arg1: number, arg2?: number) => number // 这里指定第二个参数callback是一个函数,函数的第二个参数为可选参数): number => {return callback(...arr); // error 应有 1-2 个参数,但获得的数量大于等于 0};
2.返回值
返回值个数只能大于等于不能少于。
let x = () => ({name: 'Alice'});let y = () => ({name: 'Alice', location: 'Seattle'});x = y; // OK y 赋值给x,y的返回值个数只能大于或等于x返回值的个数y = x; // Error, because x() lacks a location property
3.函数重载
4.函数的协变与逆变
A ≼   B,意味着A是B的子类型
返回值类型时协变,参数类型时逆变。
返回值可以传子类,参数可以传父类。
class Animal3{}class Dog3 extends Animal3{}class BlackDog extends Dog3{}class WhiteDog extends Dog3{}let animal3: Animal3let blackDog: BlackDoglet whiteDog: WhiteDogtype callback = (dog: Dog3) => Dog3 // 函数function exec(callback: callback): void{ // 参数是callbackcallback(whiteDog)}type ChildToChild = (blackDog: BlackDog) => BlackDoglet childToChild: ChildToChildexec(childToChild) // errortype ChildToParent = (blackDog: BlackDog) => Animal3let childToParent:ChildToParentexec(childToParent) // errortype ParentToParent = (animal3: Animal3) => Animal3let parentToParent: ParentToParentexec(parentToParent) // errortype ParentToChild = (animal3: Animal3) => BlackDoglet parentToChild: ParentToChildexec(parentToChild) //
四种情况:
参数是子类,返回值是子类
参数是子类,返回值是父类
参数是父类,返回值是父类
参数是父类,返回值是子类
只有最后一种情况才正确
参数可以传自己和自己的父类,返回值可以传自己和自己的子类。
泛型类型兼容性
class GrandFather1{grandFather: string = ''}class Father1 extends GrandFather1{father: string = ''}class Child1 extends Father{child: string = ''}function get<T extends Father>(){}get<GrandFather1>; //类型“GrandFather1”不满足约束“Father”。类型 "GrandFather1" 中缺少属性 "father",但类型 "Father" 中需要该属性get<Child>()
