我有一些声明的数据接口:
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'可用于检查有效吗?
你可以使用Object.keys
断言key数组实际上是RegisterData
的一个键数组:
for (const itemId of Object.keys(registerData) as Array<keyof RegisterData>) {
if (itemId !== "password" && registerData[itemId]) {
nonEmptyData[itemId] = registerData[itemId];
}
}
添加索引签名也是一个选项,但不是一个很好的选项,允许通过任何字符串进行索引。
编辑
或者更好的是,根据您的目标和polyfills,您也可以使用Object.entries
for (const [itemId, value] of Object.entries(registerData)) {
if (itemId !== "password" && value) {
nonEmptyData[itemId] = value;
}
}
您可以扩展添加索引签名的接口以在需要时进行迭代:
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
,你可以在索引签名上添加readonly以防止向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: '[email protected],
password: '1234'
}
userData['foo'] = 'baz'