TypeScript一问一答04 泛型函数进阶之彻底了解逆变协变

112 阅读2分钟

初篇

熟悉泛型函数的基本使用了吗?

是的

怎样用泛型函数去限定type parameter只能是true type?

type IsTrue<Parameter extends true> = Parameter

type True =  IsTrue<true>
// Type '"dd"' does not satisfy the constraint 'true'.
type TrueErr =  IsTrue<'dd'>  // 报错

好的开始进阶吧

进阶

怎样通过泛型函数定义queue类型?

queue 排队做检查 先来(push)的先走(shift)

class Queue<T> {
  data: Array<T> = [];
  constructor () {
    this.data = []
  }
  push(item: T): number { return this.data.push(item); }
  pop(): T | undefined { return this.data.shift(); }
}

let queue: Queue<number> = new Queue();

queue.push(1)
queue.push(2)
queue.pop() // 1

怎样通过泛型函数定义stack类型?

stack 堆盘子类型 先洗(push)的碗最后被用到(pop)

// Stack push pop
class Stack<T> {
  data: Array<T>
  constructor () {
    this.data = []
  }
  push(item: T): number { return this.data.push(item)}
  pop(): T | undefined  { return this.data.pop() }
}

let stack: Stack<number> = new Stack();

stack.push(1)
stack.push(2)
stack.pop() // 2

知道 Structural Type System 它是用来干什么的吗?

用来判断两个类型是否相等以及一个类型是否是另一个类型的子类型(subtype)

1.是否相等

type IsNumber<T extends number> = T

type eqNum = IsNumber<string> // 会报错

2.子类型(subtype)判断


典型例子,所有的原始类型是any type的子类型,因为any type的所有应用场景比各种原始类型的都大,如下图所示

type IsSubType<SubType, BaseType> = SubType extends BaseType ? true : false

type StrSub = IsSubType<string, any> // true
type NumSub = IsSubType<number, any> // true

type HiSub = IsSubType<'hi', string> // true
type OneSub = IsSubType<1, number> // true

subtype从属关系怎样用符号表示?

SubType -> BaseType

泛型(generic type)怎样用符号表示?

T<Parameter>

一个类型T是否是协变的(Covariant)是怎样定义的?

如果类型T是协变的,那么应该 满足 SubType -> BaseType 且 T< SubType > -> T< BaseType >

协变(Covariant)在TypeScript中怎么体现?

// 1. SubType -> BaseType 类型参数的满足
class User {
  username: string;
 
  constructor(username: string) {
    this.username = username;
  }
}
 
class Admin extends User {
  isSuperAdmin: boolean;
 
  constructor(username: string, isSuperAdmin: boolean) {
    super(username);
    this.isSuperAdmin = isSuperAdmin;
  }
}

type Sub = IsSubType<Admin, User> // true

// 第二个条件 T<SubType> -> T<BaseType>  那么 Array 类型是协变的
type ArrayBase = Array<User>
type ArraySub = Array<Admin>
type IsCovariant = IsSubType<ArraySub, ArrayBase> // true



一个类型T是否是逆变的(Contravariant)是怎样定义的?

如果类型T是逆变的,那么应该 满足 SubType -> BaseType 且 T< BaseType > -> T< SubType>

逆变(Contravariant)在TypeScript中怎么体现?


type ContravariantType<T> = (param: T) => void 
type Base2 = ContravariantType<User>
type Sub2 = ContravariantType<Admin>
type IsCovariant2 = IsSubType<Base2, Sub2> // true
type IsCovariant3 = IsSubType<Sub2, Base2> // false