Programming TypeScript: Making Your JavaScript Applications Scale

Technical Books
In Progress
Author

Tyler Hillery

Published

September 1, 2025


Notes

TODO

What does “downlevel compiler” mean?

Typing Call

function call<T extends unknown[], U>(
    f: (...args: T) => U,
    ...args: T
): U

function add(a: number, b: number): number {
    return a + b
}

call(add, 1, 2)     // 3
call(add, 1, "2")   // type error: argument of type 'string' is not assignable to parameter of type 'number'.
call(add, 1)        // type error:Expected 3 arguments, but got 2
call(add, 1, 2, 3)  // type error Expected 3 arguments, but got 4

Typing Map

function map<T, U>(arr: T[], cb: (item: T, index: number, arr: T[]) => U): U[] {
  const result =  [];
  for (let i = 0; i < arr.length; i++) {
      result.push(cb(arr[i], i, arr));
  }
  return result
}

const myArray = [1,2,3];
const doubled = map(myArray, (num) => num * 2);         // inferred result: number[]
const strings = map(myArray, (num) => num.toString());  // inferred result: string[]

Typing Mixins

type Constructor<T> = new (...args: any[]) => T

function withEzDebug<C extends Constructor<{getDebugValue: () => object}>>(
    Class: C
) {
    return class extends Class {
        debug() {
            const name = Class.name; // I believe the book is wrong here they had Class.constructor.name which returned Function 
            const value = this.getDebugValue(); 
            return `${name}(${JSON.stringify(value)})`
        }
    }
}

class HardToDebugUser {
    #id: number;
    #firstName: string;
    #lastName: string

    constructor(id: number, firstName: string, lastName: string) {
        this.#id = id;
        this.#firstName = firstName;
        this.#lastName = lastName;
    }

    getDebugValue() {
        return {
            id: this.#id,
            name: `${this.#firstName} ${this.#lastName}`
        }
    }
}

const User = withEzDebug(HardToDebugUser);
let user = new User(1, "Tyler", "Hillery");
console.log(user.debug()); // "HardToDebugUser({"id":1,"name":"Tyler Hillery"})"

Review

Man I thought the author has lots of great content about TypeScript itself but I wasn’t the biggest fan their writing style. I appreciate them trying to make a technical book a more fun read by adding some humor but the jokes didn’t land for me. I also felt there many ways the author imposed their opinion rather than just describing the facts. Author said you should use ORMs in all places as raw sql is not type safe. Author easily could have shown the difference between using raw SQL vs ORM and let the reading come to conclusion if the benefits provided by the ORM are worth it (I have nothing against ORMs, just illustrating a point).

Another major section left out was the use of run time validation libraries like Zod that I think would have been a helpful addition. The author mentions using typed protocols like Swagger, gRPC etc. but what if you’re communicating with API that doesn’t implement one of these protocols? How can you go about validating at runtime that data you get is what you expect. I like doing this even when consuming things like OpenAPI specs because the server implementation can often be wrong.

With that said I thought the author showed some very examples, in particular I liked learning how to properly type an event emitter.

I still would recommend the book for those thing to get quickly up to speed with TypeScript.