@biggora/claude-plugins 1.2.2 → 1.3.1
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/README.md +5 -1
- package/package.json +1 -1
- package/registry/registry.json +15 -0
- package/specs/coding.md +11 -0
- package/src/commands/skills/add.js +115 -31
- package/src/commands/skills/list.js +25 -52
- package/src/commands/skills/remove.js +45 -27
- package/src/commands/skills/resolve.js +104 -0
- package/src/commands/skills/update.js +58 -74
- package/src/config.js +5 -0
- package/src/skills/nest-best-practices/SKILL.md +251 -0
- package/src/skills/nest-best-practices/references/best-practices-request-lifecycle.md +158 -0
- package/src/skills/nest-best-practices/references/cli-monorepo.md +106 -0
- package/src/skills/nest-best-practices/references/cli-overview.md +157 -0
- package/src/skills/nest-best-practices/references/core-controllers.md +165 -0
- package/src/skills/nest-best-practices/references/core-dependency-injection.md +179 -0
- package/src/skills/nest-best-practices/references/core-middleware.md +139 -0
- package/src/skills/nest-best-practices/references/core-modules.md +138 -0
- package/src/skills/nest-best-practices/references/core-providers.md +188 -0
- package/src/skills/nest-best-practices/references/faq-raw-body-hybrid.md +122 -0
- package/src/skills/nest-best-practices/references/fundamentals-circular-dependency.md +89 -0
- package/src/skills/nest-best-practices/references/fundamentals-custom-decorators.md +107 -0
- package/src/skills/nest-best-practices/references/fundamentals-dynamic-modules.md +125 -0
- package/src/skills/nest-best-practices/references/fundamentals-exception-filters.md +202 -0
- package/src/skills/nest-best-practices/references/fundamentals-execution-context.md +107 -0
- package/src/skills/nest-best-practices/references/fundamentals-guards.md +136 -0
- package/src/skills/nest-best-practices/references/fundamentals-interceptors.md +187 -0
- package/src/skills/nest-best-practices/references/fundamentals-lazy-loading.md +89 -0
- package/src/skills/nest-best-practices/references/fundamentals-lifecycle-events.md +87 -0
- package/src/skills/nest-best-practices/references/fundamentals-module-reference.md +107 -0
- package/src/skills/nest-best-practices/references/fundamentals-pipes.md +197 -0
- package/src/skills/nest-best-practices/references/fundamentals-provider-scopes.md +92 -0
- package/src/skills/nest-best-practices/references/fundamentals-testing.md +142 -0
- package/src/skills/nest-best-practices/references/graphql-overview.md +233 -0
- package/src/skills/nest-best-practices/references/graphql-resolvers-mutations.md +199 -0
- package/src/skills/nest-best-practices/references/graphql-scalars-unions-enums.md +180 -0
- package/src/skills/nest-best-practices/references/graphql-subscriptions.md +228 -0
- package/src/skills/nest-best-practices/references/microservices-grpc.md +175 -0
- package/src/skills/nest-best-practices/references/microservices-overview.md +221 -0
- package/src/skills/nest-best-practices/references/microservices-transports.md +119 -0
- package/src/skills/nest-best-practices/references/openapi-swagger.md +207 -0
- package/src/skills/nest-best-practices/references/recipes-authentication.md +97 -0
- package/src/skills/nest-best-practices/references/recipes-cqrs.md +176 -0
- package/src/skills/nest-best-practices/references/recipes-crud-generator.md +87 -0
- package/src/skills/nest-best-practices/references/recipes-documentation.md +93 -0
- package/src/skills/nest-best-practices/references/recipes-mongoose.md +153 -0
- package/src/skills/nest-best-practices/references/recipes-prisma.md +98 -0
- package/src/skills/nest-best-practices/references/recipes-terminus.md +148 -0
- package/src/skills/nest-best-practices/references/recipes-typeorm.md +122 -0
- package/src/skills/nest-best-practices/references/security-authorization.md +196 -0
- package/src/skills/nest-best-practices/references/security-cors-helmet-rate-limiting.md +204 -0
- package/src/skills/nest-best-practices/references/security-encryption-hashing.md +93 -0
- package/src/skills/nest-best-practices/references/techniques-caching.md +142 -0
- package/src/skills/nest-best-practices/references/techniques-compression-streaming-sse.md +194 -0
- package/src/skills/nest-best-practices/references/techniques-configuration.md +132 -0
- package/src/skills/nest-best-practices/references/techniques-database.md +153 -0
- package/src/skills/nest-best-practices/references/techniques-events.md +163 -0
- package/src/skills/nest-best-practices/references/techniques-fastify.md +137 -0
- package/src/skills/nest-best-practices/references/techniques-file-upload.md +140 -0
- package/src/skills/nest-best-practices/references/techniques-http-module.md +176 -0
- package/src/skills/nest-best-practices/references/techniques-logging.md +146 -0
- package/src/skills/nest-best-practices/references/techniques-mvc-serve-static.md +132 -0
- package/src/skills/nest-best-practices/references/techniques-queues.md +162 -0
- package/src/skills/nest-best-practices/references/techniques-serialization.md +158 -0
- package/src/skills/nest-best-practices/references/techniques-sessions-cookies.md +167 -0
- package/src/skills/nest-best-practices/references/techniques-task-scheduling.md +166 -0
- package/src/skills/nest-best-practices/references/techniques-validation.md +126 -0
- package/src/skills/nest-best-practices/references/techniques-versioning.md +153 -0
- package/src/skills/nest-best-practices/references/websockets-advanced.md +96 -0
- package/src/skills/nest-best-practices/references/websockets-gateways.md +215 -0
- package/src/skills/typescript-expert/SKILL.md +145 -0
- package/src/skills/typescript-expert/commands/typescript-fix.md +65 -0
- package/src/skills/typescript-expert/references/advanced-conditional-types.md +190 -0
- package/src/skills/typescript-expert/references/advanced-decorators.md +243 -0
- package/src/skills/typescript-expert/references/advanced-mapped-types.md +223 -0
- package/src/skills/typescript-expert/references/advanced-template-literals.md +209 -0
- package/src/skills/typescript-expert/references/advanced-type-guards.md +308 -0
- package/src/skills/typescript-expert/references/best-practices-patterns.md +313 -0
- package/src/skills/typescript-expert/references/best-practices-performance.md +185 -0
- package/src/skills/typescript-expert/references/best-practices-tsconfig.md +242 -0
- package/src/skills/typescript-expert/references/core-generics.md +246 -0
- package/src/skills/typescript-expert/references/core-interfaces-types.md +231 -0
- package/src/skills/typescript-expert/references/core-type-system.md +261 -0
- package/src/skills/typescript-expert/references/core-utility-types.md +235 -0
- package/src/skills/typescript-expert/references/features-ts5x.md +370 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# Built-in Utility Types
|
|
2
|
+
|
|
3
|
+
TypeScript ships with utility types that transform existing types. These are invaluable for deriving new types without repetition.
|
|
4
|
+
|
|
5
|
+
## Object Transformation
|
|
6
|
+
|
|
7
|
+
### `Partial<T>` — Make All Properties Optional
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
interface User {
|
|
11
|
+
name: string;
|
|
12
|
+
email: string;
|
|
13
|
+
age: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type PartialUser = Partial<User>;
|
|
17
|
+
// { name?: string; email?: string; age?: number }
|
|
18
|
+
|
|
19
|
+
// Common use: update functions that accept partial data
|
|
20
|
+
function updateUser(id: string, updates: Partial<User>): User { ... }
|
|
21
|
+
updateUser("1", { name: "Alice" }); // OK — only updating name
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### `Required<T>` — Make All Properties Required
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
interface Config {
|
|
28
|
+
host?: string;
|
|
29
|
+
port?: number;
|
|
30
|
+
debug?: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
type FullConfig = Required<Config>;
|
|
34
|
+
// { host: string; port: number; debug: boolean }
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### `Readonly<T>` — Make All Properties Readonly
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
type FrozenUser = Readonly<User>;
|
|
41
|
+
// { readonly name: string; readonly email: string; readonly age: number }
|
|
42
|
+
|
|
43
|
+
const user: FrozenUser = { name: "Alice", email: "a@b.com", age: 30 };
|
|
44
|
+
user.name = "Bob"; // Error!
|
|
45
|
+
|
|
46
|
+
// Note: Readonly is shallow — nested objects are still mutable
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### `Pick<T, K>` — Select Specific Properties
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
type UserPreview = Pick<User, "name" | "email">;
|
|
53
|
+
// { name: string; email: string }
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### `Omit<T, K>` — Remove Specific Properties
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
type UserWithoutEmail = Omit<User, "email">;
|
|
60
|
+
// { name: string; age: number }
|
|
61
|
+
|
|
62
|
+
// Common: creating input types from entity types
|
|
63
|
+
type CreateUserInput = Omit<User, "id" | "createdAt">;
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### `Record<K, V>` — Object with Known Keys and Value Type
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
// String-keyed dictionary
|
|
70
|
+
type UserMap = Record<string, User>;
|
|
71
|
+
|
|
72
|
+
// Enum/union-keyed object (ensures all keys are covered)
|
|
73
|
+
type RolePermissions = Record<"admin" | "user" | "guest", string[]>;
|
|
74
|
+
const perms: RolePermissions = {
|
|
75
|
+
admin: ["read", "write", "delete"],
|
|
76
|
+
user: ["read", "write"],
|
|
77
|
+
guest: ["read"],
|
|
78
|
+
};
|
|
79
|
+
// Missing a key would be an error
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Union Manipulation
|
|
83
|
+
|
|
84
|
+
### `Exclude<T, U>` — Remove Types from Union
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
type T = "a" | "b" | "c";
|
|
88
|
+
type WithoutA = Exclude<T, "a">; // "b" | "c"
|
|
89
|
+
type OnlyStrings = Exclude<string | number | boolean, number | boolean>; // string
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### `Extract<T, U>` — Keep Only Matching Types
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
type T = string | number | (() => void);
|
|
96
|
+
type Funcs = Extract<T, Function>; // () => void
|
|
97
|
+
type Primitives = Extract<T, string | number>; // string | number
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### `NonNullable<T>` — Remove `null` and `undefined`
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
type MaybeString = string | null | undefined;
|
|
104
|
+
type DefiniteString = NonNullable<MaybeString>; // string
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Function Utilities
|
|
108
|
+
|
|
109
|
+
### `ReturnType<T>` — Extract Return Type
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
function getUser() {
|
|
113
|
+
return { id: "1", name: "Alice", roles: ["admin"] };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
type User = ReturnType<typeof getUser>;
|
|
117
|
+
// { id: string; name: string; roles: string[] }
|
|
118
|
+
|
|
119
|
+
// Works with generics via conditional types
|
|
120
|
+
type AsyncReturn<T extends (...args: any) => any> =
|
|
121
|
+
ReturnType<T> extends Promise<infer R> ? R : ReturnType<T>;
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### `Parameters<T>` — Extract Parameter Types as Tuple
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
function createUser(name: string, age: number, admin: boolean): User { ... }
|
|
128
|
+
|
|
129
|
+
type CreateUserParams = Parameters<typeof createUser>;
|
|
130
|
+
// [name: string, age: number, admin: boolean]
|
|
131
|
+
|
|
132
|
+
// Access individual parameters
|
|
133
|
+
type FirstParam = Parameters<typeof createUser>[0]; // string
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### `ConstructorParameters<T>` — Constructor Parameter Types
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
class User {
|
|
140
|
+
constructor(public name: string, public age: number) {}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
type UserCtorParams = ConstructorParameters<typeof User>;
|
|
144
|
+
// [name: string, age: number]
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### `InstanceType<T>` — Instance Type from Constructor
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
type UserInstance = InstanceType<typeof User>; // User
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## String Manipulation Types
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
type Upper = Uppercase<"hello">; // "HELLO"
|
|
157
|
+
type Lower = Lowercase<"HELLO">; // "hello"
|
|
158
|
+
type Cap = Capitalize<"hello">; // "Hello"
|
|
159
|
+
type Uncap = Uncapitalize<"Hello">; // "hello"
|
|
160
|
+
|
|
161
|
+
// Powerful with template literals
|
|
162
|
+
type EventName<T extends string> = `on${Capitalize<T>}`;
|
|
163
|
+
type ClickEvent = EventName<"click">; // "onClick"
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Promise Utilities
|
|
167
|
+
|
|
168
|
+
### `Awaited<T>` — Unwrap Promise Types (TS 4.5+)
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
type A = Awaited<Promise<string>>; // string
|
|
172
|
+
type B = Awaited<Promise<Promise<number>>>; // number (recursive unwrap)
|
|
173
|
+
type C = Awaited<boolean | Promise<string>>; // boolean | string
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## `NoInfer<T>` (TS 5.4+)
|
|
177
|
+
|
|
178
|
+
Prevents a type parameter position from being used for inference:
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
function createStreetLight<C extends string>(
|
|
182
|
+
colors: C[],
|
|
183
|
+
defaultColor?: NoInfer<C>
|
|
184
|
+
) { ... }
|
|
185
|
+
|
|
186
|
+
createStreetLight(["red", "yellow", "green"], "blue");
|
|
187
|
+
// Error! "blue" is not "red" | "yellow" | "green"
|
|
188
|
+
// Without NoInfer, TypeScript would widen C to include "blue"
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Composing Utility Types
|
|
192
|
+
|
|
193
|
+
Utility types compose naturally:
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
// Readonly partial (for frozen default configs)
|
|
197
|
+
type Defaults<T> = Readonly<Partial<T>>;
|
|
198
|
+
|
|
199
|
+
// Pick and make required
|
|
200
|
+
type RequiredPick<T, K extends keyof T> = Required<Pick<T, K>>;
|
|
201
|
+
|
|
202
|
+
// Omit and make readonly
|
|
203
|
+
type ProtectedOmit<T, K extends keyof T> = Readonly<Omit<T, K>>;
|
|
204
|
+
|
|
205
|
+
// Make some properties optional, keep the rest
|
|
206
|
+
type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
|
207
|
+
|
|
208
|
+
type UserOptionalEmail = PartialBy<User, "email">;
|
|
209
|
+
// { name: string; age: number; email?: string }
|
|
210
|
+
|
|
211
|
+
// Make some properties required, keep the rest optional
|
|
212
|
+
type RequiredBy<T, K extends keyof T> = Partial<Omit<T, K>> & Required<Pick<T, K>>;
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Quick Reference Table
|
|
216
|
+
|
|
217
|
+
| Utility | Input | Output |
|
|
218
|
+
|---------|-------|--------|
|
|
219
|
+
| `Partial<T>` | `{ a: string; b: number }` | `{ a?: string; b?: number }` |
|
|
220
|
+
| `Required<T>` | `{ a?: string; b?: number }` | `{ a: string; b: number }` |
|
|
221
|
+
| `Readonly<T>` | `{ a: string }` | `{ readonly a: string }` |
|
|
222
|
+
| `Pick<T, K>` | `{ a: string; b: number }, "a"` | `{ a: string }` |
|
|
223
|
+
| `Omit<T, K>` | `{ a: string; b: number }, "a"` | `{ b: number }` |
|
|
224
|
+
| `Record<K, V>` | `"a" \| "b", number` | `{ a: number; b: number }` |
|
|
225
|
+
| `Exclude<T, U>` | `"a" \| "b" \| "c", "a"` | `"b" \| "c"` |
|
|
226
|
+
| `Extract<T, U>` | `string \| number, string` | `string` |
|
|
227
|
+
| `NonNullable<T>` | `string \| null` | `string` |
|
|
228
|
+
| `ReturnType<T>` | `() => string` | `string` |
|
|
229
|
+
| `Parameters<T>` | `(a: string, b: number) => void` | `[string, number]` |
|
|
230
|
+
| `Awaited<T>` | `Promise<string>` | `string` |
|
|
231
|
+
| `NoInfer<T>` | Prevents inference at position | Same type, no inference |
|
|
232
|
+
| `Uppercase<S>` | `"hello"` | `"HELLO"` |
|
|
233
|
+
| `Lowercase<S>` | `"HELLO"` | `"hello"` |
|
|
234
|
+
| `Capitalize<S>` | `"hello"` | `"Hello"` |
|
|
235
|
+
| `Uncapitalize<S>` | `"Hello"` | `"hello"` |
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
# TypeScript 5.x Features
|
|
2
|
+
|
|
3
|
+
A comprehensive guide to features added in TypeScript 5.0 through 5.8.
|
|
4
|
+
|
|
5
|
+
## TypeScript 5.0
|
|
6
|
+
|
|
7
|
+
### TC39 Decorators
|
|
8
|
+
|
|
9
|
+
Standard decorators without `experimentalDecorators`. See [advanced-decorators](advanced-decorators.md) for full details.
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
function log(target: Function, context: ClassMethodDecoratorContext) {
|
|
13
|
+
return function (...args: any[]) {
|
|
14
|
+
console.log(`Calling ${String(context.name)}`);
|
|
15
|
+
return target.apply(this, args);
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
class Api {
|
|
20
|
+
@log
|
|
21
|
+
fetchData() { ... }
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### `const` Type Parameters
|
|
26
|
+
|
|
27
|
+
Add `const` modifier to type parameters for const-like inference:
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
function createConfig<const T extends Record<string, unknown>>(config: T): T {
|
|
31
|
+
return config;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Infers literal types without 'as const' at call site
|
|
35
|
+
const config = createConfig({
|
|
36
|
+
env: "production",
|
|
37
|
+
port: 3000,
|
|
38
|
+
features: ["auth", "logging"],
|
|
39
|
+
});
|
|
40
|
+
// Type: { readonly env: "production"; readonly port: 3000; readonly features: readonly ["auth", "logging"] }
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### `--verbatimModuleSyntax`
|
|
44
|
+
|
|
45
|
+
Forces explicit `type` annotations on type-only imports/exports:
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import type { User } from "./models"; // Erased
|
|
49
|
+
import { type Role, createUser } from "./models"; // Role erased, createUser kept
|
|
50
|
+
export type { User }; // Erased
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Replaces the older `importsNotUsedAsValues` and `preserveValueImports` flags.
|
|
54
|
+
|
|
55
|
+
### `export type *`
|
|
56
|
+
|
|
57
|
+
Re-export all types from a module as type-only:
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
export type * from "./internal-types";
|
|
61
|
+
export type * as models from "./models";
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Bundler Module Resolution
|
|
65
|
+
|
|
66
|
+
`"moduleResolution": "bundler"` — use when a bundler handles resolution:
|
|
67
|
+
|
|
68
|
+
```jsonc
|
|
69
|
+
{
|
|
70
|
+
"compilerOptions": {
|
|
71
|
+
"moduleResolution": "bundler",
|
|
72
|
+
"allowImportingTsExtensions": true // Optional: allow .ts imports
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
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
|
+
// Before 5.1: needed 'return;' or 'return undefined;'
|
|
85
|
+
function logMessage(msg: string): undefined {
|
|
86
|
+
console.log(msg);
|
|
87
|
+
// No return needed — implicitly returns undefined
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Unrelated Types for Getters and Setters
|
|
92
|
+
|
|
93
|
+
Getters and setters can have different types:
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
class State {
|
|
97
|
+
#value: number = 0;
|
|
98
|
+
|
|
99
|
+
get value(): number {
|
|
100
|
+
return this.#value;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
set value(input: string | number) {
|
|
104
|
+
this.#value = typeof input === "string" ? parseInt(input) : input;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const s = new State();
|
|
109
|
+
s.value = "42"; // Setter accepts string | number
|
|
110
|
+
const n = s.value; // Getter returns number
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### JSX Improvements
|
|
114
|
+
|
|
115
|
+
Support for different JSX element types per-tag. Enables React Server Components to be typed differently from client components.
|
|
116
|
+
|
|
117
|
+
## TypeScript 5.2
|
|
118
|
+
|
|
119
|
+
### `using` Declarations (Explicit Resource Management)
|
|
120
|
+
|
|
121
|
+
Deterministic cleanup with `Symbol.dispose` and `Symbol.asyncDispose`:
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
class TempFile implements Disposable {
|
|
125
|
+
#path: string;
|
|
126
|
+
|
|
127
|
+
constructor(path: string) {
|
|
128
|
+
this.#path = path;
|
|
129
|
+
writeFileSync(path, "");
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
write(data: string) {
|
|
133
|
+
appendFileSync(this.#path, data);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
[Symbol.dispose]() {
|
|
137
|
+
unlinkSync(this.#path);
|
|
138
|
+
console.log(`Cleaned up ${this.#path}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function processData() {
|
|
143
|
+
using file = new TempFile("/tmp/data.txt");
|
|
144
|
+
file.write("processing...");
|
|
145
|
+
// file is automatically disposed when scope exits
|
|
146
|
+
// Even if an exception is thrown
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Async version
|
|
150
|
+
class DatabaseConnection implements AsyncDisposable {
|
|
151
|
+
async [Symbol.asyncDispose]() {
|
|
152
|
+
await this.close();
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async function query() {
|
|
157
|
+
await using conn = await connect();
|
|
158
|
+
return await conn.query("SELECT ...");
|
|
159
|
+
// conn.close() called automatically
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Decorator Metadata
|
|
164
|
+
|
|
165
|
+
Access shared metadata object from decorator context:
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
function route(path: string) {
|
|
169
|
+
return (target: any, context: ClassMethodDecoratorContext) => {
|
|
170
|
+
context.metadata[String(context.name)] = { path };
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
class Controller {
|
|
175
|
+
@route("/users")
|
|
176
|
+
getUsers() { ... }
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const meta = Controller[Symbol.metadata];
|
|
180
|
+
// { getUsers: { path: "/users" } }
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## TypeScript 5.3
|
|
184
|
+
|
|
185
|
+
### `import` Attributes
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
import data from "./data.json" with { type: "json" };
|
|
189
|
+
import styles from "./styles.css" with { type: "css" };
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### `switch (true)` Narrowing
|
|
193
|
+
|
|
194
|
+
TypeScript now properly narrows types in `switch (true)` patterns:
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
function process(value: string | number | boolean) {
|
|
198
|
+
switch (true) {
|
|
199
|
+
case typeof value === "string":
|
|
200
|
+
value.toUpperCase(); // value is string
|
|
201
|
+
break;
|
|
202
|
+
case typeof value === "number":
|
|
203
|
+
value.toFixed(2); // value is number
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## TypeScript 5.4
|
|
210
|
+
|
|
211
|
+
### `NoInfer<T>` Utility Type
|
|
212
|
+
|
|
213
|
+
Prevents a position from contributing to type inference:
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
function createStreetLight<C extends string>(
|
|
217
|
+
colors: C[],
|
|
218
|
+
defaultColor?: NoInfer<C>
|
|
219
|
+
) { ... }
|
|
220
|
+
|
|
221
|
+
createStreetLight(["red", "yellow", "green"], "blue");
|
|
222
|
+
// Error! "blue" not in "red" | "yellow" | "green"
|
|
223
|
+
// Without NoInfer, C would widen to include "blue"
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Closure Narrowing in `Array.isArray`
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
function process(value: string | string[]) {
|
|
230
|
+
if (Array.isArray(value)) {
|
|
231
|
+
value.map(s => s.toUpperCase()); // value is string[]
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## TypeScript 5.5
|
|
237
|
+
|
|
238
|
+
### Inferred Type Predicates
|
|
239
|
+
|
|
240
|
+
TypeScript can now infer type guard return types:
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
// Before: needed explicit annotation
|
|
244
|
+
function isString(x: unknown): x is string {
|
|
245
|
+
return typeof x === "string";
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// TS 5.5: inferred automatically for simple cases
|
|
249
|
+
const isString = (x: unknown) => typeof x === "string";
|
|
250
|
+
// Return type inferred as: x is string
|
|
251
|
+
|
|
252
|
+
// filter(Boolean) just works now
|
|
253
|
+
const items = [1, null, 2, undefined, 3];
|
|
254
|
+
const numbers = items.filter(Boolean); // number[]
|
|
255
|
+
// Previously: (number | null | undefined)[]
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Regular Expression Syntax Checking
|
|
259
|
+
|
|
260
|
+
TypeScript now validates regex syntax at the type level:
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
const re = /\p{Letter}/u; // OK
|
|
264
|
+
const bad = /[/; // Error: Unterminated character class
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## TypeScript 5.6
|
|
268
|
+
|
|
269
|
+
### Iterator Helper Methods
|
|
270
|
+
|
|
271
|
+
Built-in iterator methods like `.map()`, `.filter()`, `.take()`:
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
function* naturals() {
|
|
275
|
+
let n = 0;
|
|
276
|
+
while (true) yield n++;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const evens = naturals()
|
|
280
|
+
.filter(n => n % 2 === 0)
|
|
281
|
+
.take(5)
|
|
282
|
+
.toArray();
|
|
283
|
+
// [0, 2, 4, 6, 8]
|
|
284
|
+
|
|
285
|
+
// Works with any Iterable
|
|
286
|
+
const map = new Map([["a", 1], ["b", 2]]);
|
|
287
|
+
const keys = map.keys().filter(k => k !== "a").toArray();
|
|
288
|
+
// ["b"]
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### Disallowed Nullish and Truthy Checks
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
// New errors for always-truthy or always-nullish comparisons
|
|
295
|
+
function process(x: string) {
|
|
296
|
+
if (x) { } // OK — string can be falsy ("")
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function process(x: () => void) {
|
|
300
|
+
if (x) { } // Error! Function is always truthy — did you mean x()?
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## TypeScript 5.7
|
|
305
|
+
|
|
306
|
+
### `--squash` for Project References
|
|
307
|
+
|
|
308
|
+
Faster `--build` by squashing intermediate outputs.
|
|
309
|
+
|
|
310
|
+
### Relative Path Rewriting in Declaration Files
|
|
311
|
+
|
|
312
|
+
Declaration files now preserve relative path structure, improving monorepo support.
|
|
313
|
+
|
|
314
|
+
### Initialized `Symbol.dispose` in `using` Declarations
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
using _ = {
|
|
318
|
+
[Symbol.dispose]() {
|
|
319
|
+
console.log("cleanup");
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
## TypeScript 5.8
|
|
325
|
+
|
|
326
|
+
### `--erasableSyntaxOnly`
|
|
327
|
+
|
|
328
|
+
Ensures only erasable TypeScript syntax is used — no enums, namespaces, or parameter properties:
|
|
329
|
+
|
|
330
|
+
```jsonc
|
|
331
|
+
{
|
|
332
|
+
"compilerOptions": {
|
|
333
|
+
"erasableSyntaxOnly": true
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
This flag is designed for use with Node.js `--strip-types` (Node 22.6+), which strips TypeScript annotations but doesn't transform:
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
// Allowed: type annotations are erasable
|
|
342
|
+
const x: string = "hello";
|
|
343
|
+
function greet(name: string): void { }
|
|
344
|
+
|
|
345
|
+
// Disallowed: these need transformation, not just erasure
|
|
346
|
+
enum Color { Red, Green, Blue } // Error
|
|
347
|
+
namespace Foo { export const x = 1; } // Error
|
|
348
|
+
class C { constructor(public x: number) {} } // Error (parameter property)
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### Granular Checks on Branches in Return Expressions
|
|
352
|
+
|
|
353
|
+
TypeScript 5.8 checks individual branches of ternary expressions against the return type:
|
|
354
|
+
|
|
355
|
+
```typescript
|
|
356
|
+
function process(value: string | null): string {
|
|
357
|
+
return value ?? 42;
|
|
358
|
+
// Error on 42 specifically — previous versions gave a less helpful error
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
## Migration Tips
|
|
363
|
+
|
|
364
|
+
When upgrading TypeScript versions:
|
|
365
|
+
|
|
366
|
+
1. **Read the release notes** — each version has breaking changes
|
|
367
|
+
2. **Update `@types/*` packages** — they often need matching versions
|
|
368
|
+
3. **Run `tsc --noEmit` first** — check for new errors before building
|
|
369
|
+
4. **Enable new strict flags gradually** — add one at a time
|
|
370
|
+
5. **Use `// @ts-expect-error`** — for known issues you'll fix later (not `@ts-ignore`)
|