Reducing Boilerplate with TagExt for TypeScript

How do we feel about this for reducing some boilerplate for tags?

type Foo = Readonly<{
  make: () => 'foo';
}>;

const Foo = TagExt.make<Foo>('@api/foo');
//    ^? Context.TagClass<symbol, string, Readonly<{
//         make: () => 'foo';
//       }>>

With the impl of TagExt looking like this:

declare const RequiredTypeArgumentSymbol: unique symbol;

function make<T = typeof RequiredTypeArgumentSymbol>(
  name: string,
  ..._: T extends typeof RequiredTypeArgumentSymbol
    ? ['Type argument is required', never]
    : []
): Context.TagClass<symbol, string, T> {
  const typeId: symbol = Symbol.for(name);

  return Context.Tag(name)<typeof typeId, T>();
}

export const TagExt = {
  make,
};
Was this page helpful?