I would like to be able to construct a type dynamically with a property name which is one of the specified parameters. While I can construct the actual object, I cannot seem to construct the actual type. I would like to use this type for composition alter
export function mapProp<AssignedType>(value: AssignedType, propertyName: string) {
type ReturnType = {
[propertyName]: value
}; // errors on this line
return {
[propertyName]: value
};
}
The error emitted is as follows:
A computed property name in a type literal must refer to an expression whose type is a literal type or a 'unique symbol' type.
Example playground: http://www.typescriptlang.org/play/#src=%0D%0Aexport%20function%20mapProp%3CAssignedType%3E(value%3A%20AssignedType%2C%20propertyName%3A%20string)%20%7B%0D%0A%0D%0A%20%20type%20ReturnType%20%3D%20%7B%0D%0A%20%20%20%20%5BpropertyName%5D%3A%20value%0D%0A%20%20%7D%3B%0D%0A%0D%0A%20%20return%20%7B%0D%0A%20%20%20%20%5BpropertyName%5D%3A%20value%0D%0A%20%20%7D%3B%0D%0A%7D
In C#, you can access dynamic properties by obtaining a PropertyObject reference from the specific object reference using the AsPropertyObject method on the object.
Use an index signature to dynamically add properties to an object, e.g. const obj: {[key: string]: any} = {} . Index signatures are used when we don't know all of the names of a type's properties and the type of their values ahead of time. Copied!
I think the closest you're going to get is something like this:
export function mapProp<PropertyName extends string, AssignedType>(
value: AssignedType,
propertyName: PropertyName
) {
type ReturnType = {
[K in PropertyName]: AssignedType
};
// equivalent to Record<PropertyName, AssignedType>
return {
[propertyName]: value
} as ReturnType;
}
In this case you'd be using a mapped type instead of a type with an index signature. The addition of the PropertyName
generic type parameter allows the narrowing of the key past string
, if you pass it a string literal:
const thing = mapProp(123, "abc");
thing.abc; // number
thing.def; // error
In that case ReturnType
is known to be equivalent to {abc: number}
. If all you know is that the key is a string
at compile time, then you get this:
declare const propName: string;
const stuff = mapProp(123, propName);
stuff.abc; // number
stuff.def; // number
Now ReturnType
is equivalent to {[k: string]: number}
, meaning it accepts any string
key (and gives it a number
value). This might not be what you want, but it's the best the compiler can do in this case.
Also note that without using a type assertion (as ReturnType
), computed properties usually end up as string indexes instead of something more specific. This is currently a design limitation of TypeScript. There have been some attempts to deal with this, but nothing has made it into the language yet.
Hope that helps; good luck!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With