TypeScript中的高级类型工具类型及关键字

2020-11-13 10:02:46 浏览数 (1)

本文主要帮助理解 TypeScript 中的高级类型及工具类型。在实际使用 TypeScript 的开发过程中,得益于这些高级类型于工具类型,我们可以更方便的构建出我们需要的类型。

比如说:我们在后台登陆信息认证中构建了一个用户,它是 LoginUser 的类型, 它包含了:“name 用户名”、“email 邮箱”、“roles:角色”等多个信息,其中 name 可能不是必选项。但是未登录时它肯定是一个 Undefined 的类型。当进行权限认证时它是只读的,当进行用户名 name 进行修改时 name 是必选属性。

代码语言:txt复制
type LoginUser = {
  name?: string;
  email: string;
  roles: string[];
};

type CurrentUser = LoginUser | undefined;

type Muteable<T> = {
   readonly [P in keyof T]: T[P];
};
type CertUser = Muteable<LoginUser>;
type SuerUser = Required<LoginUser>;

如果每个类型都重新声明一个新类型来满足程序,代码将会变得臃肿,反之如果我们高级类型来解决时,他将会变得简单高效。

一、高级类型

泛型

泛型可以理解为一个变量,这个变量的值是一个类型。和函数的参数一样。它通常配合一组尖括号进行声明使用:

代码语言:txt复制
// 一个带有 name 属性的类型
type Cup = {
  name: string;
};
// 声明一个接收三个参数的函数,
// 第一个参数是必须拥有name属性的 object
// 第二个参数设置为第一个参数这个对象中的一个属性
// 第三个参数设置为第二个参数的属性值
const addAttr = <T extends {name: string}, K, U>(obj: T, attrName: K, attrValue: U) => {
  const temp: any = {};
  temp[attrName] = attrValue;
  return {...obj, ...temp};
};
// 函数名后使用尖括号传入限定类型
addAttr<Cup, string, number>({ name: 'mgdi' }, 'age', 18);

联合类型

联合类型是指将多个类型结合,使用 符号进行连接。当使用这个类型时,值只需满足其中一个类型即可

代码语言:txt复制
// 声明Foo类型
type Foo = {
  width: number;
}
// 声明一个Bar类型
type Bar = {
  height: number;
}
// 声明一个Foo, Bar的联合类型
type Baz = Foo | Bar;
// 赋值时只需要满足其中一个类型即可
const baz: Baz = {
  width: 20,
//  height: 10
}

字面量类型

字面量类型与联合类型很像,不同之处在于,联合类型用 | 分割的是类型,而字面量类型分割的是值。

代码语言:txt复制
type Roles = 'student' | 'teacher' | 'kids';
const ading: Roles = "kids";

枚举类型

enum 类型通常也是多个键值对的集合,使用其类型时赋值只能是声明的值之一。

代码语言:txt复制
enum UserRoleType {
  GHOST = "ghost",
  EDITOR = "editor",
  PUBLISH = "publish",
  ADMIN = "admin",
}
const ading: UserRoleType = UserRoleType.ADMIN;

交叉类型

交叉类型是多个类型的集合,使用 “ & ”连接多个类型,使用其作为值类型时必需同时满足所有类型。

代码语言:txt复制
// 声明Foo类型
type Foo = { width: number }
// 声明一个Bar类型
type Bar = { height: number }
// 声明一个Foo, Bar的交叉类型
type Baz = Foo & Bar;
const baz: Baz = {
  width: 3,
  heght: 4,
}

类型断言

类型断言指将一个不确定的类型断言为一个自己确定的类型。通常使用一组尖括号 “<T>” 配合断言的目标类型 T 类型使用, 比如说在后端的登录的用户角色认证。

代码语言:txt复制
import { Request } from 'express';
type CurrentUser = {
  username: string;
  email?: string;
};
const getCurrentUser = (req: Request): CurrentUser => {
  return <CurrentUser>req.currentUser;
};

类型别名

声明一个别名来代指当前类型,它是别名,不是一个新的类型。

代码语言:txt复制
type MyString = string;

二、工具类型

Partial

Partial<T>: 可以将传入类型 T 的所有属性变为可选属性。

代码语言:txt复制
// type Partial<T> = { [P in keyof T]?: T[P] | undefined; }

type Foo = {
  name: string;
  age: number;
};
const partFoo: Partial<Foo> = {};

Required

Required<T>: Required 与 Partial 刚好相反,功能是将传入类型 T 的所有可选项转换为必选项。

代码语言:txt复制
// type Required<T> = { [P in keyof T]-?: T[P]; }

type Foo = {
  name?: string;
  age?: number;
};
const requiredFoo: Required<Foo> = {
  name: 'ading',
  age: 18,
};

Readonly

Readonly<T> Readonly 可以将构造类型 T 的所有属性转换为只读属性。

代码语言:txt复制
// type Readonly<T> = { readonly [P in keyof T]: T[P]; }

type Foo = {foo: string};
const foo1: Foo = {foo: 'foo'};
foo1.foo = 'bar';
type ReadonlyFoo = Readonly<Foo>;
const readonlyFoo: ReadonlyFoo = {
  foo: 'foo',
}
// readonlyFoo.foo = 'bar'  //Error 

Record

Record<k, T> 类型复制,将构造类型 T 设置到属性 k 上。

代码语言:txt复制
// type Record<K extends string | number | symbol, T> = { [P in K]: T; }

type Foo = {foo: string};
type Bar = {
  name: string;
  age: number;
};
type Baz = Record<keyof Bar, Foo>;
const baz: Baz = {
  name: { foo: 'foo' },
  age: { foo: 'foo' },
};

Pick

PicK<T, K extends keyof T>挑选属性,将属性 T 中的其中一部分属性挑选出来

代码语言:txt复制
// type Pick<T, K extends keyof T> = { [P in K]: T[P]; }

type Transportation = {
  name: string;
  speed: number;
  price: number;
  transportAble?: boolean;
};
type Transportable = Pick<Transportation, 'name' | 'speed'>;
const transportAble: Transportable = {
  name: '小火车',
  speed: 2,
};

Omit

Omit<T, K>;Omit 与 Pick刚好相反,它是剔除选定属性,使用剩余类型构造新类型。

代码语言:txt复制
// type Omit<T, K extends string | number | symbol> = { [P in Exclude<keyof T, K>]: T[P]; }

type Transportation = {
  name: string;
  speed: number;
  price: number;
  transportAble?: boolean;
};
type MyOmit = Omit<Transportation, 'name' | 'speed'>;
const myomit: MyOmit = {
  price: 20,
}

Exclude

Exclude<T, K> 去除 T 类型中于K类型包含的相同属性,使用剩余属性构造一个新类型

代码语言:txt复制
// type Exclude<T, U> = T extends U ? never : T

type Foo = Exclude<"a" | "b" | "c", "a">;  // "b" | "c"
type Bar = Exclude<"a" | "b" | "c", "a" | "b">;  // "c"
type Baz = Exclude<string | number | (() => void), Function>;
// string | number
type TExcludeTrain = Exclude<Foo, Baz>; // naver

Extract

Extract<T, K> 获取构造类型 T, K 中相同的类型构造一个新的类型

代码语言:txt复制
// type Extract<T, U> = T extends U ? T : never

type Foo = Extract<"a" | "b" | "c", "a" | "f">;  // "a"
type Bar = Extract<string | number | (() => void), Function>;  
// () => void

NonNullable

NonNullable<T>; 去除类型 T 中的 null 与 undefined

代码语言:txt复制
// type NonNullable<T> = T extends null | undefined ? never : T

type NoNonNullType = NonNullable<string | null | number>;
let noNonNullType: NoNonNullType = 10;

ReturnType

构造一个由函数类型返回值类型 T 的类型

代码语言:txt复制
// type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any

type FunReturnBoolean = () => boolean ; 
type ReturnTypeBoolean = ReturnType<FunReturnBoolean>;
type ReturnNumArr = ReturnType<<T extends U, U extends number[]>() => T>;
const numbers: ReturnNumArr = [1, 2];

InstanceType

由构造函数类型 T 的实例类型构造一个类型

代码语言:txt复制
class Human {
  name= '人类';
  age= 800;
};
type HumanType = InstanceType<typeof Human>;
let newHuman: HumanType;
let newHuman2: HumanType = new Human();

三、关键字

keyof

keyof T;返回一个由构造类型 T 的所有属性组成的字面量类型

代码语言:txt复制
type Light = {
  light: number;
  energy: string;
};
type LightKey = keyof Light; // "light" | "energy"

typeof

typeof k; 返回变量 k 的类型

代码语言:txt复制
let computer: string[] = ["a"];
type MyComputerType = typeof computer; //  string[]

Infer

infer T; 将在类型 T 的处理过程中的某个部分抽离出来当做类型变量

代码语言:txt复制
type Unpacked<T> =
  T extends (infer U)[] ? U :
  T extends (...args: any[]) => infer U ? U :
  T extends Promise<infer U> ? U :
  T;

type Foo = Unpacked<string>;  // string
type Bar = Unpacked<string[]>;  // string
type Baz = Unpacked<() => string>;  // string
type Qux = Unpacked<Promise<string>>;  // string
type Quux = Unpacked<Promise<string>[]>;  // Promise<string>
type Garply = Unpacked<Unpacked<Promise<string>[]>>;  // string

四、官方文档:

https://www.tslang.cn/docs/release-notes/typescript-3.1.html

0 人点赞