Type safety with Matchbox
Pattern Matching with Exhaustive Checking
Section titled “Pattern Matching with Exhaustive Checking”One of the most powerful features of Matchbox is exhaustive pattern matching with the match
method:
// Calculate area with pattern matchingconst getArea = (shape) => shape.match({ Circle: ({ radius }) => Math.PI * radius * radius, Rectangle: ({ width, height }) => width * height, Triangle: ({ base, height }) => (base * height) / 2,});
// TypeScript error if you forget a case!const getPerimeter = (shape) => shape.match({ Circle: ({ radius }) => 2 * Math.PI * radius, Rectangle: ({ width, height }) => 2 * (width + height), // Error: Property 'Triangle' is missing in type '...'});
Type Guards
Section titled “Type Guards”Tagged union instances created with matchboxFactory
provide automatic type narrowing with the is
method:
// Create a Light matchbox with On/Off states
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.matchboxFactory({
type Off: undefined
Off: var undefined
undefined,
type On: (percentage?: number) => {
percentage: number;
}
On: (percentage: number
percentage = 100) => ({ percentage: number
percentage }),
});
// Create light instances
const const light1: MatchboxMember<"Off", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag">
light1 = 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 light2: MatchboxMember<"On", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag">
light2 = 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(75);
// Type guards with automatic type narrowing
if (const light2: MatchboxMember<"On", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag">
light2.MatchboxMemberApi<{ Off: undefined; On: (percentage?: number) => { percentage: number; }; }, "tag">.is: <"On">(key: "On") => this is MatchboxMember<T, DataSpecs, TagProp>
is("On")) {
// TypeScript knows light2.data has percentage
var console: Console
The `console` module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
* A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream.
* A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstderr). The global `console` can be used without calling `require('console')`.
_**Warning**_: The global console object's methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v20.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
```
Example using the `Console` class:
```js
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
```console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
Prints to `stdout` with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v20.x/api/util.html#utilformatformat-args)).
```js
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
```
See [`util.format()`](https://nodejs.org/docs/latest-v20.x/api/util.html#utilformatformat-args) for more information.log(`Brightness: ${const light2: MatchboxMember<"On", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag">
light2.data: {
percentage: number;
}
data.percentage: number
percentage}%`);
// This would be a TypeScript error:
// console.log(light2.data.invalid); // Error: Property 'invalid' does not exist
}
// Type guards can be used in conditions
function function getBrightness(light: ReturnType<typeof Light.Off> | ReturnType<typeof Light.On>): number
getBrightness(
light: MatchboxMember<"Off", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag"> | MatchboxMember<"On", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag">
light: type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any
Obtain the return type of a function typeReturnType<typeof 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> | type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any
Obtain the return type of a function typeReturnType<typeof 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>
) {
if (light: MatchboxMember<"Off", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag"> | MatchboxMember<"On", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag">
light.MatchboxMemberApi<DataSpecs, TagProp extends string>.is: <"Off">(key: "Off") => this is MatchboxMember<T, DataSpecs, TagProp>
is("Off")) {
return 0;
}
// TypeScript knows this must be the "On" state with percentage
return light: MatchboxMember<"On", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag">
light.data: {
percentage: number;
}
data.percentage: number
percentage;
}
var console: Console
The `console` module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
* A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream.
* A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstderr). The global `console` can be used without calling `require('console')`.
_**Warning**_: The global console object's methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v20.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
```
Example using the `Console` class:
```js
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
```console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
Prints to `stdout` with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v20.x/api/util.html#utilformatformat-args)).
```js
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
```
See [`util.format()`](https://nodejs.org/docs/latest-v20.x/api/util.html#utilformatformat-args) for more information.log(function getBrightness(light: ReturnType<typeof Light.Off> | ReturnType<typeof Light.On>): number
getBrightness(const light1: MatchboxMember<"Off", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag">
light1)); // 0
var console: Console
The `console` module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
* A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream.
* A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstderr). The global `console` can be used without calling `require('console')`.
_**Warning**_: The global console object's methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v20.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
```
Example using the `Console` class:
```js
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
```console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
Prints to `stdout` with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v20.x/api/util.html#utilformatformat-args)).
```js
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
```
See [`util.format()`](https://nodejs.org/docs/latest-v20.x/api/util.html#utilformatformat-args) for more information.log(function getBrightness(light: ReturnType<typeof Light.Off> | ReturnType<typeof Light.On>): number
getBrightness(const light2: MatchboxMember<"On", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag">
light2)); // 75
Type-Safe Casting with Runtime Validation
Section titled “Type-Safe Casting with Runtime Validation”Use the as
method for type-safe casting with runtime validation:
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.matchboxFactory } from "matchina";
// Create a Light matchbox with On/Off states
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.matchboxFactory({
type Off: undefined
Off: var undefined
undefined,
type On: (percentage?: number) => {
percentage: number;
}
On: (percentage: number
percentage = 100) => ({ percentage: number
percentage }),
});
const const light: MatchboxMember<"On", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag">
light = 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(80);
// Safe casting with runtime validation
try {
// This works because light is actually in the "On" state
const const asOn: MatchboxMember<"On", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag">
asOn = const light: MatchboxMember<"On", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag">
light.MatchboxMemberApi<{ Off: undefined; On: (percentage?: number) => { percentage: number; }; }, "tag">.as: <"On">(key: "On") => MatchboxMember<"On", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag">
as("On");
var console: Console
The `console` module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
* A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream.
* A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstderr). The global `console` can be used without calling `require('console')`.
_**Warning**_: The global console object's methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v20.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
```
Example using the `Console` class:
```js
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
```console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
Prints to `stdout` with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v20.x/api/util.html#utilformatformat-args)).
```js
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
```
See [`util.format()`](https://nodejs.org/docs/latest-v20.x/api/util.html#utilformatformat-args) for more information.log(`Brightness: ${const asOn: MatchboxMember<"On", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag">
asOn.data: {
percentage: number;
}
data.percentage: number
percentage}%`); // Works fine: "Brightness: 80%"
// This will throw because light is not in the "Off" state
const const asOff: MatchboxMember<"Off", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag">
asOff = const light: MatchboxMember<"On", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag">
light.MatchboxMemberApi<{ Off: undefined; On: (percentage?: number) => { percentage: number; }; }, "tag">.as: <"Off">(key: "Off") => MatchboxMember<"Off", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag">
as("Off");
var console: Console
The `console` module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
* A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream.
* A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstderr). The global `console` can be used without calling `require('console')`.
_**Warning**_: The global console object's methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v20.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
```
Example using the `Console` class:
```js
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
```console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
Prints to `stdout` with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v20.x/api/util.html#utilformatformat-args)).
```js
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
```
See [`util.format()`](https://nodejs.org/docs/latest-v20.x/api/util.html#utilformatformat-args) for more information.log("This line will never execute", const asOff: MatchboxMember<"Off", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag">
asOff);
} catch (var e: any
e: any) {
var console: Console
The `console` module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
* A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream.
* A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstderr). The global `console` can be used without calling `require('console')`.
_**Warning**_: The global console object's methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v20.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
```
Example using the `Console` class:
```js
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
```console.Console.error(message?: any, ...optionalParams: any[]): void (+1 overload)
Prints to `stderr` with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v20.x/api/util.html#utilformatformat-args)).
```js
const code = 5;
console.error('error #%d', code);
// Prints: error #5, to stderr
console.error('error', code);
// Prints: error 5, to stderr
```
If formatting elements (e.g. `%d`) are not found in the first string then
[`util.inspect()`](https://nodejs.org/docs/latest-v20.x/api/util.html#utilinspectobject-options) is called on each argument and the
resulting string values are concatenated. See [`util.format()`](https://nodejs.org/docs/latest-v20.x/api/util.html#utilformatformat-args)
for more information.error("Cast failed:", var e: any
e.message); // "Attempted to cast On as Off"
}
// Practical example: only adjust brightness for "On" lights
export function function adjustBrightness(light: ReturnType<typeof Light.Off> | ReturnType<typeof Light.On>, adjustment: number): MatchboxMember<"On", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag"> | MatchboxMember<...>
adjustBrightness(
light: MatchboxMember<"On", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag"> | MatchboxMember<"Off", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag">
light: type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any
Obtain the return type of a function typeReturnType<typeof 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> | type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any
Obtain the return type of a function typeReturnType<typeof 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>,
adjustment: number
adjustment: number
) {
try {
// Try to cast to "On" state
const const onLight: MatchboxMember<"On", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag">
onLight = light: MatchboxMember<"On", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag"> | MatchboxMember<"Off", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag">
light.MatchboxMemberApi<DataSpecs, TagProp extends string>.as: <"On">(key: "On") => MatchboxMember<"On", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag">
as("On");
// If successful, create a new light with adjusted brightness
const const newBrightness: number
newBrightness = var Math: Math
An intrinsic object that provides basic mathematics functionality and constants.Math.Math.max(...values: number[]): number
Returns the larger of a set of supplied numeric expressions.max(
0,
var Math: Math
An intrinsic object that provides basic mathematics functionality and constants.Math.Math.min(...values: number[]): number
Returns the smaller of a set of supplied numeric expressions.min(100, const onLight: MatchboxMember<"On", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag">
onLight.data: {
percentage: number;
}
data.percentage: number
percentage + adjustment: number
adjustment)
);
return 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(const newBrightness: number
newBrightness);
} catch {
// Light is off, return it unchanged
return light: MatchboxMember<"On", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag"> | MatchboxMember<"Off", {
Off: undefined;
On: (percentage?: number) => {
percentage: number;
};
}, "tag">
light;
}
}
Advanced Type Guards with Filters
Section titled “Advanced Type Guards with Filters”Matchina also provides filter functions for more complex type guards:
import { matchbox, withKey, withData } from "matchina";// ---cut---const Shape = matchbox({ Circle: (radius: number, color: string = "black") => ({ radius, color }), Rectangle: (width: number, height: number, color: string = "black") => ({ width, height, color, }), Triangle: (base: number, height: number, color: string = "black") => ({ base, height, color, }),});
const shapes = [ Shape.Circle(5, "red"), Shape.Rectangle(10, 20, "blue"), Shape.Circle(8, "green"), Shape.Triangle(15, 10, "red"),];
// Filter by keyconst circles = shapes.filter(withKey("Circle"));console.log(`Found ${circles.length} circles`);
// Filter by data propertyconst redShapes = shapes.filter(withData((data) => data.color === "red"));console.log(`Found ${redShapes.length} red shapes`);
// Combine filtersconst largeCircles = shapes.filter( (shape) => shape.is("Circle") && shape.data.radius > 7,);console.log(`Found ${largeCircles.length} large circles`);
Benefits of Type Guards
Section titled “Benefits of Type Guards”- Type safety: Prevent runtime errors by catching type mismatches at compile time
- Code completion: Get proper IDE suggestions based on narrowed types
- Refactoring safety: When you change a state’s structure, TypeScript will flag all places that need updates
- Exhaustive checking: Ensure all possible states are handled with pattern matching
Next Steps
Section titled “Next Steps”Now that you understand type guards, explore these related guides:
- Matchbox: Type-Safe Unions - Learn more about the foundation of type guards
- Factory Machines - See how type guards work with state machines
- Lifecycle Hooks - Add hooks for intercepting state changes