一个大多数人在学习TypeScript时都会遇到的问题,你能想到多少解决方案呢?
你在学习TypeScript时遇到过类似的错误吗?
要解决这个错误,一个非常暴力的方法是使用?any
?类型:
let user: any = {}
user.id = "TS001";
user.name = "Bytefer";
除了使用?any
?类型,你还知道多少种解决方案? 在本文中,我将介绍另外3种解决方案。在继续阅读之前,我建议你花点时间思考一下。
一种解决方案是使用?type
?或?interface
?定义?User
?类型:???????
interface User {
id: string;
name: string;
}
??????
let user = {} as User;
user.id = "TS001";
user.name = "Bytefer";
尽管使用?User
?类型,前面的问题可以解决。但是,如果您为用户对象设置了一个新的?age
?属性,将显示以下错误消息:
Property 'age' does not exist on type 'User'.ts(2339)
那么,如何解决动态属性分配问题呢? 现在,我们可以使用TypeScript的索引签名了。当我们只知道对象键和值的类型时,可以使用索引签名来定义该对象的类型。索引签名的语法如下:
键的类型只能是字符串、数字、符号或模板文字类型,而值的类型可以是任何类型。
模板文字类型是TypeScript 4.1中引入的一种新类型,结合索引签名,我们可以定义更强大的类型。
一旦理解了索引签名的语法,就可以很容易地定义一个新的?User
?类型:???????
interface User {
id: string;
name: string;
[key: string]: string;
}
在id和name已经是属性的情况下,我们通过索引签名将?User
?类型的其他属性的类型设置为字符串类型。在使用索引签名时,您可能会产生以下疑问:
为什么可以通过字符串“1”和数字1访问相应的属性值?
为什么keyof NumbersNames返回字符串和数字类型的联合类型?
?
这是因为当在属性访问器中用作键时,JavaScript隐式地将数字强制转换为字符串,TypeScript也会执行这种转换。
除了使用索引签名,我们还可以使用TypeScript内置的实用工具类型?Record
?类型来定义?User
?类型。?Record
?实用程序类型的作用如下:
type User = Record<string, string>
???????
let user = {} as User;
user.id = "TS001"; // Ok
user.name = "Bytefer"; // Ok
那么索引签名和Record实用程序类型之间的区别是什么呢? 在某些情况下,它们都定义了期望的类型。???????
const user1: Record<string, string> = { name: "Bytefer" }; // Ok
const user2: { [key: string]: string } = { name: "Bytefer" }; // Ok
对于索引签名,键类型只能是字符串、数字、符号或模板文字类型。对于Record实用程序类型,键类型可以是文字类型或文字类型的联合:
为了更好地理解?Record
?实用程序类型,让我们看一下它的内部实现:???????
/**
* Construct a type with a set of properties K of type T.
* typescript/lib/lib.es5.d.ts
*/
type Record<K extends keyof any, T> = {
[P in K]: T;
};
Record
?实用程序类型在内部使用TypeScript映射的类型,它在其他内置实用程序类型中也被广泛使用。
读完这篇文章,我相信你已经理解了TypeScript索引类型和Record??Record
?工具类型。
欢迎关注公众号:文本魔术,了解更多