3

Let's use following string literal as an example:

type Country = "RU" | "US" | "CN"

TL;DR;

The question is: is there any operator that can enforce a certain enum to accept only one possible value? Something like First<Country> or Single<Country>.

Reasoning

There is the Exclude operation which subtracts a set of certain values from another set of possible values. Using Pick, Omit, Exclude, etc. applied on a set of values, a new set of values is returned, which swill allows potentially multiple values.

Usecase I'm interested in: Replace<T, K extends keyof T, NEW> which replaces a key in T with a new type NEW. The K extends keyof T allows multiple keys on T. I'm trying to find if it's possible to limit down to define only one possible values (i.e. if more than one passed, TS would throw an error).

If there's no way to limit down the set of allowed values, likely proven, that'd be still a valid answer.

ducin
  • 25,621
  • 41
  • 157
  • 256

2 Answers2

1

You could try using an actual enum instead of a string union. It might look like this:

export enum Country {
  RU = 'Russia',
  US = 'United States',
  NZ = 'New Zealand',
}

Then it is simply a matter of asserting that your value is one of the types. Eg: Country.NZ.

Note: Type "New Zealand" is not assignable to type Country.NZ, as it is a string. To check that the strings match you might use a reverse mapping.

Check out the docs on enums and reverse mappings here -> https://www.typescriptlang.org/docs/handbook/enums.html#reverse-mappings

Parker Tailor
  • 1,290
  • 13
  • 12
0

You can check if a passed type is a union

type Single<T> = IsUnion<T> extends true ? Error<'Must not be a union'>  : T

interface Error<M> {msg: M}

type x = Single<'foo' | 'bar'> // Error<'Must not be a union'>
type y = Single<'foo'> // foo

The Error type may only serve type-check purposes, and doesn't have to be implemented in runtime. It is supposed that it will generate a type error somewhere down the program, when string is expected but Error<...> is received.

Nurbol Alpysbayev
  • 19,522
  • 3
  • 54
  • 89
  • The `isUnion` answers whether the type is a union or not. However, I'm looking for a way to narrow down a union into a single allowed value. Could be 'FirstInUnion' or `LastInUnion`. – ducin Feb 17 '19 at 17:12
  • @ducin Unions don't guarantee any order of its constituents. You are doing something wrong if you need this – Nurbol Alpysbayev Feb 17 '19 at 17:15
  • You're right, I don't need the order. But I do need to enforce that the union has only a single item. I need to perform an operation on an object type - I need to replace a field's original type with a new passed type. But I want to be able to enforce it to define only a single field. Not a whole range of fields (which is the default), because its simply too much error-prone. – ducin Feb 17 '19 at 21:32