Reputation: 663
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.
Upvotes: 1
Views: 477
Reputation: 329953
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.
Upvotes: 2