@grimoire-cc/cli 0.4.1 → 0.5.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/dist/static/log-viewer.html +1 -0
- package/dist/static/static/log-viewer.html +1 -0
- package/package.json +1 -1
- package/packs/ts-pack/grimoire.json +33 -0
- package/packs/ts-pack/skills/grimoire:modern-typescript/SKILL.md +336 -0
- package/packs/ts-pack/skills/grimoire:modern-typescript/reference/modern-features.md +373 -0
- package/packs/ts-pack/skills/grimoire:modern-typescript/reference/patterns-and-idioms.md +477 -0
- package/packs/ts-pack/skills/grimoire:modern-typescript/reference/type-system.md +389 -0
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
# Modern Features Guide — TypeScript 5.0 to 5.9
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
|
|
5
|
+
- [TypeScript 5.0](#typescript-50)
|
|
6
|
+
- [TypeScript 5.1](#typescript-51)
|
|
7
|
+
- [TypeScript 5.2](#typescript-52)
|
|
8
|
+
- [TypeScript 5.3](#typescript-53)
|
|
9
|
+
- [TypeScript 5.4](#typescript-54)
|
|
10
|
+
- [TypeScript 5.5](#typescript-55)
|
|
11
|
+
- [TypeScript 5.6](#typescript-56)
|
|
12
|
+
- [TypeScript 5.7](#typescript-57)
|
|
13
|
+
- [TypeScript 5.8](#typescript-58)
|
|
14
|
+
- [TypeScript 5.9](#typescript-59)
|
|
15
|
+
- [Looking Ahead: TypeScript 7](#looking-ahead-typescript-7)
|
|
16
|
+
|
|
17
|
+
## TypeScript 5.0
|
|
18
|
+
|
|
19
|
+
### Decorators (Stage 3 Standard)
|
|
20
|
+
|
|
21
|
+
TC39-compliant decorators replacing the experimental decorator implementation.
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
function logged(target: Function, context: ClassMethodDecoratorContext) {
|
|
25
|
+
const name = String(context.name);
|
|
26
|
+
return function (this: unknown, ...args: unknown[]) {
|
|
27
|
+
console.log(`Calling ${name}`);
|
|
28
|
+
return (target as Function).apply(this, args);
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
class UserService {
|
|
33
|
+
@logged
|
|
34
|
+
getUser(id: string): User { /* ... */ }
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### `const` Type Parameters
|
|
39
|
+
|
|
40
|
+
Infer literal types from generic arguments without requiring `as const` at call sites.
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
function createRoutes<const T extends Record<string, string>>(routes: T): T {
|
|
44
|
+
return routes;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Infers { readonly home: "/"; readonly about: "/about" }
|
|
48
|
+
const routes = createRoutes({ home: "/", about: "/about" });
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### `satisfies` Operator
|
|
52
|
+
|
|
53
|
+
Validates that an expression matches a type without widening the inferred type.
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
type Color = "red" | "green" | "blue";
|
|
57
|
+
type ColorMap = Record<Color, string | [number, number, number]>;
|
|
58
|
+
|
|
59
|
+
const palette = {
|
|
60
|
+
red: [255, 0, 0],
|
|
61
|
+
green: "#00ff00",
|
|
62
|
+
blue: [0, 0, 255],
|
|
63
|
+
} satisfies ColorMap;
|
|
64
|
+
|
|
65
|
+
// palette.green is string (not string | number[])
|
|
66
|
+
palette.green.toUpperCase(); // OK
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Enum Improvements
|
|
70
|
+
|
|
71
|
+
All enums are now union enums, and enum members can be computed from other enum values.
|
|
72
|
+
|
|
73
|
+
### `--moduleResolution bundler`
|
|
74
|
+
|
|
75
|
+
New module resolution mode for bundler-based workflows (Vite, esbuild, webpack).
|
|
76
|
+
|
|
77
|
+
## TypeScript 5.1
|
|
78
|
+
|
|
79
|
+
### Easier Implicit Returns for `undefined`
|
|
80
|
+
|
|
81
|
+
Functions returning `undefined` no longer need an explicit `return` statement.
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
function log(msg: string): undefined {
|
|
85
|
+
console.log(msg);
|
|
86
|
+
// No return needed
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Unlinked Type Predicates for Getters/Setters
|
|
91
|
+
|
|
92
|
+
Getters and setters can now have unrelated types.
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
class Box {
|
|
96
|
+
#value: unknown;
|
|
97
|
+
|
|
98
|
+
get value(): string {
|
|
99
|
+
return String(this.#value);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
set value(newValue: string | number | boolean) {
|
|
103
|
+
this.#value = newValue;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## TypeScript 5.2
|
|
109
|
+
|
|
110
|
+
### `using` Declarations (Explicit Resource Management)
|
|
111
|
+
|
|
112
|
+
Deterministic cleanup of resources when they go out of scope.
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
class TempFile implements Disposable {
|
|
116
|
+
#path: string;
|
|
117
|
+
|
|
118
|
+
constructor(path: string) {
|
|
119
|
+
this.#path = path;
|
|
120
|
+
writeFileSync(path, "");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
write(data: string): void {
|
|
124
|
+
appendFileSync(this.#path, data);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
[Symbol.dispose](): void {
|
|
128
|
+
unlinkSync(this.#path);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function processTempData(): void {
|
|
133
|
+
using tmp = new TempFile("/tmp/work.dat");
|
|
134
|
+
tmp.write("data");
|
|
135
|
+
// tmp is automatically deleted when scope exits
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### `await using` for Async Disposal
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
class DbConnection implements AsyncDisposable {
|
|
143
|
+
async [Symbol.asyncDispose](): Promise<void> {
|
|
144
|
+
await this.close();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async function query(): Promise<Result> {
|
|
149
|
+
await using conn = await pool.acquire();
|
|
150
|
+
return conn.execute("SELECT 1");
|
|
151
|
+
// Connection returned to pool automatically
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Decorator Metadata
|
|
156
|
+
|
|
157
|
+
Access metadata set by decorators via `Symbol.metadata`.
|
|
158
|
+
|
|
159
|
+
## TypeScript 5.3
|
|
160
|
+
|
|
161
|
+
### `import` Attributes
|
|
162
|
+
|
|
163
|
+
Support for import attributes (JSON modules, CSS modules).
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
import config from "./config.json" with { type: "json" };
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### `switch (true)` Narrowing
|
|
170
|
+
|
|
171
|
+
TypeScript now narrows types within `switch (true)` patterns.
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
function describe(value: string | number | boolean): string {
|
|
175
|
+
switch (true) {
|
|
176
|
+
case typeof value === "string":
|
|
177
|
+
return value.toUpperCase(); // value is string
|
|
178
|
+
case typeof value === "number":
|
|
179
|
+
return value.toFixed(2); // value is number
|
|
180
|
+
default:
|
|
181
|
+
return String(value);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## TypeScript 5.4
|
|
187
|
+
|
|
188
|
+
### `NoInfer<T>` Utility Type
|
|
189
|
+
|
|
190
|
+
Prevents a type parameter position from contributing to inference.
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
function createStreetLight<C extends string>(
|
|
194
|
+
colors: C[],
|
|
195
|
+
defaultColor: NoInfer<C>,
|
|
196
|
+
): void { /* ... */ }
|
|
197
|
+
|
|
198
|
+
createStreetLight(["red", "yellow", "green"], "red"); // OK
|
|
199
|
+
createStreetLight(["red", "yellow", "green"], "blue"); // Error
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Preserved Narrowing in Closures
|
|
203
|
+
|
|
204
|
+
Variables narrowed in the containing scope remain narrowed inside closures when the variable isn't reassigned.
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
function process(value: string | null) {
|
|
208
|
+
if (value !== null) {
|
|
209
|
+
// value is narrowed to string
|
|
210
|
+
setTimeout(() => {
|
|
211
|
+
console.log(value.length); // Still narrowed in closure
|
|
212
|
+
}, 100);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### `Object.groupBy` and `Map.groupBy` Types
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
const grouped = Object.groupBy(users, (user) => user.role);
|
|
221
|
+
// Record<string, User[]>
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## TypeScript 5.5
|
|
225
|
+
|
|
226
|
+
### Inferred Type Predicates
|
|
227
|
+
|
|
228
|
+
TypeScript automatically infers type predicates for functions that narrow types.
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
// Before 5.5 — required explicit annotation
|
|
232
|
+
function isString(x: unknown): x is string {
|
|
233
|
+
return typeof x === "string";
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// 5.5+ — inferred automatically
|
|
237
|
+
const strings = values.filter((v) => typeof v === "string");
|
|
238
|
+
// Correctly typed as string[]
|
|
239
|
+
|
|
240
|
+
const nonNull = items.filter((item) => item != null);
|
|
241
|
+
// Correctly typed as NonNullable<T>[]
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Regular Expression Checking
|
|
245
|
+
|
|
246
|
+
TypeScript validates regular expression syntax at compile time.
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
const re = /(?<=\d+)\s+/; // Validated at compile time
|
|
250
|
+
const bad = /(?<=/; // Error: unterminated regex
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Isolated Declarations
|
|
254
|
+
|
|
255
|
+
New `--isolatedDeclarations` flag ensures `.d.ts` files can be generated without type checking.
|
|
256
|
+
|
|
257
|
+
## TypeScript 5.6
|
|
258
|
+
|
|
259
|
+
### Disallowed Nullish and Truthy Checks
|
|
260
|
+
|
|
261
|
+
TypeScript errors on always-truthy or always-nullish checks to catch bugs.
|
|
262
|
+
|
|
263
|
+
```typescript
|
|
264
|
+
function check(x: string) {
|
|
265
|
+
if (x) { /* OK — string can be falsy ("") */ }
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function check2(x: () => boolean) {
|
|
269
|
+
// Error — function reference is always truthy
|
|
270
|
+
// Did you mean to call it? x()
|
|
271
|
+
if (x) { /* ... */ }
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### `--noUncheckedSideEffectImports`
|
|
276
|
+
|
|
277
|
+
Verifies that side-effect imports (`import "./setup"`) actually resolve to existing files.
|
|
278
|
+
|
|
279
|
+
### Iterator Helper Methods
|
|
280
|
+
|
|
281
|
+
Built-in support for iterator helpers like `.map()`, `.filter()`, `.take()` on iterators.
|
|
282
|
+
|
|
283
|
+
```typescript
|
|
284
|
+
function* naturals() {
|
|
285
|
+
let n = 0;
|
|
286
|
+
while (true) yield n++;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const firstTenEvens = naturals()
|
|
290
|
+
.filter((n) => n % 2 === 0)
|
|
291
|
+
.take(10)
|
|
292
|
+
.toArray();
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
## TypeScript 5.7
|
|
296
|
+
|
|
297
|
+
### Never-Initialized Variable Checks
|
|
298
|
+
|
|
299
|
+
Detects variables used before assignment even when accessed inside nested functions.
|
|
300
|
+
|
|
301
|
+
```typescript
|
|
302
|
+
function example() {
|
|
303
|
+
let value: string;
|
|
304
|
+
|
|
305
|
+
function inner() {
|
|
306
|
+
console.log(value); // Error: used before assigned
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
inner();
|
|
310
|
+
value = "hello";
|
|
311
|
+
}
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### `--target es2024`
|
|
315
|
+
|
|
316
|
+
Enables `Object.groupBy`, `Map.groupBy`, `Promise.withResolvers`, and enhanced `ArrayBuffer` / `SharedArrayBuffer` support.
|
|
317
|
+
|
|
318
|
+
### `--rewriteRelativeImportExtensions`
|
|
319
|
+
|
|
320
|
+
Automatically rewrites `.ts` → `.js`, `.mts` → `.mjs`, `.cts` → `.cjs` in relative imports during compilation.
|
|
321
|
+
|
|
322
|
+
### JSON Import Validation
|
|
323
|
+
|
|
324
|
+
Under `--module nodenext`, JSON imports require `with { type: "json" }` and only support default exports.
|
|
325
|
+
|
|
326
|
+
```typescript
|
|
327
|
+
import config from "./config.json" with { type: "json" };
|
|
328
|
+
// config.setting — OK
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### V8 Compile Caching
|
|
332
|
+
|
|
333
|
+
Leverages Node.js 22's `module.enableCompileCache()` for ~2.5x faster startup.
|
|
334
|
+
|
|
335
|
+
## TypeScript 5.8
|
|
336
|
+
|
|
337
|
+
### Granular Return Expression Checks
|
|
338
|
+
|
|
339
|
+
Each branch of a conditional return expression is independently checked against the declared return type.
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
function process(input: string): number {
|
|
343
|
+
// Each branch checked separately for return type compatibility
|
|
344
|
+
return input.length > 0
|
|
345
|
+
? parseInt(input) // checked: number ← OK
|
|
346
|
+
: "default"; // checked: string ← Error!
|
|
347
|
+
}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### Performance Optimizations
|
|
351
|
+
|
|
352
|
+
Build and watch mode performance improvements for large codebases.
|
|
353
|
+
|
|
354
|
+
## TypeScript 5.9
|
|
355
|
+
|
|
356
|
+
### Clean Default Configuration
|
|
357
|
+
|
|
358
|
+
`tsc --init` generates sensible defaults: `"module": "nodenext"`, `"target": "esnext"`, and strict type-checking enabled out of the box.
|
|
359
|
+
|
|
360
|
+
### Conditional Return Types (Refined)
|
|
361
|
+
|
|
362
|
+
Improved checking of functions with conditional return types based on parameter types.
|
|
363
|
+
|
|
364
|
+
## Looking Ahead: TypeScript 7
|
|
365
|
+
|
|
366
|
+
Microsoft is rewriting the TypeScript compiler in Go (`tsgo`) for 8-10x performance improvements. Key points:
|
|
367
|
+
|
|
368
|
+
- **TypeScript 6.x** — Continues the JS-based compiler with deprecations and breaking changes to align with the native codebase
|
|
369
|
+
- **TypeScript 7.0** — First fully native release, targeting early 2026
|
|
370
|
+
- **Backwards compatible** — Same TypeScript language, dramatically faster tooling
|
|
371
|
+
- **`tsgo`** available for early testing now
|
|
372
|
+
|
|
373
|
+
The language features and best practices in this guide will continue to work unchanged in TypeScript 7.
|