1

I am trying to define a TypeScript type that restricts values to the string versions of a set of numbers. Explanation below:

Say I have a union numeric type like so:

const ONE = 1;
const TWO = 2;

type ALLOWED_NUMBER = typeof ONE | typeof TWO;

I would like to also define a companion string type that only allows the stringified versions of these numbers. So that I could do the following:

type ALLOWED_NUMBER_STRING = /* insert solution here :) */

const numericStringA: ALLOWED_NUMBER_STRING = '1';    // no error
const numericStringB: ALLOWED_NUMBER_STRING = '3';    // error
const numericStringC: ALLOWED_NUMBER_STRING = 'foo';  // error

I could manually define this type but it would be great to avoid the redundancy!

Benny B
  • 357
  • 1
  • 3
  • 13
  • [Here](https://tsplay.dev/WJ4PlN) you can find dry generic solution and [here](https://stackoverflow.com/questions/69089549/typescript-template-literal-type-how-to-infer-numeric-type#answer-69090186) you can find an explanation – captain-yossarian from Ukraine Feb 18 '22 at 08:13

1 Answers1

1

You're looking for template literal types:

TS Playground

const ONE = 1;
const TWO = 2;

type ALLOWED_NUMBER = typeof ONE | typeof TWO;
type ALLOWED_NUMBER_STRING = `${ALLOWED_NUMBER}`;

const numericStringA: ALLOWED_NUMBER_STRING = '1';

const numericStringB: ALLOWED_NUMBER_STRING = '3'; /*
      ^^^^^^^^^^^^^^
Type '"3"' is not assignable to type '"1" | "2"'.(2322) */

const numericStringC: ALLOWED_NUMBER_STRING = 'foo'; /*
      ^^^^^^^^^^^^^^
Type '"foo"' is not assignable to type '"1" | "2"'.(2322) */


And, for a collection of numbers, you can make it DRYer this way:

TS Playground

const allowedNumbers = [1, 2, 3] as const;
type AllowedNumber = typeof allowedNumbers[number]; // 1 | 2 | 3
type AllowedNumberStr = `${AllowedNumber}`; // "1" | "2" | "3"
jsejcksn
  • 27,667
  • 4
  • 38
  • 62