TS 注意事项

TS 对象动态 key 类型报错

问题一
问题描述

先声明一个接口:

1
2
3
4
5
interface User {
name: string;
sex: string;
email: string;
}

然后创建一个对象:

1
2
3
4
5
const user: User = {
name: "xxx",
sex: "female",
email: "1234567@qq.com"
}

现在需要我们将 user 对象中的值置空:

1
2
3
for (const key in user) {
user[key] = ""
}

这时会报错:

1
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'User'.   No index signature with a parameter of type 'string' was found on type 'User'.

意思是 User 没有 string 类型的索引签名。

解决方法
1
2
3
for (const key in user) {
user[key as keyof User] = "";
}
问题二
问题描述

若一个接口中有不同的类型:

1
2
3
4
5
6
interface User {
name: string;
age: number;
sex: string;
email?: string;
}

创建一个对象:

1
2
3
4
5
6
const user: User = {
name: "",
age: NaN,
sex: "",
email: ""
}

现在有另一个 User 类型的对象 data,需要将 data 中的值循坏遍历到 user 中:

1
2
3
for (const key in user) {
user[key as keyof User] = data[key as keyof User];
}

依然会报错:

1
Type 'string | number | undefined' is not assignable to type 'never'.   Type 'undefined' is not assignable to type 'never'.

是因为有多种类型后,不能确定是否是将一种类型的值赋值给相同的类型,比如 string 类型的值可能会赋值给 number,会产生歧义。

解决方法

第一种:

分类赋值。就是将各种类型分开赋值。

1
2
3
4
5
6
7
8
9
10
for (const key in user) {
const tkey = key as keyof User;
if (tkey === "age"){
user[tkey] = data[tkey];
} else if (tkey === "email") {
user[tkey] = data[tkey];
} else {
user[tkey] = data[tkey];
}
}

这样做太过繁琐,如果只有两种类型可以考虑。

第二种:

添加索引签名。

1
2
3
4
for (const key in user) {
const tkey = key as keyof User;
(user as { [ key: string ]: any })[tkey] = data[tkey];
}