TypeScript——小知识总结

346 阅读3分钟

泛型

假如我们要实现一个函数,这个函数会返回任何传入它的值。不用泛型的话就只能使用any或者是用类型推断。这时用泛型就是一个很好的选择。

function identity<T>(arg: T): T {
    return arg;
}

泛型简单来说就是当你传进来的参数是string,那么T在这个执行中就等于string。

never

官方文档所说

never 类型表示的是那些永不存在的值的类型。 例如, never 类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型; 变量也可能是 never 类型,当它们被永不为真的类型保护所约束时。 never 类型是任何类型的子类型,也可以赋值给任何类型;然而,没有类型是 never 的子类型或可以赋值给 never 类型(除了 never 本身之外)。 即使 any 也不可以赋值给 never。

never不能被赋值,而且代表的是无法到达的终点。也就是说你的程序就不应该执行到这,never的其中一个用法就是收窄类型。

下面举个尤大大说的例子,假如你有一个联合类型

interface Foo {
  type: 'foo'
}

interface Bar {
  type: 'bar'
}

type All = Foo | Bar

在 switch 当中判断 type,TS 是可以收窄类型的 (discriminated union):

function handleValue(val: All) {
  switch (val.type) {
    case 'foo':
      // 这里 val 被收窄为 Foo
      break
    case 'bar':
      // val 在这里是 Bar
      break
    default:
      // val 在这里是 never
      const exhaustiveCheck: never = val
      break
  }
}

注意在 default 里面我们把被收窄为 never 的 val 赋值给一个显式声明为 never 的变量。如果一切逻辑正确,那么这里应该能够编译通过。但是假如后来有一天你的同事改了 All 的类型:

type All = Foo | Bar | Baz

然而他忘记了在 handleValue 里面加上针对 Baz 的处理逻辑,这个时候在 default branch 里面 val 会被收窄为 Baz,导致无法赋值给 never,产生一个编译错误。所以通过这个办法,你可以确保 handleValue 总是穷尽 (exhaust) 了所有 All 的可能类型。

keyof

keyof的作用就是取所有的键,只取键,并且keyof 取到键后会保存为联合类型。

interface person {
  sex: string;
  age: number;
}
type keys = keyof person; // type keys =sex | age

in

in的作用是遍历所有的健

type age = 'dog' | 'cat';
type age={
  [key in age]:number;
};

/*  相当于
*  type age={
*     dog:number;
*     cat:number;
*/ };

映射类型

  • Partial
  • Required
  • Readonly
  • Pick<T,K extends keyof T>
  • Record<K extends keyof any, T>
  • Exclude<T,U> 主要用于联合类型
  • Extract<T,U>
  • Omit<T, K extends keyof any> 主要用于interface

Partial,Required,Readonly

Partial,Required,Readonly这三个比较简单,所以就一起讲了

  1. Partial作用是将属性变为可选属性

     type Partial<T> = {
       [P in keyof T]?: T[P];
     };
    

用法:

interface Age:{
    son:number;
    father:number;
};

type person=Partial<Age>

/* person就等于
*interface person:{
*   son?:number;
*   father?:number;
*/};

下面同理
2. Required作用是将属性变成必须属性

    type Required<T> = {
        [P in keyof T]-?: T[P];
    };
  1. Readonly作用是将属性变成只读属性

     type Readonly<T> = {
         readonly [P in keyof T]: T[P];
     };
    

Pick与Record

pick是筛选出我想要的属性。
源码如下:

type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};

    interface Age:{
        son:number;
        father:number;
    };
    
    type person=Pick<Age,'son'>
    
    /* person就等于
    *interface person:{
    *   son:number;
    */};

pick会在Age中筛选出son的属性赋值给person

Record将某个类型转化成目标类型。
官方源码:

type Record<K extends keyof any, T> = {
    [P in K]: T;
};

将K中的每个属性([P in K]),都转为T类型

interface Age:{
            son:number;
            father:number;
        };
        
type person=Record<Age,string>

   /*
    *这时person就等于:
    *interface person:{
    *            son:string;
    *            father:string;
    *        };
    */