跳到主要内容

索引访问类型

文章来源

作者:冴羽

链接:https://ts.yayujs.com/

著作权归原作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

我们可以使用   索引访问类型(indexed access type)  查找另外一个类型上的特定属性:

type Person = { age: number; name: string; alive: boolean };
type Age = Person["age"];
// type Age = number

因为索引名本身就是一个类型,所以我们也可以使用联合、keyof  或者其他类型:

type I1 = Person["age" | "name"];
// type I1 = string | number

type I2 = Person[keyof Person];
// type I2 = string | number | boolean

type AliveOrName = "alive" | "name";
type I3 = Person[AliveOrName];
// type I3 = string | boolean

如果你尝试查找一个不存在的属性,TypeScript 会报错:

type I1 = Person["alve"];
// Property 'alve' does not exist on type 'Person'.

接下来是另外一个示例,我们使用  number  来获取数组元素的类型。结合  typeof  可以方便的捕获数组字面量的元素类型:

const MyArray = [
{ name: "Alice", age: 15 },
{ name: "Bob", age: 23 },
{ name: "Eve", age: 38 },
];

type Person = (typeof MyArray)[number];

// type Person = {
// name: string;
// age: number;
// }

type Age = (typeof MyArray)[number]["age"];
// type Age = number

// Or
type Age2 = Person["age"];
// type Age2 = number

作为索引的只能是类型,这意味着你不能使用  const  创建一个变量引用:

const key = "age";
type Age = Person[key];

// Type 'key' cannot be used as an index type.
// 'key' refers to a value, but is being used as a type here. Did you mean 'typeof key'?

然而你可以使用类型别名实现类似的重构:

type key = "age";
type Age = Person[key];

最后讲一个实战案例:​

假设有这样一个业务场景,一个页面要用在不同的 APP 里,比如淘宝、天猫、支付宝,根据所在 APP 的不同,调用的底层 API 会不同,我们可能会这样写:

const APP = ["TaoBao", "Tmall", "Alipay"];

function getPhoto(app: string) {
// ...
}

getPhoto("TaoBao"); // ok
getPhoto("whatever"); // ok

如果我们仅仅是对 app 约束为  string  类型,即使传入其他的字符串,也不会导致报错,我们可以使用字面量联合类型约束一下:

const APP = ["TaoBao", "Tmall", "Alipay"];
type app = "TaoBao" | "Tmall" | "Alipay";

function getPhoto(app: app) {
// ...
}

getPhoto("TaoBao"); // ok
getPhoto("whatever"); // not ok

但写两遍又有些冗余,我们怎么根据一个数组获取它的所有值的字符串联合类型呢?我们就可以结合上一篇的  typeof  和本节的内容实现:

const APP = ["TaoBao", "Tmall", "Alipay"] as const;
type app = (typeof APP)[number];
// type app = "TaoBao" | "Tmall" | "Alipay"

function getPhoto(app: app) {
// ...
}

getPhoto("TaoBao"); // ok
getPhoto("whatever"); // not ok

我们来一步步解析: 首先是使用  as const  将数组变为  readonly  的元组类型:

const APP = ["TaoBao", "Tmall", "Alipay"] as const;
// const APP: readonly ["TaoBao", "Tmall", "Alipay"]

但此时  APP  还是一个值,我们通过  typeof  获取  APP  的类型:

type typeOfAPP = typeof APP;
// type typeOfAPP = readonly ["TaoBao", "Tmall", "Alipay"]

最后在通过索引访问类型,获取字符串联合类型:

type app = (typeof APP)[number];
// type app = "TaoBao" | "Tmall" | "Alipay"