TS 知识点

132 阅读2分钟

一、 unknown 和 any 的区别

  • unknown 和 any 都是top type,但是 any 还同时是bottom type;
// 1. 任何类型都可以赋值给 unknown 和 any(包括彼此)
let a: unknown = 2;
let b: any = 3;
// any 也可以赋值给 unknown,unknown 也可以赋值给 any
a = b;
b = a;
// 2. unknown 只能赋值给 unknown 和 any
let c: number = a; // 报错,unknown 不能赋值给 number
let d: unknown = a; // 不报错,unknown 可以赋值给 unknown
// 3. any 可以赋值给任何类型
let e: number = b; // 不报错,any 可以赋值给 number
d = b; // 不报错,any 可以赋值给 unknown
  • unknow 比 any 更安全。因为如果 unknown 没有先断言或者缩小到一个更具体的类型,则不允许对一个 unknown 进行任何操作(会报错)。
let a: unknown = 2;
console.log(a.toString()); // 报错,'a' is of type 'unknown'.
console.log(a++); // 报错,'a' is of type 'unknown'.
console.log((a as number).toString()); // 正常输出字符串'2'

二、手写一些 ts 的方法

1. Partial

 type MyPartial<T> = {
  [k in keyof T]?: T[k];
};   

2. Pick<T, K>

使用:从T中挑选一组属性K组成新的类型。

interface A {
  a: string;
  b: number;
  c: boolean;
}
type T = Pick<A, 'a' | 'b'>;
// type T = {a: string; b:number}

手写:

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

3. Exclude<T, U>

使用:提取存在于T但不存在于U的类型组成联合类型

type T1 = Exclude<string | number, number>;  // T1 = string
type T2 = Exclude<'a' | 'b', 'a'>;  // T2 = 'b'

手写:

type MyExclude<T, U> = T extends U ? never : T;

4. Extract<T, U>

使用:提取联合类型T和联合类型U的交集

type T = Extract<'a' | 'b', 'b' | 'c'>; // T = "b"
type T1 = Extract<string | number, number>;  // T1 = number

手写:

type MyExtract<T, U> = T extends U ? T : never;

5. Omit<T, K>

使用:从T中剔除K的所有属性

interface A {
  a: string;
  b: number;
}
type T = Omit<A, 'a'>;  // T={b:number}

手写:

type MyOmit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

6. Record<K extends keyof any, T>

使用:构造一个type,key为联合类型K中的子类型,类型为T

type T7 = Record<'a' | 'b', number>; 
/* 
T7 = {  
  a: number;  
  b: number;  
}
*/
type T8 = Record<'a' | 'b', { name: string }>;
/* 
T8 = {  
  a: {  
    name: string;  
  };  
  b: {  
    name: string;  
  };  
}
*/

手写:

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

三、ts 混入