@zigrivers/scaffold 3.7.0 → 3.9.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.
Files changed (97) hide show
  1. package/README.md +113 -8
  2. package/content/knowledge/browser-extension/browser-extension-architecture.md +195 -0
  3. package/content/knowledge/browser-extension/browser-extension-content-scripts.md +264 -0
  4. package/content/knowledge/browser-extension/browser-extension-conventions.md +156 -0
  5. package/content/knowledge/browser-extension/browser-extension-cross-browser.md +229 -0
  6. package/content/knowledge/browser-extension/browser-extension-dev-environment.md +247 -0
  7. package/content/knowledge/browser-extension/browser-extension-manifest.md +220 -0
  8. package/content/knowledge/browser-extension/browser-extension-project-structure.md +183 -0
  9. package/content/knowledge/browser-extension/browser-extension-requirements.md +107 -0
  10. package/content/knowledge/browser-extension/browser-extension-security.md +202 -0
  11. package/content/knowledge/browser-extension/browser-extension-service-workers.md +265 -0
  12. package/content/knowledge/browser-extension/browser-extension-store-submission.md +155 -0
  13. package/content/knowledge/browser-extension/browser-extension-testing.md +270 -0
  14. package/content/knowledge/data-pipeline/data-pipeline-architecture.md +175 -0
  15. package/content/knowledge/data-pipeline/data-pipeline-batch-patterns.md +263 -0
  16. package/content/knowledge/data-pipeline/data-pipeline-conventions.md +176 -0
  17. package/content/knowledge/data-pipeline/data-pipeline-dev-environment.md +350 -0
  18. package/content/knowledge/data-pipeline/data-pipeline-orchestration.md +291 -0
  19. package/content/knowledge/data-pipeline/data-pipeline-project-structure.md +257 -0
  20. package/content/knowledge/data-pipeline/data-pipeline-quality.md +324 -0
  21. package/content/knowledge/data-pipeline/data-pipeline-requirements.md +145 -0
  22. package/content/knowledge/data-pipeline/data-pipeline-schema-management.md +295 -0
  23. package/content/knowledge/data-pipeline/data-pipeline-security.md +326 -0
  24. package/content/knowledge/data-pipeline/data-pipeline-streaming-patterns.md +280 -0
  25. package/content/knowledge/data-pipeline/data-pipeline-testing.md +406 -0
  26. package/content/knowledge/library/library-api-design.md +306 -0
  27. package/content/knowledge/library/library-architecture.md +247 -0
  28. package/content/knowledge/library/library-bundling.md +244 -0
  29. package/content/knowledge/library/library-conventions.md +229 -0
  30. package/content/knowledge/library/library-dev-environment.md +220 -0
  31. package/content/knowledge/library/library-documentation.md +300 -0
  32. package/content/knowledge/library/library-project-structure.md +237 -0
  33. package/content/knowledge/library/library-requirements.md +173 -0
  34. package/content/knowledge/library/library-security.md +257 -0
  35. package/content/knowledge/library/library-testing.md +319 -0
  36. package/content/knowledge/library/library-type-definitions.md +284 -0
  37. package/content/knowledge/library/library-versioning.md +300 -0
  38. package/content/knowledge/ml/ml-architecture.md +172 -0
  39. package/content/knowledge/ml/ml-conventions.md +209 -0
  40. package/content/knowledge/ml/ml-dev-environment.md +299 -0
  41. package/content/knowledge/ml/ml-experiment-tracking.md +285 -0
  42. package/content/knowledge/ml/ml-model-evaluation.md +256 -0
  43. package/content/knowledge/ml/ml-observability.md +253 -0
  44. package/content/knowledge/ml/ml-project-structure.md +216 -0
  45. package/content/knowledge/ml/ml-requirements.md +138 -0
  46. package/content/knowledge/ml/ml-security.md +188 -0
  47. package/content/knowledge/ml/ml-serving-patterns.md +243 -0
  48. package/content/knowledge/ml/ml-testing.md +301 -0
  49. package/content/knowledge/ml/ml-training-patterns.md +269 -0
  50. package/content/knowledge/mobile-app/mobile-app-architecture.md +283 -0
  51. package/content/knowledge/mobile-app/mobile-app-conventions.md +180 -0
  52. package/content/knowledge/mobile-app/mobile-app-deployment.md +298 -0
  53. package/content/knowledge/mobile-app/mobile-app-dev-environment.md +257 -0
  54. package/content/knowledge/mobile-app/mobile-app-distribution.md +264 -0
  55. package/content/knowledge/mobile-app/mobile-app-observability.md +317 -0
  56. package/content/knowledge/mobile-app/mobile-app-offline-patterns.md +311 -0
  57. package/content/knowledge/mobile-app/mobile-app-project-structure.md +245 -0
  58. package/content/knowledge/mobile-app/mobile-app-push-notifications.md +321 -0
  59. package/content/knowledge/mobile-app/mobile-app-requirements.md +147 -0
  60. package/content/knowledge/mobile-app/mobile-app-security.md +338 -0
  61. package/content/knowledge/mobile-app/mobile-app-testing.md +400 -0
  62. package/content/methodology/browser-extension-overlay.yml +82 -0
  63. package/content/methodology/data-pipeline-overlay.yml +70 -0
  64. package/content/methodology/library-overlay.yml +67 -0
  65. package/content/methodology/ml-overlay.yml +70 -0
  66. package/content/methodology/mobile-app-overlay.yml +71 -0
  67. package/dist/cli/commands/init.d.ts +22 -0
  68. package/dist/cli/commands/init.d.ts.map +1 -1
  69. package/dist/cli/commands/init.js +202 -3
  70. package/dist/cli/commands/init.js.map +1 -1
  71. package/dist/cli/commands/init.test.js +190 -0
  72. package/dist/cli/commands/init.test.js.map +1 -1
  73. package/dist/config/schema.d.ts +1456 -80
  74. package/dist/config/schema.d.ts.map +1 -1
  75. package/dist/config/schema.js +87 -0
  76. package/dist/config/schema.js.map +1 -1
  77. package/dist/config/schema.test.js +312 -3
  78. package/dist/config/schema.test.js.map +1 -1
  79. package/dist/core/assembly/overlay-loader.test.js +55 -0
  80. package/dist/core/assembly/overlay-loader.test.js.map +1 -1
  81. package/dist/e2e/project-type-overlays.test.d.ts +2 -1
  82. package/dist/e2e/project-type-overlays.test.d.ts.map +1 -1
  83. package/dist/e2e/project-type-overlays.test.js +780 -14
  84. package/dist/e2e/project-type-overlays.test.js.map +1 -1
  85. package/dist/types/config.d.ts +16 -1
  86. package/dist/types/config.d.ts.map +1 -1
  87. package/dist/wizard/questions.d.ts +28 -1
  88. package/dist/wizard/questions.d.ts.map +1 -1
  89. package/dist/wizard/questions.js +127 -1
  90. package/dist/wizard/questions.js.map +1 -1
  91. package/dist/wizard/questions.test.js +224 -4
  92. package/dist/wizard/questions.test.js.map +1 -1
  93. package/dist/wizard/wizard.d.ts +22 -0
  94. package/dist/wizard/wizard.d.ts.map +1 -1
  95. package/dist/wizard/wizard.js +28 -1
  96. package/dist/wizard/wizard.js.map +1 -1
  97. package/package.json +1 -1
@@ -0,0 +1,319 @@
1
+ ---
2
+ name: library-testing
3
+ description: Unit tests, consumer integration tests, example app tests, snapshot testing, and type testing for published libraries
4
+ topics: [library, testing, unit-tests, integration-tests, type-testing, tsd, snapshot-testing, consumer-testing]
5
+ ---
6
+
7
+ Library testing has a different threat model than application testing. You are not just testing that your code works internally — you are testing that the public API works correctly from a consumer's perspective, across different environments and module systems, and that type definitions accurately reflect runtime behavior. A library with excellent unit tests but untested consumer integration can still fail spectacularly when installed in a real project. Every public API export needs test coverage that exercises it as a consumer would.
8
+
9
+ ## Summary
10
+
11
+ Library testing requires four layers: unit tests for internal logic (fast, isolated), consumer-perspective integration tests (exercise the public API as an external consumer would), example application tests (run the examples from the docs to catch regressions), and type tests (verify TypeScript types are accurate and don't regress). Use vitest for unit and integration tests. Use `tsd` or vitest's `expectTypeOf` for type tests. Run example apps in CI. Aim for 100% coverage of public API exports.
12
+
13
+ Testing layers:
14
+ - Unit tests: pure functions, internal logic, error conditions
15
+ - Integration tests: public API called without any internal access
16
+ - Type tests: `tsd` or `expect-type` assertions on all public exports
17
+ - Example tests: run examples/ as standalone scripts in CI
18
+ - Cross-environment tests: Node ESM, Node CJS, and bundler environments
19
+
20
+ ## Deep Guidance
21
+
22
+ ### Unit Tests
23
+
24
+ Unit tests cover individual functions and classes in isolation. Use vitest for its TypeScript support and fast execution:
25
+
26
+ ```typescript
27
+ // tests/unit/parser.test.ts
28
+ import { describe, it, expect } from 'vitest'
29
+ import { parseConfig } from '../../src/parser'
30
+ import { ParseError } from '../../src/errors'
31
+
32
+ describe('parseConfig', () => {
33
+ it('parses a valid TOML string', () => {
34
+ const result = parseConfig('[server]\nhost = "localhost"\nport = 3000')
35
+ expect(result.server.host).toBe('localhost')
36
+ expect(result.server.port).toBe(3000)
37
+ })
38
+
39
+ it('throws ParseError on invalid TOML', () => {
40
+ expect(() => parseConfig('invalid = {toml')).toThrow(ParseError)
41
+ })
42
+
43
+ it('includes line number in ParseError', () => {
44
+ try {
45
+ parseConfig('line1 = "ok"\nline2 = {invalid')
46
+ } catch (err) {
47
+ expect(err).toBeInstanceOf(ParseError)
48
+ expect((err as ParseError).line).toBe(2)
49
+ }
50
+ })
51
+
52
+ it('returns empty config for empty input', () => {
53
+ const result = parseConfig('')
54
+ expect(result).toEqual({})
55
+ })
56
+
57
+ it('handles special characters in string values', () => {
58
+ const result = parseConfig('key = "hello\\nworld"')
59
+ expect(result.key).toBe('hello\nworld')
60
+ })
61
+ })
62
+ ```
63
+
64
+ **Unit test coverage targets:**
65
+ - Every exported function: 100% coverage
66
+ - Every error case: tested explicitly
67
+ - Edge cases: empty inputs, null/undefined, very large inputs, special characters
68
+ - Option combinations: test that each option modifies behavior correctly
69
+
70
+ ### Consumer-Perspective Integration Tests
71
+
72
+ These tests exercise the public API exactly as a consumer would — importing from the package root, never accessing internal modules:
73
+
74
+ ```typescript
75
+ // tests/integration/consumer-api.test.ts
76
+ // Import from the package root, not from src/
77
+ // This tests the actual public API surface
78
+ import { parseConfig, createClient, ParseError, ValidationError } from 'my-library'
79
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest'
80
+
81
+ // If running in Node, import the dist/ version not the source
82
+ // Configure vitest to resolve 'my-library' to './dist/index.js'
83
+
84
+ describe('Consumer API', () => {
85
+ describe('parseConfig()', () => {
86
+ it('is callable with a single string argument', () => {
87
+ expect(() => parseConfig('[test]\nvalue = 1')).not.toThrow()
88
+ })
89
+
90
+ it('returns an object with the parsed structure', () => {
91
+ const config = parseConfig('[db]\nhost = "localhost"')
92
+ expect(config).toMatchObject({ db: { host: 'localhost' } })
93
+ })
94
+
95
+ it('throws ParseError (a named export) on syntax errors', () => {
96
+ expect(() => parseConfig('invalid')).toThrow(ParseError)
97
+ })
98
+ })
99
+
100
+ describe('createClient()', () => {
101
+ let client: ReturnType<typeof createClient>
102
+
103
+ beforeEach(() => {
104
+ const config = parseConfig('[server]\nhost = "localhost"\nport = 3000')
105
+ client = createClient({ config })
106
+ })
107
+
108
+ afterEach(async () => {
109
+ await client.close()
110
+ })
111
+
112
+ it('creates a client with a query method', () => {
113
+ expect(client.query).toBeTypeOf('function')
114
+ })
115
+ })
116
+ })
117
+ ```
118
+
119
+ **Configure vitest to test against dist/ for integration tests:**
120
+ ```typescript
121
+ // vitest.config.ts
122
+ import { defineConfig } from 'vitest'
123
+
124
+ export default defineConfig({
125
+ test: {
126
+ // Unit tests use src/ directly
127
+ // Integration tests use the built dist/
128
+ include: ['tests/unit/**/*.test.ts'],
129
+ }
130
+ })
131
+
132
+ // vitest.integration.config.ts
133
+ export default defineConfig({
134
+ resolve: {
135
+ alias: {
136
+ 'my-library': new URL('./dist/index.js', import.meta.url).pathname
137
+ }
138
+ },
139
+ test: {
140
+ include: ['tests/integration/**/*.test.ts'],
141
+ }
142
+ })
143
+ ```
144
+
145
+ ### Type Tests with tsd
146
+
147
+ Type tests verify that TypeScript types are accurate and don't regress:
148
+
149
+ ```typescript
150
+ // tests/types/index.test-d.ts
151
+ import { expectType, expectError, expectAssignable, expectNotType } from 'tsd'
152
+ import type { Config, ParseOptions, ParseError as PE } from 'my-library'
153
+ import { parseConfig, createClient, ParseError } from 'my-library'
154
+
155
+ // Return type tests
156
+ expectType<Config>(parseConfig('[test]\nvalue = 1'))
157
+
158
+ // Overload resolution
159
+ expectType<Config>(parseConfig('input', { async: false }))
160
+ expectType<Promise<Config>>(parseConfig('input', { async: true }))
161
+
162
+ // Input type constraints
163
+ expectError(parseConfig(42))
164
+ expectError(parseConfig(null))
165
+ expectError(parseConfig(undefined))
166
+ expectError(parseConfig([]))
167
+
168
+ // Options shape
169
+ const validOptions: ParseOptions = { strict: true, encoding: 'utf-8' }
170
+ expectAssignable<ParseOptions>(validOptions)
171
+ expectAssignable<ParseOptions>({}) // All options are optional
172
+
173
+ // Error type hierarchy
174
+ const err = new ParseError('msg', 1, 1)
175
+ expectAssignable<Error>(err)
176
+ expectType<number>(err.line)
177
+ expectType<number>(err.column)
178
+
179
+ // Discriminated union types
180
+ type ParseResult = ReturnType<typeof parseConfig>
181
+ expectNotType<undefined>(null as ParseResult) // Result is never null
182
+ ```
183
+
184
+ ```json
185
+ // package.json — configure tsd
186
+ {
187
+ "tsd": {
188
+ "directory": "tests/types"
189
+ },
190
+ "scripts": {
191
+ "test:types": "tsd"
192
+ }
193
+ }
194
+ ```
195
+
196
+ ### Snapshot Testing for Serialized Output
197
+
198
+ Snapshot tests catch unintentional changes to formatted output:
199
+
200
+ ```typescript
201
+ // tests/unit/formatter.test.ts
202
+ import { describe, it, expect } from 'vitest'
203
+ import { formatConfig } from '../../src/formatter'
204
+
205
+ describe('formatConfig', () => {
206
+ it('formats a config object to TOML', () => {
207
+ const config = { server: { host: 'localhost', port: 3000 } }
208
+ expect(formatConfig(config)).toMatchSnapshot()
209
+ })
210
+
211
+ it('formats an array value', () => {
212
+ const config = { allowed: ['read', 'write'] }
213
+ expect(formatConfig(config)).toMatchSnapshot()
214
+ })
215
+ })
216
+ ```
217
+
218
+ Snapshot files are committed to the repository. When intentional output changes are made, update snapshots with `vitest --update-snapshots`. In CI, fail on unexpected snapshot changes.
219
+
220
+ **When to use snapshots vs. explicit assertions:**
221
+ - Use snapshots for complex serialized output (HTML, TOML, JSON with many fields)
222
+ - Use explicit assertions for simple return values — snapshots hide intent
223
+ - Never snapshot non-deterministic output (timestamps, random IDs)
224
+
225
+ ### Cross-Environment Testing
226
+
227
+ Libraries must work in both Node ESM and CJS environments:
228
+
229
+ ```typescript
230
+ // tests/env/esm.test.mjs — ES module import test
231
+ import { parseConfig } from 'my-library'
232
+ console.assert(typeof parseConfig === 'function', 'ESM import works')
233
+ console.log('ESM: OK')
234
+
235
+ // tests/env/cjs.test.cjs — CommonJS require test
236
+ const { parseConfig } = require('my-library')
237
+ console.assert(typeof parseConfig === 'function', 'CJS require works')
238
+ console.log('CJS: OK')
239
+ ```
240
+
241
+ ```yaml
242
+ # .github/workflows/ci.yml
243
+ - name: Test CJS compatibility
244
+ run: node tests/env/cjs.test.cjs
245
+
246
+ - name: Test ESM compatibility
247
+ run: node tests/env/esm.test.mjs
248
+
249
+ - name: Test with latest Node
250
+ run: npm test
251
+ env:
252
+ NODE_VERSION: 22
253
+
254
+ - name: Test with minimum Node
255
+ run: npm test
256
+ env:
257
+ NODE_VERSION: 18
258
+ ```
259
+
260
+ ### Example Application Tests
261
+
262
+ Run examples in CI to catch regressions in the documented usage:
263
+
264
+ ```yaml
265
+ # .github/workflows/ci.yml
266
+ - name: Build library
267
+ run: npm run build
268
+
269
+ - name: Test basic-usage example
270
+ run: |
271
+ cd examples/basic-usage
272
+ npm install
273
+ node index.js
274
+ # Fails if the example throws an error or exits non-zero
275
+
276
+ - name: Test advanced example
277
+ run: |
278
+ cd examples/advanced-plugin
279
+ npm install
280
+ node index.js
281
+ ```
282
+
283
+ Each example's `package.json` references `"my-library": "file:../../"` so it uses the locally built dist/, not a published version:
284
+
285
+ ```json
286
+ {
287
+ "dependencies": {
288
+ "my-library": "file:../../"
289
+ }
290
+ }
291
+ ```
292
+
293
+ If an example breaks, the public API has regressed. Fix the library, not the example.
294
+
295
+ ### Test Coverage Configuration
296
+
297
+ ```typescript
298
+ // vitest.config.ts
299
+ import { defineConfig } from 'vitest'
300
+
301
+ export default defineConfig({
302
+ test: {
303
+ coverage: {
304
+ provider: 'v8',
305
+ include: ['src/**/*.ts'],
306
+ exclude: ['src/internal/**', 'src/**/*.test.ts'],
307
+ thresholds: {
308
+ functions: 100, // Every exported function must be tested
309
+ branches: 90, // 90% branch coverage
310
+ lines: 95,
311
+ statements: 95
312
+ },
313
+ reporter: ['text', 'lcov', 'html']
314
+ }
315
+ }
316
+ })
317
+ ```
318
+
319
+ A 100% function coverage target is achievable for libraries and enforces that every public export has at least one test. Combined with type tests (which test every function's type signature), this gives comprehensive coverage of the public API contract.
@@ -0,0 +1,284 @@
1
+ ---
2
+ name: library-type-definitions
3
+ description: Declaration files (.d.ts), type testing with tsd/expect-type, conditional types, and API surface documentation via types
4
+ topics: [library, typescript, type-definitions, declarations, tsd, expect-type, conditional-types, dts]
5
+ ---
6
+
7
+ Type definitions are a first-class deliverable for TypeScript libraries. They are part of the public API contract, not an afterthought. Declaration files (`.d.ts`) must be accurate, complete, and expressive — they determine whether consumers can use the library with type safety, whether IDEs provide useful completions, and whether type errors are caught at compile time rather than runtime. Inaccurate types are worse than no types because they create false confidence.
8
+
9
+ ## Summary
10
+
11
+ Emit declaration files alongside compiled JavaScript using TypeScript's `declaration: true` compiler option or a bundler like tsup. Test types with `tsd` or `expect-type` to catch type regressions. Use conditional types to express relationships between input and output types. Export all types that appear in public API signatures — unexported types force consumers to use `any` or `ReturnType<typeof fn>` workarounds. Document type parameters with JSDoc. Include declaration maps (`declarationMap: true`) so Go-to-Definition works across the source.
12
+
13
+ Core type definition practices:
14
+ - Enable `declaration` and `declarationMap` in tsconfig build config
15
+ - Export every type that appears in any public API signature
16
+ - Write type tests with `tsd` or `expect-type` as part of the test suite
17
+ - Use conditional types to narrow return types based on input types
18
+ - Avoid `any` in public signatures — use `unknown` for unvalidated input
19
+
20
+ ## Deep Guidance
21
+
22
+ ### TypeScript Configuration for Declaration Emission
23
+
24
+ The build tsconfig must enable declaration emission:
25
+
26
+ ```json
27
+ {
28
+ "compilerOptions": {
29
+ "declaration": true, // Emit .d.ts files
30
+ "declarationMap": true, // Emit .d.ts.map for Go-to-Definition
31
+ "declarationDir": "./dist/types", // Put declarations in dist/types/
32
+ "emitDeclarationOnly": false, // Emit JS too (or use separate tsc runs)
33
+ "stripInternal": true, // Remove @internal JSDoc items from declarations
34
+ "strict": true,
35
+ "noUncheckedIndexedAccess": true,
36
+ "exactOptionalPropertyTypes": true
37
+ }
38
+ }
39
+ ```
40
+
41
+ With tsup:
42
+ ```typescript
43
+ export default defineConfig({
44
+ entry: ['src/index.ts'],
45
+ dts: true, // tsup generates declarations using tsc under the hood
46
+ })
47
+ ```
48
+
49
+ ### What to Export
50
+
51
+ Every type that appears in a public API signature must be exported:
52
+
53
+ ```typescript
54
+ // src/index.ts — export all types consumers will need
55
+
56
+ // Types used in function signatures
57
+ export type { ParseOptions, ParseResult } from './parser'
58
+ export type { ValidationResult, ValidationError, ValidationRule } from './validator'
59
+ export type { ClientOptions, Client, RequestOptions, Response } from './client'
60
+
61
+ // Error classes (constructors are values AND types)
62
+ export { ParseError, ValidationError, NetworkError } from './errors'
63
+
64
+ // Enums or const objects used as parameter values
65
+ export { LogLevel, OutputFormat } from './constants'
66
+
67
+ // Utility types consumers may want to use
68
+ export type { DeepPartial, Awaited } from './utils'
69
+ ```
70
+
71
+ **What NOT to export:**
72
+ - Internal implementation types (`InternalCacheEntry`, `HttpClientConfig`)
73
+ - Types used only within the library's own internals
74
+ - Types from `src/internal/` modules
75
+
76
+ Mark internal types with `@internal` JSDoc to exclude them from declaration files when `stripInternal: true` is set:
77
+
78
+ ```typescript
79
+ /** @internal */
80
+ export interface InternalCacheEntry {
81
+ value: unknown
82
+ expiresAt: number
83
+ }
84
+ ```
85
+
86
+ ### Type Testing with tsd
87
+
88
+ `tsd` lets you write assertions about types as test files. These catch type regressions — when a refactor accidentally changes the type of a public API:
89
+
90
+ ```typescript
91
+ // tests/types/index.test-d.ts
92
+ import { expectType, expectError, expectAssignable } from 'tsd'
93
+ import { parseConfig, ParseOptions, ParseError, Config } from 'my-library'
94
+
95
+ // Assert parseConfig returns Config
96
+ expectType<Config>(parseConfig('input'))
97
+
98
+ // Assert ParseOptions is accepted
99
+ const options: ParseOptions = { strict: true }
100
+ expectAssignable<ParseOptions>(options)
101
+
102
+ // Assert ParseError has the right shape
103
+ const err = new ParseError('message', 1, 1)
104
+ expectType<number>(err.line)
105
+ expectType<number>(err.column)
106
+
107
+ // Assert that invalid input types cause a type error
108
+ expectError(parseConfig(42))
109
+ expectError(parseConfig(null))
110
+
111
+ // Assert overload resolution
112
+ expectType<Config>(parseConfig('input'))
113
+ expectType<Promise<Config>>(parseConfig('input', { async: true }))
114
+ ```
115
+
116
+ Run type tests as part of CI:
117
+ ```bash
118
+ # package.json
119
+ "test:types": "tsd"
120
+ "test": "vitest run && tsd"
121
+ ```
122
+
123
+ `tsd` will fail the test suite if any `expectType` assertion fails (wrong type) or any `expectError` assertion fails (expected error didn't occur).
124
+
125
+ ### Using expect-type (Alternative to tsd)
126
+
127
+ `expect-type` works inline with your test runner (vitest, jest):
128
+
129
+ ```typescript
130
+ // tests/types/parser.test.ts
131
+ import { expectTypeOf } from 'vitest'
132
+ import { parseConfig } from 'my-library'
133
+
134
+ test('parseConfig return type', () => {
135
+ expectTypeOf(parseConfig).toBeFunction()
136
+ expectTypeOf(parseConfig).parameter(0).toBeString()
137
+ expectTypeOf(parseConfig).returns.toEqualTypeOf<Config>()
138
+ })
139
+
140
+ test('ParseOptions is a valid options object', () => {
141
+ expectTypeOf<ParseOptions>().toHaveProperty('strict')
142
+ expectTypeOf<ParseOptions['strict']>().toEqualTypeOf<boolean | undefined>()
143
+ })
144
+ ```
145
+
146
+ The advantage of `expect-type` within vitest: type tests live alongside runtime tests and run in the same test command. The advantage of `tsd`: it's a dedicated type testing tool with more ergonomic syntax for complex assertions.
147
+
148
+ ### Conditional Types for Precise Return Types
149
+
150
+ Conditional types allow the return type to depend on the input type:
151
+
152
+ ```typescript
153
+ // Return type narrows based on whether async option is set
154
+ function parseConfig(input: string, options?: { async?: false }): Config
155
+ function parseConfig(input: string, options: { async: true }): Promise<Config>
156
+ function parseConfig(input: string, options?: { async?: boolean }): Config | Promise<Config>
157
+
158
+ // Generic conditional type
159
+ type ParseResult<T extends ParseOptions> =
160
+ T extends { async: true } ? Promise<Config> : Config
161
+
162
+ // Deep conditional: extract value type from Result
163
+ type Unwrap<T> = T extends Promise<infer U> ? U : T
164
+ ```
165
+
166
+ **Practical conditional type patterns:**
167
+
168
+ ```typescript
169
+ // Input determines output type
170
+ function transform<T extends string | Buffer>(
171
+ input: T
172
+ ): T extends string ? string : Buffer
173
+
174
+ // Stricter types in strict mode
175
+ interface ParseOptions {
176
+ strict?: boolean
177
+ }
178
+
179
+ type ParseReturn<T extends ParseOptions> =
180
+ T extends { strict: true } ? StrictConfig : Config
181
+
182
+ // Utility: make deeply optional
183
+ type DeepPartial<T> = {
184
+ [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K]
185
+ }
186
+ ```
187
+
188
+ Use conditional types when the return type genuinely depends on the input. Don't overuse them — complex conditional types are hard to debug and can produce confusing error messages.
189
+
190
+ ### Declaration Maps
191
+
192
+ Declaration maps (`.d.ts.map`) enable Go-to-Definition in IDEs to jump to the TypeScript source rather than the compiled declaration file. This dramatically improves the experience of debugging library code:
193
+
194
+ ```json
195
+ // tsconfig.json
196
+ {
197
+ "compilerOptions": {
198
+ "declarationMap": true // Emits .d.ts.map alongside .d.ts
199
+ }
200
+ }
201
+ ```
202
+
203
+ Include the source maps in the published package:
204
+ ```json
205
+ // package.json
206
+ {
207
+ "files": [
208
+ "dist/", // includes .d.ts.map files
209
+ "src/", // include source for source map resolution
210
+ "README.md"
211
+ ]
212
+ }
213
+ ```
214
+
215
+ Including `src/` in the published package allows IDEs to resolve the original TypeScript source through the declaration map.
216
+
217
+ ### Template Literal Types for String APIs
218
+
219
+ When a library accepts string patterns, template literal types provide exact-match checking:
220
+
221
+ ```typescript
222
+ // HTTP method type
223
+ type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS'
224
+
225
+ // Route parameter extraction
226
+ type ExtractParams<Route extends string> =
227
+ Route extends `${string}:${infer Param}/${infer Rest}`
228
+ ? Param | ExtractParams<`/${Rest}`>
229
+ : Route extends `${string}:${infer Param}`
230
+ ? Param
231
+ : never
232
+
233
+ // Usage:
234
+ type Params = ExtractParams<'/users/:userId/posts/:postId'>
235
+ // Type: "userId" | "postId"
236
+
237
+ function route<R extends string>(
238
+ path: R,
239
+ handler: (params: Record<ExtractParams<R>, string>) => void
240
+ ): void
241
+ ```
242
+
243
+ Template literal types are powerful for configuration DSLs and string-based APIs. Use them when the consumer's strings have a predictable structure that TypeScript can validate.
244
+
245
+ ### JSDoc for Type Documentation
246
+
247
+ TypeDoc and IDE hover text both read JSDoc comments from type declarations:
248
+
249
+ ```typescript
250
+ /**
251
+ * Options for controlling the parsing behavior.
252
+ *
253
+ * @example
254
+ * ```typescript
255
+ * const config = parseConfig(input, {
256
+ * strict: true,
257
+ * encoding: 'utf-8'
258
+ * })
259
+ * ```
260
+ */
261
+ export interface ParseOptions {
262
+ /**
263
+ * Enable strict mode validation.
264
+ * In strict mode, unknown fields cause a ValidationError.
265
+ * @default false
266
+ */
267
+ strict?: boolean
268
+
269
+ /**
270
+ * File encoding for file-based parsing.
271
+ * @default 'utf-8'
272
+ */
273
+ encoding?: BufferEncoding
274
+
275
+ /**
276
+ * Maximum input size in bytes.
277
+ * Inputs larger than this limit throw a ParseError.
278
+ * @default 1_048_576 (1 MB)
279
+ */
280
+ maxSize?: number
281
+ }
282
+ ```
283
+
284
+ JSDoc on interfaces and their properties generates rich documentation and appears in IDE hover. Always document: the purpose, any constraints, and the default value.