Typescript create a type based of variable value

I have a array of shadow styles that looks like this

const shadows = [
  'none',
  '0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)',
  "...And more"
];

My goal is to be able to use them safely in my JSS with intellisense, so I have this to accomplish that

type Enumerate<
  N extends number,
  Acc extends number[] = []
> = Acc['length'] extends N
  ? Acc[number]
  : Enumerate<N, [...Acc, Acc['length']]>;

export type IntRange<F extends number, T extends number> = Exclude<
  Enumerate<T>,
  Enumerate<F>
>;

export const shadow = (num: Shadow) => shadows[num];
// This will make it possible to only input numbers from 0 to 24
export type Shadow = IntRange<0, 24>;

And using them like this in my components boxShadow: theme.shadows(10) and this will throw a error if out of range.

Instead of hardcoding 24 as maximum is it possible to utilize the length of the array here?
To have it be something like this export type Shadow = IntRange<0, shadows.length>;

>Solution :

If you make your shadows a tuple (shortcut with as const), then you can use the length property, as it will be a number literal type:

const shadows = [
  'none',
  '0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)',
  "...And more",
] as const; // now type is a readonly tuple of length 3

export type Shadow = IntRange<0, typeof shadows["length"]>; // OK

Playground (with 24 elements)

Leave a Reply