Deep dive into powerful TS features & patterns
You’ve mastered the basics, leveled up through intermediate patterns — now it’s time to unlock the true power of TypeScript. This is where generics bend to your will, decorators make your classes magical, and configs turn projects into well-oiled enterprise machines. Welcome to Advanced TypeScript.
📕 Advanced TypeScript (Pro Level, Enterprise Ready)
🔹 1. Advanced Generics
Variance (Covariant & Contravariant)
Don’t overthink — it’s about whether you can safely substitute one type for another.
type Animal = { name: string };
type Dog = { name: string; bark: () => void };
let dogHandler: (dog: Dog) => void = (dog) => console.log(dog.name);
// Covariance: assigning more general → more specific ❌
let animalHandler: (animal: Animal) => void;
// animalHandler = dogHandler; ❌ not safe
👉 You won’t often write this directly, but knowing it helps when debugging type errors.
Conditional Generics (T extends U ? X : Y)
type IsString<T> = T extends string ? "yes" : "no";
type A = IsString<string>; // "yes"
type B = IsString<number>; // "no"
Infer Keyword
Extract types inside generics.
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
function getUser() { return { id: 1, name: "Ali" }; }
type User = ReturnType<typeof getUser>; // { id: number; name: string }
🔹 2. Mapped & Conditional Types
Creating Custom Utility Types
type MyPartial<T> = {
[K in keyof T]?: T[K];
};
interface User {
id: number;
name: string;
}
type PartialUser = MyPartial<User>;
// { id?: number; name?: string }
keyof
and in
Operator
interface Person {
id: number;
name: string;
}
type Keys = keyof Person; // "id" | "name"
type Flags = {
};
// { id: boolean; name: boolean }
Remapping Keys
type RemoveId<T> = {
};
type WithoutId = RemoveId<{ id: number; name: string }>;
// { name: string }
🔹 3. Advanced Utility Types
type A = "a" | "b" | "c";
type B = "a" | "d";
type Ex1 = Exclude<A, B>; // "b" | "c"
type Ex2 = Extract<A, B>; // "a"
type NonNull = NonNullable<string | null | undefined>; // string
type AsyncData = Promise<string>;
type Resolved = Awaited<AsyncData>; // string
🔹 4. Type Manipulation & Inference
Index Access Types
interface User {
id: number;
name: string;
}
type IdType = User["id"]; // number
Lookup Types
type PropType<T, K extends keyof T> = T[K];
type UserName = PropType<User, "name">; // string
Recursive Types
type NestedArray<T> = T | NestedArray<T>[];
let nums: NestedArray<number> = [1, [2, [3, 4]]];
🔹 5. Decorators (Experimental / Angular / NestJS)
Enable in tsconfig.json:
"experimentalDecorators": true
Class Decorator
function Logger(constructor: Function) {
console.log("Class created:", constructor.name);
}
@Logger
class Car {}
Method Decorator
function LogMethod(target: any, key: string, descriptor: PropertyDescriptor) {
const original = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`Calling ${key} with`, args);
return original.apply(this, args);
};
}
class Calculator {
@LogMethod
add(a: number, b: number) {
return a + b;
}
}
new Calculator().add(2, 3);
🔹 6. Declaration Files (.d.ts)
Used to describe external libraries.
// math.d.ts
declare module "my-math" {
export function add(a: number, b: number): number;
}
Install community ones:
npm install --save-dev @types/lodash
🔹 7. TypeScript with Frameworks
TS + React
type Props = { name: string; age?: number };
const UserCard: React.FC<Props> = ({ name, age }) => (
<div>{name} {age && `(${age})`}</div>
);
TS + Node/Express
import express, { Request, Response } from "express";
const app = express();
app.get("/", (req: Request, res: Response) => {
res.send("Hello TS + Node");
});
TS + Next.js
// pages/api/hello.ts
import { NextApiRequest, NextApiResponse } from "next";
export default function handler(req: NextApiRequest, res: NextApiResponse) {
res.json({ message: "Hello Next.js + TS" });
}
🔹 8. Config Mastery
Inside tsconfig.json
:
{
"compilerOptions": {
"strict": true,
"strictNullChecks": true,
"noImplicitAny": true,
"incremental": true,
"moduleResolution": "node",
"baseUrl": "./src"
}
}
🔹 9. Performance & Large-Scale Patterns
- Avoid overly complex types (keep generics simple).
- Use project references in monorepos (tsconfig.build.json).
- Split code into modules for maintainability.
🔹 10. TypeScript 5.x+ Features
satisfies Operator
const colors = {
red: "#f00",
green: "#0f0",
} satisfies Record<string, string>;
// ensures keys are string → string
Variadic Tuple Types
type Push<T extends any[], V> = [...T, V];
type Test = Push<[1, 2], 3>; // [1, 2, 3]
Stable Decorators (TS 5+)
@sealed
class MyClass {}
using Declarations (Disposable Resources)
class File {
[Symbol.dispose]() {
console.log("File closed");
}
}
using f = new File();
// auto-disposed after scope
Congrats! If you’ve followed along through Beginner, Intermediate, and now Advanced — you’re not just learning TypeScript, you’re mastering it at a level most devs never reach.
From generics sorcery to enterprise-scale configs — you’ve got the skills to write code that’s clean, scalable, and future-proof.
Part 1: Beginner Foundations
Part 2: Intermediate Concepts
Thanks for reading! 🙌
Until next time, 🫡
Usman Awan (your friendly dev 🚀)
Top comments (0)