Search code examples
javascriptarraystypescripttypestype-inference

Typescript `Array.join` literal return type


I have an array like:

const arr = ['a', 'b'] as const;
// type: readonly ["a", "b"]

Now I want to join the strings in the array:

const joined = arr.join('');
// type: string

My goal is to write a function that joins strings in an array and returns them as a literal string type ("ab").

Does someone know if this is even possible? I think it should be, since all the type information needed is given. I don't expect a full solution to the problem - maybe just a hint for further research would be great.


Solution

  • Here is a version that works with both readonly and mutable tuples types and a separator.

    type Join<
      TElements,
      TSeparator extends string,
    > = TElements extends Readonly<[infer First, ...infer Rest]>
      ? Rest extends ReadonlyArray<string>
        ? First extends string
          ? `${First}${Rest extends [] ? '' : TSeparator}${Join<Rest, TSeparator>}`
          : never
        : never
      : '';
    
    type MutableTuple = ["a", "b", "c"];
    type MutableTupleJoined = Join<MutableTuple, " | ">;
    //   ^? "a | b | c"
    
    type ReadonlyTuple = readonly ["a", "b", "c"];
    type ReadonlyTupleJoined = Join<ReadonlyTuple, " | ">;
    //   ^? "a | b | c"
    

    A readonly type often comes from const assertions e.g.

    const tuple = ["a", "b", "c"] as const;
    type Joined = Join<typeof tuple, " | ">;
    

    When inlining the tuple type, it is usually mutable e.g.

    type Joined = Join<["a", "b", "c"], " | ">;