It also covers fixing LLM-authored anti-patterns: legacy enum (un-erasable by Node's type stripper, replace with const objects as const), namespace wrapping runtime code, and missing import type under verbatimModuleSyntax.
Out of scope: tsconfig/compiler flags belong to ts-config; SOLID structure and file-size rules belong to solid-generic; framework-specific APIs are not covered.
TypeScript Language Patterns (TS 6.0)
Agent Workflow (MANDATORY)
Before writing non-trivial TypeScript, spawn 3 agents in parallel, one Agent call each with a name:
- fuse-ai-pilot:explore-codebase - Detect existing idioms,
verbatimModuleSyntax, tsconfig - fuse-ai-pilot:research-expert - Verify current syntax on typescriptlang.org
- mcp__context7__query-docs -
/microsoft/typescriptfor exact API shapes
After writing, run fuse-ai-pilot:sniper for validation.
Overview
| Feature | What it gives you |
|---|---|
const type parameters |
<const T> infers the narrowest literal type without as const at call sites |
using / await using |
Deterministic cleanup via Symbol.dispose / Symbol.asyncDispose |
| Standard decorators | ECMAScript decorators — NOT experimentalDecorators |
satisfies |
Validate a value against a type while keeping its narrow inferred type |
| 6.0 inference | Method-syntax callbacks are no longer contextually sensitive → order-independent inference |
Critical Rules
import typeis mandatory underverbatimModuleSyntax- type-only imports must saytype, or emit/stripping breaks.- No legacy
enum- preferconstobjectsas const;enumis un-erasable by Node's type stripper. - No
namespacewith runtime code - use ESM modules; type-onlynamespaceis acceptable. - Use standard decorators - never enable
experimentalDecoratorsfor new code. - Never rely on implicit
any-strictis the 6.0 default; annotate or infer explicitly.
Reference Guide
Concepts
| Topic | Reference | When to Consult |
|---|---|---|
| Resource management | resource-management.md | Load when using using / await using / disposables |
| Generics & inference | generics-and-inference.md | Load when using const type params, satisfies, or debugging inference |
| Decorators | decorators.md | Load when adding decorators |
| LLM pitfalls | llm-pitfalls.md | Load when reviewing or migrating legacy/AI-authored TypeScript |
Templates
| Template | When to Use |
|---|---|
| modern-patterns.md | Copy-paste const/satisfies/decorator examples |
| resource-management.md | Copy-paste using / DisposableStack examples |
Quick Reference
const type parameter
function first<const T extends readonly unknown[]>(arr: T): T[0] {
return arr[0];
}
const x = first(["a", "b"]); // x: "a" (literal, no `as const` needed)
using for deterministic cleanup
function openFile(path: string) {
const handle = acquire(path);
return { handle, [Symbol.dispose]() { release(handle); } };
}
{
using file = openFile("./data"); // released automatically at block end
}
satisfies
const config = {
port: 3000,
host: "localhost",
} satisfies Record<string, string | number>;
// config.port stays `number`, not widened to `string | number`
Best Practices
DO
- Replace
enum Color { Red }withconst Color = { Red: "red" } as const - Reach for
usingover manualtry/finallycleanup when a resource has a disposer - Use
satisfiesinstead of a type annotation when you want to keep the narrow inferred type
DON'T
- Write
import { SomeType }for a type-only import — useimport type { SomeType } - Enable
experimentalDecoratorsoremitDecoratorMetadatafor new code - Use
namespaceto organize runtime code — that is what ESM modules are for