You can extend the interface adding the index signature to iterate when needed:
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];
}
}
If you don't need to mutate registerData
inside the loop, you can add readonly on the index signature to prevent adding new properties to iterableRegisterData
:
interface IterableRegisterData extends RegisterData {
readonly [key: string]: string | undefined
}
Original answer (bad practice)
Just add the index signature:
export interface RegisterData {
email: string
password: string
firstName?: string
lastName?: string
[key: string]: string | undefined
}
Note that you must use a union type because some of your properties could be undefined. In case you add more properties with different types, you must add that types to the index signature:
export interface RegisterData {
email: string
age: number
name?: string
data: AdditionalData
[key: string]: string | number | AdditionalData | undefined
}
Warning
As pointed in the comments, this could be a bad practice, because adding the index signature will let you add new properties not defined in the interface, and probably you don't want to let that:
const userData: RegisterData = {
email: 'user@domain.com,
password: '1234'
}
userData['foo'] = 'baz'