Type for "every possible string value except ..."

There isn't a general solution to this problem since there is no way to express in the typescript type system the fact that a string can be any value except a list. (One might think the conditional type Exclude<string, ReservedNames> would work but it does not, it just evaluates back to string).

As a work around, if we have a function and we specifically want to not allow certain constants to be passed in we can us a conditional type to check for ReservedNames and, if the passed in parameter is ReservedNames then type the input parameter in such a way it is effectively impossible to satisfy (using an intersection type).

type ReservedNames = "this" | "that"
type FooName = Exclude<string, ReservedNames>;
const f1 : FooName = "This" // Works
const f2 : FooName = "this" // One might expect this to work but IT DOES NOT as FooName is just evaluates to string


function withName<T extends string>(v: T & (T extends ReservedNames ? "Value is reserved!": {})) {
  return v;
}

withName("this"); // Type '"this"' is not assignable to type '"Value is reserved!"'.
withName("This") // ok

Playground


This isn't currently possibly in Typescript, however you can create a generic type that can handle many of the practical use cases if you add the concrete string value as a parameter of FooName.

type ReservedNames = "this" | "that"
type NotA<T> = T extends ReservedNames ? never : T
type NotB<T> = ReservedNames extends T ? never : T
type FooName<T> = NotA<T> & NotB<T>

const f1: FooName<'This'> = 'This' // works
const f2: FooName<'this'> = 'this' // error

const f3: FooName<string> = 'this' //error
const f4: FooName<any> = 'this' // error
const f5: FooName<unknown> = 'this' // error

And in a function it works as expected if you make the function generic on the string value:

function foo<T extends string> (v: FooName<T>) {
  ...
}

foo('this') // error
foo('This') // works