I have an array of objects:
export const inputsArray: InputAttributes[] = [
{
label: 'Name',
type: 'text',
name: 'name',
required: true
},
{
label: 'User name',
type: 'text',
name: 'username',
required: true
},
...
]
and map it like so:
const inputs = inputsArray.map(input => {
const value = (input.name === 'street' || input.name === 'city' || input.name === 'zipcode') // <= PROBLEM : NOT EFFECTIVE CONDITION!
? user?.address?.[input.name]
: user?.[input.name] // <= TYPESCRIPT PROBLEM
return (
<Input
key={input.name}
defaultValue={value}
input={input}
disabled={disabled}
onChange={hadndleChange}
/>
)
})
Info in user:
export interface User {
id: number,
name: string,
username: string,
email: string,
address: {
street: string,
city: string,
zipcode: string,
}
phone: string,
website: string,
company: {
name: string
}
}
user?.[input.name] Typescrips says that "type 'string' can't be used to index type 'Users'". I can avoid that problem by setting [key: string] : any inside User interface, but is there any better pattern?Input attributes interface if needed:
export interface InputAttributes {
label: string,
type: string,
name: string,
pattern?: string,
required: boolean
}
You should modify the InputAttributes interface like this:
type DeepKeyOf<T> = {
[K in keyof T]: T[K] extends Record<string, any> ? DeepKeyOf<T[K]> : K
}[keyof T]
export interface InputAttributes {
label: string,
type: string,
name: DeepKeyOf<User>,
pattern?: string,
required: boolean
}
Now TypeScript knows that the name property must contain some key of User.
Store the values in an array, then use Array.prototype.some(). This will let you support as many names as you want.
const names = ['street', 'zipcode', 'city'];
const value = names.some((name) => input.name === name) ? user?.address?.[input.name] : user?.[input.name];