| name | typescript |
| description | Best practices and guidelines for TypeScript (2025-2026 Edition), focusing on TS 5.x+, modern type safety, and performance. |
TypeScript Skill (2025-2026 Edition)
This skill outlines the latest best practices for writing robust, performant, and type-safe TypeScript code, aligned with the 2025-2026 ecosystem (TypeScript 5.x and beyond).
🚀 Key Trends & Features (2025/2026)
- Native Speed: The transition to a Go-based compiler (native port) is underway (TS 7+), promising massive performance gains.
- Default Strictness: Modern projects treat
strict: true as the absolute baseline.
- Framework First: TS is now deeply integrated into frameworks (Next.js, Remix, NestJS) rather than an add-on.
🛠️ Configuration Best Practices (tsconfig.json)
Use strict defaults to prevent bugs before they happen.
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"useUnknownInCatchVariables": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
"module": "NodeNext",
"moduleResolution": "NodeNext",
"target": "ES2022",
"skipLibCheck": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"verbatimModuleSyntax": true,
"allowSyntheticDefaultImports": true
}
}
🧩 Type Safety & Patterns
1. unknown over any
Never use any unless absolutely necessary (e.g., migrating legacy code). Use unknown and narrow the type safely.
function processData(input: any) {
input.doSomething();
}
function processData(input: unknown) {
if (typeof input === 'string') {
console.log(input.toUpperCase());
} else if (isCustomType(input)) {
input.doSomething();
}
}
2. satisfies Operator (TS 4.9+)
Use satisfies to validate a value matches a type without widening the type (preserving inference).
type Config = Record<string, string | number>;
const myConfig = {
port: 8080,
host: "localhost"
} satisfies Config;
myConfig.port.toFixed(2);
3. Immutable Data by Default
Use readonly to prevent accidental mutations, especially for function arguments and React props.
interface User {
readonly id: string;
readonly name: string;
tags: readonly string[];
}
function printTags(tags: readonly string[]) {
}
4. Template Literal Types
Create precise string types for better autocompletion and safety.
type EventName = "click" | "hover";
type HandlerName = `on${Capitalize<EventName>}`;
⚡ Performance Optimization
- Type Imports: Use
import type { ... } or import { type ... } explicitly. Enabling verbatimModuleSyntax enforces this, ensuring zero JS overhead for type-only imports using modern bundlers.
- Lazy Loading: Leverage
await import(...) for splitting code in large applications.
⚠️ Common Pitfalls to Avoid
- Excessive Type Assertions (
as): Use type guards or zod for validation instead of forcing types with as.
- Broad Types: Avoid
Function or object. Use () => void or Record<string, unknown> instead.
- Enum Misuse: Prefer union types of strings (
type Status = 'open' | 'closed') over standard TS enums to keep runtime code cleaner and avoid nominal typing surprises.
📚 References