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>;