The Complete Guide to TypeScript in 2026
A complete guide to TypeScript — types, interfaces vs type aliases, unions and narrowing, generics, utility types, the satisfies operator, tsconfig and modern features — with examples and current (2026) context.
TypeScript is JavaScript with static types — it catches bugs before you run the code, powers better autocomplete, and is effectively the industry default for professional web development in 2026. This complete guide covers the type system from basics to generics and utility types, plus config and the modern features worth knowing.
Getting started
Install TypeScript, initialize a config, and compile. In practice most projects run TS through a bundler (Vite) or a runtime that strips types, but tsc is the reference compiler and type-checker.
npm install -D typescript
npx tsc --init # creates tsconfig.json
npx tsc # type-check + compile
npx tsc --noEmit # type-check only
Basic types
You annotate variables, parameters and return values with types. TypeScript also *infers* types, so you often don’t need to write them — annotate function signatures and let inference handle the rest.
let name: string = "Ada";
let age: number = 36;
let active: boolean = true;
let tags: string[] = ["a", "b"];
let point: [number, number] = [0, 0]; // tuple
function add(a: number, b: number): number { return a + b; }
// special types
let u: unknown; // must be narrowed before use
let n: never; // a value that never occurs
// avoid `any` — it turns off type checking
Interfaces vs type aliases
Both describe the shape of data. Use an interface for object shapes and public contracts (they extend and merge cleanly); use a type alias for unions, intersections, primitives, tuples and anything computed.
interface User {
id: number;
name: string;
email?: string; // optional
readonly createdAt: Date;
}
type ID = string | number; // union — needs a type alias
type Admin = User & { role: "admin" }; // intersection
Unions, literals and narrowing
A union (A | B) means "one of these." Literal types narrow further to exact values. TypeScript then *narrows* a union to a specific type based on your checks — typeof, in, instanceof, equality, or a discriminant field.
type Status = "idle" | "loading" | "error"; // literal union
function area(s: { kind: "circle"; r: number } | { kind: "square"; side: number }) {
// discriminated union — narrow on `kind`
if (s.kind === "circle") return Math.PI * s.r ** 2;
return s.side ** 2;
}
Generics
Generics let you write reusable, type-safe functions and types that work over any type while preserving the relationship between inputs and outputs. The type parameter (<T>) is filled in by the caller or inferred.
function first<T>(arr: T[]): T | undefined {
return arr[0];
}
first([1, 2, 3]); // T = number
first(["a", "b"]); // T = string
interface ApiResponse<T> { data: T; error: string | null; }
Utility types
TypeScript ships built-in generic types that transform other types — you’ll use these constantly instead of hand-writing variants.
Partial<T>— all properties optional;Required<T>— all required.Pick<T, K>— a subset of keys;Omit<T, K>— all keys except some.Readonly<T>— all properties read-only.Record<K, V>— an object type with keysKand valuesV.ReturnType<F>/Parameters<F>— a function’s return type / parameter types.Awaited<T>— the resolved type of a Promise;NonNullable<T>— removesnull/undefined.
type UserUpdate = Partial<User>; // every field optional
type PublicUser = Omit<User, "email">; // hide email
type UsersById = Record<number, User>; // { [id]: User }
The satisfies operator
satisfies checks that a value matches a type without widening or changing the inferred type — so you get validation *and* keep the precise literal types for autocomplete. Introduced in TS 4.9, it’s now a staple.
const config = {
port: 3000,
host: "localhost",
} satisfies Record<string, string | number>;
config.port; // still typed as number (not string | number)
Enums vs const objects
TypeScript’s enum generates runtime code and doesn’t tree-shake well. In 2026 many teams prefer a const object plus a derived union type — zero runtime overhead and the same ergonomics.
// preferred: const object + union
const Role = { Admin: "admin", User: "user" } as const;
type Role = typeof Role[keyof typeof Role]; // "admin" | "user"
// vs a classic enum (generates runtime code)
enum RoleEnum { Admin = "admin", User = "user" }
Type-checking JavaScript with JSDoc
You don’t need .ts files to get type safety. Add // @ts-check to a .js file (or "checkJs": true in tsconfig) and annotate with JSDoc — great for gradually typing an existing JavaScript codebase.
// @ts-check
/** @param {number} a @param {number} b @returns {number} */
function add(a, b) { return a + b; }
add("1", 2); // ❌ type error, in a plain .js file
Modern features worth knowing
satisfies(above) — validate without widening.using/await using(TS 5.2) — explicit resource management; a resource withSymbol.disposeis cleaned up automatically at the end of the scope.consttype parameters (TS 5.0) —<const T>infers the most literal type without callers writingas const.noUncheckedIndexedAccess— makes indexed access (arr[i],obj[key]) includeundefined, catching a whole class of bugs.
function query(sql: string) {
using conn = openConnection(); // auto-disposed at scope end
return conn.run(sql);
}
tsconfig essentials
"strict": true— turn on all the strict checks (do this first)."target"/"module"— the JS version and module system to emit."moduleResolution": "bundler"— for modern bundler-based projects."esModuleInterop": true— smoother CommonJS/ESM interop."skipLibCheck": true— skip type-checking of dependencies’.d.ts(faster)."noUncheckedIndexedAccess": true— safer array/object indexing.
Frequently asked questions
Is TypeScript worth learning in 2026?
What is the difference between interface and type in TypeScript?
interface for object contracts and type for everything else.What does the satisfies operator do?
satisfies checks that a value conforms to a type without changing (widening) the value’s inferred type. For example, a config object can be validated against Record<string, string | number> while each property keeps its precise literal type, so autocomplete and narrowing still work. It gives you validation and precision at once, which a plain type annotation would lose.Should I use enums in TypeScript?
const object plus a derived union type is a better choice than a classic enum. Enums generate runtime JavaScript and don’t tree-shake well, whereas const objects have zero runtime cost and give you the same string/number constants and union types. Enums are still fine, but the as const object pattern is increasingly preferred in 2026.Write and type-check TypeScript live in XCODX Studio — run it in the browser, no setup. See also JavaScript vs TypeScript, JavaScript best practices and the web development roadmap 2026.