ยท Jake Worth
Union type from array
You often want the same string list in three places: runtime values, a state type, and function parameters. Duplicating a union by hand drifts out of sync:
const builderSteps = ['communications', 'estimates', 'procedures'];type BuilderStep = 'communications' | 'estimates' | 'procedures';With as const and an indexed access type, the array is the single source of
truth:
const builderSteps = ['communications', 'estimates', 'procedures'] as const;
type BuilderStep = (typeof builderSteps)[number];// 'communications' | 'estimates' | 'procedures'This lets us both type a slice of state, type a function that might receive that state, and build TSX elements all from the same array, a virtuous cycle.
import {useState} from 'react';
const [step, setStep] = useState<BuilderStep>('communications');
const handleStepClick = (step: BuilderStep) => setStep(step);
{ builderSteps.map((step) => ( <button key={step} onClick={() => handleStepClick(step)}> Set step: {step} </button> ));}When we skip as const, TypeScript widens the array to string[]. Then
(typeof builderSteps)[number] becomes string, and you lose the union. The
const assertion freezes the elements as readonly literal types so the
[number] lookup can turn the array into a union.