FuryStack

Bye-bye extension methods

Using extension methods was fun at the beginning but I've ran into more and more problems with them

The Heritage from C#

It’s not a big sectet that one of the main inspiration for FuryStack is the .NET (legacy and Core) stack where extension methods are quite common. The same can achieved in the JS world where everything is possible, every prototype can be hacked and it can be also type-safe.

The Problem

The main problem in short that extending another module is not officially supported by Typescript - however the type system can be hacked like it was in FuryStack and as you can see in the following example:

import { Injector } from '@furystack/inject/dist/injector';

declare module '@furystack/inject/dist/injector' {
  export interface Injector {
    /**
     *  returns the current authorization status from the identity context
     */
    isAuthorized: (...roles: string[]) => Promise<boolean>;
  }
}

Injector.prototype.isAuthorized = async function (...roles) {
  return this.getInstance(IdentityContext).isAuthorized(...roles);
};

/** ...and the usage */

import '../path-to-my-extension';

const result = await injector.isAuthorized('admin');

…well, it works but I’ve ran into unexpected issues with conflicting import declarations and overrides. The problems appeared random, but somewhat based on the running context (ts-node, jest, browser) and it started to block dependency upgrades…

How it works now

The extensions has been replaced by helpers, as you can see in the following example. These helpers are simple shortcuts - you should usually pass the injector (or the related manager class) to them as a parameter. The imports are clear, as well as the execution path and the types.

import { isAuthorized } from '@furystack/core';

const result = await isAuthorized(injector, 'admin');

For more details, you can check out this commit.