Mastering Modern TypeScript
Build enterprise-grade, type-safe applications with TypeScript 5.9+.
Compatibility: TypeScript 5.9+, Node.js 22 LTS, Vite 7, NestJS 11, React 19
Quick Start
Initialize TypeScript project with ESM
pnpm create vite@latest my-app --template vanilla-ts cd my-app && pnpm install
Configure strict TypeScript
cat > tsconfig.json << 'EOF' { "compilerOptions": { "target": "ES2024", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "noUncheckedIndexedAccess": true, "exactOptionalPropertyTypes": true, "esModuleInterop": true, "skipLibCheck": true } } EOF
When to Use This Skill
Use when:
Building type-safe React, NestJS, or Node.js applications Migrating JavaScript codebases to TypeScript Implementing advanced type patterns (generics, mapped types, conditional types) Configuring modern TypeScript toolchains (Vite, pnpm, ESLint) Designing type-safe API contracts with Zod validation Comparing TypeScript approaches with Java or Python Project Setup Checklist
Before starting any TypeScript project:
- [ ] Use pnpm for package management (faster, disk-efficient)
- [ ] Configure ESM-first (type: "module" in package.json)
- [ ] Enable strict mode in tsconfig.json
- [ ] Set up ESLint with @typescript-eslint
- [ ] Add Prettier for consistent formatting
- [ ] Configure Vitest for testing
Type System Quick Reference Primitive Types const name: string = "Alice"; const age: number = 30; const active: boolean = true; const id: bigint = 9007199254740991n; const key: symbol = Symbol("unique");
Union and Intersection Types // Union: value can be one of several types type Status = "pending" | "approved" | "rejected";
// Intersection: value must satisfy all types type Employee = Person & { employeeId: string };
// Discriminated union for type-safe handling
type Result
function handleResult
Type Guards // typeof guard function process(value: string | number): string { if (typeof value === "string") { return value.toUpperCase(); } return value.toFixed(2); }
// Custom type guard interface User { type: "user"; name: string } interface Admin { type: "admin"; permissions: string[] }
function isAdmin(person: User | Admin): person is Admin { return person.type === "admin"; }
The satisfies Operator (TS 5.0+)
Validate type conformance while preserving inference:
// Problem: Type assertion loses specific type info
const colors1 = {
red: "#ff0000",
green: "#00ff00"
} as Record
colors1.red.toUpperCase(); // OK, but red could be undefined
// Solution: satisfies preserves literal types
const colors2 = {
red: "#ff0000",
green: "#00ff00"
} satisfies Record
colors2.red.toUpperCase(); // OK, and TypeScript knows red exists
Generics Patterns
Basic Generic Function
function first
const num = first([1, 2, 3]); // number | undefined const str = first(["a", "b"]); // string | undefined
Constrained Generics interface HasLength { length: number; }
function logLength
logLength("hello"); // OK: string has length logLength([1, 2, 3]); // OK: array has length logLength(42); // Error: number has no length
Generic API Response Wrapper
interface ApiResponse
async function fetchUser(id: string): Promise/api/users/${id});
const data = await response.json();
return {
data,
status: response.status,
timestamp: new Date()
};
}
Utility Types Reference
Type Purpose Example
Partial
// Extract array element type
type ArrayElement
type Numbers = ArrayElement
// Practical: Extract Promise result type
type UnwrapPromise
Mapped Types
// Make all properties readonly
type Immutable
// Make all properties nullable
type Nullable
// Create getter functions for each property
type Gettersget${Capitalize<string & K>}]: () => T[K];
};
interface Person { name: string; age: number }
type PersonGetters = Getters
Framework Integration React with TypeScript // Typed functional component interface ButtonProps { label: string; onClick: () => void; variant?: "primary" | "secondary"; }
const Button: React.FC
// Typed hooks
const [count, setCount] = useState
NestJS with TypeScript // Type-safe DTO with class-validator import { IsString, IsEmail, MinLength } from 'class-validator';
class CreateUserDto { @IsString() @MinLength(2) name: string;
@IsEmail() email: string; }
// Or with Zod (modern approach) import { z } from 'zod';
const CreateUserSchema = z.object({ name: z.string().min(2), email: z.string().email() });
type CreateUserDto = z.infer
See react-integration.md and nestjs-integration.md for detailed patterns.
Validation with Zod import { z } from 'zod';
// Define schema const UserSchema = z.object({ id: z.string().uuid(), name: z.string().min(1).max(100), email: z.string().email(), role: z.enum(["user", "admin", "moderator"]), createdAt: z.coerce.date() });
// Infer TypeScript type from schema
type User = z.infer
// Validate at runtime function parseUser(data: unknown): User { return UserSchema.parse(data); // Throws ZodError if invalid }
// Safe parsing (returns result object) const result = UserSchema.safeParse(data); if (result.success) { console.log(result.data); // Typed as User } else { console.error(result.error.issues); }
Modern Toolchain (2025) Tool Version Purpose TypeScript 5.9+ Type checking and compilation Node.js 22 LTS Runtime environment Vite 7.x Build tool and dev server pnpm 9.x Package manager ESLint 9.x Linting with flat config Vitest 3.x Testing framework Prettier 3.x Code formatting ESLint Flat Config (ESLint 9+) // eslint.config.js import eslint from '@eslint/js'; import tseslint from 'typescript-eslint';
export default tseslint.config( eslint.configs.recommended, ...tseslint.configs.strictTypeChecked, { languageOptions: { parserOptions: { projectService: true, tsconfigRootDir: import.meta.dirname, }, }, } );
Migration Strategies Incremental Migration Add allowJs: true and checkJs: false to tsconfig.json Rename files from .js to .ts one at a time Add type annotations gradually Enable stricter options incrementally JSDoc for Gradual Typing // Before full migration, use JSDoc /* * @param {string} name * @param {number} age * @returns {User} / function createUser(name, age) { return { name, age }; }
See enterprise-patterns.md for comprehensive migration guides.
Common Mistakes Mistake Problem Fix Using any liberally Defeats type safety Use unknown and narrow Ignoring strict mode Misses null/undefined bugs Enable all strict options Type assertions (as) Can hide type errors Use satisfies or guards Enum for simple unions Generates runtime code Use literal unions instead Not validating API data Runtime type mismatches Use Zod at boundaries Cross-Language Comparison Feature TypeScript Java Python Type System Structural Nominal Gradual (duck typing) Nullability Explicit (T | null) @Nullable annotations Optional via typing Generics Type-level, erased Type-level, erased Runtime via typing Interfaces Structural matching Must implement Protocol (3.8+) Enums Avoid (use unions) First-class Enum class Reference Files type-system.md — Complete type system guide generics.md — Advanced generics patterns enterprise-patterns.md — Error handling, validation, architecture react-integration.md — React + TypeScript patterns nestjs-integration.md — NestJS API development toolchain.md — Modern build tools configuration Assets tsconfig-template.json — Strict enterprise config eslint-template.js — ESLint 9 flat config Scripts validate-setup.sh — Verify TypeScript environment