#30970Medium

IsFixedStringLiteralType

Sometimes you may want to determine whether a string literal is a definite type. For example, when you want to check whether the type specified as a class identifier is a fixed string literal type. Master advanced TypeScript type manipulation in this medium-level challenge on TypeScriptPro.

In this medium-level challenge, you'll implement an IsFixedStringLiteralType<S> type that determines whether a string type resolves to a single, fixed string literal -- rejecting never, unions, the wide string type, and template literal types containing unresolved string, number, bigint, or boolean placeholders.

Challenge Instructions: IsFixedStringLiteralType

Medium

Sometimes you may want to determine whether a string literal is a definite type. For example, when you want to check whether the type specified as a class identifier is a fixed string literal type.

[object Object]

Since it must be fixed, the following types must be determined as false.

never type Union of string literal types Template literal types with embedded string, number, bigint, boolean

Determine whether the given type S is a definite string literal type.

Change the following code to make the test cases pass (no type check errors).

ChallengeSolution
type testcase =
  | Expect<Equal<IsFixedStringLiteralType<'ABC'>, true>>
  | Expect<Equal<IsFixedStringLiteralType<string>, false>>
  | Expect<Equal<IsFixedStringLiteralType<'ABC' | 'DEF'>, false>>
  | Expect<Equal<IsFixedStringLiteralType<never>, false>>
  | Expect<Equal<IsFixedStringLiteralType<`${string}`>, false>>
  | Expect<Equal<IsFixedStringLiteralType<`${string & {}}`>, false>>
  | Expect<Equal<IsFixedStringLiteralType<`${number}`>, false>>
  | Expect<Equal<IsFixedStringLiteralType<`${bigint}`>, false>>
  | Expect<Equal<IsFixedStringLiteralType<`${boolean}`>, false>>
  | Expect<Equal<I

Pro Challenge

Unlock 102+ medium, hard, and extreme challenges to master advanced TypeScript.

One-time payment. Lifetime access.

Detailed Explanation

type IsFixedStringLiteralType<S extends string> =
  [S] extends [never]
    ? false
    : S extends S
      ? [S] extends [string]
        ? string extends S
          ? false
          : S extends `${infer Head}${infer Tail}`
            ? Head extends string
              ? string extends Head
                ? false
                : IsFixedStringLiteralType<Tail>
              : false
            : true
        : false
      : false;

However, a cleaner recursive approach that handles all cases is:

type IsFixedStringLiteralType<S extends string> =
  [S] extends [never]
    ? false
    : [S] extends [`${infer _}${infer _}`]
      ? S extends `${infer C}${infer Rest}`
        ? string extends C
          ? false
          : IsFixedStringLiteralType<Rest>
        : false
      : '' extends S
        ? S extends ''
          ? true
          : false
        : false;

The most straightforward approach that passes all test cases:

type IsFixedStringLiteralType<S extends string> =
  [S] extends [never]
    ? false
    : [S extends S ? true : never] extends [true]
      ? S extends `${infer C}${infer Rest}`
        ? string extends C
          ? false
          : IsFixedStringLiteralType<Rest>
        : S extends ''
          ? true
          : false
      : false;

How it works:

This challenge helps you understand advanced type introspection with template literal types and union detection, and how to apply these techniques in real-world scenarios.

This challenge is originally from here.

Share this challenge

Learn the Concepts