TS-day6

67 阅读3分钟

一、映射类型(Mapped Types)

1、当一个类型基于另一个类型,则需使用映射类型

大部分内置工具通过映射类型来实现

大多数类型体操通过映射类型完成

2、映射类型建立在索引签名的语法上

映射类型是使用了PropertyKeys联合类型的泛型

其中PropertyKeys多是通过keyof创建,然后循环遍历键名创建一个类型

// 映射类型 不能使用interface定义

type MapPerson<Type> = {
    [aaa in keyof Type]: Type[aaa]
}

interface IPerson {
    name: string
    age: number
}

// 拷贝一份Iperson
type NewPerson = MapPerson<IPerson>

3、在使用映射类型时,有两个额外的修饰符

readonly 只读

? 可选

4、通过前缀-、+删除或添加这些修饰符,默认+

type MapPerson<Type> = {
    [Property in keyof Type]-?: Type[Property]
}

interface IPerson {
    name: string
    age?: number
    readonly height: number
    address?: string
}

type IPersonRequired = MapPerson<IPerson>
// 拷贝的类型少了?属性

二、条件类型和类型工具

1、条件类型用来帮助我们描述输入类型和输出类型之间的关系,类似JS三元表达式

SomeType extends OtherType? TrueType: FalseType;

function sum<T exends number | string>(arg1: T, arg2: T): T extends string ? string: number
function sum(arg1: any, arg2: any) {
    return arg1 + arg2
}
const res1 = sum(10, 20)
const res2 = sum("a", "b")

2、inter

在条件类型中推断,在true分支里引用该推断结果,比如有一个数组类型,想要获取到一个函数的参数类型和返回值类型

type CalcFnType = (num1: number, num2: number) => number

function foo() {
  return "abc"
}

// 传入的必须是个函数
// 返回函数类型
type MyReturnType<T extends (...args: any[]) => any> = T extends (...args: any[]) => inter R? R: never

// 返回参数类型
type MyParameterType<T extends (...args: any[]) => any> = T extends (...args: infer A) => any? A: never

type CalcReturnType = MyReturnType<CalcFnType>// number
type FooReturnType = MyReturnType<typeof foo>// string
type CalcParameterType = MyParameterType<CalcFnType>// [num1: number, num2: string]

3、分发条件类型

当在泛型中使用条件类型时,如果传入一个联合类型,就会变成分发的

type toArray<T> = T extends any? T[]: never

type NumArray = toArray<number>

type NumAndStrArray = toArray<number|string>
// number[]|string[] 而不是 (number|string)[]
// 分别传入number和string,再将结果合并

4、Partial

用于构造一个Type下面的所有属性都设置为可选的类型

interface IKun {
  name: string
  age: number
  slogan?: string
}
type IKunOptional1 = Partial<IKun>

// 类型体操
type MyPartial<T> = {
  [P in keyof T]?: T[P] 
}

// IKun都变成可选的
type IKunOptional2 = MyPartial<IKun>

5、Required

所有属性都变成必选

interface IKun {
  name: string
  age: number
  slogan?: string
}
type IKun1 = Required<IKun>

// 类型体操
type MyRequired<T> = {
  [P in keyof T]-?: T[P] 
}

// IKun都变成可选的
type IKun2 = MyRequired<IKun>

6、Readonly

interface IKun {
  name: string
  age: number
  slogan?: string
}
type IKun1 = Readonly<IKun>

// 类型体操
type MyReadonly<T> = {
  readonly [P in keyof T]: T[P] 
}

// IKun都变成只读的
type IKun2 = MyReadonly<IKun>

7、Record<Keys, Type>

用于构造一个对象类型,它所有的key(键)都是Keys类型,它所有的value(值)都是Type类型。

interface IKun {
  name: string
  age: number
  slogan?: string
}

// 类型体操
// name | age | slogan
type keys = keyof IKun
type Res = keyof any // => number|string|symbol

// 确实keys一定是可以作为key的联合类型
type MyRecord<Keys extends keyof any, T> = {
  [P in Keys]: T
}

type t1 = "上海" | "北京" | "洛杉矶"
type IKuns = MyRecord<t1, IKun>
/** 
type IKuns = {  
上海: IKun;  
北京: IKun;  
洛杉矶: IKun;  
}
**/

const ikuns: IKuns = {
  "上海": {
    name: "xxx",
    age: 10
  },
  "北京": {
    name: "yyy",
    age: 5
  },
  "洛杉矶": {
    name: "zzz",
    age: 3
  }
}

8、Pick<Type, Keys>

用于构造一个类型,它是从Type类型里面挑了一些属性Keys

interface IKun {
  name: string
  age: number
  slogan?: string
}

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

type IKuns = MyPick<IKun, "slogan"|"name">

9、Omit<Type, Keys>

用于构造一个类型,它是从Type类型里面过滤了一些属性Keys

interface IKun {
  name: string
  age: number
  slogan?: string
}

type MyOmit<T, K extends keyof T> = {
  [P in keyof T as P extends K ? never: P]: T[P]
}

type IKuns = MyOmit<IKun, "slogan"|"name">

/*
type IKuns = {  
age: number;  
}
*/

10、Exclude

排除

type IKun = "sing" | "dance" | "rap"

type MyExclude<T, E> = T extends E? never: T

type IKuns = MyExclude<IKun, "rap">
//type IKuns = "sing" | "dance"

11、Extract

提取

type IKun = "sing" | "dance" | "rap"

type MyExtract<T, E> = T extends E? T: never

type IKuns = MyExtract<IKun, "rap"|"dance">
//type IKuns = "dance" | "rap"