1

How can I write a generic type which can be used for all const assertions to enforce their respective values?

Code

const GENDER = {
  male: 'm',
  female: 'f',
} as const;

type GenderType = typeof GENDER[keyof typeof GENDER];

// enforces userGender to be either 'm' of 'f'
let userGender: GenderType;

userGender = 'f'; // valid
userGender = 'm'; // valid
userGender = 'o'; // invalid

How can I generalise it such that it can be used with all const assertions?

// generalise the boilerplate of
// typeof SOMETHING[keyof typeof SOMETHING]

type GenderType = ValueType<GENDER>;
type FooType = ValueType<FOO>;
type BarType = ValueType<BAR>;
type BazType = ValueType<BAZ>;
Vinay Sharma
  • 3,291
  • 4
  • 30
  • 66
  • You can make a type alias that works like `ValueType` but no `ValueType`, because `FOO` is a value but generics take types and not values. – jcalz Jul 25 '22 at 16:53
  • So what do you want to see as an answer here? If `type ValueType = T[keyof T]` and then `ValueType` is okay, great. If you insist on `ValueType` then the answer here is just "no, this can't be done" and I can write up an explanation for why. Let me know which way to go with this. – jcalz Jul 25 '22 at 17:35

1 Answers1

0

Solution

Use a generic type that accepts the type of the object literal.

// ===== const assertion ===== //

const GENDER = {
  male: 'm',
  female: 'f',
} as const;

// ===== generic solution ===== //

type ValueOf<T> = T[keyof T]

// ====== generic usage ====== //

type GenderType = ValueOf<typeof GENDER>;

// enforces userGender to be either 'm' or 'f'
let userGender: GenderType;

userGender = 'f'; // valid
userGender = 'm'; // valid
userGender = 'o'; // invalid

// === more usage examples === //

type FooType = ValueOf<typeof FOO>;
type BarType = ValueOf<typeof BAR>;
type BazType = ValueOf<typeof BAZ>;
Vinay Sharma
  • 3,291
  • 4
  • 30
  • 66