Type System & Annotations
TypeScript Type System & Annotations TypeScript extends JavaScript by adding static type definitions. Types provide a way to describe the shape of objects, enab…
TypeScript Type System & Annotations
TypeScript extends JavaScript by adding static type definitions. Types provide a way to describe the shape of objects, enabling better documentation and error detection.
Basic Types
// Primitives
let name: string = 'John';
let age: number = 30;
let isActive: boolean = true;
let nothing: null = null;
let notDefined: undefined = undefined;
// BigInt and Symbol
let bigNumber: bigint = 100n;
let uniqueId: symbol = Symbol('id');
// Arrays
let numbers: number[] = [1, 2, 3];
let strings: Array<string> = ['a', 'b', 'c'];
// Tuples - fixed length and types
let tuple: [string, number] = ['age', 30];
let RGB: [number, number, number] = [255, 0, 0];
// Tuple with optional and rest
let optional: [string, number?] = ['hello'];
let rest: [string, ...number[]] = ['numbers', 1, 2, 3];
// Objects
let user: { name: string; age: number } = {
name: 'John',
age: 30
};
// Optional properties
let person: { name: string; age?: number } = { name: 'Jane' };
// Readonly properties
let readonlyUser: { readonly id: number; name: string } = {
id: 1,
name: 'John'
};
// readonlyUser.id = 2; // Error!
// Index signatures
interface StringMap {
[key: string]: string;
}
const map: StringMap = {
name: 'John',
email: 'john@example.com'
};Function Types
// Function declarations
function add(a: number, b: number): number {
return a + b;
}
// Arrow functions
const multiply = (a: number, b: number): number => a * b;
// Optional parameters
function greet(name: string, greeting?: string): string {
return `${greeting || 'Hello'}, ${name}`;
}
// Default parameters
function createUser(name: string, age: number = 18): User {
return { name, age };
}
// Rest parameters
function sum(...numbers: number[]): number {
return numbers.reduce((acc, n) => acc + n, 0);
}
// Function type
type MathOperation = (a: number, b: number) => number;
const divide: MathOperation = (a, b) => a / b;
// Void return type
function log(message: string): void {
console.log(message);
}
// Never return type (never returns)
function throwError(message: string): never {
throw new Error(message);
}
function infiniteLoop(): never {
while (true) {}
}
// Function overloads
function getValue(value: string): string;
function getValue(value: number): number;
function getValue(value: boolean): boolean;
function getValue(value: string | number | boolean): string | number | boolean {
return value;
}
const str = getValue('hello'); // Type: string
const num = getValue(42); // Type: numberUnion & Intersection Types
// Union types (OR)
let id: string | number;
id = 'abc'; // ✅
id = 123; // ✅
// id = true; // ❌ Error
type Status = 'pending' | 'active' | 'completed';
let status: Status = 'pending'; // ✅
// status = 'invalid'; // ❌ Error
// Intersection types (AND)
type Person = {
name: string;
age: number;
};
type Employee = {
company: string;
salary: number;
};
type EmployedPerson = Person & Employee;
const employee: EmployedPerson = {
name: 'John',
age: 30,
company: 'ACME',
salary: 50000
};
// Discriminated unions
type Circle = {
kind: 'circle';
radius: number;
};
type Rectangle = {
kind: 'rectangle';
width: number;
height: number;
};
type Shape = Circle | Rectangle;
function getArea(shape: Shape): number {
switch (shape.kind) {
case 'circle':
return Math.PI * shape.radius ** 2;
case 'rectangle':
return shape.width * shape.height;
}
}Type Aliases & Interfaces
// Type alias
type Point = {
x: number;
y: number;
};
type ID = string | number;
// Interface
interface User {
id: number;
name: string;
email: string;
age?: number; // Optional
readonly createdAt: Date; // Readonly
}
const user: User = {
id: 1,
name: 'John',
email: 'john@example.com',
createdAt: new Date()
};
// Interface extension
interface Admin extends User {
role: 'admin' | 'superadmin';
permissions: string[];
}
const admin: Admin = {
id: 1,
name: 'Jane',
email: 'jane@example.com',
createdAt: new Date(),
role: 'admin',
permissions: ['read', 'write']
};
// Interface merging (declaration merging)
interface Window {
myCustomProperty: string;
}
interface Window {
myOtherProperty: number;
}
// Now Window has both properties
// Type vs Interface:
// - Interface: can be extended, supports declaration merging
// - Type: more flexible, can use unions/intersections
// - Use interface for object shapes, type for everything elseType Assertions & Type Guards
// Type assertion
const value: any = 'hello';
const length1 = (value as string).length;
const length2 = (<string>value).length; // Alternative syntax
// Non-null assertion
function getValue(id: string | null): string {
return id!.toUpperCase(); // Asserts id is not null
}
// Type guards
function isString(value: unknown): value is string {
return typeof value === 'string';
}
function processValue(value: string | number) {
if (isString(value)) {
console.log(value.toUpperCase()); // TypeScript knows it's string
} else {
console.log(value.toFixed(2)); // TypeScript knows it's number
}
}
// typeof guard
function example(value: string | number) {
if (typeof value === 'string') {
return value.toUpperCase();
}
return value.toFixed(2);
}
// instanceof guard
class Dog {
bark() { console.log('Woof!'); }
}
class Cat {
meow() { console.log('Meow!'); }
}
function makeSound(animal: Dog | Cat) {
if (animal instanceof Dog) {
animal.bark();
} else {
animal.meow();
}
}
// in operator
type Fish = { swim: () => void };
type Bird = { fly: () => void };
function move(animal: Fish | Bird) {
if ('swim' in animal) {
animal.swim();
} else {
animal.fly();
}
}