我有一些声明的数据接口:
export interface RegisterData {
email: string
password: string
firstName?: string
lastName?: string
}
并且想创建和对象只有接口实例的非空字段(并避免一些非空的特殊字段,如密码):
const nonEmptyData: any = { };
for(const itemId in registerData) {
if(itemId !== "password" && registerData[itemId]) {
nonEmptyData[itemId] = registerData[itemId];
}
}
然而,当“noImplicitAny”检查激活时,我得到下一个错误:
error TS7017: Element implicitly has an 'any' type because type 'RegisterData' has no index signature.
如果'for in'可用于检查是否有效?
答案 0 :(得分:3)
您可以使用Object.keys
断言key数组实际上是RegisterData
的键数组:
for (const itemId of Object.keys(registerData) as Array<keyof RegisterData>) {
if (itemId !== "password" && registerData[itemId]) {
nonEmptyData[itemId] = registerData[itemId];
}
}
添加索引签名也是一个选项,但不是一个很好的选项,它允许通过任何字符串进行索引。
修改强>
或者更好的是,根据您的目标和polyfill,您还可以使用Object.entries
for (const [itemId, value] of Object.entries(registerData)) {
if (itemId !== "password" && value) {
nonEmptyData[itemId] = value;
}
}
答案 1 :(得分:1)
您可以扩展添加索引签名的接口以在需要时进行迭代:
interface IterableRegisterData extends RegisterData {
[key: string]: string | undefined
}
const iterableRegisterData = registerData as IterableRegisterData;
for(const itemId in iterableRegisterData) {
if(itemId !== "password" && iterableRegisterData[itemId]) {
nonEmptyData[itemId] = iterableRegisterData[itemId];
}
}
如果您不需要在循环内更改registerData
,则可以在索引签名上添加只读,以防止向iterableRegisterData
添加新属性:
interface IterableRegisterData extends RegisterData {
readonly [key: string]: string | undefined
}
原始答案(错误做法)
只需添加索引签名:
export interface RegisterData {
email: string
password: string
firstName?: string
lastName?: string
[key: string]: string | undefined
}
请注意,由于某些属性可能未定义,因此必须使用联合类型。如果要添加更多具有不同类型的属性,则必须将该类型添加到索引签名中:
export interface RegisterData {
email: string
age: number
name?: string
data: AdditionalData
[key: string]: string | number | AdditionalData | undefined
}
警告
正如评论中指出的那样,这可能是一个不良做法,因为添加索引签名将使您可以添加接口中未定义的新属性,并且您可能不想这样做:
const userData: RegisterData = {
email: 'user@domain.com,
password: '1234'
}
userData['foo'] = 'baz'