【TS】TypeScript 类型映射

文章目录

映射基本语法

映射修饰符

键名重映射

【更改键名】

【属性过滤】

【映射联合类型】


类型映射基于索引类型,将一种类型按照映射规则,转换成另一种类型,通常用于对象类型。

注意:类型映射只能与类型别名一起使用

映射基本语法

场景:基于旧类型创建新类型(对象类型),减少重复、提升开发效率。

例1:使用 in 关键字( 类似 for in )遍历联合类型 'x' | 'y' | 'z',循环创建 x,y,z 属性并设置类型注解 number。通过类型映射创建的新对象类型 Type1 和类型 Type2 结构完全相同。

type PropKeys = 'x' | 'y' | 'z';

// 使用类型映射创建类型Type1
type Type1 = { [Key in PropKeys]: number }
// 等同于
type Type2 = { x: number; y: number; z: number}

例1:下面示例中,先执行 keyof Props 获取对象类型 Props 中所有键的联合类型即 'a' | 'b'| 'c' ,再通过 in 关键字(类似 for in)遍历联合类型,循环创建 a,b,c 属性并设置类型注解 number。通过类型映射创建的新对象类型 Type3 和类型 Type4 结构完全相同。

// 创建对象类型
type Props = { a: number; b: string; c: boolean }
// 通过映射创建新类型
type Type3 = { [key in keyof Props]: number }
// 等同于
type Type4 = {
    a: number;
    b: number;
    c: number;
}

Partial<Type> 就是基于类型映射实现的。

  • keyof T 即 keyof Props 表示获取 Props 的所有键,也就是:'a' | 'b' | 'c'。
  • 在 [] 后面添加 ?(问号),表示将这些属性变为可选的,以此来实现 Partial 的功能。
  • 冒号后面的 T[P] 表示获取 T 中每个键对应的类型。比如,如果是 'a' 则类型是 number;如果是 'b' 则类型是 string。
  • 最终,新类型 PartialProps 和旧类型 Props 结构完全相同,只是让所有类型都变为可选了。
type Props = { a: number; b: string; c: boolean }
type PartialProps = Partial<Props>

 Partial 底层代码 

 

映射修饰符

TS 引入了两个映射修饰符,用来在映射时添加或移除某个属性的 ? 修饰符和 readonly 修饰符。

  • + 修饰符:写成 +? 或 +readonly,为映射属性添加 ? 修饰符或 readonly 修饰符。可以省略+
  • – 修饰符:写成 –? 或 –readonly,为映射属性移除 ? 修饰符或 readonly 修饰符。
type Props = {
    a: number;
    b?: string;
    readonly c: boolean;
}
// 所有属性添加可选修饰符 +
type Type5 = {
    [key in keyof Props]+?: Props[key]
}
// 所有属性移除可选修饰符 -
type Type6 = {
    [key in keyof Props]-?: Props[key]
}
// 所有属性添加只读修饰符 readonly
type Type7 = {
    +readonly [key in keyof Props]: Props[key]
}
// 所有属性移除只读修饰符 readonly
type Type8 = {
    -readonly [key in keyof Props]: Props[key]
}

 所有属性添加可选修饰符 +

 

 所有属性移除可选修饰符 -

 

 所有属性添加只读修饰符 readonly

 

 所有属性移除只读修饰符 readonly

 

键名重映射

由于键名重映射可以修改键名类型,所以原始键名的类型不必是 string | number | symbol,任意的类型都可以用来进行键名重映射。

【更改键名】

interface Person {
  name: string;
  age: number;
  location: string;
}
type Getters<T> = {
  [P in keyof T
    as `get${Capitalize<string & P>}`]: () => T[P];
};
type LazyPerson1 = Getters<Person>;
// 等同于
type LazyPerson2 = {
  getName: () => string;
  getAge: () => number;
  getLocation: () => string;
}

解释:

  • P in keyof T:获取类型 T 的每一个属性。
  • as:修改键名。
  • get:为键名添加的前缀。
  • Capitalize<T>:一个原生的工具泛型,用来将T的首字母变成大写。
  • string & P:一个交叉类型,其中的P是 keyof 运算符返回的键名联合类型string|number|symbol,但是 Capitalize<T> 只能接受字符串作为类型参数,因此 string & P 只返回 P 的字符串属性名。

【属性过滤】

type User = {
    name: string,
    age: number
}
type Filter<T> = {
    [K in keyof T as T[K] extends string ? K : never]: string
}
type FilteredUser = Filter<User> // { name: string }

解释:

  • K in keyof T:获取类型 T 的每一个属性。
  • as:修改键名。
  • T[K] extends string ? K : never]:使用了条件运算符,如果属性值他 T[K] 的类型是字符串,那么属性名不变,否则属性名类型改为 never,即这个属性名不存在。这样就等于过滤了不符合条件的属性,只保留属性值为字符串的属性。

【映射联合类型】

type S = {
  kind: 'square',
  x: number,
  y: number,
};
type C = {
  kind: 'circle',
  radius: number,
};
type MyEvents<Events extends { kind: string }> = {
  [E in Events as E['kind']]: (event: E) => void;
}
type Config1 = MyEvents<S|C>;
// 等同于
type Config2 = {
  square: (event:S) => void;
  circle: (event:C) => void;
}

解释:

  • E in Events:Events 是两个对象组成的联合类型 S | C,所以 E 是一个对象。
  • as E['kind']:修改键名。
  • Events extends { kind: string }:传入的泛型参数必须有 kind 属性,且为 string 类型。
  • S|C:对象组成的联合类型。

TypeScript 教程——阮一峰·著

TypeScript 中文网

TypeScript 官网

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值