如何在“noImplicitAny”检查激活的情况下重写in循环的typescript?

时间:2018-04-24 13:46:20

标签: typescript typescript2.0

我有一些声明的数据接口:

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'可用于检查是否有效?

2 个答案:

答案 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'