DEV Community

Cover image for TypeScript Expert Revision Handbook
Animesh Pandey
Animesh Pandey

Posted on

TypeScript Expert Revision Handbook

๐Ÿ“‘ Table of Contents


๐ŸŸฆ Fundamentals (Expert Level)


1. ๐Ÿงฉ Type System vs Runtime Behavior

Definition:
TypeScript is a compile-time type system โ€” all types are erased at runtime.

โœ… Key Points

  • Types are structural, not nominal (duck typing).
  • Type checking = compile-time only.
  • At runtime, itโ€™s just JavaScript.

โš ๏ธ Gotchas

  • Type safety doesnโ€™t prevent runtime errors:
function greet(name: string) {
  return "Hello " + name.toUpperCase();
}
greet((123 as unknown) as string); // compiles, but runtime crash
Enter fullscreen mode Exit fullscreen mode
  • No runtime enforcement โ€” you need runtime validators (zod, io-ts, yup).

๐ŸŽฏ Interview One-Liner

โ€œTypeScriptโ€™s types disappear at runtime. They make dev-time guarantees, but runtime safety requires explicit validation.โ€


2. ๐Ÿ”ข Core Primitive Types

โœ… Basic Types

  • string, number, boolean
  • null, undefined
  • symbol, bigint

โœ… Special Types

  • any โ†’ Opt-out of type system (unsafe).
  • unknown โ†’ Safer alternative; must narrow before use.
  • never โ†’ Function that never returns (errors, infinite loops).
  • void โ†’ Function returns nothing.

โš ๏ธ Gotchas

let x: any = 42;
x.toUpperCase(); // compiles, runtime crash

let y: unknown = 42;
y.toUpperCase(); // โŒ compile error
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ Interview One-Liner

โ€œany disables safety. Prefer unknown when you donโ€™t know the type, since it forces narrowing before use.โ€


3. ๐Ÿท๏ธ Type Assertions vs Casting

Definition:
Tell the compiler โ€œtrust me, this is of type X.โ€

โœ… Syntax

const el = document.getElementById("foo") as HTMLDivElement;
Enter fullscreen mode Exit fullscreen mode

โœ… Non-null Assertion

const el = document.getElementById("foo")!; // never null
Enter fullscreen mode Exit fullscreen mode

โš ๏ธ Gotchas

  • Overusing assertions bypasses safety.
  • Wrong assertions โ†’ runtime crashes.
  • Non-null ! can hide real null bugs.

๐ŸŽฏ Interview One-Liner

โ€œAssertions tell TS to trust you. They donโ€™t change runtime โ€” overuse can hide real errors.โ€


4. ๐Ÿ” Type Narrowing (Control Flow Analysis)

Definition:
TS refines types based on runtime checks.

โœ… Techniques

  • typeof
  • instanceof
  • Equality checks
  • Discriminated unions (tag property)

Example

function printLen(x: string | string[]) {
  if (typeof x === "string") console.log(x.length);
  else console.log(x.length); // string[] length
}
Enter fullscreen mode Exit fullscreen mode

โš ๏ธ Gotchas

  • Narrowing only works if TS can see the check.
  • External function calls wonโ€™t narrow unless you define type predicates.
function isString(x: unknown): x is string {
  return typeof x === "string";
}
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ Interview One-Liner

โ€œTypeScript narrows unions using control flow. You can extend it with custom type predicates.โ€


5. ๐Ÿšฆ Strict Null Checking

Definition:
With strictNullChecks, null and undefined are not assignable to other types unless explicitly included.

โœ… Example

let x: string = null; // โŒ error under strictNullChecks
let y: string | null = null; // โœ…
Enter fullscreen mode Exit fullscreen mode

โœ… Optional Chaining + Nullish Coalescing

const name = user?.profile?.name ?? "Guest";
Enter fullscreen mode Exit fullscreen mode

โš ๏ธ Gotchas

  • Many JS libs donโ€™t account for undefined.
  • Without strictNullChecks, you get unsound behavior (nullable everywhere).

๐ŸŽฏ Interview One-Liner

โ€œStrict null checks make nullability explicit, avoiding the billion-dollar mistake. Combine with optional chaining and nullish coalescing.โ€


6. ๐Ÿ”Ž Structural Typing (vs Nominal)

Definition:
TS uses structural typing โ€” compatibility is based on shape, not declared type.

โœ… Example

type Point = { x: number; y: number };
type Coord = { x: number; y: number };

let a: Point = { x: 1, y: 2 };
let b: Coord = a; // โœ… works (same shape)
Enter fullscreen mode Exit fullscreen mode

โš ๏ธ Gotchas

  • Extra properties are rejected in object literals:
let p: Point = { x: 1, y: 2, z: 3 }; // โŒ error
Enter fullscreen mode Exit fullscreen mode
  • But extra props are allowed if passed as variable:
const tmp = { x: 1, y: 2, z: 3 };
let p: Point = tmp; // โœ… works
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ Interview One-Liner

โ€œTypeScript is structurally typed โ€” if it quacks like a duck, itโ€™s assignable. But object literals have stricter excess property checks.โ€


7. ๐Ÿ“ Type Aliases vs Interfaces

Definition:
Two ways to define object types.

โœ… Differences

  • Interface: extendable via declaration merging.
  • Type Alias: supports unions, intersections, primitives.

Example

interface A { x: number }
interface A { y: number } // merged
type B = { x: number } & { y: number } // no merging, must intersect
Enter fullscreen mode Exit fullscreen mode

โš ๏ธ Gotchas

  • Prefer interface for public APIs (extendable).
  • Prefer type for unions and complex compositions.

๐ŸŽฏ Interview One-Liner

โ€œInterfaces are open (mergeable), types are closed but more flexible (unions, intersections). Use each where it fits.โ€


8. ๐Ÿ“ฆ Enums vs Literal Types

โœ… Enums

enum Direction { Up, Down }
Enter fullscreen mode Exit fullscreen mode

โœ… Literal Unions

type Direction = "up" | "down";
Enter fullscreen mode Exit fullscreen mode

โš ๏ธ Gotchas

  • String literal unions are usually better (type-safe, no runtime overhead).
  • Enums generate runtime objects โ†’ heavier.
  • const enum is inlined at compile time but can break tooling.

๐ŸŽฏ Interview One-Liner

โ€œPrefer literal unions over enums โ€” theyโ€™re lighter and more type-safe. Use enums only when runtime mapping is required.โ€


๐ŸŸฆ Advanced Types


1. โž• Union & Intersection Types

โœ… Union (|)

  • Represents either type.
type Input = string | number;
let val: Input = "hi";  // โœ…
val = 42;               // โœ…
Enter fullscreen mode Exit fullscreen mode

โœ… Intersection (&)

  • Combines multiple types.
type Person = { name: string };
type Worker = { company: string };
type Employee = Person & Worker; 
// { name: string; company: string }
Enter fullscreen mode Exit fullscreen mode

โš ๏ธ Gotchas

  • Union narrows to shared members:
function len(x: string | string[]) {
  return x.length; // works (length exists on both)
}
Enter fullscreen mode Exit fullscreen mode
  • Intersection of incompatible types โ†’ never:
type Impossible = string & number; // never
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œUnions = OR, intersections = AND. Incompatible intersections collapse to never.โ€


2. ๐Ÿ”ข Literal Types & Const Assertions

โœ… Literal Types

let dir: "up" | "down";
dir = "up"; // โœ…
dir = "left"; // โŒ
Enter fullscreen mode Exit fullscreen mode

โœ… as const

  • Locks values into literal types.
const colors = ["red", "green"] as const;
type Color = typeof colors[number]; // "red" | "green"
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œLiteral types restrict values to exact strings/numbers. as const freezes arrays/objects for inference.โ€


3. ๐Ÿ“ Template Literal Types

โœ… Key Points

  • Build strings at type level.
type Event = `on${Capitalize<"click" | "hover">}`;
// "onClick" | "onHover"
Enter fullscreen mode Exit fullscreen mode

โœ… Use Cases

  • Event handler names.
  • Typed CSS props.
  • API route patterns.

๐ŸŽฏ One-Liner

โ€œTemplate literal types compose strings at type level โ€” great for event names, routes, and API typings.โ€


4. ๐Ÿงฎ Conditional Types

Definition:
T extends U ? X : Y

โœ… Example

type IsString<T> = T extends string ? true : false;
type A = IsString<"hi">;   // true
type B = IsString<number>; // false
Enter fullscreen mode Exit fullscreen mode

โœ… Distributive Behavior

type ToArray<T> = T extends any ? T[] : never;
type C = ToArray<string | number>; // string[] | number[]
Enter fullscreen mode Exit fullscreen mode

โš ๏ธ Gotchas

  • Distribution only happens on naked type parameters.
  • Use brackets to disable:
type NoDistrib<T> = [T] extends [any] ? T[] : never;
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œConditional types let you branch at type level. By default they distribute over unions.โ€


5. ๐Ÿ—‚๏ธ Mapped Types

โœ… Basics

type OptionsFlags<T> = {
  [K in keyof T]: boolean;
};
type Features = { darkMode: () => void };
type Flags = OptionsFlags<Features>; 
// { darkMode: boolean }
Enter fullscreen mode Exit fullscreen mode

โœ… Modifiers

  • readonly
  • ? optional
  • -readonly / -? to remove
type Mutable<T> = { -readonly [K in keyof T]: T[K] };
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œMapped types iterate over keys to transform shape โ€” add/remove optionality, readonly, etc.โ€


6. ๐Ÿ› ๏ธ Utility Types

โœ… Built-ins

  • Partial<T> โ†’ all optional
  • Required<T> โ†’ all required
  • Readonly<T> โ†’ all readonly
  • Pick<T, K> โ†’ subset
  • Omit<T, K> โ†’ all except
  • Record<K, V> โ†’ dict type
  • ReturnType<T> โ†’ infer fn return
  • Parameters<T> โ†’ tuple of args
  • InstanceType<T> โ†’ type of new T()

Example

type Todo = { id: number; title: string; done?: boolean };
type TodoDraft = Partial<Todo>; // all optional
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œUtility types like Partial, Pick, Omit, Record abstract common transformations of object types.โ€


7. ๐Ÿงฉ Key Remapping in Mapped Types (TS 4.1+)

type Prefix<T> = {
  [K in keyof T as `on${Capitalize<string & K>}`]: T[K]
};
type Events = Prefix<{ click: () => void }>;
// { onClick: () => void }
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œMapped types can rename keys dynamically using as clauses and template literals.โ€


8. ๐ŸŒ€ Recursive & Deep Types

โœ… Recursive Types

type JSONValue = string | number | boolean | JSONValue[] | { [k: string]: JSONValue };
Enter fullscreen mode Exit fullscreen mode

โœ… Deep Utility

type DeepPartial<T> = { [K in keyof T]?: DeepPartial<T[K]> };
Enter fullscreen mode Exit fullscreen mode

โš ๏ธ Gotchas

  • Deep recursion can slow compiler dramatically.
  • Use cautiously in very large codebases.

๐ŸŽฏ One-Liner

โ€œRecursive types enable JSON-like structures and deep utilities, but may hit compiler perf limits.โ€


๐ŸŸฆ Generics in Depth


1. ๐Ÿงฉ Generic Functions

Definition:
Functions parameterized with type variables.

โœ… Example

function identity<T>(arg: T): T {
  return arg;
}
const a = identity<string>("hello");
const b = identity(42); // inferred as number
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œGenerics make functions reusable across types, with inference for convenience.โ€


2. ๐Ÿ”’ Constraints (extends)

Restrict generics to a subset of types.

โœ… Example

function getLength<T extends { length: number }>(x: T) {
  return x.length;
}
getLength("hi");       // โœ…
getLength([1,2,3]);    // โœ…
getLength(42);         // โŒ
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œConstraints limit generics with extends, allowing access to known members.โ€


3. ๐Ÿท๏ธ Generic Interfaces & Classes

โœ… Interfaces

interface Box<T> { value: T }
const stringBox: Box<string> = { value: "hi" };
Enter fullscreen mode Exit fullscreen mode

โœ… Classes

class Container<T> {
  constructor(public value: T) {}
}
const c = new Container<number>(123);
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œGenerics extend beyond functions โ€” interfaces and classes can also be parameterized.โ€


4. โš–๏ธ Default Generic Parameters

Provide defaults for flexibility.

โœ… Example

interface ApiResponse<T = any> {
  data: T;
  error?: string;
}
const res: ApiResponse = { data: "hi" }; // T defaults to any
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œDefaults reduce boilerplate when generic type can be inferred or safely assumed.โ€


5. ๐Ÿ”„ Keyof & Indexed Access with Generics

โœ… Keyof

type Keys<T> = keyof T;
type User = { id: number; name: string };
type UKeys = Keys<User>; // "id" | "name"
Enter fullscreen mode Exit fullscreen mode

โœ… Indexed Access

type Value<T, K extends keyof T> = T[K];
type NameType = Value<User, "name">; // string
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œKeyof + indexed access lets you make type-safe utilities (like Pick/Omit).โ€


6. ๐ŸŽญ Conditional Generics

Generics inside conditional types = super powerful.

โœ… Example

type Flatten<T> = T extends any[] ? T[number] : T;
type A = Flatten<string[]>; // string
type B = Flatten<number>;   // number
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œConditional generics let you branch inside generics โ€” e.g., flatten arrays, unwrap promises.โ€


7. โš–๏ธ Variance (Covariance vs Contravariance)

Definition:
How subtyping interacts with generics.

โœ… Covariance

  • Safe to use subtype in place of supertype.
let str: string = "hi";
let val: string | number = str; // โœ…
Enter fullscreen mode Exit fullscreen mode

โœ… Contravariance

  • Function parameters are contravariant:
type Fn<T> = (x: T) => void;
let fn: Fn<string | number> = (x: string) => {}; // โœ…
Enter fullscreen mode Exit fullscreen mode

โš ๏ธ Gotchas

  • TypeScript uses bivariant function parameters by default for compatibility (unsafe but practical).
  • --strictFunctionTypes enforces contravariance.

๐ŸŽฏ One-Liner

โ€œFunction parameters are contravariant, return types are covariant. TS is bivariant by default unless strictFunctionTypes is on.โ€


8. ๐ŸŒ€ Higher-Kinded Types (HKTs, Workarounds)

TypeScript doesnโ€™t support true HKTs (types parameterized over type constructors), but you can simulate.

โœ… Example

interface Functor<F> {
  map<A, B>(fa: F & { value: A }, fn: (a: A) => B): F & { value: B }
}
Enter fullscreen mode Exit fullscreen mode

Or libraries like fp-ts emulate HKT with encoding tricks.

๐ŸŽฏ One-Liner

โ€œTypeScript lacks HKTs, but libraries like fp-ts emulate them with encoding patterns.โ€


9. ๐Ÿ”— Generics in React

โœ… Typing useState

const [val, setVal] = useState<string | null>(null);
Enter fullscreen mode Exit fullscreen mode

โœ… Typing useReducer

type Action = { type: "inc" } | { type: "dec" };
function reducer(s: number, a: Action): number {
  return a.type === "inc" ? s+1 : s-1;
}
const [count, dispatch] = useReducer(reducer, 0);
Enter fullscreen mode Exit fullscreen mode

โœ… Typing Props

interface ButtonProps<T extends "button" | "a"> {
  as: T;
  props: T extends "a" ? { href: string } : { onClick: () => void };
}
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œGenerics in React type hooks, props, reducers, and flexible components (e.g., polymorphic components).โ€


๐ŸŸฆ Type Inference & Compatibility


1. ๐Ÿ” Type Inference Basics

Definition:
TypeScript infers types when not explicitly annotated.

โœ… Examples

let x = 42;      // inferred as number
let y = [1, 2];  // inferred as number[]
Enter fullscreen mode Exit fullscreen mode

โœ… Contextual Typing

  • Function parameters infer type from usage:
window.onmousedown = (e) => { 
  console.log(e.button); // e inferred as MouseEvent
};
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œType inference works both from initializer values and from context (like callbacks).โ€


2. โš–๏ธ Excess Property Checks

Definition:
TypeScript enforces stricter checks for object literals.

โœ… Example

type User = { name: string };
const u1: User = { name: "Alice", age: 30 }; // โŒ excess property
const tmp = { name: "Alice", age: 30 };
const u2: User = tmp; // โœ… allowed (assignment, not literal)
Enter fullscreen mode Exit fullscreen mode

โš ๏ธ Gotchas

  • Literal checks prevent typos in inline objects.
  • Assigning via variable bypasses check.

๐ŸŽฏ One-Liner

โ€œObject literals get extra checks for unknown properties. Assign via variable to bypass.โ€


3. ๐Ÿ”„ Type Widening & Narrowing

โœ… Widening

  • Without as const, literal types widen:
let a = "hi";     // type string (widened)
const b = "hi";   // type "hi" (literal)
Enter fullscreen mode Exit fullscreen mode

โœ… Narrowing

  • Control-flow analysis narrows union types:
function f(x: string | null) {
  if (x !== null) return x.toUpperCase(); // narrowed to string
}
Enter fullscreen mode Exit fullscreen mode

โš ๏ธ Gotchas

  • let x = null โ†’ type is any unless strictNullChecks.
  • Arrays widen unless frozen with as const.

๐ŸŽฏ One-Liner

โ€œTS widens literals by default. Use as const to keep narrow literal types.โ€


4. ๐Ÿท๏ธ Assignability & Compatibility

Definition:
TypeScript is structurally typed โ†’ assignability depends on shape.

โœ… Example

type Point = { x: number; y: number };
type Coord = { x: number; y: number; z?: number };

let p: Point = { x: 1, y: 2 };
let c: Coord = p;  // โœ… works
p = c;             // โœ… works (z optional)
Enter fullscreen mode Exit fullscreen mode

โš ๏ธ Gotchas

  • Function parameters are bivariant by default (unsafe).
  • Use strictFunctionTypes for true contravariance.

๐ŸŽฏ One-Liner

โ€œTS uses structural typing: if shapes match, types are compatible. Functions default to bivariant params unless strict.โ€


5. ๐Ÿงฉ any vs unknown vs never

โœ… any

  • Opt-out of type checking.
  • Can be assigned to/from anything.
let a: any = 42;
a.foo.bar(); // compiles, runtime error
Enter fullscreen mode Exit fullscreen mode

โœ… unknown

  • Top type (safe any).
  • Must be narrowed before use.
let b: unknown = 42;
b.toUpperCase(); // โŒ error
if (typeof b === "string") b.toUpperCase(); // โœ…
Enter fullscreen mode Exit fullscreen mode

โœ… never

  • Bottom type (no value possible).
  • Used in exhaustiveness checks.
type Shape = { kind: "circle" } | { kind: "square" };
function area(s: Shape): number {
  switch (s.kind) {
    case "circle": return 1;
    case "square": return 2;
    default: const _exhaustive: never = s; // โœ… ensures all cases handled
  }
}
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œany disables safety, unknown forces narrowing, never represents impossible cases.โ€


6. ๐Ÿง  Inference in Functions

โœ… Return Inference

function add(a: number, b: number) {
  return a + b; // inferred as number
}
Enter fullscreen mode Exit fullscreen mode

โœ… Generic Inference

function first<T>(arr: T[]): T {
  return arr[0];
}
const v = first(["a", "b"]); // v: string
Enter fullscreen mode Exit fullscreen mode

โš ๏ธ Gotchas

  • Sometimes inference is too wide:
function f() { return Math.random() ? "a" : "b"; }
// inferred as string, not "a"|"b"
Enter fullscreen mode Exit fullscreen mode

โ†’ Fix with as const or explicit typing.

๐ŸŽฏ One-Liner

โ€œFunction return types are inferred, but unions may widen. Use as const or annotations for precision.โ€


7. ๐Ÿ› ๏ธ Type Compatibility in Enums

โœ… Numeric Enums

  • Compatible with numbers.
enum Dir { Up, Down }
let d: Dir = 0; // โœ…
Enter fullscreen mode Exit fullscreen mode

โœ… String Enums

  • Not compatible with strings unless explicitly.
enum Color { Red = "red" }
let c: Color = "red"; // โŒ
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œNumeric enums are assignable to numbers, but string enums require exact matches.โ€


8. โšก Type Compatibility in Tuples vs Arrays

โœ… Tuples

type Pair = [string, number];
let p: Pair = ["hi", 42];
Enter fullscreen mode Exit fullscreen mode
  • Tuples have fixed length, arrays are flexible.

โš ๏ธ Gotchas

let t: [number, number] = [1, 2];
t.push(3); // โœ… allowed! TS doesnโ€™t enforce length at runtime
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œTuples enforce order but not length at runtime โ€” theyโ€™re arrays under the hood.โ€


๐ŸŸฆ Type Safety in JavaScript Interop


1. ๐Ÿ“œ Ambient Declarations (declare)

Definition:
Tell TypeScript about variables/modules that exist at runtime (JS), but arenโ€™t defined in TS code.

โœ… Examples

declare const VERSION: string;
console.log(VERSION); // TS knows VERSION is string

declare module "legacy-lib" {
  export function legacyFn(): void;
}
Enter fullscreen mode Exit fullscreen mode

โš ๏ธ Gotchas

  • Declarations donโ€™t generate runtime code โ€” only inform compiler.
  • If declaration doesnโ€™t match actual runtime โ†’ runtime errors.

๐ŸŽฏ One-Liner

โ€œdeclare informs the type system about external JS values but doesnโ€™t emit code. Accuracy is critical or youโ€™ll get runtime errors.โ€


2. ๐Ÿ“ฆ Type Declarations for JS Libraries

โœ… Strategies

  • @types packages:
npm install --save-dev @types/lodash
Enter fullscreen mode Exit fullscreen mode
  • Manual d.ts files for missing types:
// lodash.d.ts
declare module "lodash" {
  export function chunk<T>(arr: T[], size: number): T[][];
}
Enter fullscreen mode Exit fullscreen mode

โš ๏ธ Gotchas

  • If types are outdated/mismatched โ†’ TS lies about API.
  • Can โ€œaugmentโ€ instead of redefining (see below).

๐ŸŽฏ One-Liner

โ€œMissing types for JS libs? Install @types or write .d.ts files โ€” but keep them accurate with the runtime.โ€


3. ๐Ÿงฉ Module Augmentation & Declaration Merging

Definition:
Extend existing module or type definitions without rewriting.

โœ… Example

// add a method to lodash
declare module "lodash" {
  export function customHello(): string;
}
Enter fullscreen mode Exit fullscreen mode

โœ… Declaration Merging

  • Interfaces with the same name merge:
interface User { id: number }
interface User { name: string }
const u: User = { id: 1, name: "Alice" }; // โœ…
Enter fullscreen mode Exit fullscreen mode

โš ๏ธ Gotchas

  • Augmentation is global โ†’ can cause conflicts across packages.
  • Prefer module augmentation for libs, not any hacks.

๐ŸŽฏ One-Liner

โ€œDeclaration merging/augmentation extends types safely. Useful for adding custom fields or extending 3rd-party libraries.โ€


4. ๐ŸŽฏ as const for Safe Interop

Definition:
as const freezes literals into readonly narrow types.

โœ… Example

const roles = ["admin", "user", "guest"] as const;
type Role = typeof roles[number]; 
// "admin" | "user" | "guest"
Enter fullscreen mode Exit fullscreen mode

โœ… Use Case

  • Ensures config/constants match at runtime.
  • Great for enums/union types from JS arrays.

๐ŸŽฏ One-Liner

โ€œas const locks JS literals into readonly narrow types โ€” perfect for role lists, config, or enum-like structures.โ€


5. โš™๏ธ tsconfig Strictness Flags

โœ… Important Flags

  • strict โ†’ enables all strict checks.
  • noImplicitAny โ†’ no silent any.
  • strictNullChecks โ†’ enforce explicit nullability.
  • noUncheckedIndexedAccess โ†’ array lookups can return undefined.
  • exactOptionalPropertyTypes โ†’ ? means strictly optional.

โš ๏ธ Gotchas

  • Teams often disable strictness โ†’ leaks any.
  • Migrating large JS โ†’ TS requires incremental adoption.

๐ŸŽฏ One-Liner

โ€œAlways enable strict. Key flags like noImplicitAny and strictNullChecks catch hidden bugs in JS interop.โ€


6. ๐Ÿ› ๏ธ Working with Untyped JS Objects

โœ… Options

  • Use unknown + type guards:
function isUser(u: any): u is { id: number } {
  return typeof u.id === "number";
}
Enter fullscreen mode Exit fullscreen mode
  • Or validate at runtime with Zod/io-ts:
import { z } from "zod";
const User = z.object({ id: z.number(), name: z.string() });
type User = z.infer<typeof User>;
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œUntyped JS objects should be validated at runtime with schemas (Zod/io-ts), not just trusted via any.โ€


7. ๐Ÿ”— Migrating JS โ†’ TS (Gradual Typing)

โœ… Strategies

  • Rename .js โ†’ .ts or .tsx.
  • Use allowJs + checkJs in tsconfig to gradually type JS.
  • Add JSDoc annotations:
/**
 * @param {string} name
 * @returns {string}
 */
function greet(name) { return "Hello " + name; }
Enter fullscreen mode Exit fullscreen mode
  • TS infers types from JSDoc until converted.

โš ๏ธ Gotchas

  • JSDoc typing is weaker than TS proper.
  • Incremental migration often mixes any โ†’ must clean up later.

๐ŸŽฏ One-Liner

โ€œMigrate JS โ†’ TS gradually: enable checkJs, add JSDoc types, then refactor into full TypeScript.โ€


8. ๐Ÿ›ก๏ธ Runtime vs Compile-Time Safety

Core Rule:
Types vanish at runtime โ†’ if interoping with JS, you need runtime checks.

โœ… Example

function safeParse(json: string): unknown {
  try { return JSON.parse(json) } catch { return null }
}
const data = safeParse("not-json"); // type unknown
// must validate before using
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œTypeScript only checks at compile time. For JS interop, add runtime validation to truly guarantee safety.โ€


๐ŸŸฆ Type Guards & Narrowing


1. ๐Ÿ”Ž Built-in Type Guards: typeof

Definition:
typeof lets TypeScript narrow primitive types.

โœ… Example

function log(val: string | number) {
  if (typeof val === "string") {
    console.log(val.toUpperCase()); // val: string
  } else {
    console.log(val.toFixed(2));    // val: number
  }
}
Enter fullscreen mode Exit fullscreen mode

โš ๏ธ Gotchas

  • Only works on primitives: "string" | "number" | "boolean" | "bigint" | "symbol" | "undefined" | "object" | "function".
  • Doesnโ€™t differentiate null vs object (typeof null === "object").

๐ŸŽฏ One-Liner

โ€œUse typeof for primitives โ€” but note typeof null === 'object'.โ€


2. ๐Ÿ—๏ธ Built-in Type Guards: instanceof

Definition:
Narrow objects by checking prototype chain.

โœ… Example

function handleError(e: Error | string) {
  if (e instanceof Error) {
    console.error(e.message); // Error
  } else {
    console.error(e); // string
  }
}
Enter fullscreen mode Exit fullscreen mode

โš ๏ธ Gotchas

  • Only works with classes/constructors (not plain objects).
  • Inheritance hierarchy is respected.

๐ŸŽฏ One-Liner

โ€œUse instanceof for class-based narrowing โ€” it checks prototype chain.โ€


3. ๐Ÿงฉ In-Operator Narrowing

Definition:
Check if a property exists in object โ†’ narrows union.

โœ… Example

type Cat = { meow: () => void };
type Dog = { bark: () => void };

function speak(animal: Cat | Dog) {
  if ("meow" in animal) animal.meow();
  else animal.bark();
}
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œThe in operator narrows unions by checking for property existence.โ€


4. ๐Ÿท๏ธ Discriminated (Tagged) Unions

Definition:
Unions with a common literal field (โ€œtagโ€) for safe narrowing.

โœ… Example

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number };

function area(s: Shape) {
  switch (s.kind) {
    case "circle": return Math.PI * s.radius ** 2;
    case "square": return s.side ** 2;
  }
}
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œDiscriminated unions use a common literal field to guarantee safe narrowing in switches.โ€


5. ๐Ÿ› ๏ธ Custom Type Predicates

Definition:
User-defined functions that tell TS a condition implies a type.

โœ… Example

function isString(x: unknown): x is string {
  return typeof x === "string";
}

function log(x: unknown) {
  if (isString(x)) console.log(x.toUpperCase());
}
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œCustom type predicates (x is T) let you teach TS how to narrow beyond built-ins.โ€


6. ๐Ÿšฆ Exhaustiveness Checking with never

Definition:
Force handling all cases in a union.

โœ… Example

type Shape =
  | { kind: "circle"; r: number }
  | { kind: "square"; s: number };

function perimeter(s: Shape) {
  switch (s.kind) {
    case "circle": return 2 * Math.PI * s.r;
    case "square": return 4 * s.s;
    default:
      const _exhaustive: never = s; // compile error if new case added
      return _exhaustive;
  }
}
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œExhaustiveness checks with never ensure all union cases are handled โ€” future-proofing code.โ€


7. ๐Ÿง  Control Flow Analysis

Definition:
TS tracks variables through branches to narrow automatically.

โœ… Example

function f(x: string | null) {
  if (!x) return; 
  // x is now string, since null was filtered out
  return x.toUpperCase();
}
Enter fullscreen mode Exit fullscreen mode

โš ๏ธ Gotchas

  • TS is flow-sensitive โ€” order matters.
  • Reassignments can widen again.

๐ŸŽฏ One-Liner

โ€œTS narrows types flow-sensitively โ€” once a check passes, TS refines type until reassignment.โ€


8. ๐Ÿงฉ Assertion Functions (TS 3.7+)

Definition:
Custom functions that throw on invalid values while narrowing type.

โœ… Example

function assertIsString(x: any): asserts x is string {
  if (typeof x !== "string") throw new Error("Not a string");
}

function shout(x: any) {
  assertIsString(x);
  console.log(x.toUpperCase()); // x: string
}
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œAssertion functions throw at runtime and tell TS the variable is narrowed if no error occurs.โ€


9. ๐Ÿ“ฆ Combining Guards

โœ… Example

function handle(input: string | number | null) {
  if (input == null) return;          // null/undefined filtered
  if (typeof input === "string") {    // narrowed to string
    return input.toUpperCase();
  }
  return input.toFixed(2);            // number
}
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œCombine guards (== null, typeof, instanceof) for precise narrowing of complex unions.โ€


๐ŸŸฆ Advanced Patterns


1. ๐Ÿท๏ธ Branded Types (Nominal Typing in TS)

Problem:
TS is structural โ€” type UserId = string is indistinguishable from any string.

Solution:
Add a โ€œbrandโ€ field to enforce nominal typing.

โœ… Example

type UserId = string & { __brand: "UserId" };
function getUser(id: UserId) {}
getUser("123" as UserId);  // โœ…
getUser("random");         // โŒ must be branded
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œBranded types simulate nominal typing in TS, preventing accidental mixing of structurally identical types.โ€


2. ๐ŸŒ€ Opaque Types

Definition:
Similar to branded types, but completely hide the underlying type from consumers.

โœ… Example

type Opaque<K, T> = T & { __TYPE__: K };
type UserId = Opaque<"UserId", string>;

function createUserId(s: string): UserId {
  return s as UserId;
}
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œOpaque types hide implementation details and prevent misuse, forcing controlled constructors.โ€


3. ๐Ÿ› ๏ธ Recursive Utility Types

โœ… DeepPartial

type DeepPartial<T> = {
  [K in keyof T]?: DeepPartial<T[K]>;
};
Enter fullscreen mode Exit fullscreen mode

โœ… DeepReadonly

type DeepReadonly<T> = {
  readonly [K in keyof T]: DeepReadonly<T[K]>;
};
Enter fullscreen mode Exit fullscreen mode

โš ๏ธ Gotchas

  • Deep recursion can slow down compiler.
  • Use selectively in large projects.

๐ŸŽฏ One-Liner

โ€œRecursive types enable deep utilities like DeepPartial, but heavy use impacts compiler performance.โ€


4. ๐Ÿงฉ Conditional & Mapped Utilities

โœ… NonNullable

type NonNullable<T> = T extends null | undefined ? never : T;
Enter fullscreen mode Exit fullscreen mode

โœ… Diff

type Diff<T, U> = T extends U ? never : T;
Enter fullscreen mode Exit fullscreen mode

โœ… Overwrite

type Overwrite<T, U> = Omit<T, keyof U> & U;
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œMapped + conditional types let you build powerful utilities like Diff, Overwrite, NonNullable.โ€


5. ๐Ÿ”„ Variadic Tuple Types

Definition:
Model tuples of variable length with generics.

โœ… Example

type Push<T extends any[], V> = [...T, V];
type T1 = Push<[1,2], 3>; // [1,2,3]

type Concat<T extends any[], U extends any[]> = [...T, ...U];
type T2 = Concat<[1,2], [3,4]>; // [1,2,3,4]
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œVariadic tuple types let you append, prepend, or merge tuples while preserving type precision.โ€


6. ๐Ÿ—๏ธ Builder Pattern in TypeScript

โœ… Example

class RequestBuilder {
  private url: string = "";
  private method: "GET" | "POST" = "GET";

  setUrl(url: string) { this.url = url; return this; }
  setMethod(m: "GET" | "POST") { this.method = m; return this; }
  build() { return { url: this.url, method: this.method }; }
}

const req = new RequestBuilder().setUrl("/api").setMethod("POST").build();
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œBuilder patterns ensure chained configuration APIs with type safety and autocomplete.โ€


7. ๐Ÿ›ก๏ธ Exact Types (Prevent Excess Keys)

Problem:
TS normally allows extra props via assignment.

Solution:
Create an Exact<T, U> utility.

โœ… Example

type Exact<T, U extends T> = T & { [K in Exclude<keyof U, keyof T>]?: never };

type Person = { name: string };
const p: Exact<Person, { name: string; age: number }> = { name: "A", age: 20 }; 
// โŒ error: extra 'age'
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œExact types prevent excess keys, useful for APIs where only known fields are allowed.โ€


8. ๐Ÿ“ฆ Extracting Types from Values

โœ… typeof + keyof

const config = {
  roles: ["admin", "user", "guest"] as const,
};
type Role = typeof config["roles"][number]; 
// "admin" | "user" | "guest"
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œUse typeof and as const to derive union types from runtime values like config arrays.โ€


9. ๐Ÿง  Phantom Types (Static Guarantees)

Definition:
Types that exist only at compile-time, to encode invariants.

โœ… Example

type Celsius = number & { __unit: "Celsius" };
type Fahrenheit = number & { __unit: "Fahrenheit" };

function toF(c: Celsius): Fahrenheit { return (c * 9/5 + 32) as Fahrenheit; }

let t: Celsius = 100 as Celsius;
toF(t); // โœ…
toF(100 as Fahrenheit); // โŒ
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œPhantom types enforce domain-specific rules (like units) without runtime cost.โ€


๐ŸŸฆ TypeScript in React


1. ๐ŸŽฏ Typing Component Props

โœ… Functional Components

type ButtonProps = {
  label: string;
  onClick?: () => void;
};

const Button: React.FC<ButtonProps> = ({ label, onClick }) => (
  <button onClick={onClick}>{label}</button>
);
Enter fullscreen mode Exit fullscreen mode

โš ๏ธ Gotchas

  • React.FC implicitly adds children prop โ€” often unwanted.
  • Better to type children explicitly.
type Props = { children?: React.ReactNode };
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œPrefer explicit prop typing over React.FC to avoid hidden children.โ€


2. ๐Ÿท๏ธ Children Typing

โœ… Common Patterns

type Props = { children: React.ReactNode }; // anything renderable
type Props2 = { children: React.ReactElement }; // exactly one element
type Props3<T> = { children: (data: T) => React.ReactNode }; // render prop
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œUse ReactNode for generic children, ReactElement for single elements, and functions for render props.โ€


3. ๐Ÿงฉ Typing Hooks (useState, useReducer)

โœ… useState

const [count, setCount] = useState<number>(0); // explicit
const [name, setName] = useState("Alice"); // inferred as string
Enter fullscreen mode Exit fullscreen mode
  • useState<T | null>(null) when initial value is null.

โœ… useReducer

type Action = { type: "inc" } | { type: "dec" };
function reducer(state: number, action: Action): number {
  switch (action.type) {
    case "inc": return state + 1;
    case "dec": return state - 1;
  }
}
const [count, dispatch] = useReducer(reducer, 0);
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œType state & actions explicitly in hooks. Use union types for reducers.โ€


4. ๐ŸŒ Typing Context Providers

โœ… Example

type User = { id: string; name: string };
type UserContextType = { user: User | null; setUser: (u: User) => void };

const UserContext = React.createContext<UserContextType | undefined>(undefined);

function useUser() {
  const ctx = React.useContext(UserContext);
  if (!ctx) throw new Error("useUser must be inside UserProvider");
  return ctx;
}
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œContext values should include both data and setters, wrapped in a custom hook for safety.โ€


5. ๐Ÿงต Typing Refs & forwardRef

โœ… DOM Refs

const inputRef = React.useRef<HTMLInputElement>(null);
inputRef.current?.focus();
Enter fullscreen mode Exit fullscreen mode

โœ… forwardRef

type InputProps = { label: string };
const Input = React.forwardRef<HTMLInputElement, InputProps>(
  ({ label }, ref) => <input ref={ref} placeholder={label} />
);
Enter fullscreen mode Exit fullscreen mode

โœ… useImperativeHandle

type Handle = { focus: () => void };
const CustomInput = React.forwardRef<Handle>((props, ref) => {
  const inputRef = React.useRef<HTMLInputElement>(null);
  React.useImperativeHandle(ref, () => ({
    focus: () => inputRef.current?.focus(),
  }));
  return <input ref={inputRef} />;
});
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œUse forwardRef with generic ref types. Expose imperative APIs with useImperativeHandle.โ€


6. ๐Ÿงฎ Typing Higher-Order Components (HOCs)

โœ… Example

function withLoading<T>(Component: React.ComponentType<T>) {
  return (props: T & { loading: boolean }) =>
    props.loading ? <div>Loading...</div> : <Component {...props} />;
}
Enter fullscreen mode Exit fullscreen mode

โš ๏ธ Gotchas

  • Must preserve props (T) and merge with new ones.
  • Watch out for lost generics when wrapping.

๐ŸŽฏ One-Liner

โ€œHOCs should preserve original props via generics and merge additional ones.โ€


7. ๐Ÿง‘โ€๐Ÿ”ฌ Typing Generic Components

โœ… Example

type ListProps<T> = {
  items: T[];
  render: (item: T) => React.ReactNode;
};

function List<T>({ items, render }: ListProps<T>) {
  return <ul>{items.map(render)}</ul>;
}

<List items={[1, 2, 3]} render={(x) => <li>{x}</li>} />;
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œGeneric components let props depend on type parameters โ€” perfect for reusable lists and tables.โ€


8. ๐Ÿ”„ Typing Event Handlers

โœ… Example

function Form() {
  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    console.log(e.target.value);
  };
  return <input onChange={handleChange} />;
}
Enter fullscreen mode Exit fullscreen mode

โœ… Common Event Types

  • React.MouseEvent<HTMLButtonElement>
  • React.ChangeEvent<HTMLInputElement>
  • React.FormEvent<HTMLFormElement>

๐ŸŽฏ One-Liner

โ€œUse Reactโ€™s synthetic event types (MouseEvent, ChangeEvent) for handlers, parameterized by element type.โ€


9. ๐Ÿงฉ Typing Polymorphic as Components

โœ… Example

type PolymorphicProps<T extends React.ElementType> = {
  as?: T;
  children: React.ReactNode;
} & React.ComponentProps<T>;

function Box<T extends React.ElementType = "div">({ as, ...props }: PolymorphicProps<T>) {
  const Component = as || "div";
  return <Component {...props} />;
}

<Box as="a" href="https://ts">Link</Box>; // href type-safe
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ One-Liner

โ€œPolymorphic components use as + generics + ComponentProps<T> to forward correct props.โ€


๐ŸŸฆ Performance & Scaling TypeScript


1. โšก Type-Checking Performance in Large Projects

โœ… Common Bottlenecks

  • Deeply nested conditional types.
  • Overuse of recursive mapped types (e.g., DeepPartial, DeepReadonly).
  • Giant union types (e.g., "A" | "B" | ... | "Z" with hundreds of members).
  • Heavy infer usage inside generics.

โœ… Tools

  • tsc --diagnostics โ†’ measure type-check performance.
  • tsc --extendedDiagnostics โ†’ detailed breakdown (parse time, check time, emit time).

๐ŸŽฏ One-Liner

โ€œThe biggest type-check killers are deep recursion, massive unions, and heavy conditional types โ€” profile with --diagnostics.โ€


2. ๐Ÿ› ๏ธ Avoiding Over-Complex Types

โœ… Problem

Some teams abuse TS to encode too much at type level.

type Crazy<T> = T extends string 
  ? { str: T } 
  : T extends number 
    ? { num: T } 
    : never;
Enter fullscreen mode Exit fullscreen mode
  • Hard to maintain, slows compiler.

โœ… Guidelines

  • Keep types simple for DX (developer experience).
  • Donโ€™t encode logic that belongs in runtime code.
  • Prefer branded/opaque types for safety, instead of extreme conditional gymnastics.

๐ŸŽฏ One-Liner

โ€œDonโ€™t over-engineer types โ€” TS is for safety, not replacing runtime logic.โ€


3. ๐Ÿ“ฆ Build Pipelines: tsc vs Babel vs SWC

โœ… tsc

  • Full type-checker + emit.
  • Slowest, but canonical.

โœ… Babel with @babel/preset-typescript

  • Strips types โ†’ no type-checking.
  • Fast, but must run tsc --noEmit separately.

โœ… SWC (used in Next.js, Vite, Turborepo)

  • Rust-based transpiler, very fast.
  • Strips types only.

โš ๏ธ Gotchas

  • Babel/SWC do not catch type errors โ€” must run type-check separately in CI.

๐ŸŽฏ One-Liner

โ€œUse SWC/Babel for fast builds, but keep tsc --noEmit in CI for type safety.โ€


4. ๐Ÿ”„ Incremental Compilation

โœ… Options

  • "incremental": true in tsconfig.json โ†’ saves .tsbuildinfo cache.
  • "composite": true for project references (multi-package repos).

โœ… Benefits

  • Only re-check changed files.
  • Required for monorepos with shared libraries.

๐ŸŽฏ One-Liner

โ€œEnable incremental + composite in tsconfig to avoid full re-checks in large repos.โ€


5. ๐Ÿงฉ Project References (Scaling Monorepos)

Definition:
Break project into multiple sub-projects with clear build boundaries.

โœ… Example

// tsconfig.json
{
  "files": [],
  "references": [
    { "path": "./packages/ui" },
    { "path": "./packages/server" }
  ]
}
Enter fullscreen mode Exit fullscreen mode

โœ… Benefits

  • Faster builds (independent packages).
  • Enforces dependency contracts.
  • Works great with Nx/Turborepo.

๐ŸŽฏ One-Liner

โ€œProject references let you split large codebases into smaller typed units with enforced contracts.โ€


6. ๐Ÿง  Type-Only Imports & Exports (TS 3.8+)

โœ… Example

import type { User } from "./types"; // stripped at runtime
export type { Config } from "./config";
Enter fullscreen mode Exit fullscreen mode

โœ… Benefits

  • Avoids accidentally bundling type-only modules.
  • Reduces unnecessary runtime imports.

๐ŸŽฏ One-Liner

โ€œUse import type and export type to ensure pure type imports donโ€™t affect runtime bundles.โ€


7. โš–๏ธ Managing any at Scale

โœ… Problems

  • any spreads like a virus in codebases.
  • One any can propagate through dozens of types.

โœ… Solutions

  • Use unknown instead of any when possible.
  • Use eslint rules (@typescript-eslint/no-explicit-any).
  • Introduce โ€œescape hatchesโ€ (TODO: fix any) but track debt.

๐ŸŽฏ One-Liner

โ€œManage any aggressively โ€” prefer unknown, enforce lint rules, and track escape hatches.โ€


8. ๐Ÿ“Š Large Codebase Best Practices

  • โœ… Strict mode always (strict: true).
  • โœ… Type-only imports (import type).
  • โœ… Use Zod/io-ts for runtime validation of API responses.
  • โœ… Add tsc --noEmit in CI to enforce type safety.
  • โœ… Use paths in tsconfig.json for clean imports.
  • โœ… Monitor tsc --diagnostics to spot type-check slowdowns.

๐ŸŽฏ One-Liner

โ€œLarge TS projects succeed when strict mode, type-only imports, runtime validation, and CI type-checks are enforced.โ€


๐ŸŸฆ Ecosystem & Future


1. ๐Ÿงฉ Decorators (Stage 3 Proposal)

Definition:
Annotations for classes, methods, and properties.

โœ… Example

function readonly(target: any, key: string) {
  Object.defineProperty(target, key, { writable: false });
}

class User {
  @readonly
  name = "Alice";
}
Enter fullscreen mode Exit fullscreen mode

โœ… Use Cases

  • Dependency injection (NestJS).
  • ORMs (TypeORM, Prisma).
  • Metadata reflection.

โš ๏ธ Gotchas

  • Still experimental โ€” syntax differs across versions.
  • Requires "experimentalDecorators": true in tsconfig.json.

๐ŸŽฏ One-Liner

โ€œDecorators add metadata to classes/members โ€” useful in frameworks like NestJS, but still experimental in TS.โ€


2. ๐Ÿ“œ Type Annotations in JavaScript (TC39 Proposal)

Definition:
JavaScript itself may gain type syntax (stripped at runtime).

โœ… Example (future JS)

function add(a: number, b: number): number {
  return a + b;
}
Enter fullscreen mode Exit fullscreen mode
  • Types would be ignored at runtime, like TS today.
  • TS would align with native JS type syntax.

๐ŸŽฏ One-Liner

โ€œJS is moving toward built-in type annotations. TS will align, making gradual adoption easier.โ€


3. โš–๏ธ TypeScript vs Flow vs Others

โœ… TypeScript

  • Mainstream, broad ecosystem.
  • Stronger tooling, VSCode integration.

โœ… Flow (Meta)

  • Better type inference in theory.
  • Lost adoption due to ecosystem fragmentation.

โœ… Elm / ReasonML / PureScript

  • Stronger type systems, but niche.

๐ŸŽฏ One-Liner

โ€œTS won the ecosystem war โ€” Flow and others have niche uses, but TS dominates frontend and Node.โ€


4. ๐Ÿ†• New & Recent TS Features

โœ… satisfies Operator (TS 4.9)

const theme = {
  primary: "blue",
  secondary: "red"
} satisfies Record<string, string>;
Enter fullscreen mode Exit fullscreen mode
  • Ensures structure without widening values.

โœ… const Type Parameters (coming soon)

function tuple<const T extends string[]>(...args: T): T {
  return args;
}
const t = tuple("a", "b"); // type ["a", "b"]
Enter fullscreen mode Exit fullscreen mode

โœ… Variance Annotations (future)

  • Explicitly mark generics as in (contravariant) or out (covariant).

๐ŸŽฏ One-Liner

โ€œFeatures like satisfies and const generics improve precision without hacks โ€” future TS is about better inference + clarity.โ€


5. ๐Ÿ—๏ธ Migration Strategies

โœ… JS โ†’ TS

  • Enable allowJs + checkJs.
  • Rename .js โ†’ .ts gradually.
  • Add strict config (noImplicitAny, strictNullChecks).
  • Replace JSDoc with real types.

โœ… Flow โ†’ TS

  • Use codemods (flow-to-ts).
  • Incrementally replace types.

โœ… Legacy TS โ†’ Modern

  • Remove namespace in favor of ES modules.
  • Switch to strict mode.
  • Replace /// <reference> with proper imports.

๐ŸŽฏ One-Liner

โ€œMigrate incrementally: JS โ†’ TS with checkJs, Flow โ†’ TS with codemods, legacy TS โ†’ strict modules.โ€


6. ๐Ÿข TypeScript at Scale

โœ… Observations

  • At very large scale (10M+ LOC), TS type-checking can bottleneck.
  • Some companies (Google, Meta) experiment with faster type-checkers (SWC, Rome, incremental builds).
  • Types become API contracts between teams โ€” not just safety.

๐ŸŽฏ One-Liner

โ€œAt scale, TypeScript types are contracts between teams. Performance requires project references + incremental builds.โ€


7. ๐Ÿ”ฎ Future of TypeScript

โœ… Trends

  • Closer alignment with JavaScript (native type annotations).
  • Better inference (const generics, variance).
  • Compiler performance improvements (Rust-based checkers like tsc-swc).
  • More runtime type-checking integration (Zod + TS).

๐ŸŽฏ One-Liner

โ€œThe future of TS is tighter JS integration, better inference, and faster compilers โ€” runtime validation will bridge static gaps.โ€


โœ… Summary (Full Handbook)

This TypeScript handbook covers staff/architect-level depth:

  • Fundamentals (type system vs runtime, primitives, assertions, narrowing, null checks, structural typing, interfaces vs types, enums vs literal types)
  • Advanced Types (unions, intersections, literals, const assertions, template literals, conditional, mapped, utility types, recursive types)
  • Generics (functions, constraints, defaults, keyof/indexed access, conditional generics, variance, HKTs, React generics)
  • Type Inference & Compatibility (inference, widening/narrowing, assignability, any vs unknown vs never, enums, tuples vs arrays)
  • JavaScript Interop (ambient declarations, @types, module augmentation, declaration merging, as const, tsconfig strictness, runtime validation, gradual migration)
  • Type Guards & Narrowing (typeof, instanceof, in-operator, discriminated unions, custom predicates, assertion functions, exhaustiveness checks)
  • Advanced Patterns (branded types, opaque types, recursive utilities, mapped utilities, variadic tuples, builder pattern, exact types, phantom types)
  • TypeScript in React (props, children, hooks, context, refs, HOCs, generic components, event handlers, polymorphic components)
  • Performance & Scaling (diagnostics, avoiding complex types, Babel/SWC vs tsc, incremental compilation, project references, import type, managing any, best practices)
  • Ecosystem & Future (decorators, JS type annotations proposal, TS vs Flow, new features like satisfies/const generics, migration strategies, TS at scale, future trends)

Top comments (0)