Typescript 从入门到放弃系列(八)-兼容性

189 阅读2分钟

TypeScript 的类型系统是它的一个重要特性,它可以在编译时检查类型错误,提高代码的可靠性和可维护性。但是,在实际开发中,我们经常需要与其他库或框架进行交互,这时就需要考虑 TypeScript 的兼容性问题。

TypeScript 的兼容性规则是基于结构子类型化(structural subtyping)的,也就是说,只要两个类型的结构相似,它们就是兼容的。

一.基本数据类型的兼容性

let temp: string | number;
let num!: number;
temp = num;

你要的我有就可以

let num: {
  toString(): string;
};
let str: string = "james";
num = str; // 字符串中具备toString()方法,所以可以进行兼容

二.接口兼容性

interface IAnimal {
  name: string;
  age: number;
}
interface IPerson {
  name: string;
  age: number;
  address: string;
}
let animal: IAnimal;
let person: IPerson = {
  name: "zf",
  age: 11,
  address: "回龙观",
};
animal = person;

接口的兼容性,只要满足接口中所需要的类型即可!

三.函数的兼容性

函数的兼容性主要是比较参数和返回值

  • 参数

    let sum1 = (a: string, b: string) => a + b;
    let sum2 = (a: string) => a;
    sum1 = sum2;
    

    赋值函数的参数要少于等于被赋值的函数,与对象相反,例如:

    type Func<T> = (item: T, index: number) => void;
    function forEach<T>(arr: T[], cb: Func<T>) {
      for (let i = 0; i < arr.length; i++) {
        cb(arr[i], i);
      }
    }
    forEach([1, 2, 3], (item) => {
      console.log(item);
    });
    
  • 返回值

    type sum1 = () => string | number;
    type sum2 = () => string;
    
    let fn1: sum1;
    let fn2!: sum2;
    fn1 = fn2;
    

四.函数的逆变与协变

函数的参数是逆变的,返回值是协变的 (在非严格模式下函数的参数是双向协变的)

class Parent {
  address: string = "回龙观";
}
class Child extends Parent {
  money: number = 100;
}
class Grandsom extends Child {
  name: string = "吉姆";
}
type Callback = (person: Child) => Child;
function execCallback(cb: Callback) {}
let fn = (person: Parent) => new Grandsom();
execCallback(fn);

通过这个案例可以说明,函数参数可以接收父类,返回值可以返回子类

五.类的兼容性

class Parent {
  name: string = "james";
  age: number = 18;
}
class Parent1 {
  name: string = "james";
  age: number = 18;
}
let parent: Parent = new Parent1();

这里要注意的是,只要有 private 或者 protected 关键字类型就会不一致;但是继承的类可以兼容

class Parent {
    private name: string = "james";
    age: number = 18;
}
class Parent1 {
    name: string = "james";
    age: number = 18;
}
let parent: Parent = new Parent1();
// Type 'Parent1' is not assignable to type 'Parent'.
// Property 'name' is private in type 'Parent' but not in type 'Parent1'.
class Parent1 {
  protected name: string = "zf";
  age: number = 11;
}
class Child extends Parent1 {}
let child: Parent1 = new Child();

六.泛型的兼容性

interface IT<T> {}
let obj1: IT<string>;
let obj2!: IT<number>;
obj1 = obj2;

七.枚举的兼容性

enum USER1 {
  role = 1,
}
enum USER2 {
  role = 1,
}
let user1!: USER1;
let user2!: USER2;
user1 = user2; // 错误语法
// Type 'USER2' is not assignable to type 'USER1'.ts(2322)

不同的枚举类型不兼容