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
}
}
- As you can see, inside map method I have a condition for value. But it's not good, because if user object have more additional properties inside address or company or other property with object as value, I need to put more conditions inside. Is there any better pattern for doing that?
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
}
CodePudding user response:
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
.
CodePudding user response:
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];