How can I constrain generic parameter to be assignable to string?

I have a function with a generic parameter T. I intend this generic parameter to be either a sum types of different constant strings, like "alpha"|"beta", or an enum with string values, like enum ExampleEnum { Alpha = "ALPHA", Beta = "BETA" }. Either way, in runtime all the values will be strings and I should be able to use them wherever strings are used.

Here's the example function:

function chooseRandom<T>(inputs: T[], callback: (chosen: T) => void) {
  const t = inputs[4]; // die roll, guaranteed to be random
  acceptsOnlyString(t);
  callback(t);
}

function acceptsOnlyString(input: string) {
  console.log(input);
}

And of course, with this, I get an error when I call acceptsOnlyString:

Type 'T' is not assignable to type 'string'

I included the callback function in this example to explain why I can't just use string — the users of chooseRandom function will want to specify a callback that only accepts T and not any possible string.

How do I explain to typescript that T should be constrained to types that are assignable to a string?


You can restrict what types are allowed for a generic with the extends keyword:

function chooseRandom<T extends string>(inputs: T[], callback: (chosen: T) => void) {
  const t = inputs[4]; // die roll, guaranteed to be random
  acceptsOnlyString(t);
  callback(t);
}

With this restriction, typescript knows it's safe to pass t into acceptsOnlyString

Playground link