Matchbox Factories
The matchboxFactory function creates factories for working with tagged unions in TypeScript, providing type-safe pattern matching, exhaustiveness checking, and comprehensive type inference.
Its main features include:
- Factory Functions - Create tagged union instances with proper typing
- Pattern Matching - Match against union variants with exhaustiveness checking
- Type Predicates - Built-in type guards with the
ismethod - Type Assertion - Convert between variants with the
asmethod - Complete Type Inference - Full inference with minimal type annotations
Creating a Factory
Section titled “Creating a Factory”You can create a factory using the matchboxFactory function. This factory then provides functions to create individual tagged union instances:
import { function matchboxFactory<Config extends TaggedTypes | string, TagProp extends string = "tag", R = MatchboxFactory<Config extends readonly string[] ? { [K in Config[number]]: (data: any) => any; } : Config, TagProp>>(config: Config, tagProp?: TagProp): R
matchboxFactory } from "matchina";
export const const Light: MatchboxFactory<{ Off: undefined; On: (percentage?: number) => { percentage: number; };}, "tag">
Light = matchboxFactory<{ Off: undefined; On: (percentage?: number) => { percentage: number; };}, "tag", MatchboxFactory<{ Off: undefined; On: (percentage?: number) => { percentage: number; };}, "tag">>(config: { Off: undefined; On: (percentage?: number) => { percentage: number; };}, tagProp?: "tag" | undefined): MatchboxFactory<{ Off: undefined; On: (percentage?: number) => { percentage: number; };}, "tag">
matchboxFactory({ // Off state with no parameters type Off: undefined
Off: var undefined
undefined, // On state with optional brightness percentage type On: (percentage?: number) => { percentage: number;}
On: (percentage: number
percentage = 100) => ({ percentage: number
percentage }),});
// Create light instancesconst const off: MatchboxMember<"Off", { Off: undefined; On: (percentage?: number) => { percentage: number; };}, "tag">
off = const Light: MatchboxFactory<{ Off: undefined; On: (percentage?: number) => { percentage: number; };}, "tag">
Light.type Off: () => MatchboxMember<"Off", { Off: undefined; On: (percentage?: number) => { percentage: number; };}, "tag">
Off();const const onFull: MatchboxMember<"On", { Off: undefined; On: (percentage?: number) => { percentage: number; };}, "tag">
onFull = const Light: MatchboxFactory<{ Off: undefined; On: (percentage?: number) => { percentage: number; };}, "tag">
Light.type On: (percentage?: number | undefined) => MatchboxMember<"On", { Off: undefined; On: (percentage?: number) => { percentage: number; };}, "tag">
On(); // Uses default 100%const const dimmed: MatchboxMember<"On", { Off: undefined; On: (percentage?: number) => { percentage: number; };}, "tag">
dimmed = const Light: MatchboxFactory<{ Off: undefined; On: (percentage?: number) => { percentage: number; };}, "tag">
Light.type On: (percentage?: number | undefined) => MatchboxMember<"On", { Off: undefined; On: (percentage?: number) => { percentage: number; };}, "tag">
On(50); // 50% brightnessconst { const percentage: number
percentage } = const dimmed: MatchboxMember<"On", { Off: undefined; On: (percentage?: number) => { percentage: number; };}, "tag">
dimmed.data: { percentage: number;}
data;
export { const off: MatchboxMember<"Off", { Off: undefined; On: (percentage?: number) => { percentage: number; };}, "tag">export off
off, const onFull: MatchboxMember<"On", { Off: undefined; On: (percentage?: number) => { percentage: number; };}, "tag">export onFull
onFull, const dimmed: MatchboxMember<"On", { Off: undefined; On: (percentage?: number) => { percentage: number; };}, "tag">export dimmed
dimmed, const percentage: numberexport percentage
percentage };Custom Tag Property
Section titled “Custom Tag Property”By default, the tag property is named tag, but you can customize it:
const const states: MatchboxFactory<{ Idle: () => {}; Done: (x: number) => { result: number; };}, "key">
states = matchboxFactory<{ Idle: () => {}; Done: (x: number) => { result: number; };}, "key", MatchboxFactory<{ Idle: () => {}; Done: (x: number) => { result: number; };}, "key">>(config: { Idle: () => {}; Done: (x: number) => { result: number; };}, tagProp?: "key" | undefined): MatchboxFactory<{ Idle: () => {}; Done: (x: number) => { result: number; };}, "key">
matchboxFactory( { type Idle: () => {}
Idle: () => ({}), type Done: (x: number) => { result: number;}
Done: (x: number
x: number) => ({ result: number
result: x: number
x }), }, "key");
const const events: MatchboxFactory<{ add: (x: number, y: number) => { x: number; y: number; }; square: (x: number) => number;}, "type">
events = matchboxFactory<{ add: (x: number, y: number) => { x: number; y: number; }; square: (x: number) => number;}, "type", MatchboxFactory<{ add: (x: number, y: number) => { x: number; y: number; }; square: (x: number) => number;}, "type">>(config: { add: (x: number, y: number) => { x: number; y: number; }; square: (x: number) => number;}, tagProp?: "type" | undefined): MatchboxFactory<{ add: (x: number, y: number) => { x: number; y: number; }; square: (x: number) => number;}, "type">
matchboxFactory( { add: (x: number, y: number) => { x: number; y: number;}
add: (x: number
x: number, y: number
y: number) => ({ x: number
x, y: number
y }), square: (x: number) => number
square: (x: number
x: number) => x: number
x, }, "type");
const states: MatchboxFactory<{ Idle: () => {}; Done: (x: number) => { result: number; };}, "key">
states.type Idle: () => MatchboxMember<"Idle", { Idle: () => {}; Done: (x: number) => { result: number; };}, "key">
Idle().key: "Idle"
key; // "Idle"const events: MatchboxFactory<{ add: (x: number, y: number) => { x: number; y: number; }; square: (x: number) => number;}, "type">
events.add: (x: number, y: number) => MatchboxMember<"add", { add: (x: number, y: number) => { x: number; y: number; }; square: (x: number) => number;}, "type">
add(1, 2).type: "add"
type; // "add"Conclusion
Section titled “Conclusion”Matchbox provides a powerful way to work with tagged unions in TypeScript, with additional type safety mechanisms, pattern matching, and improved developer experience.
This makes complex state modeling and data handling more robust and maintainable, with TypeScript providing excellent completion support and helping to catch errors at compile time rather than runtime.