As I couldn't come up with a valid syntax to solve my problem using TypeScript's template literal types, I will give a textual description of what I would like to achieve:
Given a function fn
with an input name: string
, I would like to annotate the result to be an object of type
{[`use${Capitalize<name>}`]: any}
with one inferred property key.
It should thus satisfy the following logic for an arbitrary name
:
function createTypedObject(name) {
return {[`use${name.charAt(0).toUpperCase() name.substring(1)}`]: "any"}
}
I am not sure whether this is at all possible to do for template literals where the interpolated variable is not known at the time of definition of the function.
CodePudding user response:
You need to use a mapped type like { [K in `use${Capitalize<T>}`]: any }
, equivalent to Record<`use${Capitalize<T>}`, any>
using the Record<K, V>
utility type). For example:
function createTypedObject<T extends string>(
name: T
): { [K in `use${Capitalize<T>}`]: any } {
return {
[`use${name.charAt(0).toUpperCase() name.substring(1)}`]: "any"
} as any; // compiler not smart enough to verify this
}
Note that the implementation needs a type assertion because the compiler is unable to verify that the value returned conforms to the return type. I assume this is mostly out of scope for the question so I won't digress into the various ways the compiler fails to see this.
Anyway, let's test it:
const x = createTypedObject("hello");
// const x: { useHello: any; }
console.log(x.useHello) // "any"
Looks good. The compiler knows that x
has a useHello
property, as desired.