Skip to content

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.

While TypeScript has built-in support for discriminated unions, the matchboxFactory system adds powerful capabilities:

  1. Factory Functions - Create tagged union instances with proper typing
  2. Pattern Matching - Match against union variants with exhaustiveness checking
  3. Type Predicates - Built-in type guards with the is method
  4. Type Assertion - Convert between variants with the as method
  5. Complete Type Inference - Full inference with minimal type annotations

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
Create a tagged union from a record mapping tags to value types, along with associated variant constructors, type predicates and `match` function.
@templateConfig - The configuration object or array of tags@templateTagProp - The property name used for the tag (default: "tag")@returnsAn object with constructors for each variant, type predicates, and match function@example```ts // Define a union of variants for a Result type const Result = matchboxFactory({ Ok: (value: number) => ({ value }), Err: (error: string) => ({ error }), }); // Create instances const ok = Result.Ok(42); const err = Result.Err("fail"); // Type predicates ok.is("Ok"); // true err.is("Err"); // true // Pattern matching const message = ok.match({ Ok: ({ value }) => `Value: ${value}`, Err: ({ error }) => `Error: ${error}`, }); // message === "Value: 42" ```
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: {
    ...;
}, tagProp?: "tag" | undefined): MatchboxFactory<...>
Create a tagged union from a record mapping tags to value types, along with associated variant constructors, type predicates and `match` function.
@templateConfig - The configuration object or array of tags@templateTagProp - The property name used for the tag (default: "tag")@returnsAn object with constructors for each variant, type predicates, and match function@example```ts // Define a union of variants for a Result type const Result = matchboxFactory({ Ok: (value: number) => ({ value }), Err: (error: string) => ({ error }), }); // Create instances const ok = Result.Ok(42); const err = Result.Err("fail"); // Type predicates ok.is("Ok"); // true err.is("Err"); // true // Pattern matching const message = ok.match({ Ok: ({ value }) => `Value: ${value}`, Err: ({ error }) => `Error: ${error}`, }); // message === "Value: 42" ```
matchboxFactory
({
// Off state with no parameters type Off: undefinedOff: var undefinedundefined, // On state with optional brightness percentage
type On: (percentage?: number) => {
    percentage: number;
}
On
: (percentage: numberpercentage = 100) => ({ percentage: numberpercentage }),
}); // Create light instances const
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% brightness
const { const percentage: numberpercentage } =
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: number
export percentage
percentage
};

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<...>
Create a tagged union from a record mapping tags to value types, along with associated variant constructors, type predicates and `match` function.
@templateConfig - The configuration object or array of tags@templateTagProp - The property name used for the tag (default: "tag")@returnsAn object with constructors for each variant, type predicates, and match function@example```ts // Define a union of variants for a Result type const Result = matchboxFactory({ Ok: (value: number) => ({ value }), Err: (error: string) => ({ error }), }); // Create instances const ok = Result.Ok(42); const err = Result.Err("fail"); // Type predicates ok.is("Ok"); // true err.is("Err"); // true // Pattern matching const message = ok.match({ Ok: ({ value }) => `Value: ${value}`, Err: ({ error }) => `Error: ${error}`, }); // message === "Value: 42" ```
matchboxFactory
(
{ type Idle: () => {}Idle: () => ({}),
type Done: (x: number) => {
    result: number;
}
Done
: (x: numberx: number) => ({ result: numberresult: x: numberx }),
}, "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: {
    ...;
}, tagProp?: "type" | undefined): MatchboxFactory<...>
Create a tagged union from a record mapping tags to value types, along with associated variant constructors, type predicates and `match` function.
@templateConfig - The configuration object or array of tags@templateTagProp - The property name used for the tag (default: "tag")@returnsAn object with constructors for each variant, type predicates, and match function@example```ts // Define a union of variants for a Result type const Result = matchboxFactory({ Ok: (value: number) => ({ value }), Err: (error: string) => ({ error }), }); // Create instances const ok = Result.Ok(42); const err = Result.Err("fail"); // Type predicates ok.is("Ok"); // true err.is("Err"); // true // Pattern matching const message = ok.match({ Ok: ({ value }) => `Value: ${value}`, Err: ({ error }) => `Error: ${error}`, }); // message === "Value: 42" ```
matchboxFactory
(
{
add: (x: number, y: number) => {
    x: number;
    y: number;
}
add
: (x: numberx: number, y: numbery: number) => ({ x: numberx, y: numbery }),
square: (x: number) => numbersquare: (x: numberx: number) => x: numberx, }, "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"

Matchbox provides a powerful way to work with tagged unions in TypeScript, offering better type safety, pattern matching, and developer experience than plain TypeScript discriminated unions.

The key advantages are:

  • Factory functions for creating properly typed variants
  • Exhaustive pattern matching
  • Built-in type guards and assertions
  • Excellent type inference

This makes complex state modeling and data handling more robust and maintainable, with TypeScript helping to catch errors at compile time rather than runtime.