Skip to content

keyof

keyof 操作符用来提取接口、对象、类的属性的名称。

keyof 操作接口类型

返回值为一个联合类型("key1" | "key2" | ...)

js
interface Animal {
  name : string;
  age : number;
}

type AnimalKey = keyof Animal; // "name" | "age"

keyof 操作对象

返回值为一个联合类型("key1" | "key2" | ...)

js
const animal = {
  name : "瓜子",
  age: 1
}

const a = Object.create(animal)

// 错误的
type AnimalKey1 = keyof animal; // Cannot find name 'animal'

// 正确的
type AnimalKey1 = keyof typeof animal; // "name" | "age"

// 正确的
type AnimalKey1 = keyof typeof a; // "string" | "number" | "symbol"

keyof 操作 类

返回值为一个联合类型("key1" | "key2" | ...)

js
class Animal {
    name: string;
    // 保护类型
    protected age: number;
    // 私有类型属性
    private sex: number;
    // 静态方法
    static getInstance() {
        return Animal
    }
    constructor(name: string, age: number, sex: number) {
        this.name = name
        this.age = age
        this.sex = sex
    }
    getName() {
        return this.name
    }
}
// 正确的
type AnimalKey2 = keyof Animal; // "name" | "getName"

为什么获取不到 Class 类中私有属性、保护类型、静态类型?

下面我们看转换后的结果

js
var Animal = /** @class */ (function () {
  function Animal(name, age, sex) {
    this.name = name
    this.age = age
    this.sex = sex
  }
  // 静态方法
  Animal.getInstance = function () {
    return Animal
  }
  Animal.prototype.getName = function () {
    return this.name
  }
  return Animal
})()

可以看出转换后其保护类型属性、私有类型属性不会显式的存在于对象的属性或者原型中,所以keyof获取不到对应的属性

js
class Dog extends Animal  {
  bark() {
        console.log('Woof! Woof!');
  }
}
// 正确的
type AnimalKey2 = keyof Animal; // "bark" | "name" | "getName"

作用

  1. 操作键名的时候进行限制
ts
const prop = <T, K extends keyof T>(obj: T, key: K): any => {
  return obj[key]
}

const obj = {
  name: "战三",
}
prop(obj, "na") // Argument of type '"na"' is not assignable to parameter of type '"name"'.
  1. in keyofextends keyof 的区别

首先我们需要分别了解in keyofextends keyof 的作用。

  • extends keyof

生成一个继承于对象 Key 类型的子集 (联合类型),就像上面的 K extends keyof person 其结果为"name"、 "age"、"address" 三个类型随意组合,即可以是 "name" | "age" "name" | "address" ...

js
const person = {
    "name": "张三",
    "age": 12,
    "address": "南京"
}

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

type MiniPerson = Exclude<keyof typeof person, "address">           // "name" | "age"
type LargePerson = Exclude<keyof typeof person, "address"> | "sex"  // "name" | "age" | "sex"

// 在这里K是联合类型,传入的key可以是K中的一种
// K === "name"|"age"
const prop = <T, K extends keyof T>(obj: T, key: K): any => {
    return obj[key]
}

const key1= "name"

prop(person, key1 as MiniPerson)
prop(person , key1 as LargePerson)
  • in keyof

其返回的是一个 对象 Key 类型 中某一个 Key 的字符串(字符串类型),所以其常用于对象中定义 Key

ts
const person = {
    "name": "张三",
    "age": 12,
    "address": "南京"
}

type Person = typeof person

const b = {
  [K in keyof Person] :  Person[K]  // K得是一个字符串,而不能是一个联合类型
}
js
const person = {
    "name": "张三",
    "age": 12,
    "address": "南京"
}

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

type MiniPerson = Exclude<keyof typeof person, "address">           // "name" | "age"
type LargePerson = Exclude<keyof typeof person, "address"> | "sex"  // "name" | "age" | "sex"

// 在这里K是联合类型,传入的key可以是K中的一种
// K === "name"|"age"
const prop = <T, K extends keyof T>(obj: T, key: K): any => {
    return obj[key]
}

// const prop1 = <T, K in keyof T > (obj: T, key: K): any => {
//     return obj[key]
// }

type Person<T> = {
    [K in keyof T]: T[K]    // 在这里K是一个字符串类型的,而不是一个联合类型
}

const key1= "name"

prop(person, key1 as MiniPerson)
prop(person , key1 as LargePerson)