类型兼容性就是看一个类型能赋值给其他类型。Typescript 的兼容性是基于结构类型的。如果x要兼容y,那么y至少具有与x相同的属性。

基本类型

  1. // 基本类型兼容性
  2. let num:string | number;
  3. let str: string = 'str'
  4. num = str
  5. let num2:{ // 有个 toString方法,并且返回string
  6. toString():string
  7. }
  8. let str2:string = 'll' // 字符串也有个toString 方法
  9. num2=str2
  10. str2 = num2 // 不能将类型“{ toString(): string; }”分配给类型“string” num2 至少要具有与str2 相同的的属性

接口兼容

  1. interface Animal{
  2. name: string;
  3. age: number
  4. }
  5. interface Person1{
  6. name: string
  7. age: number;
  8. gender: string
  9. }
  10. function getName(a: Animal):string{
  11. return a.name
  12. }
  13. let a1: Animal = {
  14. name: '',
  15. age: 10
  16. }
  17. getName(a1)
  18. let p: Person1 = {
  19. name: '',
  20. age: 10,
  21. gender: 'man'
  22. }
  23. getName(p) // 因为Animal里的属性,Person里都有
  24. let p2 = {
  25. name: '',
  26. }
  27. getName(p2) // Property 'age' is missing in type '{ name: string; }' but required in type 'Animal'.ts(2345)

类类型兼容性

类类型的兼容性,只比较实例成员和方法,类的静态成员和构造函数不进行比较:

  1. class Animal {
  2. static age: number;
  3. constructor(public name: string) {}
  4. }
  5. class People {
  6. static age: string;
  7. constructor(public name: string) {}
  8. }
  9. class Food {
  10. constructor(public name: number) {}
  11. }
  12. let a: Animal;
  13. let p: People;
  14. let f: Food;
  15. a = p; // ok
  16. a = f; // error Type 'Food' is not assignable to type 'Animal'

函数类型兼容性

1.参数

(1)参数类型

  1. let x = (a: number) => 0;
  2. let y = (b: number, s: string) => 0;
  3. y = x; // OK x是否能赋值给y, 就看x的每个参数必须能在y里找到对应类型的参数。
  4. x = y; // Error y有个必需的第二个参数类型string,但是x并没有,所以不允许赋值。

(2)参数个数

参数个数只能少不能多

  1. let x = (a: number) => 0;
  2. let y = (b: number, s: string) => 0;
  3. y = x; // OK x 赋值给y,y有两个参数,x的参数个数只能小于等于y的参数个数。
  4. x = y; // Error y参数个数只能少于等于 x 的参数个数

为什么允许忽略参数,像例子y = x中那样。 原因是忽略额外的参数在JavaScript里是很常见的。 例如,Array#forEach给回调函数传3个参数:数组元素,索引和整个数组。 尽管如此,传入一个只使用第一个参数的回调函数也是很有用的。

(3)剩余参数和可选参数

  1. const getNum = ( // 这里定义一个getNum函数,他有两个参数
  2. arr: number[], // 第一个参数是一个数组
  3. callback: (...args: number[]) => number // 第二个参数是一个函数,这个函数的类型要求可以传入任意多个参数,但是类型必须是数值类型,返回值必须是数值类型
  4. ): number => {
  5. return callback(...arr); // 这个getNum函数直接返回调用传入的第二个参数这个函数,以第一个参数这个数组作为参数的函数返回值
  6. };
  7. getNum(
  8. [1, 2],
  9. (...args: number[]): number => args.length // 这里传入一个函数,逻辑是返回参数的个数
  10. );
  1. const getNum = (
  2. arr: number[],
  3. callback: (arg1: number, arg2?: number) => number // 这里指定第二个参数callback是一个函数,函数的第二个参数为可选参数
  4. ): number => {
  5. return callback(...arr); // error 应有 1-2 个参数,但获得的数量大于等于 0
  6. };

2.返回值

返回值个数只能大于等于不能少于。

  1. let x = () => ({name: 'Alice'});
  2. let y = () => ({name: 'Alice', location: 'Seattle'});
  3. x = y; // OK y 赋值给x,y的返回值个数只能大于或等于x返回值的个数
  4. y = x; // Error, because x() lacks a location property

3.函数重载

4.函数的协变与逆变

A ≼ B,意味着A是B的子类型
返回值类型时协变,参数类型时逆变。
返回值可以传子类,参数可以传父类。

  1. class Animal3{}
  2. class Dog3 extends Animal3{}
  3. class BlackDog extends Dog3{}
  4. class WhiteDog extends Dog3{}
  5. let animal3: Animal3
  6. let blackDog: BlackDog
  7. let whiteDog: WhiteDog
  8. type callback = (dog: Dog3) => Dog3 // 函数
  9. function exec(callback: callback): void{ // 参数是callback
  10. callback(whiteDog)
  11. }
  12. type ChildToChild = (blackDog: BlackDog) => BlackDog
  13. let childToChild: ChildToChild
  14. exec(childToChild) // error
  15. type ChildToParent = (blackDog: BlackDog) => Animal3
  16. let childToParent:ChildToParent
  17. exec(childToParent) // error
  18. type ParentToParent = (animal3: Animal3) => Animal3
  19. let parentToParent: ParentToParent
  20. exec(parentToParent) // error
  21. type ParentToChild = (animal3: Animal3) => BlackDog
  22. let parentToChild: ParentToChild
  23. exec(parentToChild) //

四种情况:
参数是子类,返回值是子类
参数是子类,返回值是父类
参数是父类,返回值是父类
参数是父类,返回值是子类
只有最后一种情况才正确
参数可以传自己和自己的父类,返回值可以传自己和自己的子类。

泛型类型兼容性

  1. class GrandFather1{
  2. grandFather: string = ''
  3. }
  4. class Father1 extends GrandFather1{
  5. father: string = ''
  6. }
  7. class Child1 extends Father{
  8. child: string = ''
  9. }
  10. function get<T extends Father>(){
  11. }
  12. get<GrandFather1>; //类型“GrandFather1”不满足约束“Father”。类型 "GrandFather1" 中缺少属性 "father",但类型 "Father" 中需要该属性
  13. get<Child>()