Advanced TypeScript Features
(Updated on )
Advanced TypeScript Features
TypeScript offers powerful features for creating robust and maintainable applications. In this guide, we’ll explore advanced TypeScript concepts and patterns.
Advanced Types
Union and Intersection Types
type StringOrNumber = string | number;
type NumberAndString = { num: number } & { str: string };
const value: StringOrNumber = "hello";
const obj: NumberAndString = { num: 42, str: "hello" };
Mapped Types
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
type Partial<T> = {
[P in keyof T]?: T[P];
};
interface User {
name: string;
age: number;
}
type ReadonlyUser = Readonly<User>;
type PartialUser = Partial<User>;
Conditional Types
type TypeName<T> = T extends string
? "string"
: T extends number
? "number"
: T extends boolean
? "boolean"
: T extends undefined
? "undefined"
: T extends Function
? "function"
: "object";
type T0 = TypeName<string>; // "string"
type T1 = TypeName<number>; // "number"
Utility Types
Pick and Omit
interface Todo {
title: string;
description: string;
completed: boolean;
}
type TodoPreview = Pick<Todo, "title" | "completed">;
type TodoInfo = Omit<Todo, "completed">;
Record
type CatInfo = {
age: number;
breed: string;
};
type CatName = "miffy" | "boris";
const cats: Record<CatName, CatInfo> = {
miffy: { age: 10, breed: "Persian" },
boris: { age: 5, breed: "Maine Coon" }
};
Decorators
function log(target: any, key: string) {
let value = target[key];
const getter = function() {
console.log(`Getting ${key}`);
return value;
};
const setter = function(newVal: any) {
console.log(`Setting ${key} to ${newVal}`);
value = newVal;
};
Object.defineProperty(target, key, {
get: getter,
set: setter,
enumerable: true,
configurable: true
});
}
class Example {
@log
name: string;
}
Advanced Generics
Generic Constraints
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
return arg;
}
Generic Classes
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = (x, y) => x + y;
Type Guards
function isString(value: any): value is string {
return typeof value === "string";
}
function processValue(value: string | number) {
if (isString(value)) {
// value is string
console.log(value.toUpperCase());
} else {
// value is number
console.log(value.toFixed(2));
}
}
Best Practices
- Use type guards for runtime type checking
- Leverage utility types for common transformations
- Use decorators for cross-cutting concerns
- Implement proper error handling with custom types
- Use advanced generics for type-safe APIs
Next Steps
- Learn about TypeScript Basics
- Explore TypeScript with React
- Master TypeScript Design Patterns
Happy coding!