Home > OS >  Is it possible to create an object from a Typescript string union?
Is it possible to create an object from a Typescript string union?

Time:10-21

I have a string union type like

type example = "foo" | "bar" | "baz";

Is it possible to turn that type into an object like below?

const example = {
  foo: "foo",
  bar: "bar",
  baz: "baz"
};

I want to try and keep it as DRY as possible and not have to create a separate object with those values hardcoded.

CodePudding user response:

I do not think if you can create an object using type definition because everything is compiled down to JavaScript that does not have strong type info. If you wanted to create another type object based on the union, you can do this:

type example = "foo" | "bar" | "baz";
type exampleObject = {[key in example]: string}
// equivalent to
// type exampleObject = {
//     foo: string;
//     bar: string;
//     baz: string;
// }

// You can use the object type
const example: exampleObject = {
  foo: "foo",
  bar: "bar",
  baz: "baz"
};

TS Playground link: https://tsplay.dev/w6BOrw

But as the comment says, if you want to restrict the values as given in your example, you can do this:

type exampleObjectExact = {[key in example]: key}
// equivalent to
// type exampleObjectExact = {
//     foo: "foo";
//     bar: "bar";
//     baz: "baz";
// }

You can also use built in utility type: Record:

type Result = Record<example, example>;

Seeing your own answer, it seems like you have slightly changed the problem definition. Initial question was about the union type to object type conversion. I assumed you did not have any control over the union type, perhaps it was coming from a library or something. But, if you have control over this, you could do this (which @Aleksey rightly mentioned):

const example = ['foo', 'bar', 'baz'] as const;

type exampleObjExact = { [key in typeof example[number]]: key }
// is equivalent to
// type exampleObjExact = {
//     foo: "foo";
//     bar: "bar";
//     baz: "baz";
// }

const x = example.reduce<exampleObjExact>((cum, v) => ({...cum, v}), {} as any)

TS Playground: https://tsplay.dev/WPjreN

CodePudding user response:

I was able to figure out a solution to my problem, although it is rather long-winded.

const buildReflectionFromArray = <T>(values: readonly T[]): Record<string, T> => values.reduce((acc, curr) => {
  Reflect.set(acc, String(curr), curr);
  return acc;
}, {});

const exampleType = ['foo', 'bar', 'baz'] as const;
type ExampleType = typeof exampleType[number];
// Casting the response here to enabled autocomplete from editors
const exampleTypes = buildReflectionFromArray<ExampleType>(exampleType) as Record<ExampleType, ExampleType>;

TS Playground Link: https://www.typescriptlang.org/play?jsx=0#code/MYewdgzgLgBARgVwJYBsAmAlApgMxV4KJcAMQCcQBbAQTLIEMBPGAXhgB4AVAPgAoA3eigRYIALhhks9NOBTNOAbQC6ASgnZQZNO2hkkYAOYAaGD1bcYg4aIB0UtAmBZevesGCngCOqoswAbwAoGBhsPAIoWwgsKDcPUwBlKH0jXm9fLx8yVQBuEMlYnzAYd2B8gF9TAIq8oKDQSFgsAA96SgAHfE5GDqxWGEUAchwQECHTIbh6MgmYKfoALyHlUogYRuh8qF7 gFE2zu7dgZ2 kBwYVvaurB6 xTAESjgsMmV8gHpPmABhemgBkMMCgAAt lIIB1wDEYOCpCCQFcwPQ4Pg0KUEFAQKAjrF jgKJQrmgkNiyBAGjDmodbvdRANEKhMLh8IRiGByFRaAxGOwDjdjn0 Nc8fS-ACwgQQNp bShVhTAKxbtuLkgA

  • Related