How can Lazy<T> be integrated into TypeScript?

While working in .NET, I came across the Lazy<T> type which proved to be very helpful for tasks like lazy loading and caching. However, when it comes to TypeScript, I couldn't find an equivalent solution so I decided to create 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 develop my own solution has raised some questions:

  • Is there an existing alternative that I may have overlooked in TypeScript?
  • Could there be any flaws in my approach to wanting a .NET-style Lazy<T> in TypeScript?

Answer №1

A class is not necessary in this scenario. By utilizing a function with a closure, you can achieve the desired functionality.

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

To use it, simply follow this format:

var lazyGreeting = createLazyValue(() => {
    console.debug("Factory function for greeting called");
    return "Greetings";
});

var lazyFarewell = createLazyValue(() => {
    console.debug("Factory function for farewell called");
    return "Farewell";
});

for(var count = 0; count < 4; count++) {
    console.debug(lazyGreeting());
    console.debug(lazyFarewell());
}

The factory function will only execute once, ensuring efficient performance.

Answer №2

To achieve this, you can easily define a Lazy<T> type that functions as a return value with type T. Here's an example:

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

After defining the Lazy<T> type, you have the option to create lazy data structures such as a LazyList implementation which can accommodate an infinite number of elements:

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

Here, the concept of null indicates an empty list.

Furthermore, you can develop a range function as follows:

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

This structure of the list resembles that found in Haskell, where each list follows a similar pattern.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

I desire for it to effortlessly unlock within my matmenu as soon as the webpage loads

Upon opening my page, I want the material menu to automatically open. However, since there is no click action, I am encountering an error stating that "trigger" is undefined. An error occurred: TypeError: Cannot read properties of undefined (reading &apo ...

Steer clear of using the non-null assertion operator while assigning object members

Looking for a practical method to assign object members to another object without using the non-null assertion operator "!". In the example below, consider that formData can be any JavaScript object. some.component.ts export class SomeComponent { someMo ...

Is there a way to create an interpolated string using a negative lookahead condition?

When analyzing my code for imports, I will specifically be searching for imports that do not end with -v3. Here are some examples: @ui/components <- this will match @ui/components/forms/field <- this will match @ui/components-v3 ...

There are zero assumptions to be made in Spec - Jasmine analyzing the callback function

I've encountered a challenge with a method that is triggered by a d3 timer. Each time the method runs, it emits an object containing several values. One of these values is meant to increase gradually over time. My goal is to create a test to verify wh ...

What could be the reason for receiving an HttpErrorResponse when making a GET request that returns byte data

When using these headers, the API returns byte data as a response. let headers = { headers: new HttpHeaders({ 'Content-Type': 'application/octet-stream', 'responseType':'arraybuffer' as 'js ...

Optimal method for accessing params and queryParams in Angular 2

Seeking insights on how to craft a route with information stored in its URL parameters. Here's an example of my route (app.routes.ts): {path: 'results/:id', component: MyResultsComponent}, How I navigate to the route : goToResultsPage(qu ...

Automatically assign the "Restricted" cursor to disabled fields within a dynamic form

Is there a method in Angular 6/7 that allows the cursor to change to "Not Allowed" when hovering over a disabled field in a reactive form? I prefer not to use CSS for this cursor change. Is there a way to achieve this through Angular alone? Currently, th ...

What is the correct way to implement Vue.use() with TypeScript?

I am trying to incorporate the Vuetify plugin into my TypeScript project. The documentation (available at this link) suggests using Vue.use(), but in TypeScript, I encounter the following error: "error TS2345: Argument of type '{}' is not assign ...

Having trouble showing table data in Angular

My goal is to showcase data from a table created using Spring-Boot Below is my model.ts: export class Quiz1 { QuestionId?: any; Question?: string; OptionsA?: string; OptionsB?: string; OptionsC?: string; OptionsD?: string;} He ...

The functionality of Angular/Typescript class.name appears to fail during a production build

Using Angular 5, I encountered an unusual problem with the class.name property. We have a TypeScript function as shown below: export class ApiService { public list<T>(c: new(values: Object)=> T) { var cname = c.name; .... } } When ...

Implementing unique behaviors based on data types in Typescript

I'm currently working on a React project where I need to showcase different types of articles, which I refer to as "Previews." These articles can be either text-based or contain images/videos. To handle this, I've defined two interfaces (TextPre ...

Ways to include a js configuration file within a TypeScript npm package that can be customized by future users of the package

In my current project, I am working on coding a Typescript NPM package designed to function as a CLI tool. To simplify things, let's imagine that this package will take the default export from a developer-created "config.js" file and display it in th ...

Executing a typescript class from a bash script: tips and tricks

Is it possible to invoke a TypeScript class and function from a bash script file? I have been unable to locate any relevant documentation on this topic. Below is the code snippet: TypeScript code: export class TestClass { constructor( public name ...

Unable to locate any NativeScript modules for tns-core-module/ui

I'm working on a {N}-Application and facing an issue with importing Images from the tns-core-modules/ui/image module. Unfortunately, it seems that the target cannot be found within the tns-core-module. This is my code snippet: import * as ImageModul ...

Error encountered during unit testing: The function _reactRouterDom.useHistory.mockReturnValue is not a valid function

I'm having trouble writing unit tests for a React component implemented in TypeScript. I encountered an error when trying to mock some hook functions. Here is my current unit test implementation: import React from 'react'; import { useHisto ...

MUI Gradient Tracked Button

Take a look at this Codepen example I created. It showcases a hover effect where the gradient follows the mouse cursor. In order to achieve this effect, I have defined two CSS variables - --x and --y, to keep track of the mouse position on the button. The ...

Exploring the wonders of Angular 2: Leveraging NgbModal for transclusion within

If I have a modal template structured like this: <div class="modal-header"> <h3 [innerHtml]="header"></h3> </div> <div class="modal-body"> <ng-content></ng-content> </div> <div class="modal-footer"& ...

Can someone please explain the result of console.log(error) and how can I convert it into a string?

Within a Node.js project that utilizes Typescript and is aimed at ES2020 compatibility, I have implemented a custom Error class in the following manner: class InvalidParamsError extends Error { } try { throw new InvalidParamsError(); } catch (error) { ...

How can I pass an array of string inputs into Vue 3?

Working with Vue 3, I'm setting up a form that will display text input fields corresponding to a fixed-length array of strings. Each field's v-model should connect to the respective string in the array. Here is my current code snippet for the vie ...

Break apart the string and transform each element in the array into a number or string using a more specific type inference

I am currently working on a function that has the ability to split a string using a specified separator and then convert the values in the resulting array to either strings or numbers based on the value of the convertTo property. Even when I call this fun ...