TypeScript 高级类型

103 阅读3分钟

映射类型

TypeScript 中的映射类型意味着将一种类型转换为另一种类型(映射类型只能在类型别名中使用,不能在接口中使用)

// 将Student中的类型全部变为boolean同时生成一个新的类型 
type BooleanFlags<Type> = { [Property in keyof Type]: boolean; }; 
type Student = { name: string, age: number; } 
type StudentOpitons = BooleanFlags<Student>; //{name: boolean, age: boolean}

映射修饰符

在映射过程中可以使用两个额外的修饰符,readonly只读,?可选可以通过添加

-符号前缀来删除原有的只读(readonly)属性和可选(?)属性, 不使用-默认是添加这些修饰符+

例如:

// 这种情况下会默认保留原有修饰符
type BooleanFlags = {
  [Property in keyof Type]: boolean;
};


type Student = {
  readonly name: string,
  age?: number;
}

type StudentOpitons = BooleanFlags; //{readonly name: boolean, age?: boolean}
// -readonly将原有的readonly属性修饰符去除了
type BooleanFlags<Type> = {
  -readonly [Property in keyof Type]: boolean;
};


type Student = {
  readonly name: string,
  age?: number;
}

type StudentOpitons = BooleanFlags<Student>; //{name: boolean, age?: boolean}
// -?将原有的可选属性去除了
type BooleanFlags<Type> = {
  -readonly [Property in keyof Type] -?: boolean;
};


type Student = {
  readonly name: string,
  age?: number;
}

type StudentOpitons = BooleanFlags<Student>; //{name: boolean, age: boolean}

as关键字

在TypeScript4.1 及更高的版本中, 你可以使用映射类型中as字句, 重新映射类型中的键的名称

// 映射类型
type MappedTypeWithNewProp<Type> = {
  [Properties in keyof Type as NewKeyType]: Type[Properties]
}

也可以利用利用模板文字类型等功能从以前的属性名称中创建新的属性名称

type Getters<Type> = {
  [Property in keyof Type as `get${ Capitalize<string & Property> }` ]: () => Type[Property]
}

// 目标类型
interface Person  {
  name: string
  age:number
  location: string
}

// 映射返回的新类型
type LazyPerson = Getters<Person>
/**
 *
 * {getId: () => Person["id"], getName: () => Person["name"], getAge: () => Person["age"], getLocation: () => Person["location"]}
 */

所谓高级类型,是typescript为了保证语言的灵活性,所使用的一下语言特性

1.keyof

在了解其他的高级类型之前,我们首先要明白keyof的使用方法

type Person = {
  id: number;
  name: string;
  age: number;
};

type k = keyof Person; // "id" | "name" | "age"

可以看到,k的类型就是Person的所有键组成的联合类型,既然能得到Person的所有key值,那么自然也能获取所有键的类型

type k2 = Person[keyof Person]; //string | number

2.Pick

下面是Pick在ts中的源码定义

type Pick<T, U extends keyof T> = {
  [P in U]: T[P];
};
// 可以看到 Pick能从第一个类型中提取需要的几个属性 
type PickType = Pick<Person, "name" | "age">; // {name: string, age: number}

3.Exlcude

以下是Exclude的源码定义,Exclude的作用就是将第一个type中不需要的类型剔除掉,形成一个新的type

type Exclude<T, U> = T extends U ? never : T;
type STRING = string;
type STRINGANDNUMBER = string | number;
// never | number 因为never是number的子类型,所以结果是 number
type ExcludeType = Exclude<STRINGANDNUMBER, STRING>;

4.Extract

与Exclude相反

type Extract = T extends U ? T : never;
type ExtractType = Extract<STRINGANDNUMBER, STRING>; //string

5.Partial

Partial会将所有的属性转为可选的

type Partial = {
  [P in keyof T]?: T[P];
};
type Person2 = Partial; // {id?: number, name?: string, age?: number}

6.Record

Record用于批量定义类型

type Record<K extends keyof any, T> = {
  [P in K]: T;
};
type RecordType = Record<"name" | "age", string | number>; 
//{name: string | number, age: string | number}

7.实现一个相反的Pick

type OppositePick<T, U> = Pick<T, 
{
    [P in keyof T]: P extends U ? never : P;
}[keyof T]>;
type OppositePick
type OppositePickType = OppositePick<Person, "name" | "age">; //{id: number}

8.Required

Required类型能够构造一个新类型,并将实际类型参数T中的所有属性变为必选属性

type Required = {     [P in keyof T]-?: T[P]; };
interface A {
  x?: number;
  y: number;
}

type RequeiredType = Required<A>; //{x: number, y: number}

9.NonNullable

NonNullable会将null和undefined从Type中排除掉,由剩余类型组成一个新的类型。

type NonNullable = T extends null | undefined ? never : T;    
type Foo = number | null | undefined;

type NullableFoo = NonNullable; // :number

10.Parameters

作用是用于获取函数 T 的参数类型

type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never
type getuserInfo = (user: string, age: number) => Person
type ParametersUserInfo = Parameters<getuserInfo>  //[string, number]

#### 有错误欢迎大家指出~~~~~