TypeScript adds static types to JavaScript. Compiled to JS for execution; types are checked at compile time. Modern frontend development is largely TypeScript; node back-ends increasingly are too.
This page covers the practical TypeScript that matters day-to-day.
The case:
The cost:
For most non-trivial JavaScript projects, TypeScript pays for itself.
let name: string = "Alice";
let age: number = 30;
let active: boolean = true;
let scores: number[] = [1, 2, 3];
let user: { name: string, age: number } = { name: "Bob", age: 25 };
Most of the time, you don't write the type — TypeScript infers it.
function greet(name: string): string {
return `Hello, ${name}`;
}
const greet2 = (name: string): string => `Hello, ${name}`;
Parameters and return types specified; everything else inferred.
Two ways to declare object shapes:
interface User {
id: string;
name: string;
email?: string; // optional
}
type User = {
id: string;
name: string;
email?: string;
};
Mostly interchangeable. Use whichever is conventional in your codebase.
type Status = 'pending' | 'active' | 'cancelled';
A value of Status can only be one of those strings. Compiler checks.
function first<T>(items: T[]): T | undefined {
return items[0];
}
const x = first([1, 2, 3]); // T inferred as number
const y = first(['a', 'b']); // T inferred as string
The <T> is a type parameter — fills in based on usage.
TypeScript types are structural, not nominal:
interface Point { x: number; y: number; }
const p1: Point = { x: 1, y: 2 };
const p2: { x: number, y: number, z: number } = { x: 1, y: 2, z: 3 };
function distance(p: Point) { /* ... */ }
distance(p1); // OK
distance(p2); // Also OK — has the required fields
The shape matters; the name doesn't. This is unlike Java/C# (nominal typing).
function process(value: string | number) {
if (typeof value === 'string') {
// value is narrowed to string here
return value.toUpperCase();
}
// value is narrowed to number here
return value * 2;
}
The compiler tracks what type a variable has at each point.
type Result =
| { kind: 'success', value: string }
| { kind: 'error', error: string };
function handle(r: Result) {
if (r.kind === 'success') {
// r.value is accessible here
} else {
// r.error is accessible here
}
}
The kind field discriminates between variants. Pattern matching emerges from narrowing.
const value = obj?.prop?.nested ?? 'default';
?. returns undefined if anything in the chain is null/undefined.
?? provides a default for null/undefined (not for empty strings or zero).
const elem = document.getElementById('foo') as HTMLDivElement;
Tell the compiler "trust me, it's this type." Use sparingly; it bypasses type checking.
TypeScript has built-in utility types:
Partial<User> // all fields optional
Required<User> // all fields required
Readonly<User> // all fields readonly
Pick<User, 'id' | 'name'> // just specific fields
Omit<User, 'email'> // exclude fields
Useful for transforming types.
Enable strict checks in tsconfig.json:
{
"compilerOptions": {
"strict": true
}
}
This enables: noImplicitAny, strictNullChecks, strictFunctionTypes, etc. The strict mode catches dramatically more bugs than the loose mode.
For new projects, always start with strict.
Start with TypeScript and strict mode. No transition.
Two paths:
Convert everything at once. Risky; usually delayed indefinitely.
Add tsconfig.json with allowJs: true. Convert files one at a time. New files are TS; existing files stay JS until touched.
The incremental path is realistic. Some files may stay JS for years; that's fine.
anyany is TypeScript's escape hatch — anything goes. Useful in transition; should be avoided in new code.
For unknown values, use unknown instead of any. unknown requires you to narrow before use.
TypeScript works well with React:
type Props = {
name: string;
age?: number;
};
const Greeting: React.FC<Props> = ({ name, age }) => (
<div>Hello, {name}, age {age ?? 'unknown'}</div>
);
// Or
function Greeting({ name, age }: Props) {
return <div>Hello, {name}</div>;
}
The function-component declaration is increasingly preferred over React.FC.
any everywhere. Defeats the purpose.