如何在 "noImplicitAny" 检查活动的情况下重写 in 循环的打字稿?

How to rewrite typescript for in loop with "noImplicitAny" check active?

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

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 断言键数组实际上是 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;
    }
}

可扩展接口添加索引签名,需要时进行迭代:

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'