TypeScript patterns: Lazy

by DotNetNerd 12. July 2017 08:48

I have been working with TypeScript for quite a while now, and I really enjoy how the strong typing enables better tooling, as well as more understandable code, where the patterns of old look more like themselves, than they do in plain JavaScript. With the adoptation that TypeScript has seen in the last couple of years, I think it is safe to say that it is a good bet going forward, so if you are not already on board I highly recommend it. I will bet your time is better spent with languages and patterns, than they are learning the framework flavour of the day – although they do in themselves provide inspiration for patterns.

Getting lazy

A simple pattern that I like to use is the good old Lazy pattern – and what is more fitting for a blogpost in this vacation time. It is a pattern that is well suited for initialization of stuff you only want to create or query once, and that you may not need right away. Client-side this could be complex services that are resource intensive or simply for providing access to an element that may not be needed or that is loaded at a later time.

A concrete example of that latter could be an accessor that you wish to declare once for a widget that is loaded asynchronously - so it is not loaded right away, but will be available before user interactions can affect it.

One way of implementing the pattern could look as simple as this.

export interface ILazyInitializer<T> {
    (): T
}

export class Lazy<T> {
    private instance: T = null;
    private initializer: ILazyInitializer<T>;
 
    constructor(initializer: ILazyInitializer<T>) {
        this.initializer = initializer;
    }
 
    public get value(): T {
        if (this.instance == null) {
            this.instance = this.initializer();
        }
 
        return this.instance;
    }
}

With this in place we can create a lazy type like this new Lazy(() => “My lazy value”);

I sometimes use this for fields that provide access to elements that are loaded asynchronously. If for instance I have a form that is rendered by a widget on the client and I at some point need to access the name field I could have a field like this in my widget.

export class MyWidget {
    private name: Lazy<HTMLInputElement>;

    constructor() {
        this.name = new Lazy(() => <HTMLInputElement>document.querySelector('#name'));
        ...
    }

    private onClick() {
        this.name.value.value = 'Christian';
    }
}

In some solutions this is needed very often, so it could make sence to wrap it as a function and make it look a little nicer and more functional like so.

export module Dom {
    export function query<T>(selector: string): Lazy<T> {
       return new Lazy(() => <T><any>document.querySelector('#name'));
    }   
}

Allowing you to simply write.

this.name = Dom.query<HTMLInputElement>('#name');

Of course, this is just one way of using the pattern, but I often find that it can help me when I want to structure my code a certain way, and don’t want my hand forced by the order elements are loaded.

Who am I?

My name is Christian Holm Diget, and I work as an independent consultant, in Denmark, where I write code, give advice on architecture and help with training. On the side I get to do a bit of speaking and help with miscellaneous community events.

Some of my primary focus areas are code quality, programming languages and using new technologies to provide value.

Microsoft Certified Professional Developer

Microsoft Most Valuable Professional

Month List