hanzio 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +5 -6
- package/dist/api-wrapper/endpoint.d.ts +8 -5
- package/dist/api-wrapper/transport.d.ts +1 -0
- package/dist/api-wrapper/types.d.ts +7 -0
- package/dist/{index-j1ybktbr.js → index-zbj9s3s3.js} +6 -4
- package/dist/src/api-wrapper/index.js +1 -1
- package/dist/src/secrets/index.js +1 -1
- package/package.json +10 -3
- package/src/api-wrapper/README.md +738 -0
- package/src/api-wrapper/create-client.ts +9 -3
- package/src/api-wrapper/endpoint.ts +19 -5
- package/src/api-wrapper/transport.ts +6 -2
- package/src/api-wrapper/types.ts +13 -0
- package/src/crypto/README.md +144 -0
- package/src/format/README.md +120 -0
- package/src/i18n/README.md +65 -0
- package/src/jwt/README.md +70 -0
- package/src/p-queue/README.md +237 -0
- package/src/secrets/README.md +413 -0
- package/src/sitemap/README.md +61 -0
- package/src/storage/README.md +71 -0
- package/src/typedswitch/README.md +319 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Discover and crawl XML sitemaps for URL discovery; uses the local p-queue utility for concurrency.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# hanzio/sitemap
|
|
6
|
+
|
|
7
|
+
`getDomainSitemap(domain, options)` finds a domain's sitemaps (the `Sitemap:` lines in robots.txt first, then common locations like `/sitemap.xml`) and crawls them with bounded parallelism using the local `hanzio/p-queue` utility.
|
|
8
|
+
|
|
9
|
+
- A document whose root element is `<sitemapindex>` is treated as a list of child sitemaps. A document whose root element is `<urlset>` is treated as a list of pages.
|
|
10
|
+
- `<loc>` values are XML-entity decoded, and CDATA is supported.
|
|
11
|
+
- Gzipped sitemaps (`.xml.gz`) are decompressed with `DecompressionStream`.
|
|
12
|
+
- Every request has its own timeout (`AbortSignal.timeout`).
|
|
13
|
+
|
|
14
|
+
Requires runtime `fetch`, `AbortSignal.timeout` and `DecompressionStream` (Node 18+, Bun, modern browsers), or pass your own `fetch`.
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { getDomainSitemap, getDomainSitemapEntries } from 'hanzio/sitemap'
|
|
18
|
+
|
|
19
|
+
const urls = await getDomainSitemap('example.com', {
|
|
20
|
+
filterIndexes: 'posts', // substring, RegExp or (url) => boolean
|
|
21
|
+
filterUrls: /\/blog\//,
|
|
22
|
+
maxUrls: 1000
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
// With lastmod
|
|
26
|
+
const entries = await getDomainSitemapEntries('example.com')
|
|
27
|
+
// [{ loc: 'https://example.com/a', lastmod: '2024-01-05' }, ...]
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Options (`SitemapOptions`)
|
|
31
|
+
|
|
32
|
+
| Option | Default | Description |
|
|
33
|
+
| --- | --- | --- |
|
|
34
|
+
| `filterIndexes` | none | Only follow child sitemaps that match (substring, RegExp or predicate). |
|
|
35
|
+
| `filterUrls` | none | Only keep page URLs that match. |
|
|
36
|
+
| `concurrency` | `10` | The maximum number of sitemap fetches that run at the same time. |
|
|
37
|
+
| `maxDepth` | `5` | The maximum sitemap-index nesting depth. |
|
|
38
|
+
| `maxUrls` | none | Stop crawling after this many URLs have been collected. |
|
|
39
|
+
| `timeout` | `10000` | The timeout for each request, in ms. |
|
|
40
|
+
| `userAgent` | `'SitemapCrawler/1.0'` | The `User-Agent` header sent with each request. |
|
|
41
|
+
| `fetch` | `globalThis.fetch` | A custom fetch implementation. |
|
|
42
|
+
| `onError` | `console.warn` | `(url, error) => void`, called when a robots.txt or sitemap request fails. |
|
|
43
|
+
| `respectRobots` | `false` | Drop page URLs that robots.txt disallows for `userAgent` (reuses the robots.txt fetched for discovery). A missing or failed robots.txt allows everything. |
|
|
44
|
+
|
|
45
|
+
Both functions throw `No sitemaps found for the domain` when discovery finds nothing.
|
|
46
|
+
|
|
47
|
+
## robots.txt
|
|
48
|
+
|
|
49
|
+
`parseRobotsTxt(body, userAgent = '*')` returns the rules for one crawler, following RFC 9309: the groups that name its product token (case-insensitive, so `MyBot/2.0` matches `User-agent: mybot`), merged, or else the `User-agent: *` groups. Directive names are case-insensitive and `#` comments are ignored. `sitemaps` lists every `Sitemap:` line.
|
|
50
|
+
|
|
51
|
+
`isAllowedByRobots(rules, url)` checks an absolute URL or a path (plus query string). The longest matching pattern wins, `Allow` wins a tie, `*` matches any characters and a trailing `$` anchors the end. An empty `Disallow:` allows everything, and `/robots.txt` is always allowed.
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import { isAllowedByRobots, parseRobotsTxt } from 'hanzio/sitemap'
|
|
55
|
+
|
|
56
|
+
const rules = parseRobotsTxt(body, 'MyBot/1.0')
|
|
57
|
+
// { allow: ['/cart/help'], disallow: ['/cart/'], sitemaps: [...], crawlDelaySec?: 5 }
|
|
58
|
+
|
|
59
|
+
isAllowedByRobots(rules, 'https://example.com/cart/add?id=1') // false
|
|
60
|
+
isAllowedByRobots(rules, '/cart/help') // true
|
|
61
|
+
```
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Typed persisted values over localStorage/sessionStorage or async stores like React Native AsyncStorage, with fallbacks that never throw.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# hanzio/storage
|
|
6
|
+
|
|
7
|
+
`createStorageItem` wraps one key in `localStorage` (or any `SyncStorageLike`) as a typed value. It never throws:
|
|
8
|
+
|
|
9
|
+
- A missing, corrupt (bad JSON) or invalid (`parse` throws) value reads as `fallback`.
|
|
10
|
+
- When the storage throws (quota exceeded, Safari private mode, sandboxed iframes), the latest `set`/`remove` is kept in memory for that item, so reads stay consistent for the session.
|
|
11
|
+
- Without an accessible `globalThis.localStorage` (SSR, Node, Bun, blocked access) it uses a shared in-memory store.
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { z } from 'zod'
|
|
15
|
+
import { createStorageItem } from 'hanzio/storage'
|
|
16
|
+
|
|
17
|
+
const PanelPrefs = z.object({ open: z.boolean(), width: z.number() })
|
|
18
|
+
|
|
19
|
+
const panelPrefs = createStorageItem({
|
|
20
|
+
key: 'panel-prefs',
|
|
21
|
+
fallback: { open: false, width: 320 },
|
|
22
|
+
parse: PanelPrefs.parse
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
panelPrefs.get() // { open: false, width: 320 }
|
|
26
|
+
panelPrefs.set({ open: true, width: 400 })
|
|
27
|
+
panelPrefs.remove()
|
|
28
|
+
|
|
29
|
+
// Another tab changed it (the `storage` event). Returns an unsubscribe function.
|
|
30
|
+
const stop = panelPrefs.subscribe((prefs) => console.log(prefs))
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Use `sessionStorage` or plain strings:
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
const sendOnEnter = createStorageItem({
|
|
37
|
+
key: 'send-on-enter',
|
|
38
|
+
fallback: false,
|
|
39
|
+
storage: sessionStorage,
|
|
40
|
+
serialize: String,
|
|
41
|
+
deserialize: (raw) => raw === 'true'
|
|
42
|
+
})
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Async stores
|
|
46
|
+
|
|
47
|
+
`createAsyncStorageItem` takes the same options, but `storage` is required and the methods return promises. It never rejects.
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import AsyncStorage from '@react-native-async-storage/async-storage'
|
|
51
|
+
import { createAsyncStorageItem } from 'hanzio/storage'
|
|
52
|
+
|
|
53
|
+
const readIds = createAsyncStorageItem({
|
|
54
|
+
key: '@notification_read_session_ids',
|
|
55
|
+
fallback: [] as string[],
|
|
56
|
+
storage: AsyncStorage,
|
|
57
|
+
parse: z.array(z.string()).parse
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
await readIds.set([...(await readIds.get()), 'abc'])
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## API
|
|
64
|
+
|
|
65
|
+
| Export | Description |
|
|
66
|
+
| --- | --- |
|
|
67
|
+
| `createStorageItem(options)` | `{ key, get, set, remove, subscribe }` over a `SyncStorageLike` (default `localStorage`). |
|
|
68
|
+
| `createAsyncStorageItem(options)` | `{ key, get, set, remove }` over an `AsyncStorageLike`. |
|
|
69
|
+
| `createMemoryStorage()` | A `Map`-backed `SyncStorageLike`, for tests and SSR. |
|
|
70
|
+
|
|
71
|
+
Options: `key`, `fallback`, `storage`, `parse` (validate the deserialized value; throwing means `fallback`), `serialize` (default `JSON.stringify`), `deserialize` (default `JSON.parse`).
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
# typedswitch
|
|
2
|
+
|
|
3
|
+
A type-safe, exhaustive switch expression for TypeScript. Handle discriminated unions and string literals with full type inference, compile-time exhaustiveness checking, and async support.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install typedswitch
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add typedswitch
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bun add typedswitch
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Features
|
|
20
|
+
|
|
21
|
+
- **Full type inference** — Return types are automatically inferred from your handlers
|
|
22
|
+
- **Exhaustiveness checking** — TypeScript ensures all cases are handled at compile time
|
|
23
|
+
- **Discriminated union support** — Works with any discriminant key, not just `type`
|
|
24
|
+
- **Async-aware** — Async handlers preserve their `Promise` return type
|
|
25
|
+
- **Default handlers** — Handle remaining cases with a fallback
|
|
26
|
+
- **Return type constraints** — Enforce that all handlers return a specific type
|
|
27
|
+
- **`assertNever`** — Exhaustiveness checking for regular `switch` statements
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
### String/Enum Input
|
|
32
|
+
|
|
33
|
+
Switch on a string literal or enum value directly:
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { typedSwitch } from 'typedswitch'
|
|
37
|
+
|
|
38
|
+
type Status = 'success' | 'error' | 'pending'
|
|
39
|
+
|
|
40
|
+
const status: Status = 'success'
|
|
41
|
+
|
|
42
|
+
// All cases required — TypeScript enforces exhaustiveness
|
|
43
|
+
const message = typedSwitch(status, {
|
|
44
|
+
success: () => 'Operation completed!',
|
|
45
|
+
error: () => 'Something went wrong',
|
|
46
|
+
pending: () => 'Please wait...',
|
|
47
|
+
})
|
|
48
|
+
// message: string
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Each handler receives the narrowed value:
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
const result = typedSwitch(status, {
|
|
55
|
+
success: (val) => val.toUpperCase(), // val: 'success'
|
|
56
|
+
error: (val) => val.toUpperCase(), // val: 'error'
|
|
57
|
+
pending: (val) => val.toUpperCase(), // val: 'pending'
|
|
58
|
+
})
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Discriminated Union Input
|
|
62
|
+
|
|
63
|
+
Switch on objects with a string, number, or boolean discriminant property (like `type`, `kind`, `status`, etc.):
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
type Event =
|
|
67
|
+
| { type: 'click'; x: number; y: number }
|
|
68
|
+
| { type: 'scroll'; offset: number }
|
|
69
|
+
| { type: 'keypress'; key: string }
|
|
70
|
+
|
|
71
|
+
const event: Event = { type: 'click', x: 100, y: 200 }
|
|
72
|
+
|
|
73
|
+
// Specify the discriminant key as the second argument
|
|
74
|
+
const description = typedSwitch(event, 'type', {
|
|
75
|
+
click: (e) => `Clicked at (${e.x}, ${e.y})`, // e: { type: 'click'; x: number; y: number }
|
|
76
|
+
scroll: (e) => `Scrolled ${e.offset}px`, // e: { type: 'scroll'; offset: number }
|
|
77
|
+
keypress: (e) => `Pressed ${e.key}`, // e: { type: 'keypress'; key: string }
|
|
78
|
+
})
|
|
79
|
+
// description: string
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Works with any discriminant key:
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
type Order =
|
|
86
|
+
| { status: 'pending'; createdAt: Date }
|
|
87
|
+
| { status: 'completed'; completedAt: Date }
|
|
88
|
+
| { status: 'cancelled'; reason: string }
|
|
89
|
+
|
|
90
|
+
const order: Order = { status: 'completed', completedAt: new Date() }
|
|
91
|
+
|
|
92
|
+
const info = typedSwitch(order, 'status', {
|
|
93
|
+
pending: (o) => `Created: ${o.createdAt}`,
|
|
94
|
+
completed: (o) => `Done: ${o.completedAt}`,
|
|
95
|
+
cancelled: (o) => `Cancelled: ${o.reason}`,
|
|
96
|
+
})
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Number and boolean discriminants work too. Cases are keyed by `String(value)`:
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
type Response =
|
|
103
|
+
| { code: 200; body: string }
|
|
104
|
+
| { code: 404; path: string }
|
|
105
|
+
|
|
106
|
+
typedSwitch(response, 'code', {
|
|
107
|
+
200: (r) => r.body, // r: { code: 200; body: string }
|
|
108
|
+
404: (r) => `Missing ${r.path}`, // r: { code: 404; path: string }
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
type Result = { ok: true; value: number } | { ok: false; error: string }
|
|
112
|
+
|
|
113
|
+
typedSwitch(result, 'ok', {
|
|
114
|
+
true: (r) => r.value,
|
|
115
|
+
false: (r) => r.error,
|
|
116
|
+
})
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Default Handler
|
|
120
|
+
|
|
121
|
+
Handle a subset of cases and catch the rest with a default handler:
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
type Status = 'success' | 'error' | 'pending' | 'cancelled'
|
|
125
|
+
|
|
126
|
+
const status: Status = 'cancelled'
|
|
127
|
+
|
|
128
|
+
// Only handle specific cases, default handles the rest
|
|
129
|
+
const message = typedSwitch(
|
|
130
|
+
status,
|
|
131
|
+
{
|
|
132
|
+
success: () => 'Done!',
|
|
133
|
+
error: () => 'Failed!',
|
|
134
|
+
},
|
|
135
|
+
(val) => `Unhandled status: ${val}` // val: 'pending' | 'cancelled' (unhandled cases only)
|
|
136
|
+
)
|
|
137
|
+
// message: string
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Only required, defined handlers narrow the default handler's input. Optional
|
|
141
|
+
handlers (including reusable `PartialStringSwitchCases` and
|
|
142
|
+
`PartialObjectSwitchCases` maps) can be absent, so their cases remain in the
|
|
143
|
+
default handler's input type.
|
|
144
|
+
|
|
145
|
+
Works with discriminated unions too:
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
const description = typedSwitch(
|
|
149
|
+
event,
|
|
150
|
+
'type',
|
|
151
|
+
{
|
|
152
|
+
click: (e) => `Clicked at (${e.x}, ${e.y})`,
|
|
153
|
+
},
|
|
154
|
+
(e) => `Unhandled event: ${e.type}` // e: scroll or keypress event (unhandled members only)
|
|
155
|
+
)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Async Handlers
|
|
159
|
+
|
|
160
|
+
Mix sync and async handlers freely. `typedSwitch` returns the selected handler's value directly, so async branches preserve their `Promise` return type while sync branches remain sync:
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
// All sync — returns string
|
|
164
|
+
const syncResult = typedSwitch(status, {
|
|
165
|
+
success: () => 'ok',
|
|
166
|
+
error: () => 'err',
|
|
167
|
+
pending: () => 'wait',
|
|
168
|
+
})
|
|
169
|
+
// syncResult: string
|
|
170
|
+
|
|
171
|
+
// All async — returns Promise<string>
|
|
172
|
+
const asyncResult = typedSwitch(status, {
|
|
173
|
+
success: async () => {
|
|
174
|
+
const data = await fetchData()
|
|
175
|
+
return data.message
|
|
176
|
+
},
|
|
177
|
+
error: async () => 'err',
|
|
178
|
+
pending: async () => 'wait',
|
|
179
|
+
})
|
|
180
|
+
// asyncResult: Promise<string>
|
|
181
|
+
|
|
182
|
+
const message = await asyncResult
|
|
183
|
+
|
|
184
|
+
// Mixed sync/async — returns string | Promise<string>
|
|
185
|
+
const mixedResult = typedSwitch(status, {
|
|
186
|
+
success: () => 'ok',
|
|
187
|
+
error: async () => 'err',
|
|
188
|
+
pending: () => 'wait',
|
|
189
|
+
})
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Return Type Inference
|
|
193
|
+
|
|
194
|
+
Return types are inferred from all handlers as a union:
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
const result = typedSwitch(status, {
|
|
198
|
+
success: () => ({ ok: true, data: 'hello' }),
|
|
199
|
+
error: () => ({ ok: false, code: 500 }),
|
|
200
|
+
pending: () => null,
|
|
201
|
+
})
|
|
202
|
+
// result: { ok: true; data: string } | { ok: false; code: number } | null
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Return Type Constraints
|
|
206
|
+
|
|
207
|
+
Enforce that all handlers return a type extending a constraint with `typedSwitch<Constraint>(...)`. The `<Constraint>` is optional; omit it when you want TypeScript to infer the return types freely.
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
interface HasId {
|
|
211
|
+
id: string
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// All handlers must return something with { id: string }
|
|
215
|
+
const result = typedSwitch<HasId>(status, {
|
|
216
|
+
success: () => ({ id: '123', name: 'John' }), // ✓ OK
|
|
217
|
+
error: () => ({ id: '456', code: 500 }), // ✓ OK
|
|
218
|
+
pending: () => ({ id: '789' }), // ✓ OK
|
|
219
|
+
})
|
|
220
|
+
// result: HasId
|
|
221
|
+
|
|
222
|
+
// This would be a compile error:
|
|
223
|
+
typedSwitch<HasId>(status, {
|
|
224
|
+
success: () => ({ name: 'John' }), // ✗ Error: missing 'id'
|
|
225
|
+
error: () => ({ id: '456' }),
|
|
226
|
+
pending: () => ({ id: '789' }),
|
|
227
|
+
})
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Constraints also work with discriminated unions and default handlers:
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
const result = typedSwitch<HasId>(
|
|
234
|
+
event,
|
|
235
|
+
'type',
|
|
236
|
+
{
|
|
237
|
+
click: () => ({ id: 'click-1', x: 10, y: 20 }),
|
|
238
|
+
scroll: () => ({ id: 'scroll-1', offset: 100 }),
|
|
239
|
+
keypress: () => ({ id: 'key-1', key: 'Enter' }),
|
|
240
|
+
}
|
|
241
|
+
)
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## Error Handling
|
|
245
|
+
|
|
246
|
+
When a case is unhandled at runtime (e.g., due to unsafe casts), `typedSwitch` throws a descriptive error:
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
const status = 'unknown' as Status
|
|
250
|
+
|
|
251
|
+
typedSwitch(status, {
|
|
252
|
+
success: () => 'ok',
|
|
253
|
+
error: () => 'err',
|
|
254
|
+
})
|
|
255
|
+
// Throws: "Unhandled case: unknown. Available cases: success, error"
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
For discriminated unions:
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
// Throws: "Unhandled case: unknown (discriminant key: "type"). Available cases: click, scroll, keypress"
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Object discriminants must be strings, numbers, or booleans. Missing or other discriminant values throw a runtime error if they reach `typedSwitch`.
|
|
265
|
+
|
|
266
|
+
## `assertNever`
|
|
267
|
+
|
|
268
|
+
For regular `switch` statements, put `assertNever` in the `default` branch. It fails to compile if a case is missing, and throws at runtime if an unexpected value gets through:
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
import { assertNever } from 'typedswitch'
|
|
272
|
+
|
|
273
|
+
function label(status: Status) {
|
|
274
|
+
switch (status) {
|
|
275
|
+
case 'success': return 'Done'
|
|
276
|
+
case 'error': return 'Failed'
|
|
277
|
+
case 'pending': return 'Waiting'
|
|
278
|
+
default: return assertNever(status) // compile error if a case is missing
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
## API Reference
|
|
284
|
+
|
|
285
|
+
### `typedSwitch(value, cases)`
|
|
286
|
+
|
|
287
|
+
Switch on a string literal with exhaustive case handling.
|
|
288
|
+
|
|
289
|
+
### `typedSwitch(value, cases, defaultHandler)`
|
|
290
|
+
|
|
291
|
+
Switch on a string literal with partial cases and a default fallback.
|
|
292
|
+
|
|
293
|
+
### `typedSwitch(object, key, cases)`
|
|
294
|
+
|
|
295
|
+
Switch on a discriminated union using the specified discriminant key (string, number, or boolean values).
|
|
296
|
+
|
|
297
|
+
### `typedSwitch(object, key, cases, defaultHandler)`
|
|
298
|
+
|
|
299
|
+
Switch on a discriminated union with partial cases and a default fallback.
|
|
300
|
+
|
|
301
|
+
### `typedSwitch<Constraint>(value, cases)`
|
|
302
|
+
|
|
303
|
+
Switch on a string literal while enforcing that each handler returns `Constraint` or `Promise<Constraint>`.
|
|
304
|
+
|
|
305
|
+
### `typedSwitch<Constraint>(object, key, cases)`
|
|
306
|
+
|
|
307
|
+
Switch on a discriminated union while enforcing that each handler returns `Constraint` or `Promise<Constraint>`.
|
|
308
|
+
|
|
309
|
+
### `assertNever(value, message?)`
|
|
310
|
+
|
|
311
|
+
Takes a `never` value and always throws (`Unexpected value: ${value}` or `message`). Use it for exhaustive `switch` statements.
|
|
312
|
+
|
|
313
|
+
### Exported Helper Types
|
|
314
|
+
|
|
315
|
+
`StringSwitchCases`, `PartialStringSwitchCases`, `ObjectSwitchCases`, and `PartialObjectSwitchCases` are exported for users who want to annotate reusable case maps.
|
|
316
|
+
|
|
317
|
+
## License
|
|
318
|
+
|
|
319
|
+
MIT
|