Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing Lazy<T> in TypeScript?

Tags:

typescript

In .NET, there is the Lazy<T> type which for example is useful for implementing lazy loading and caching. I'm unaware of an equivalent solution for TypeScript, so I rolled my own.

export interface Factory<TResult> { () : TResult; }

export class Lazy<T> {
    factoryOutput : T;
    isValueSet : boolean;

    constructor(private factory : Factory<T>) { }    

    get value() {
        if (!this.isValueSet) {
            this.factoryOutput = this.factory();
            this.isValueSet = true;
        }
        return this.factoryOutput;
    }
}

Having to implement it myself makes me wonder:

  • Am I overlooking an existing solution for TypeScript?
  • Is there something fundamentally wrong with my reasoning wanting to have a .NET styled Lazy<T> in TypeScript?
like image 915
Rob Wijkstra Avatar asked Sep 13 '25 01:09

Rob Wijkstra


2 Answers

You don't need a class. You can just use a function with a closure.

function lazy<T>(factory: () => NonNullable<T>) {
    let value: T | undefined;
    return () => value ?? (value = factory());
}

Use it like this:

var lazyHello = lazy(() => {
    console.debug("hello factory called");
    return "hello";
});

var lazyWorld = lazy(() => {
    console.debug("world factory called");
    return "world";
});

for(var counter = 0; counter < 5; counter++) {
    console.debug(lazyHello());
    console.debug(lazyWorld());
}

The factory will only be called once.

like image 135
John Mills Avatar answered Sep 15 '25 15:09

John Mills


This can be simply done by declaring a Lazy<T> type as a function return a value with type T, like this:

type Lazy<T> = () => T;

You can then continue to implement lazy data types, this could be a LazyList implementation (supporting an infinite amount of elements):

type LazyList<T> = {
   head: Lazy<T>,
   tail: Lazy<LazyList<T>>
} | null

where null represents an empty list.

Then you can create a range function:

function range(min: number = 0, max: number = Infinity) {
   if (max <= min) return null;
   else return {
      head: () => head;
      tail: () => range(min+1, max);
   }
}

This list type is similar to the one in Haskell, where every list is structured like this.

like image 25
leo848 Avatar answered Sep 15 '25 16:09

leo848