TypeScript basics
TypeScript is JavaScript with a static type layer erased at compile time. Types describe shapes and constraints so editors and tsc catch mistakes before runtime.
Primitives, arrays, and object types
let n: number = 42;
let s: string = 'hi';
let ok: boolean = true;
let u: undefined = undefined;
let nl: null = null;
const nums: number[] = [1, 2, 3];
const tuple: [string, number] = ['score', 100];
type User = {
id: string;
name: string;
role?: 'admin' | 'member'; // optional
readonly createdAt: Date;
};
Use readonly for fields that should not be reassigned, and ? for optional properties.
Type inference
TypeScript infers types when initialization makes them obvious.
const count = 10; // number
const title = 'Guide'; // string
const items = [1, 2, 3]; // number[]
function double(x: number) {
return x * 2; // return type inferred as number
}
Add explicit annotations at public APIs, empty arrays you will mutate, and places inference widens too far (e.g. [] as never[]).
Union and literal types
type Status = 'idle' | 'loading' | 'error';
type Id = string | number;
function formatId(id: Id) {
return typeof id === 'number' ? id.toFixed(0) : id;
}
Literal unions model fixed sets of strings or numbers—common for Redux-style state machines and component props.
Narrowing
Inside a block, TypeScript refines union types using control flow.
function printLength(x: string | string[] | null) {
if (x === null) return;
if (typeof x === 'string') {
console.log(x.length);
return;
}
console.log(x.length); // string[]
}
// Type predicate: still validate shape; `'name' in v` alone is not enough
function isUser(v: unknown): v is { name: string } {
if (typeof v !== 'object' || v === null) return false;
const o = v as Record<string, unknown>;
return typeof o.name === 'string';
}
Patterns: typeof, === / !==, instanceof, in, discriminated unions with a shared tag field, and user-defined type predicates (v is Type).
Security: Type predicates only affect compile-time types. For data from networks, storage, or users, pair narrowing with real runtime checks (schema validators, structured checks). Never trust as SomeType or a loose in check alone for auth or sensitive logic.
type vs interface
interface Box {
value: string;
}
// declaration merging: another `interface Box` adds members
type Point = { x: number; y: number };
type Result = { ok: true; data: string } | { ok: false; error: string };
interface: extendable, can merge across files (use carefully). type: unions, intersections, mapped types, and tuples—more expressive for advanced patterns. For plain object shapes, either works; teams often pick one style per codebase.
Strict compiler options
In tsconfig.json, "strict": true enables a bundle of checks. Especially valuable:
strictNullChecks—nullandundefinedare not assignable to every typenoImplicitAny— implicitanyis an errornoUncheckedIndexedAccess— indexed access may beundefined