Published on

TypeScript 泛型

Authors
  • avatar
    Name
    叫我小N就好啦
    GitHub
    @MinorN

TypeScript——泛型

什么是泛型?

泛:多;泛型:多种类型

只要能看懂JS的函数,其实就能看懂TS的泛型

// js
const f = (a, b) => a + b
const result = f(1, 2)
// 返回的是值

// ts
type F<A, B> = A | B
type Result = F<string, number> // string | number
// 返回的是类型

为什么会有泛型?

function echo(n: string | number | boolean) {
  return n
}
// Q:echo的返回值类型是什么呢?
// A: string | number |boolean ? 错误,是要有一一对应的关系,接受string返回string,接受number返回number

// 那么手动进行类型收窄?
function echo(n: string | number | boolean) {
  switch (typeof n) {
    case 'number':
      return n
      break
    case 'string':
      return n
      break
    case 'boolean':
      return n
      break
  }
}
// 可以试试?还是做不到!

example 1

type Union<A, B> = A | B

type Union3<A, B, C> = A | B | C

type Intersect<A, B> = A & B

type Intersect3<A, B, C> = A & B & C

interface List<A> {
  [index: number]: A
}
type X = List<string>
type Y = List<string | number>

interface Hash<V> {
  [key: string]: V
}

interface Hash<V = string> {
  [key: string]: V
}
// 默认值为 string

example 2

type Person = { name: string }

type LikeString<T> = T extends string ? true : false
type LikeNumber<T> = T extends number ? 1 : 2
type LikePerson<T> = T extends Person ? 'yes' : 'no'
type R1 = LikeString<'hi'> // true
type R2 = LikeString<true> // false
type S1 = LikeNumber<666666> // 1
type S2 = LikeNumber<false> // 2
type T1 = LikePerson<{ name: 'minorn'; xxx: 1 }> // yes
type T2 = LikePerson<{ xxx: 1 }> // no

规则:(前提是使用泛型)

  1. 如果传的类型是never,条件类型不适用,返回的类型是never
const a = LikeString<never> // never
  1. 如果T为联合类型,则分开计算
type ToArray<T> = T extends unknown ? T[] : never

type Result = ToArray<string | number>
// string[] | number[]

在泛型中使用keyof

type Person = { name: sting; age: number }
type GetKeys<T> = keyof T
type Result = GetKeys<Person> // 'name' | 'age'

example 3

type Person = { name: sting; age: number }
type GetKeyType<T, K extends keyof T> = T[K]
type Result = GetKeys<Person, 'name'> // string

TypeScript——泛型进阶

example 4

type Person = {
    name:strgin,
    age:number    id:number
}
type Readonly<T> = {
    readonly [K in keyof T] : T[K]
}
type X1 = Readonly<Person>

type Partial<T> = {
    [K in keyof T] ?: T[K]
}
type X2 = Partial<Person>

type Required<T> = {
    [K in keyof T] -?: T[K]
}
type X3 = Required<Person>

type Record<Key extends string|number|symbol,Value> = {
    [k in Key] : Value
}
// key 只有三种情况 string number symbol
type X4 = Record<string,number>

type Exclude<A,B> = A extends B ? never : A
// 看A的每一项在不在B里面,其实就是 乘法分配率
// 1 extends 1|2 ? =>never
// 2 extends 1|2 ? =>never
// 3 extends 1|2 ? =>3
type X5 = Exclude<1|2|3, 1|2>  // 3

type Extract<A,B> = A extends B ? A : never
// 同理
type X6 = Extract<1|2|3, 2|4>  // 2

type Omit<T,K> = {
    [Key in keyof T as Key extends K ? never : Key] : T
}
// ?????
// 分成两段
// Key in keyof T ,就是 Key必须是 T 的 key
// 后面 as 是断言,接上前面的,如果得出来的Key 在K里面,就是never,否则保留
type X7 = Omit<Person,'name'|'age'>
// Omit 是忽略

// 取 name age
type Pick<T,Key extends keyof T> = {
    [K in key] : T[K]
}
type X8 = Pick<Person, 'name'| 'age'>

// 如何用Pick来实现Omit
type Omit<T,Key extends keyof T> = Pick<T, Exclude<keyof T,Key>>

example 5

type Person = {
    readonly name:strgin,
    readonly age:number    readonly id:number
}

type Mutable<T> = {
    -readonly [K in keyof T]: T[K]
}

type Y = Mutable<Person> // 从 只读 变为 可写

推荐练习

Type Chanllenges