Dynamically assigning a function name in javascript

tmikeschu

Mike Schutte

Posted on January 16, 2021

Dynamically assigning a function name in javascript

Say you're writing some higher order functions that return other functions. In my case it was a utility that creates a typed hook to consume some context.

I wanted to let the consumer of this utility to have a reasonable name property on the hook returned, not some generic library code name like "useContext".

The first attempt did not work.



const someFunc = () => { ... }
someFunc.name = someConfig.name


Enter fullscreen mode Exit fullscreen mode

You get a nice error at least.

Cannot change read only name error

So then I think to myself 🤔 Do I know anything about dynamic naming in general in JavaScript?

💡

Objects can have dynamic keys! With square brackets, we can stringify runtime values.



{ [someVar]: "woohoo" }


Enter fullscreen mode Exit fullscreen mode

So, to solve my configurable function name problem, I used computed keys to create an object and computed keys again to destructure the function value.

🤯 Right?



const custom = "Jerome"
const { [custom]: someFunc } = { [custom]: () => void 0 }
someFunc.name === "Jerome" // true


Enter fullscreen mode Exit fullscreen mode

^ You can try that example in your browser console.

Pretty neat stuff! Here was my final solution, inspired by this cheatsheet.



import * as React from 'react';

export function assertContext<T>(
  context: T | undefined,
  config: {
    hookName: string;
    providerName: string;
  },
): asserts context is T {
  if (typeof context === 'undefined') {
    throw new Error(`\`${config.hookName}\` must be used within \`<${config.providerName} />\``);
  }
}

export function createUsableContext<T>(config: {
  hookName: string;
  providerName: string;
}): [() => T, React.Context<T | undefined>] {
  const Context = React.createContext<T | undefined>(undefined);

  // assign the function name dynamically by instantaneously assigning and destructuring an object field
  // const useContext = ... would result in the fn name being `useContext`. Not helpful.
  const { [config.hookName]: useContext } = {
    [config.hookName]: (): T => {
      const context = React.useContext(Context);
      assertContext(context, config);
      return context;
    },
  };

  return [useContext, Context];
}
```


Enter fullscreen mode Exit fullscreen mode
💖 💪 🙅 🚩
tmikeschu
Mike Schutte

Posted on January 16, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related