Updated on 2026-08-23
Enum pattern
Use an Enum (or an as const object) when you have a simple list of options that do not carry extra information.
export const SearchMessages = {
CREATE_INDEX: 'create_index',
INDEX_READY: 'index_ready',
SEARCH_INDEX: 'search_index',
SEARCH_RESULTS: 'search_results',
SEARCH_RESULTS_EMPTY: 'search_results_empty'
} as const; // <--- The magic bit
// 2. Derive the Type from the object
export type SearchMessagesType =
(typeof SearchMessages)[keyof typeof SearchMessages];
Discriminated union
Use a Discriminated Union when each "option" in your list needs to carry different data. This is often called a "Sum Type" or "Tagged Union."
A Discriminated Union requires three things:
- Types that have a common property (the discriminant).
- A literal value for that property (e.g., 'success', 'error').
- A type alias that unions them.
type ApiResponse =
| { status: 'loading' } // No extra data
| { status: 'success', data: string, timestamp: number } // Extra data
| { status: 'error', message: string, code: number }; // Different extra data
function handleResponse(res: ApiResponse) {
switch (res.status) {
case 'loading':
return 'Spinning...';
case 'success':
// TypeScript knows 'data' exists here
return `Data: ${res.data}`;
case 'error':
// TypeScript knows 'message' exists here
return `Error: ${res.message}`;
}
}