4

I want to take type stringUnion = "Value1"|"Value2" and make an array from all the strings in stringUnion

so the array looks like this ["Value1","Value2"], I want an array so I can iterate over it like this:

theArray.map((current, index)=>{

})

How do I do that?

2

3 Answers 3

6

Yes, it is possible.

// credits goes to https://stackoverflow.com/questions/50374908/transform-union-type-to-intersection-type/50375286#50375286
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
  k: infer I
) => void
  ? I
  : never;

// credits goes to https://github.com/microsoft/TypeScript/issues/13298#issuecomment-468114901
type UnionToOvlds<U> = UnionToIntersection<
  U extends any ? (f: U) => void : never
>;

type PopUnion<U> = UnionToOvlds<U> extends (a: infer A) => void ? A : never;


// credits goes to https://stackoverflow.com/questions/53953814/typescript-check-if-a-type-is-a-union#comment-94748994
type IsUnion<T> = [T] extends [UnionToIntersection<T>] ? false : true;

type UnionToArray<T, A extends unknown[] = []> = IsUnion<T> extends true
  ? UnionToArray<Exclude<T, PopUnion<T>>, [PopUnion<T>, ...A]>
  : [T, ...A];

interface Person {
  name: string;
  age: number;
  surname: string;
  children: number;
}

type Result = UnionToArray<keyof Person>; // ["name", "age", "surname", "children"]

Here is an alternative way:

// credits goes to https://twitter.com/WrocTypeScript/status/1306296710407352321
type TupleUnion<U extends string, R extends any[] = []> = {
    [S in U]: Exclude<U, S> extends never ? [...R, S] : TupleUnion<Exclude<U, S>, [...R, S]>;
}[U];

interface Person {
    firstName: string;
    lastName: string;
    dob: Date;
    hasCats: false;
}

type keys = TupleUnion<keyof Person>;

Playground

More explanation you can find in my blog

Sign up to request clarification or add additional context in comments.

8 Comments

This is a brilliant answer.
Agree, it's brilliant! Would there be a way to make it independent of the order in the array?
@jorgen could you please elaborate? I mean with some example and expected result
I mean (referring to the first method): type T = "a" | "b" means that const a: UnionToArray<T> = ["a", "b"] is permissible but not ["b", "a"]. In our case the type T is derived (using amongst other things Exclude), and somehow the correct order seems to depend on environment (local vs CI).. Not sure exactly how that happens
Note that in our case the second method gives an error "Type instantiation is excessively deep and possibly infinite.". I guess our derived type is just not amenable to this!
|
2

You can't use the stringUnion as a value in a variable (because types are not transpiled to js code).

But if this array is gonna be a constant, you can use:

const stringValues = ["value1", "value2"] as const;
type stringUnion = (typeof stringValues)[number];

Which will allow you to write the values only once.

2 Comments

The OP is asking about transforming a union type into a tuple.
@OlegValter From the question it's not clear if they ask about transforming it to a type of array or to a value of array...
0

It is not possible to create a value out of a type. So you can't convert your union type to an array. If you wish to create an array type though. You can do it in 2 ways.

  1. type YourArrayType = StringUnion[];
  2. type YourArrayType = Array<StringUnion>;

This type will create the following type: ("value1" | "value2")[] and it will only allow you to have either "value1" or "value2" in your array with this type.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.