Visitor Design Pattern Notes

Visitor classes are commonly used to perform operations on a set of objects without modifying the structure of their underlying classes.

Visitor Design Pattern allows you to add new operations(behaviours) via Visitor classes to existing classes without modifying their structure. Instead of adding the operation within the existing class, you create a visitor class named as operation you want to have in existing class, so that the operation is externalised from a set of objects without modifying the structure of their underlying classes.

Visitor Design Pattern is more about adding new operations to existing classes via Visitor classes without modifying their structure, rather than adding new fields or methods directly to the classes themselves.

Consider a system where you have a hierarchy of classes representing different shapes, like Circle, Rectangle, and Triangle. Each of these shapes implements Visitable interface(or its equivalent) to allow visitor classes to operate on them.

Continue reading

TypeScript const assertions vs satisfies operator

I compare as const assertions and satisfies operator in this post.

as const comes with TypeScript 3.4 and generates literal values for more precise and type-safe code.

satisfies comes with TypeScript 4.9 and generates more specific type and validates given object type so that it can catch possible error.

Notice that as const generates a type with readonly fields. So it is an immutable type.

Use case

Notice that satisfies just generates a type from palette object. As you can see below code, red field type is [number, number, number]

As you can see below code, red field type became string instead of [number, number, number]

Use case

satisfies operator catches unlisted field name usage, or wrong field type.

TypeScript const modifier on type parameters

It is a really good feature coming with TypeScript 5.0. We could infer type of object as general as shown in line 8 in below code, so, to infer more-specific type, we had to add as const as shown in line 11.

TypeScript 5.0 makes it easier with adding const in front of type parameter declaration in line 13 in below code.

Use case

Assume that Person type has hobbies , and i just want to infer passed values from hobbies field.

TypeScript Union Type and Distributive Conditional Types Part 2

I show the reason Distributive Conditional Type needs to be used for Union Type in this post.

If generic type T is passed as Union Type like string | number, then array item will be Union Type as below.

If you need to iterate on each type in Union Type, then Distributive Conditional Type (with extends keywod) needs to be used.

To avoid distributive behaviour in Distibutive Conditional Type, surround each side of extends keyword with square brackets.

Continue reading

TypeScript Recursive Type

Below two code blocks are doing same job and the only difference is below second code block uses variadic tuple. Check the below links for more details.

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#more-recursive-type-aliases

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-1.html#recursive-conditional-types

type CompareLength<Left extends any[], Right extends any[]> =
    Left['length'] extends Right['length'] ? 'equal' :
    Left extends [] ? 'shorterLeft' :
    Right extends [] ? 'shorterRight' :
    ((..._: Left) => any) extends ((_: any, ..._1: infer LeftRest) => any) ?
    ((..._: Right) => any) extends ((_: any, ..._1: infer RightRest) => any) ?
    CompareLength<LeftRest, RightRest> :
    never :
    never;

type T1 = CompareLength<[firstName: string], [lastName: string]>;

type T2 = CompareLength<[firstName: string], [lastName: string, age: number]>;

type T3 = CompareLength<[firstName: string, age: number], [lastName: string]>;
type CompareLength<Left extends any[], Right extends any[]> =
    Left['length'] extends Right['length'] ? 'equal' :
    Left extends [] ? 'shorterLeft' :
    Right extends [] ? 'shorterRight' :
    Left extends [any, ...infer L] ? 
    Right extends [any, ...infer R] ? 
    CompareLength<L, R> :
    never :
    never;

type T1 = CompareLength<[firstName: string], [lastName: string]>;

type T2 = CompareLength<[firstName: string], [lastName: string, age: number]>;

type T3 = CompareLength<[firstName: string, age: number], [lastName: string]>;

TypeScript Exhaustiveness Checking Part 2

type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";

const sendRequest = (url: string, method: HttpMethod) => {
    switch (method) {
        case 'DELETE':

            break;
        case 'GET':

            break;
        case 'POST':

            break;
        case 'PUT':

            break;
        default:
            const exhaustiveCheck: never = method; // ✅ no error
            throw new Error(`Unhandled case: ${exhaustiveCheck}`);
    }
};
type Fruit = 'banana' | 'orange' | 'mango';

function exhaustiveCheck(param: never): never {
    throw new Error('should not reach here')
}

function makeDessert(fruit: Fruit) {
    switch (fruit) {
        case 'banana': return 'Banana Shake'
        case 'orange': return 'Orange Juice'
    }
    exhaustiveCheck(fruit) // 🚫 ERROR! `mango` is not assignable
}
Continue reading

TypeScript Exhaustiveness Checking

Exhaustiveness checking is a good feature when you use switch block. Assume that you need to check a value of variable which data type is union type as shown below screenshot.

Shape is a discriminated union which consists of three types named Circle, Square and Triangle.

kind field is shared in Circle, Square and Triangle types so that if developer forgets to use any of kind field value in switch block, TypeScript will error in coding-time.

Notice that there is a red line in line 347, it is due to missing triangle case in switch block.

This is the error shown in the code.

After adding triangle case in line 346, the error disappeared.

Continue reading