TypeScript keyof操作符

keyof类型操作符

对一个对象类型使用keyof操作符,会返回该对象属性名组成的一个字符串或者数字字面量的联合。

type Point = {
  x: number,
  y: number
}
type P = keyof Point; //type P = 'x'|'y'

let x: P = 'z'; // 报错:不能将类型“"z"”分配给类型“keyof Point”

但如果这个类型有一个string或者number类型的索引签名,keyof则会直接返回这些类型:

type Arrayish = { [n: number]: unknown };

type A = keyof Arrayish; // type A = number

type Mapish = { [k: string]: boolean };
type M = keyof Mapish; // type M = string | number

注意在这个例子中,Mstring | number,这是因为 JavaScript 对象的属性名会被强制转为一个字符串,所以 obj[0] obj["0"] 是一样的。

数字字面量联合类型

在一开始我们说了,keyof也可能返回一个数字字面量的联合类型,当对象的key为数字类型时,则会返回数字字面量的联合:

const numberObj = {
  [1]: 'zs',
  [2]: 'ls',
  [3]: 'zl',
};
type A = typeof numberObj;
//type A = {
//   1: string;
//   2: string;
//   3: string;
// }
type B = keyof A; // type B = 1 | 2 | 3

Symbol

其实TypeScript也可以支持symbol类型的属性名:

const s1 = Symbol();
const s2 = Symbol();
const s3 = Symbol();

const symbolToNumberMap = {
  [s1]: 1,
  [s2]: 2,
  [s3]: 3,
}

type KS = keyof typeof symbolToNumberMap; // type KS = typeof s1 | typeof s2 | typeof s3

类和接口

对类使用keyof:

class A {
  name!: "zs"
}

type res = keyof A;
// type res = "name"


class B {
  [1]: string = "ls";
}

type b = keyof B;
// type b = 1

对接口使用keyof:

interface A {
  name: "string";
}

type result = keyof A;
// type result = "name"