Search code examples
typescriptduplicatesunionpermutationtemplate-literals

Typescript string literal with permutations of union but no repetitions


I have the following union:

type Letter = 'a' | 'b' | 'c' | 'd' | 'e'

I want to allow for permutations of 1-3 letters using a Template Literal Type:

type Variation = Letter | `${Letter}-${Letter}` | `${Letter}-${Letter}-${Letter}`

How can I achieve this in Typescript while preventing repeated letters, so "a" "b-d" "a-c-d" and "d-c-a" are ok but "a-a-c" is not allowed.


Solution

  • type Letter = 'a' | 'b' | 'c' | 'd' | 'e'
    
    type Variation<T> =
        (T extends `${infer A}-${infer B}`
            ? (B extends `${infer BA}-${infer BB}`
                ? (
                    `${A}-${Exclude<Letter, A>}-${Exclude<Exclude<Letter, BA>, A>}`
                )
                : (`${A}-${Exclude<Letter, A>}`)
            )
            : T
        );
    
    const a: Variation<'a'> = 'a';
    const b: Variation<'a-b'> = 'a-b';
    const c: Variation<'a-b-c'> = 'a-b-c';
    
    const d: Variation<'a-b-a'> = 'a-b-a'; // Error
    const e: Variation<'a-d-d'> = 'a-d-d'; // Error
    const f: Variation<'a-a-a'> = 'a-a-a'; // Error