Joscha Götzer
Joscha Götzer

Reputation: 663

How to use string parameter as template literal key type of return object

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

Answers (1)

jcalz
jcalz

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.

Playground link to code

Upvotes: 2

Related Questions