How to exclude substring of a Template Literal Type?

Viewed 1075

I would like to exclude some substring from a Template Literal Type (available since TypeScript 4.1), but I don't know if it's possible.

Example:

I can define a type saying "this string is a tuple-like with 2 or more elements", ie something like '[string, number]' with this literal type :

type TupleWithTwoOrMoreElements = `[${string}, ${string}]`;

Now, I would like to do the contrary, ie creating a literal type saying "this is a tuple-like which have less than 2 elements" by excluding the substring , . I thought to do something like this :

type TupleWithLessThanTwoElements = `[${someStringWithoutCommaOrSpace}]`;

I think that it's not possible to write this kind of "regex-literal-type", but I would like to know if someone would be able to solve this problem.

2 Answers

It is not possible (as far as I know) to write a type for "any string without a comma". However if the string is known in advance, it is possible to create a conditional type that checks if that string contains a comma.

type HasComma<S extends string, IfTrue = true, IfFalse = false> = 
  S extends `${string},${string}` ? IfTrue : IfFalse;
type A = HasComma<','> // true
type B = HasComma<'string'> // false
type C = HasComma<'[string, number]'> // true

So given a literal string, we can validate it and make sure that it is a tuple with only one element.

type ValidateOneTuple<S extends string, IfValid = S, IfInvalid = never> = 
  HasComma<S, IfInvalid, S extends `[${string}]` ? IfValid : IfInvalid>
type A = ValidateOneTuple<'[string, number]'> // never
type B = ValidateOneTuple<'[string]'> // "[string]"
type C = ValidateOneTuple<'[str,ing]'> // never

Typescript Playground Link

There is no way of doing it. I had the idea of explicitly allowing some chars, but that is not possible because you can't say char "x" of any length. Regex types are also not possible, and don't seem to be implemented soon. Look at this issue in GitHub.

Related