大师前传系列之TS类型变换

155 阅读3分钟

类型变换

交叉类型

  • 交叉类型(Intersection Types)表示将多个类型合并为一个类型
interface Bird{
name:string,
fly():void
}
interface Person{
 name:string,
 talk():void
}
type BirdPerson = Bird & Person;
let p:BirdPerson={name:'zhufeng',fly(){},talk(){}};
p.fly;
p.name
p.talk;

typeof

  • 可以获取一个变量的类型
//先定义类型,再定义变量
type People = {
    name:string,
    age:number,
    gender:string
}
let p1:People = {
    name:'zhufeng',
    age:10,
    gender:'male'
}
//先定义变量,再定义类型
let p1 = {
    name:'zhufeng',
    age:10,
    gender:'male'
}
type People = typeof p1;
function getName(p:People):string{
    return p.name;
}

索引访问操作符

  • 可以通过[]获取一个类型的子类型
interface Person{
    name:string;
    age:number;
    job:{
        name:string
    };
    interests:{name:string,level:number}[]
}
let FrontEndJob:Person['job'] = {
    name:'前端工程师'
}
let interestLevel:Person['interests'][0]['level'] = 2;

keyof

  • 索引类型查询操作符
interface Person{
  name:string;
  age:number;
  gender:'male'|'female';
}
//type PersonKey = 'name'|'age'|'gender';
type PersonKey = keyof Person;

function getValueByKey(p:Person,key:PersonKey){
  return p[key];
}
let val = getValueByKey({name:'zhufeng',age:10,gender:'male'},'name');
console.log(val);

映射类型

  • 在定义的时候用in操作符去批量定义类型中的属性
interface Person{
  name:string;
  age:number;
  gender:'male'|'female';
}
//批量把一个接口中的属性都变成可选的
type PartPerson = {
  [Key in keyof Person]?:Person[Key]
}

let p1:PartPerson={};
//也可以使用泛型
type Part<T> = {
  [key in keyof T]?:T[key]
}
let p2:Part<Person>={};

内置工具类型

  • TS 中内置了一些工具类型来帮助我们更好地使用类型系统
Partial
  • 可以将传入的属性由非可选变为可选
type Partial<T> = { [P in keyof T]?: T[P] };

interface A {
  a1: string;
  a2: number;
  a3: boolean;
}

type aPartial = Partial<A>;

const a: aPartial = {}; // 不会报错
Required
  • Required 可以将传入的属性中的可选项变为必选项,这里用了 -? 修饰符来实现
/**
 * Make all properties in T required
 */
type Required<T> = { [P in keyof T]-?: T[P] };

interface Person{
  name:string;
  age:number;
  gender?:'male'|'female';
}
let p:Required<Person> = {
  name:'zhufeng',
  age:10,
  //gender:'male'
}
Readonly
  • Readonly 通过为传入的属性每一项都加上 readonly 修饰符来实现。
/**
 * Make all properties in T readonly
 */
type Readonly<T> = { readonly [P in keyof T]: T[P] };

interface Person{
  name:string;
  age:number;
  gender?:'male'|'female';
}
let p:Readonly<Person> = {
  name:'zhufeng',
  age:10,
  gender:'male'
}
p.age = 11;
Pick
  • Pick 能够帮助我们从传入的属性中摘取某一项返回
/**
 * From T pick a set of properties K
 */
type Pick<T, K extends keyof T> = { [P in K]: T[P] };

interface Animal {
  name: string;
  age: number;
}
// 摘取 Animal 中的 name 属性
type AnimalSub = Pick<Animal, "name">; // { name: string; }
映射类型修饰符的控制
  • TypeScript中增加了对映射类型修饰符的控制
  • 具体而言,一个 readonly 或 ? 修饰符在一个映射类型里可以用前缀 + 或-来表示这个修饰符应该被添加或移除
  • TS 中部分内置工具类型就利用了这个特性(Partial、Required、Readonly...),这里我们可以参考 Partial、Required 的实现

条件类型

  • 在定义泛型的时候能够添加进逻辑分支,以后泛型更加灵活
定义条件类型
interface Fish{
  name:string
}
interface Water{
  name:string
}
interface Bird{
  name:string
}
interface Sky{
  name:string
}
//三元运算符
type Condition<T> = T extends Fish?Water:Sky;
let con:Condition<Fish> = {name:'水'};
条件类型的分发
interface Fish{
  name:string
}
interface Water{
  name1:string
}
interface Bird{
  name:string
}
interface Sky{
  name2:string
}
//三元运算符
type Condition<T> = T extends Fish?Water:Sky;
let con1:Condition<Fish|Water> = {name1:'水'};
let con2:Condition<Fish|Water> = {name2:'水'};
内置条件类型
  • TS 在内置了一些常用的条件类型,可以在 lib.es5.d.ts 中查看:
Exclude<T, U> // 从 T 可分配给的类型中排除 U。
Extract<T, U> // 从 T 可分配的类型中提取 U。
NonNullable<T> // 从 T 中排除 null 和 undefined。
ReturnType<T> // 获取函数类型的返回类型。
InstanceType<T> // 获取构造函数类型的实例类型。
Exclude
type  E = Exclude<string|number,string>;
let e:E = 10;
Extract
type  E = Extract<string|number,string>;
let e:E = '1';
NonNullable
type  E = NonNullable<string|number|null|undefined>;
let e:E = null;
ReturnType
function getUserInfo() {
  return { name: "zhufeng", age: 10 };
}

// 通过 ReturnType 将 getUserInfo 的返回值类型赋给了 UserInfo
type UserInfo = ReturnType<typeof getUserInfo>;

const userA: UserInfo = {
  name: "zhufeng",
  age: 10
};
InstanceType
class Person{
  name:string;
  constructor(name){
    this.name = name;
  }
  getName(){console.log(this.name)}
}

type  P = InstanceType<typeof Person>;
let p:P = {name:'zhufeng',getName(){}};