typescript索引类型_TypeScript的索引类型和映射类型

文章首发于:https://github.com/USTB-musion/fee-skills

写在前面

在ts中,索引类型和映射类型是相对复杂的内容。使用索引类型,编译器就能够检查使用了动态属性名的代码,而使用映射类型,可以将旧类型转化成新类型。下面用一篇文章来稍微深入介绍一下这两个概念。

索引类型

在实际开发中,我们经常能遇到这样的场景,在对象中获取一些属性的值,然后建立对应的集合。

let person = {

name: 'musion',

age: 35

}

function getValues(person: any, keys: string[]){

return keys.map(key => person[key])

}

console.log(getValues(person, ['name', age])) // ['musion', 35]

console.log(getValues(person, ['gender'])) // [undefined]

在上述例子中,可以看到getValues(persion, ['gender'])打印出来的是[undefined],但是ts编译器并没有给出报错信息,那么如何使用ts对这种模式进行类型约束呢?这里就要用到了索引类型,改造一下getValues函数,通过 索引类型查询和 索引访问 操作符:

function getValues(person: T, keys: K[]): T[K][] {

return keys.map(key => person[key]);

}

interface Person{

name: string;

age: number;

}

const person: Person = {

name: 'musion',

age: 35

}

getValues(person, ['name']) // ['musion']

getValues(person, ['gender']) // 报错:

// Argument of Type '"gender"[]' is not assignable to parameter of type '("name" | "age")[]'.

// Type "gender" is not assignable to type "name" | "age".

编译器会检查传入的值是否是Person的一部分。通过介绍几个概念来理解上面的代码:

1.索引类型查询操作符(keyof T)

keyof T的含义表示类型T所有公共属性的字面量的联合类型,在上述例子中,就是Person的属性名,即['name', age]

2.索引访问操作符(T[K])

T[K]表示对象T的属性K所表示的类型,在上述例子中,T[K][] 表示变量T取属性K的值的数组

3.泛型约束(K extends T)

泛型变量可以通过继承某些类型获取某些属性

介绍完这三个概念之后,应该就可以理解上面的代码了。首先看泛型,这里有T和K两种类型,根据类型推断,第一个参数person就是person,类型会被推断为Person。而第二个数组参数的类型推断(K extends keyof T),keyof关键字可以获取T,也就是Person的所有属性名,即['name', 'age']。而extends关键字让泛型K继承了Person的所有属性名,即['name', 'age']。这三个特性组合保证了代码的动态性和准确性,也让代码提示变得更加丰富了:

getValues(person, ['gender']) // 报错:

// Argument of Type '"gender"[]' is not assignable to parameter of type '("name" | "age")[]'.

// Type "gender" is not assignable to type "name" | "age".

映射类型

一个常见的任务是将一个已知的类型每个属性都变为可选的:

interface PersonPartial{

name?: string;

age?: number;

}

在实例化Person时,我们不必给每个属性都赋值,想要一个只读版本:

interface PersonReadonly{

readonly name: string;

readonly age: number;

}

这在JavaScript里经常出现,TypeScript提供了从旧类型中创建新类型的一种方式 — 映射类型。在映射类型里,新类型以相同的形式去转换旧类型里每个属性。TS内置了一些映射类型(实际上是一些语法糖),让我们可以方便地进行类型映射,可以在TypeScript包中的typescript/lib/lib.es5.d.ts中找到他们的定义:举一些例子:

// 将传入的属性变为只读选项

type Readonly = {

readonly [P in keyof T]: T[P];

}

// 将传入的属性变为可选项:keyof T 拿到 T 所有属性名, 然后 in 进行遍历, 将值赋给 P, 最后 T[P] 取得相应属性的值.

type Partial = {

[P in keyof T]?: T[P];

}

使用方式如下:

type PersonPartial = Partial;

type ReadonlyPerson = Readonly;

TypeScript内置了Readonly和Partial,所以不需要手动声明实现。除此之外,还有其他常用的内置类型如:

Record

将K中的所有属性的值转化为T类型:

type Record = { [P in K]: T };

Pick

从 T 中取出 一系列 K 的属性

type Pick = { [P in K]: T[P] };

Required

将传入的属性变为必选项

type Required = { [P in keyof T]-?: T[P] };

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值