Juraj Zovinec
Juraj Zovinec

Reputation: 316

TS type that requires string literal in the array/tuple

I am trying to build a generic type, that will guarantee presence of the string literal (no matter at what position)

What I desire for:

// 'a' is in the first position
const x1: ArrayContainingLiteral<'a'> = ['a', 'b', 'c']; // ✅
// 'a' is in the last position
const x2: ArrayContainingLiteral<'a'> = ['b', 'a']; // ✅
// 'a' is in between of other elements
const x3: ArrayContainingLiteral<'a'> = ['b', 'a', 'c', 'd']; // ✅

// 'a' is not in the array
const x4: ArrayContainingLiteral<'a'> = ['b', 'c']; // ❌
// 'a' is not in the array (array is empty)
const x5: ArrayContainingLiteral<'a'> = []; // ❌

My current progress is:

export type DoesArrayIncludeLiteral<StringLiteral extends string, StringArray extends Array<string>> = {
  [ArrayIndex in keyof StringArray]: StringArray[ArrayIndex] extends StringLiteral ? unknown : never;
}[number] extends never
  ? false
  : true;

export type ArrayContainingLiteral<Literal extends string, StringArray extends Array<string> = Array<string>> =
  DoesArrayIncludeLiteral<Literal, StringArray> extends true ? StringArray : never;

Which works somewhat fine but requires the whole array to be passed as an type argument

const x1: ArrayContainingLiteral<'a', ['a', 'b', 'c']> = ['a', 'b', 'c']; // ✅

Upvotes: 1

Views: 60

Answers (1)

Etienne Laurin
Etienne Laurin

Reputation: 7184

This can be done for arrays under a certain size, for example:

type Indices = 0 | 1 | 2 | 3 | 4 | 5;

type ArrayContainingLiteral<T> =
  Array<unknown> &
  (Indices extends infer U extends number ?
     U extends unknown ?
       { [I in U]: T }
     : never
  : never)

For larger sizes, see Is it possible to restrict number to a certain range

import { IntRange } from 'type-fest'

type Indices = IntRange<0, 32>

A naive solution like:

type ArrayContainingLiteral<T> =
  | [T, ...unknown[]]
  | [unknown, ...ArrayContainingLiteral<T>]

Does not work because of infinite recursion.

Upvotes: 1

Related Questions