最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Typescript `Array.join` literal return type - Stack Overflow

programmeradmin1浏览0评论

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.

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.

Share Improve this question edited Jun 22, 2022 at 22:26 Kostas Minaidis 5,5754 gold badges20 silver badges29 bronze badges asked Jun 22, 2022 at 22:21 nyarthannyarthan 5355 silver badges18 bronze badges 8
  • 1 Yes, it is possible. – Kostas Minaidis Commented Jun 22, 2022 at 22:28
  • You just need to define a function and move all the required operations inside the function body, then return the result. – Kostas Minaidis Commented Jun 22, 2022 at 22:28
  • @KostasMinaidis But how to get the function typed as desired? I'm thinking it might involve a recursive variadic tuple type. Easily doable if the function itself is recursive, but to use .join and recurse only in the type is a step beyond. – CertainPerformance Commented Jun 22, 2022 at 22:39
  • 3 Something like this? tsplay.dev/NnK8om – spender Commented Jun 22, 2022 at 23:00
  • 1 I'm too tired to write this up as an answer, so consider it your hint. Feel free to self-answer with what you learn from this. The type inference can also be improved with TS4.7 by using extends constraints on infer type variables – spender Commented Jun 22, 2022 at 23:05
 |  Show 3 more ments

5 Answers 5

Reset to default 1
const arr = ['a', 'b'] as const;

type JoinStrings<T extends readonly string[]> = T extends readonly [infer F, ...infer R]
  ? `${F}${JoinStrings<R>}`
  : '';

const joinArray = <T extends readonly string[]>(arr: T): JoinStrings<T> => arr.join('') as JoinStrings<T>;
const joined = joinArray(arr);

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 es 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"], " | ">;
const joinStrings = <T extends readonly string[]>(arr: T): `${T[number]}` => arr.join('') as `${T[number]}`;

const arr = ['a', 'b'] as const;
const joined = joinStrings(arr); // type: "ab"

try this. By using as ${T[number]}, you are telling TypeScript that the return value of arr.join('') should be treated as a literal string type based on the elements in the array.

This should work.

  T extends [infer F, ...infer R] ?
    F extends string ? 
      R extends string[] ?
        `${F}${Concat<R>}`
      : never
    : never
  : ""

  const alphabets:Concater<["A", "B", "C"]> = "ABC"
const joinedString = (arr as string[]).join('');
console.log(joinedString); // Output: 'ab'

This should work.

发布评论

评论列表(0)

  1. 暂无评论