Web Development

Oh TypeScript!!!

I’ve written before about the weirdness of TypeScript and instance functions of classes.

To summarise. Let’s say we’re using map on an array of strings, and we therefore need to give it a function (item: string) => Something – and maybe we have a SomethingFactory which can use its internal state to make our things from the item:

export default class SomethingFactory {

    private recipes: Map<string, Recipe>;

    ...

    public createSomething(recipeName: string): Something {

       // use the recipes to create a Something
    }

}

So far, this seems reasonable. The abstract example is easier than the details of a real-world example. However, let’s imagine that we’re using this to load records from a web service, or produce objects from a template or whatever.

The calling code for this might look like this:

<

>const somethingFactory: SomethingFactory = …;

// type not needed here, but included for clarity
const list: string[] = [ ‘first’, ‘second’, ‘third’ ];

const converted: Something[] = list.map((item) =>
  somethingFactory.createSomething(item));

The above works. However, with my use function references, rather than write functions to call functions hat on, it also looks inefficient. Can’t we instead use:

// as createSomething IS a function, can't we just reference it?
const converted: Something[] = list.map(somethingFactory.createSomething);

No.

For reasons that I don’t entirely get, the function as declared this way doesn’t directly imply the this that you need for it to refer to the internal state of the class. This is essentially a static reference to an instance function.

Boy that’s annoying.

But then I realised something accidentally while creating some helper code recently. Let’s look at what happens if we treat the function as a field of the object, rather than a method on it. This shouldn’t make sense.

public get createSomething(): (recipeName: string) => Something {
   return (recipeName: string) => {
       // use the recipes to create a Something
   };
}

Looks harder doesn’t it?

It made sense when I wrote it in my particular object, which was a test helper that was trying to provide a function to simulate some other part of the system. I needed to get a function, and this getter made sense. Let’s see how we can use it.

Can I call it?

// this does a GET and then an invocation on the
// returned function
somethingFactory.createSomething('foo');

Oh. That looks… kinda normal…

Can I use it with map?

const items = list.map(somethingFactory.createSomething);

That works too… this is because the this is essentially being baked into the ad-hoc function object that’s returned when we invoke the getter using the syntactic sugar of somethingFactory.<getter>.

Something somewhere is clunky, but if you follow this pattern, you end up with an object that you can use the way your instincts might like to use it. That said, I wonder whether the runtime efficiency of this second model is worse than the first. We probably shouldn’t worry about it.

In the class-native form, I suspect the transpiler/runtime is inserting a this binding into the invocation behind the scenes. In the second form, we’ve got a factory method creating an ad-hoc function, we’ve ALSO got a this binding when we use the getter… it may well be less efficient.

However, if runtime performance is an issue, the optimisations would probably not land on one of these.

Will I be Doing This in Future?

No. It’s too weird and it lends itself to surprise when two forms of the function operate differently depending on whether someone’s done the trick.

Published on Java Code Geeks with permission by Ashley Frieze, partner at our JCG program. See the original article here: Oh TypeScript!!!

Opinions expressed by Java Code Geeks contributors are their own.

Ashley Frieze

Software developer, stand-up comedian, musician, writer, jolly big cheer-monkey, skeptical thinker, Doctor Who fan, lover of fine sounds
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
javmagnet
1 year ago

this book is very good!

Back to top button