Core concepts - minimal brutalist documentation
Primitive type annotations.
let name: string = "John";
let age: number = 30;
let isActive: boolean = true;
let value: null = null;
let data: undefined = undefined;
Typed arrays.
let numbers: number[] = [1, 2, 3];
let names: Array<string> = ["Alice", "Bob"];
Object type definitions.
let user: { name: string; age: number } = {
name: "John",
age: 30
};
Reusable type definitions.
interface User {
id: number;
name: string;
email?: string; // Optional property
readonly createdAt: Date; // Read-only
}
const user: User = {
id: 1,
name: "John",
createdAt: new Date()
};
Alternative to interfaces.
type Point = { x: number; y: number };
type ID = string | number;
Value can be one of several types.
let id: string | number;
id = "abc123"; // OK
id = 123; // OK
type Status = "pending" | "approved" | "rejected";
Typed function parameters and returns.
function add(a: number, b: number): number {
return a + b;
}
const multiply = (a: number, b: number): number => a * b;
// Optional parameters
function greet(name: string, greeting?: string): string {
return `${greeting || "Hello"}, ${name}`;
}
Type-safe reusable code.
function identity<T>(value: T): T {
return value;
}
identity<string>("hello");
identity(42); // Type inferred
// Generic interfaces
interface Box<T> {
value: T;
}
const stringBox: Box<string> = { value: "hello" };
Narrow types at runtime.
function isString(value: unknown): value is string {
return typeof value === "string";
}
if (isString(input)) {
console.log(input.toUpperCase()); // TypeScript knows it's string
}
Built-in type transformations.
// Partial - make all properties optional
type PartialUser = Partial<User>;
// Required - make all properties required
type RequiredUser = Required<User>;
// Pick - select specific properties
type UserPreview = Pick<User, "id" | "name">;
// Omit - exclude specific properties
type UserWithoutEmail = Omit<User, "email">;
// Record - create object type with specific keys
type UserRoles = Record<string, "admin" | "user">;
Named constants.
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT"
}
let dir: Direction = Direction.Up;
Tell TypeScript the type you know.
const input = document.getElementById("input") as HTMLInputElement;
input.value = "text";
// Alternative syntax
const input2 = <HTMLInputElement>document.getElementById("input");
Typed classes with access modifiers.
class Person {
private id: number;
public name: string;
protected age: number;
constructor(id: number, name: string, age: number) {
this.id = id;
this.name = name;
this.age = age;
}
greet(): string {
return `Hello, I'm ${this.name}`;
}
}
Typed promises.
async function fetchUser(id: number): Promise<User> {
const response = await fetch(`/api/users/${id}`);
return response.json();
}
Transform existing types.
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
type Optional<T> = {
[P in keyof T]?: T[P];
};
Types that depend on conditions.
type IsString<T> = T extends string ? true : false;
type A = IsString<string>; // true
type B = IsString<number>; // false
Type-safe string templates.
type Color = "red" | "blue" | "green";
type HexColor = `#${string}`;
type ColorProp = `${Color}Color`; // "redColor" | "blueColor" | "greenColor"
any, use unknown insteadReact component props:
interface ButtonProps {
text: string;
onClick: () => void;
disabled?: boolean;
}
function Button({ text, onClick, disabled = false }: ButtonProps) {
return <button onClick={onClick} disabled={disabled}>{text}</button>;
}
API response:
interface ApiResponse<T> {
data: T;
error?: string;
loading: boolean;
}
const response: ApiResponse<User[]> = {
data: [],
loading: false
};
Event handlers:
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
console.log(event.currentTarget);
};
Type narrowing:
function process(value: string | number) {
if (typeof value === "string") {
return value.toUpperCase();
}
return value.toFixed(2);
}