TS类型之Omit与Exclude、keyof与typeof的区别

560 阅读2分钟

在使用TS的过程中总是对Omit和Exclude,keyof,typeof有点混淆;特此记录一下

keyof

keyof 操作符是在 TypeScript 2.1 版本引入的,该操作符可以用于获取某种类型的所有键,其返回类型是联合类型。

  • 注意 keyof 是获取类型【公有属性】的键值;所以对应联合类型type A='a'|'b'|'c'使用 keyof 关键字返回的不是'a'|'b'|'c'。例子如下:
type unionType = 'a'|'b'|'c'|'d';
type mapType = {
  [k in unionType] : string;
}

// 以下的用法,TS直接报错说Omit的结果无法分配给string类型
type mappedTypeWithOmit = {
  [k in Omit<unionType,"d">] : string
}

type c = Omit<unionType,"d"> ;//c的类型请看下面截图
  • 注意 keyof 用在枚举和联合类型上往往和期望的值不一样;要特别注意

type_C.PNG

  • keyof 也支持基本数据类型:
let K1: keyof boolean; //let K1:'valueOf'
let K2: keyof number; //let K2: "toString" | "toFixed" | "toExponential" | "toPrecision" | "valueOf" | "toLocaleString"
let K3: keyof symbol; //let K3: typeof Symbol.toStringTag | typeof Symbol.toPrimitive | "toString" | "valueOf" | "description"

typeof

  • typeof 的主要用途是在类型上下文中获取变量和属性的类型
interface Person {
  name: string;
  age: number;
}

const sem: Person = { name: "Tom", age: 30 };
type Sem = typeof sem;

// 上面代码中,通过typeof操作符获取变量sem的类型并赋值给Sem类型变量,之后就可以使用Sem类型:
const lolo: Sem = {
  name: "lolo",
  age: 5
};
// 也可以对嵌套类型执行相同的操作:
const Message = {
  name: "jimmy",
  age: 18,
  address: {
    province: "四川",
    city: "成都"
  }
};
type message = typeof Message;
/*
 type message = {
    name: string;
    age: number;
    address: {
        province: string;
        city: string;
    };
}
*/
  • 此外,typeof 操作符除了可以获取对象的结构类型之外,它也可以用来获取函数对象的类型:
function toArray(x: number): Array<number> {
  return [x];
}
type Func = typeof toArray; //->(x:number)=>number[]

Exclude

  • Exclude<T, U>的作用是将把类型T中含有类型U的属性移除
type Exclude<T, U> = T extends U ? never : T;
// 如果T能赋值给U类型的话,name就会返回never类型,否则返回T类型,最终实现的效果就是将T中某些属于U的类型移除掉。
type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
type T1 = Exclude<"a" | "b" | "c", "a" | "b">; // "c"
type T2 = Exclude<string | number | (() => void), Function>; // string | number

Omit

  • Omit<T, K extends keyof any>的作用是使用 T 类型中除了 K 类型的所有属性,来构造一个新的类型;
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
// 使用
interface Todo {
  title: string;
  description: string;
  completed: boolean;
}

type TodoPreview = Omit<Todo, "description">;

const todo: TodoPreview = {
  title: "Clean room",
  completed: false
};

总结

  • 注意 Omit 与 Exclude 的区别;个人理解是 Omit 一般用于对象似的类型和 interface 类型;一般不用于联合类型;而 Exclude 可以用于联合类型,一般不用于 interface 类型和对象似的类型;
  • keyof 是获取类型的键值;
  • typeof 的主要用途是在类型上下文中获取变量和属性的类型