假如我们有一个JSON对象,里边包含了name、age两个属性,我们可以通过一些TypeScript内置的工具函数来实现一些有意思的事情。
通过keyof与typeof组合可以得到我们想要的结果:

const obj = {
name: 'Niko',
age: 18
}

// 如果是这样的取值,只能写在代码中,不能写在 d.ts 文件中,因为声明文件里边不能存在实际有效的代码
type keys = keyof typeof obj

let a: keys = 'name' // pass
let b: keys = 'age' // pass

let c: keys = 'test' // error

而如果我们想要将一个类型不统一的JSON修改为统一类型的JSON也可以使用这种方式:

const obj = {
name: 'Niko',
age: 18,
birthday: new Date()
}

const infos: Record<keyof typeof obj, string> = {
name: '',
age: '',
birthday: 123, // 出错,提示类型不匹配
test: '', // 提示不是`info`的已知类型
}

keyof是索引类型查询操作符。

假设T是一个类型,那么​​keyof T​​产生的类型是T的属性名称字符串字面量类型构成的联合类型。

特别说明:T是数据类型,并非数据本身。

代码实例如下:

interface Itest{

webName:string;

age:number;

address:string

}

type ant=keyof Itest;

如果T是一个带有字符串索引签名的类型,那么​​keyof T​​​是 string 类型,并且​​T[string]​​为索引签名的类型。

代码实例如下:

interface Map<T> {

[key: string]: T;

}

let keys: keyof Map<number>;//string

let value: Map<number>['antzone'];//number

那现在又有一个问题:如果要定义一个对象的 key 和 value 类型该怎么做呢?这时候就需要用到 TS 的 Record 了。

上代码:

interface PageInfo {
title: string;
}

type Page = "home" | "about" | "contact";

const nav: Record<Page, PageInfo> = {
about: { title: "about" },
contact: { title: "contact" },
home: { title: "home" },
};

很好理解,Record 后面的泛型就是对象键和值的类型。

比如我需要一个对象,有 ABC 三个属性,属性的值必须是数字,那么就这么写:

type keys = 'A' | 'B' | 'C'
const result: Record<keys, number> = {
A: 1,
B: 2,
C: 3
}