让你知道keyof类型操作符在TypeScript内置实用程序类型中的作用。
你在TypeScript中使用过Partial、Required、Pick和Record工具类型吗?
keyof
类型操作符在这些实用程序类型中广泛使用,那么该操作符的作用是什么? 如果不清楚,看完这篇文章,也许你就会明白了。
在JavaScript中,我们可以通过 Object.keys
方法获得对象中的键,该方法返回一个键数组:
const user = {
id: 666,
name: "bytefer",
}
const keys = Object.keys(user); // ["id", "name"]
在TypeScript中,我们处理的是类型。如果希望获得对象类型中的键,则需要使用 keyof
类型操作符。该操作符在TypeScript 2.1中引入,用于获取类型中的所有键,其返回类型为联合类型。
type User = {
id: number;
name: string;
}
type UserKeys = keyof User; // "id" | "name"
在获得对象类型的键之后,可以使用类似于属性访问的语法来访问与该键对应的值的类型。
type U1 = User["id"] // number
type U2 = User["id" | "name"] // string | number
type U3 = User[keyof User] // string | number
对于上面的代码,我们使用索引访问类型查找 User
类型上的特定属性。索引类型本身就是一个类型,所以我们可以使用联合、 keyof
或其他类型。
那么keyof操作符在实践中有哪些用途呢? 这里我们举个例子。
function getProperty(obj, key) {
return obj[key];
}
const user = {
id: 666,
name: "bytefer",
}
const userName = getProperty(user, "name");
这是一个简单的 getProperty
函数,它接收两个参数obj和key,用于获取 obj
对象上参数key对应的属性值。
那么如何在TypeScript中定义上面的getProperty函数呢? 这里我们把函数直接放到TypeScript项目中。对于上面的代码,TypeScript编译器会提示以下错误信息:
该信息告诉我们,参数obj和key隐式地具有“any”类型。为了解决这个问题,我们可以显式地定义参数obj和key的类型。
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'.
No index signature with a parameter of type 'string' was found on type '{}'.ts(7053)
在显式指定类型之后,参数上的错误消息将消失,但是在函数体中出现新的错误消息。那么如何解决上述问题呢? 这里我们可以使用TypeScript泛型和keyof操作符:
function getProperty
( obj: T, key: K
) {
return obj[key];
}
在上面的代码中,定义了两个类型形参: T
和 K
。对于类型参数T, extends
用于将类型参数的实际类型约束为对象类型的子类型。类型参数K也使用 extends
将类型参数的实际类型约束为对象类型的所有键的联合类型的子类型。
之后,使用 getProperty
函数,可以获得对象上指定属性的值。当与该键对应的属性不存在时,TypeScript会提示相应的错误信息。
keyof
类型操作符不仅可以应用于对象类型,还可以应用于基本数据类型、任何类型、类和枚举类型。
前面提到的TypeScript内置实用程序类型,如Partial、Required、Pick和Record,都在内部使用 keyof
类型操作符和映射类型。
为了让大家更好地理解 keyof
类型操作符的作用,我将使用Partial实用程序类型作为示例来演示其工作流程:
/**
* Make all properties in T optional.
* typescript/lib/lib.es5.d.ts
*/
type Partial
= { [P in keyof T]?: T[P];
};
到这里,我相信你已经知道了 keyof
类型操作符在TypeScript内置实用类型中的作用。
欢迎关注微信公众号:文本魔术,了解更多