构建 Typescript 知识体系(八)-高级类型之索引类型

294 阅读1分钟

这是我参与更文挑战的第十四天,活动详情查看:更文挑战

在开发中经常会遇到这样的场景: 从对象中获取一些属性的值,然后建立一个集合

栗子,getValue 函数

抽取 obj 对象的一些值,形成一个数组

let obj = {
  a: 1,
  b: 2,
  c: 3,
};

function getValue(obj: any, keys: string[]) {
  return keys.map((key) => obj[key]);
}
// 打印出 [1,3]
console.log(getValue(obj, ["a", "c"]));
// ts 不会报错  并且打印出 [undefined,undefined]
console.log(getValue(obj, ["e", "f"]));

查询操作符

keyof T 表示类型 T 的所有公共属性的字面量联合类型

interface Obj {
  a: number;
  b: string;
}
// 类型推断为  let key: "a" | "b"
let key: keyof Obj;

索引访问操作符

T[K] 表示对象 T 的属性 K 所代表的类型

// 类型推断为   let value: number
let value: Obj["a"];

泛型约束

T extends U 表示泛型变量可以通过继承某些类型,以获得某些属性

getValue 函数改造

需求: 参数keys里面的元素一定是参数obj里面的属性

定义一个泛型变量T,用来约束obj, 定义一个泛型变量K,用来约束keys数组, 给keys的元素key添加一个类型约束,即让 K 继承所有obj所有属性的联合类型, 函数的返回值,首先是一个数组,数组元素的类型是K对应类型

let obj = {
  a: 1,
  b: 2,
  c: 3,
};

function getValue<T, K extends keyof T>(obj: T, keys: K[]): T[K][] {
  return keys.map((key) => obj[key]);
}

console.log(getValue(obj, ["a", "c"]));
/*
不能将类型“"e"”分配给类型“"a" | "c" | "b"”。
*/
console.log(getValue(obj, ["e", "f"]));

总结

索引类型可以实现 对象属性的查询和访问, 然后再配合泛型约束,就能使我们建立对象,对象属性,以及属性值之间的约束关系