Have you ever wanted to suggest some strings but still allow any string? Like "GET" | "POST" | string? But then it just doesn't work like you want it to?

[TypeScript playground link]
// Note how '"GET" | "POST" | string' gets reduced to just "string" since it's the
// broadest type of the intersection? That's expected behaviour.

type HTTPMethod = "GET" | "POST" | string
//   ^?
//                        ^ This should be "string"

function doHTTP(method: HTTPMethod): void {
    console.log(method)
    //          ^?
    //             ^ This should be "(parameter) method: string".
}

doHTTP("")
//     ^ Press CTRL+SPACE here to try and get autocomplete. You should get nothing.

From the compiler's point of view, this is just a very fancy way of writing string. By the time we're looking for suggestions at [HTTPMethod], all the literals are lost.

microsoft/TypeScript#29729

The trick is to fool the type checker into thinking that the | string part of the union type is magically (somehow?) different than the type of the literals -- that way it doesn't get reduced to just type T = string. The magic is string & {}.

[TypeScript playground link]
// It works!

type HTTPMethod = "GET" | "POST" | (string & {})
//   ^?
//                        ^ This should be '(string & {}) | "GET" | "POST"'

function doHTTP(method: HTTPMethod): void {
   console.log(method)
   //          ^?
   //             ^ This should be "(parameter) method: HTTPMethod".
}

doHTTP("")
//     ^ Press CTRL+SPACE here to try and get autocomplete. You should get string literals!

// ...but you can also just type any string you want. This is valid.
doHTTP("not-an-http-method")

The type-fest npm package has a type for this exact use-case: LiteralUnion.

import type {LiteralUnion} from 'type-fest';

// Before

type Pet = 'dog' | 'cat' | string;

const petWithoutAutocomplete: Pet = '';
// Start typing in your TypeScript-enabled IDE.
// You **will not** get auto-completion for `dog` and `cat` literals.

// After

type Pet2 = LiteralUnion<'dog' | 'cat', string>;

const petWithAutoComplete: Pet2 = '';
// You **will** get auto-completion for `dog` and `cat` literals.

There was a TypeScript GitHub issue opened about having this "one" | "two" | string literal stuff work out of the box, but it didn't go anywhere. Microsoft/TypeScript#29729