Jeggy
Jeggy

Reputation: 1650

get union type with `keyof typeof`

How can I get the union or enum type from a typeof type?

Example

const myConfs: { [k: string]: (myArg: { name: string }) => string } = {
  'Hello': ({ name }) => `World from ${name}`,
  'Goodbye': ({ name }) => `World from ${name}`,
};
type MyKeys = keyof typeof myConfs;


// I want this to trow an error
const key: MyKeys = 'hello';

I have tried just removing the type definition of myConfs and that works, but that breaks the type definement of the callback argument within the value field on myConfs.

Upvotes: 0

Views: 480

Answers (2)

Tobias S.
Tobias S.

Reputation: 23825

I would suggest using a factory function. This let's you solve your problem and avoids code duplication.

function createConfs<T extends { [k: string]: (myArg: { name: string }) => string }>(confs: T) : T{
    return confs
}

const myConfs = createConfs({
  'Hello': ({ name }) => `World from ${name}`,
  'Goodbye': ({ name }) => `World from ${name}`,
})

type MyKeys = keyof typeof myConfs;

const key: MyKeys = 'hello';
// Type '"hello"' is not assignable to type '"Hello" | "Goodbye"'. Did you mean '"Hello"'?(2820)

Playground

Upvotes: 2

Ali Habibzadeh
Ali Habibzadeh

Reputation: 11548

There are multiple ways of solving this. You are setting your keys to be any string. Use mapped type to limit it to what your set needs to be:

const keys = <const>["Hello", "Goodbye"];

type MyConfs = {
  [K in typeof keys[number]]: (myArg: { name: K }) => string;
};

const myConfs: MyConfs = {
  Hello: ({ name }) => `World from ${name}`,
  Goodbye: ({ name }) => `World from ${name}`
};

// I want this to trow an error
const key: keyof MyConfs = "hello";

Upvotes: 0

Related Questions