Typescript Snippets

Typescript Snippets


This document contains a collection of useful, interesting and sometimes quirky snippets of TypeScript I’ve gathered over the years. Some of these patterns are not unique to TypeScript, but in these examples they should be also type-safe (hopefully).

SQL Template String w/ Types




// Extract parameter name between {{ and }}
type ExtractParam<S extends string> = 
  S extends `${infer Param}}${infer _}` ? Param : never

// Recursively find all {{paramName}} patterns
type SQLParamsFromString<S extends string> = 
  S extends `${infer _}{{${infer Rest}`
    ? ExtractParam<Rest> | SQLParamsFromString<Rest>
    : never

function sqlQueryTemplate<SQLString extends string>(statement: SQLString) {
  return {
    prepare(queryParams: Record<SQLParamsFromString<SQLString>, string | number>) {
      let template = statement as string
      let params: string[] = []
      let paramIndex = 0
      
      // Replace {{paramName}} with actual values
      for (const [key, value] of Object.entries(queryParams)) {
        if (value === null || value === undefined || Number.isNaN(value)) continue
        template = template.replace(`{{${key}}}`, String(++paramIndex))
        params.push(String(value))
      }
      
      return {
        template,
        params
      }
    }
  }
}


const userQuery = sqlQueryTemplate('SELECT * FROM past_prompts WHERE user_id = {{userId}}')

const { template, params } = userQuery.prepare({
    userId: 123 // inferred!
}) 

Try it on the Typescript Playground!

Builder Pattern

The following snippet creates a typed object by progressively adding properties, this can be useful for defining different errors in an application.

CAVEAT: In order for the this in register() method to work correctly, the definition cannot use an arrow function.

type ErrorRegistry<T extends string> = Record<T, number> & {
  register<K extends string>(error: K, code: number): ErrorRegistry<K | T>
}

function createErrorRegistry<T extends string>(domain: T) {
  const errorRegistry = {
    register<K extends T>(error: K, code: number) {
      return {
        ...this,
        [error]: code,
      } as ErrorRegistry<T | K>
    },
  } as ErrorRegistry<T>
  return errorRegistry
}

const output = createErrorRegistry('app')
  .register('linking', 100)
  .register('billing', 200)
  .register('surface', 200) 

Typescript Playground Link

Branded Types

The following snippet defines a utility type Brand<any, string> which can be used to create an alias of an existing type, which is more strict than the original type.

declare const BrandSymbol: unique symbol

type Brand<T, Description extends string> = T & {
  [BrandSymbol]: Description
}

// example usage

type UserId = Brand<number, 'UserId'>

function trackUser(userId: UserId) {
  console.log('user:', userId)
}

const userOne = 123 as UserId
const userTwo = 123

trackUser(userOne) // ok
trackUser(userTwo) // error 

Typescript Playground Link

Monad*

The following is a monad-like type which has support for operatings over elements of an array, or the array itself.

/**
 * This class facilitates the chaining of operations on a value,
 * each task will either return a new Monad or MonadIterable.
 */
export class Monad<I> {
  constructor(public value: I) {}

  public pipe<O>(operation: (value: I) => O[]): MonadIterable<O[]>

  public pipe<O>(operation: (value: I) => O): Monad<O>

  public pipe<O>(operation: (value: I) => O): Monad<O> | MonadIterable<O[]> {
    const result = operation(this.value)
    return Array.isArray(result) ? new MonadIterable(result) : new Monad(result)
  }

  public print(label?: string): Monad<I> {
    console.log(`${label}:` ?? 'value:', this.value)
    return this
  }
}

/**
 * This is an extension of the Monad class that allows for operations
 * on iterable values. The reduce method will convert back to
 * a basic Monad.
 */
export class MonadIterable<I extends any[]> extends Monad<any> {
  public iterate<O>(
    operation: (value: I[number], index?: number, array?: I) => O
  ): MonadIterable<O[]> {
    return new MonadIterable(this.value.map(operation))
  }

  public filter<O>(
    operation: (value: I[number], index?: number, array?: I) => O
  ): MonadIterable<I> {
    return new MonadIterable(this.value.filter(operation))
  }

  public reduce<O>(
    operation: (prev: O, value: I[number], index?: number, array?: I) => O,
    initialValue: Partial<O> = {}
  ): Monad<O> {
    return new Monad(this.value.reduce(operation, initialValue))
  }

  /**
   * Converts an iterable monad back into a normal monad.
   */
  public combine<O>(operation: (value: I) => O): Monad<O> {
    return new Monad(operation(this.value))
  }
} 

Try it on the TypeScript playground!

Define Class via Enum (WIP)

NOTE: This has only been tested on TypeScript 5.4.5 and is still expiramental, see here for example.

This allows us to define an enum which will auto-magically be created into a class definition, and then extended. This is great for a simple ORM with SQLite!

// SPECIAL TYPES

type EnumClass<T> = {
  new (...args: any[]): T
}

type Writeable<T> = { -readonly [P in keyof T]: T[P] }

type EnumProps<T> = {
  [key in keyof T]: number | string | boolean | Date
}

// THE MAGIC

namespace Class {
  export function classFromEnum<E, T>(enumSchema: E): EnumClass<T> {
    return class {
      constructor(args: EnumProps<E>) {
        let hiddenState: EnumProps<E> = Object.assign({}, args)

        for (const property in enumSchema) {
          console.log(`defining property ${property}`)

          Object.defineProperty(this, property, {
            enumerable: true,
            configurable: true,
            writable: true,
            get value() {
              return hiddenState[property]
            },
            set value(nextValue) {
              hiddenState[property] = nextValue
            },
          })
        }
      }
    } as {
      new (args: EnumProps<E>): T
    }
  }
}

// EXAMPLE UASGES

enum UserSchema {
  userId = 'INTEGER NON NULL',
  firstName = 'TEXT NON NULL',
  lastName = 'TEXT NON NULL',
}

type SchemaBinding = {
  userId: number
  firstName: string
  lastName: string
}

class User extends Class.classFromEnum<typeof UserSchema, SchemaBinding>(
  UserSchema
) {
  setName(fullName: string) {
    const [firstName, lastName] = fullName.split(' ')
    this.firstName = firstName
    this.lastName = lastName
  }
}

const myUser = new User({
  userId: 123,
  firstName: 'Bob',
  lastName: 'Smitch',
  extra: true,
})

myUser.setName('Colin Teahan')

console.log(myUser.firstName) // Colin 

Try it on the TypeScript Playground

WebGPU Example

declare interface Navigator {
    gpu: {
        requestAdapter: () => any
    }
}

async function computeHashesGPU(n: number) {
  if (!navigator.gpu) throw new Error('WebGPU not supported');
  
  const adapter = await navigator.gpu.requestAdapter();
  const device = await adapter!.requestDevice();

  // Shader that does the computation
  const shaderCode = `
    @group(0) @binding(0) var<storage, read_write> output: array<f32>;
    
    @compute @workgroup_size(256)
    fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
      let idx = global_id.x;
      if (idx >= ${n}u) { return; }
      
      // Simulate your hash computation
      var value = f32(idx);
      for (var i = 0u; i < 10u; i = i + 1u) {
        value = sin(value * 2.718281828);
      }
      output[idx] = value;
    }
  `;

  const shaderModule = device.createShaderModule({ code: shaderCode });
  
  // Create buffer for results
  const bufferSize = n * 4; // f32 = 4 bytes
  const buffer = device.createBuffer({
    size: bufferSize,
    usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC
  });

  const pipeline = device.createComputePipeline({
    layout: 'auto',
    compute: { module: shaderModule, entryPoint: 'main' }
  });

  const bindGroup = device.createBindGroup({
    layout: pipeline.getBindGroupLayout(0),
    entries: [{ binding: 0, resource: { buffer } }]
  });

  const commandEncoder = device.createCommandEncoder();
  const passEncoder = commandEncoder.beginComputePass();
  passEncoder.setPipeline(pipeline);
  passEncoder.setBindGroup(0, bindGroup);
  passEncoder.dispatchWorkgroups(Math.ceil(n / 256));
  passEncoder.end();
  
  device.queue.submit([commandEncoder.finish()]);
  await device.queue.onSubmittedWorkDone();
}

async function mainGPU() {
  const start = performance.now();
  await Promise.all([
    computeHashesGPU(1_000_000),
    computeHashesGPU(1_000_000),
    computeHashesGPU(1_000_000),
    computeHashesGPU(1_000_000)
  ]);
  console.log('GPU time:', (performance.now() - start) / 1000, 's');
}


mainGPU() 

Try it on the Typescript Playground!

Scope (Tree)


interface ScopeCtx {
    registry: FinalizationRegistry<string>
}

interface Scope {
    isGlobal: boolean
    label: string
    path: string
    children: WeakRef<Scope>[],
    create(label: string): Scope
    [Symbol.iterator](): IterableIterator<Scope>
    [Symbol.dispose](): void
}

function createGlobalScope() {
    const globalRef = createScope.call({ 
        registry: new FinalizationRegistry<string>((scopePath) => {
            console.log('cleanup called:', scopePath)
        })
    })
    return globalRef
}

function createScope(this: ScopeCtx): Scope {
    let ctx = this
    return {
        label: 'global',
        path: '/',
        children: [],
        get isGlobal() {
            return this.path === '/'
        },
        create(label: string) {
            const child = createScope.call(ctx)
            child.path = this.path + label + '/'
            child.label = label
            const childRef = new WeakRef(child)
            this.children.push(childRef)
            ctx.registry.register(childRef, child.path)
            return child
        },
        *[Symbol.iterator]() {
            yield this
            for (const child of this.children) {
                const childRef = child.deref()
                if (!childRef) continue
                yield* childRef
            }
        },
        [Symbol.dispose]() {
            console.log(`disposed:`, this.label)
        }
    }
}



const globalScope = createGlobalScope()
const scopeA = globalScope.create('a')
const scopeB = globalScope.create('b')
const scopeC = globalScope.create('c')
const scopeD = scopeB.create('d').create('e').create('f')
const scopeG = globalScope.create('g')

{
    using disposedScope = scopeD.create('f_2').globalScope.create('f_3').create('f_4')
}

for (const scope of globalScope) {
    console.log(scope.label)
}

setTimeout(() => {
    console.log('program done')
}, 5_000) 

Try it on the Typescript Playground!

Streams


declare const StreamBrand: unique symbol

type Ints = Uint8Array<ArrayBufferLike>
type StreamableStatus = 'init' | 'open' | 'closed'
type StreamId = string & {
    [StreamBrand]: 'v1'
}

function createId() {
    const random = crypto.getRandomValues(new Uint8Array(8))
    const idString = Array.from(random).map((item) => item.toString(36)).join('')
    return idString as StreamId
}

function id(idString: string | StreamId): StreamId {
    return idString as StreamId
}


class ChildStream extends ReadableStream<Ints> {
    public controller?: ReadableStreamDefaultController

    get connected() {
        return Boolean(this.controller)
    }

    constructor(public cleanup: () => void) {
        super({
            start: (controller) => {
                this.controller = controller
            },
            cancel: () => {
                this.controller = undefined
                this.cleanup()
            }
        })
    }

    public enqueue(chunk: Ints) {
        this.controller?.enqueue(chunk)
    }

    public close() {
        this.controller?.close()
    }
}


class Streamable {
    private writable: WritableStream<Ints>
    private children: (ChildStream|null)[] = []
    private writeQueue = Promise.resolve()

    private state = {
        status: 'init' as StreamableStatus
    }

    get status() {
        return this.state.status
    }

    get count() {
        return this.children.length
    }


    constructor(
        public readonly id: StreamId
    ) {
        this.writable = new WritableStream({
            start: () => {
                this.state.status = 'open'
            },
            write: (chunk) => {
                for (const childStream of this.children) {
                    if (!childStream) continue
                    childStream.enqueue(chunk)
                }
            },
            close: () => {
                this.state.status = 'closed'
            }
        })
    }

    public subscribe(): ChildStream {
        const child = new ChildStream(() => {
            const idx = this.children.findIndex((stream) => Object.is(stream, child))
            if (idx !== -1) {
                this.children[idx] = null
            }
        })
        this.children.push(child)
        return child
    }

    public close(): void {
        try {
            if (this.status !== 'open') return console.warn('stream already closed!')
            this.state.status = 'closed'
            this.children.forEach((child) => child?.close())
            this.writable.abort('closed')
        } catch (e) {
            console.warn(e)
        } finally {
            this.children.length = 0
        }
    }

    async transaction(operation: (
        writer: WritableStreamDefaultWriter<Ints>
    ) => Promise<void>) {
        await this.writeQueue
        const writer = this.writable.getWriter()
        try {
            await operation(writer)
        } finally {
            writer.releaseLock()
        }
    }

    async bytes(chunk: Ints) {
        const promise = await this.transaction((writer) => writer.write(chunk))
        this.writeQueue = this.writeQueue.then(() => promise).catch((e) => console.warn(e))
    }
}




class Streams {
    public readonly items = new Map<StreamId, WeakRef<Streamable>>()

    public readonly defer = new FinalizationRegistry((streamIdRef: StreamId) => {
        if (!this.items.has(streamIdRef)) return console.warn('[cleanup] key not found:', streamIdRef)
        const streamRef = this.get(streamIdRef)
        streamRef?.close()
        this.items.delete(streamIdRef)
    })

    get size() {
        return this.items.size
    }

    public has(id: StreamId): boolean;
    public has(stream: Streamable): boolean;
    public has(key: StreamId | Streamable): boolean {
        if (typeof key === 'string') return Boolean(this.get(key))
        if (typeof key === 'object' && 'id' in key) {
            return Boolean(this.get(key.id))
        }
        return false
    }

    public get(streamId: StreamId): Streamable | undefined {
        return this.items.get(streamId)?.deref?.()
    }

    public ref(stream: Streamable): WeakRef<Streamable> {
        const weakRef = new WeakRef(stream)
        this.defer.register(stream, stream.id, weakRef)
        return weakRef
    }

    public add(stream: Streamable): void {
        const streamRef = this.ref(stream)
        this.items.set(stream.id, streamRef)
    }

    public delete(streamId: string | StreamId) {
        return this.items.delete(streamId as StreamId)
    }

    *[Symbol.iterator](): Generator<Streamable> {
        for (const [_id, streamRef] of this.items) {
            const stream = streamRef.deref?.()
            if (!stream) continue
            yield stream
        }
    }
}


function resp(stream: Streamable) {
    return new Response(stream.subscribe(), {
        status: 200,
        headers: {
            'Content-Type': 'text/event-stream'
        } 
    })
}


async function GET(ctx: { url: URL; streams: Streams }): Promise<Response> {
    const id = ctx.url.pathname.slice(1) as StreamId

    // if stream exists, clone and send response
    if (ctx.streams.has(id)) {
        const stream = ctx.streams.get(id)!
        return resp(stream)
    }

    // otherwise, create a new instance
    const stream = new Streamable(id)
    ctx.streams.add(stream)
    return resp(stream)
}
declare const StreamBrand: unique symbol

type Ints = Uint8Array<ArrayBufferLike>
type StreamableStatus = 'init' | 'open' | 'closed'
type StreamId = string & {
    [StreamBrand]: 'v1'
}

function createId() {
    const random = crypto.getRandomValues(new Uint8Array(8))
    const idString = Array.from(random).map((item) => item.toString(36)).join('')
    return idString as StreamId
}

function id(idString: string | StreamId): StreamId {
    return idString as StreamId
}


class ChildStream extends ReadableStream<Ints> {
    public controller?: ReadableStreamDefaultController

    get connected() {
        return Boolean(this.controller)
    }

    constructor(public cleanup: () => void) {
        super({
            start: (controller) => {
                this.controller = controller
            },
            cancel: () => {
                this.controller = undefined
                this.cleanup()
            }
        })
    }

    public enqueue(chunk: Ints) {
        this.controller?.enqueue(chunk)
    }

    public close() {
        this.controller?.close()
    }
}


class Streamable {
    private writable: WritableStream<Ints>
    private children: (ChildStream|null)[] = []
    private writeQueue = Promise.resolve()

    private state = {
        status: 'init' as StreamableStatus
    }

    get status() {
        return this.state.status
    }

    get count() {
        return this.children.length
    }


    constructor(
        public readonly id: StreamId
    ) {
        this.writable = new WritableStream({
            start: () => {
                this.state.status = 'open'
            },
            write: (chunk) => {
                for (const childStream of this.children) {
                    if (!childStream) continue
                    childStream.enqueue(chunk)
                }
            },
            close: () => {
                this.state.status = 'closed'
            }
        })
    }

    public subscribe(): ChildStream {
        const child = new ChildStream(() => {
            const idx = this.children.findIndex((stream) => Object.is(stream, child))
            if (idx !== -1) {
                this.children[idx] = null
            }
        })
        this.children.push(child)
        return child
    }

    public close(): void {
        try {
            if (this.status !== 'open') return console.warn('stream already closed!')
            this.state.status = 'closed'
            this.children.forEach((child) => child?.close())
            this.writable.abort('closed')
        } catch (e) {
            console.warn(e)
        } finally {
            this.children.length = 0
        }
    }

    async transaction(operation: (
        writer: WritableStreamDefaultWriter<Ints>
    ) => Promise<void>) {
        await this.writeQueue
        const writer = this.writable.getWriter()
        try {
            await operation(writer)
        } finally {
            writer.releaseLock()
        }
    }

    async bytes(chunk: Ints) {
        const promise = await this.transaction((writer) => writer.write(chunk))
        this.writeQueue = this.writeQueue.then(() => promise).catch((e) => console.warn(e))
    }
}




class Streams {
    public readonly items = new Map<StreamId, WeakRef<Streamable>>()

    public readonly defer = new FinalizationRegistry((streamIdRef: StreamId) => {
        if (!this.items.has(streamIdRef)) return console.warn('[cleanup] key not found:', streamIdRef)
        const streamRef = this.get(streamIdRef)
        streamRef?.close()
        this.items.delete(streamIdRef)
    })

    get size() {
        return this.items.size
    }

    public has(id: StreamId): boolean;
    public has(stream: Streamable): boolean;
    public has(key: StreamId | Streamable): boolean {
        if (typeof key === 'string') return Boolean(this.get(key))
        if (typeof key === 'object' && 'id' in key) {
            return Boolean(this.get(key.id))
        }
        return false
    }

    public get(streamId: StreamId): Streamable | undefined {
        return this.items.get(streamId)?.deref?.()
    }

    public ref(stream: Streamable): WeakRef<Streamable> {
        const weakRef = new WeakRef(stream)
        this.defer.register(stream, stream.id, weakRef)
        return weakRef
    }

    public add(stream: Streamable): void {
        const streamRef = this.ref(stream)
        this.items.set(stream.id, streamRef)
    }

    public delete(streamId: string | StreamId) {
        return this.items.delete(streamId as StreamId)
    }

    *[Symbol.iterator](): Generator<Streamable> {
        for (const [_id, streamRef] of this.items) {
            const stream = streamRef.deref?.()
            if (!stream) continue
            yield stream
        }
    }
}


function resp(stream: Streamable) {
    return new Response(stream.subscribe(), {
        status: 200,
        headers: {
            'Content-Type': 'text/event-stream'
        } 
    })
}


async function GET(ctx: { url: URL; streams: Streams }): Promise<Response> {
    const id = ctx.url.pathname.slice(1) as StreamId

    // if stream exists, clone and send response
    if (ctx.streams.has(id)) {
        const stream = ctx.streams.get(id)!
        return resp(stream)
    }

    // otherwise, create a new instance
    const stream = new Streamable(id)
    ctx.streams.add(stream)
    return resp(stream)
} 

Try it on the TypeScript Playground!

Others…