Reputation: 3932
I have a interface :
interface MyInterface {
field_1 : string
field_2 : string
// ... other fields with a certain number
}
And I have a getter function that receives an instance of MyInterface and should retrieve a value of an attribute of this object dynamically
const myFactory = (myInstance:MyInterface):string => {
// Here some logic to retrieve a specific number
// for convenience lets say that the output of this logic is 1
let output = 1
return myInstance[`field_${output}`] // <=== This does not work since it calls a property of the interface dynmically
}
How can I call a property of an interface dynamically ?
I saw the keyof
operator :
but I am not sure how to use it here
Upvotes: 2
Views: 68
Reputation: 1449
The as
keyword can only fool TypeScript into letting you do what you think you are doing.
With TypeScript 3 this might be the only way.
If you are using TypeScript 4+, you can enforce some validation on the resulting fieldKey
, by using a Template Literal Type:
type MyField = `field_${number}`;
type MyType = Record<MyField, string>;
const myFactory = (instance: MyType): string => {
let n = 12;
const fieldName: keyof MyType = `field_${n}`;
return instance[fieldName];
}
In this snippet, if you had given a non-number value to n
, (such as "x"
) then it would yield to "field_x"
which is rejected (i.e. detected as improper, by TypeScript at compile-time).
Same as if you write :
const fieldName: keyof MyType = `wrong_${n}`;
because wrong_12
is not valid in MyType
.
If you need to build a larger MyType
with additional fields not in the same shape as field_N
, you could declare:
type LargerType = MyType & {
anotherField: string;
};
Finally, if you need to limit the numbers, you could declare:
type MyField = `field_${1 | 2 | 3 | 4}`;
In this case, the snippet with n = 12
yields an error because 12
is already known to be forbidden. If the n
value was obtained dynamically instead of inferred like here, it would need to be declared as:
let n: 1|2|3|4;
(or more likely, you would declare a type
for the accepted numbers, since now you're using them in several places.)
Upvotes: 2
Reputation: 101
Option 1:
type myKey = `field_${'1' | '2' | '3'}`
const output = '3'
const fieldKey: myKey = `field_${output}`
Option 2:
const fieldKey = `field_${output}` as keyof MyInterface
return myInstance[fieldKey]
Upvotes: 3