i need to access to an object property using a string as key
interface MyObject {
prop1: string;
prop2: string;
prop3: string;
prop4: string;
prop5: string;
}
let initialValues: MyObject;
//i set some property
initialValues = {
prop1: 'xxxx'
prop2: 'yyyy'
}
//i set some other (existing) property
[3,4,5,6].map(i => {
initialValues[`prop${i}`] = 'zzzz';
});
i got this error
Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'MyObject'
CodePudding user response:
Typescript has assumed widest possible type for [3,4,5,6]
as string[]
. Add as const
to narrow it.
([3,4,5] as const).map(i => {
initialValues[`prop${i}`] = 'zzzz';});
CodePudding user response:
Typescript will not be able to understand that your values will be valid key of the interface. It is a limitation.
Best you can do is use type assertion
, but do not that it does not provide type safety instead you are telling TS that the type is correct :
interface MyObject {
prop1: string;
prop2: string;
prop3?: string;
prop4?: string;
prop5?: string;
}
let initialValues: MyObject = {
prop1: 'x',
prop2: 'y'
}
let ans = [3,4,5,6].map(i => {
initialValues[`prop${i}` as keyof MyObject] = 'zzzz';
});
Notice TS cannot figure out that 6
will not be a problem here.
CodePudding user response:
Use a type assertion to tell TypeScript that this will be a property of the object:
interface MyObject {
prop1: string;
prop2: string;
prop3: string;
prop4: string;
prop5: string;
}
let initialValues: MyObject;
//i set some property
initialValues = {
prop1: 'xxxx'
prop2: 'yyyy'
}
//i set some other (existing) property
[3,4,5,6].map(i => {
initialValues[`prop${i}` as keyof MyObject] = 'zzzz';
});
However, be careful when you do this! TypeScript won't check that the property is a valid property of the object, so you lose complete runtime type safety. You can see that in this case TypeScript doesn't complain.
Alternatively, if you know which values will be in the array, you can tell TypeScript that, and it will be able to recognize valid keys:
interface MyObject {
prop1: string;
prop2: string;
prop3?: string;
prop4?: string;
prop5?: string;
}
let initialValues: MyObject;
//i set some property
initialValues = {
prop1: 'xxxx',
prop2: 'yyyy'
};
//i set some other (existing) property
let values: (3 | 4 | 5 | 6)[] = [3, 4, 5, 6];
values.map(i => {
initialValues[`prop${i}`] = 'zzzz';
});
You can see that in this case, TypeScript only complains about prop6
. This is the preferred solution if you can do it, because we keep type safety.
CodePudding user response:
When you want to init some properties, you could use an init function that accepts a partial type and returns MyObject
.
interface MyObject {
prop1: string;
prop2: string;
prop3: string;
prop4: string;
prop5: string;
}
function init(partial: Partial<MyObject>): MyObject {
const result: any = {...partial};
[3,4,5].map(i => {
result[`prop${i}`] = 'zzzz';
});
return result;
}
const initializedObj = init({
prop1: 'xxxx',
prop2: 'yyyy'
});
console.log(initializedObj);
- the type of the init function will make sure, that you only pass an allowed object
- But of course you must be very careful that you really return an object that is a valid
MyObject
: i.e. in your question you also fill inprop6
which does not exist onMyObject