0

I have a function I want to convert to generics Typescript to provide as an utility. I have reached it but what happens when a function returns a function. I know it is not required but still

/**
 * createConstants Type
 */
type createConstantsType =
  <T extends string, U extends string>(namespace: T, prefix: U | null) =>
    <V extends string>(...constants: V[]) => Record<V, string>;

/**
 * function for creating namespaced constants
 * @param {String} namespace the namespace for the constant to create
 * @param {String} prefix the prefix for the constant to create
 * @returns {Object} namespaced constants for a module/feature
 * 
 *    // Common approach
 *    export const NAMESPACE = 'manual';
 *    export const SIDEBAR_TOGGLE = `${NAMESPACE}/SIDEBAR_TOGGLE`;
 *    export const SIDEBAR_OPEN = `${NAMESPACE}/SIDEBAR_OPEN`;
 *    export const SIDEBAR_CLOSE = `${NAMESPACE}/SIDEBAR_CLOSE`;
 *
 *    // Usage of this utility
 *    export const NAMESPACE = 'manual';
 *    export const SIDEBAR = createConstants(NAMESPACE, 'sidebar')('TOGGLE', 'OPEN', 'CLOSE');
 *
 *    // which will generate:
 *    SIDEBAR = {
 *      TOGGLE: 'manual/SIDEBAR_TOGGLE',
 *      OPEN: 'manual/SIDEBAR_OPEN',
 *      CLOSE: 'manual/SIDEBAR_CLOSE',
 *    }
 * 
 */
export const createConstants: createConstantsType =
  <T extends string, U extends string>(namespace: T, prefix: U | null = null) =>
    <V extends string>(...constants: V[]): Record<V, string> => (
    constants.reduce((result: Record<V, string>, constant: string): Record<V, string>  => ({
      [constant.toUpperCase()]:
        `${namespace}/${(prefix) ? `${prefix.toUpperCase()}_` : ''}${constant.toUpperCase()}`,
      ...result,
    }), {} as Record<V, string>)
  );

1 Answer 1

2

There are a few things to be aware of:

  • Don't use String when what you mean is string. The uppercase one is a reference to the global String object in JavaScript.
  • Avoid defining functions as Function. The definition of Function is very broad, and even if your function makes use of some precise types and generics, TypeScript will ignore all of that because it's told to treat it as just any Function. If you want to create a function type, write its signature this way: type MyFunction = (argument: number) => boolean instead.
  • As a rule of thumb, if your argument is of type string, you can start just by creating a type parameter (a generic) and saying it extends string. So, <T extends string>(argument: T) instead of (argument: string).

When you apply these rules, your solution will look like this:

export const createConstants = <T extends string, U extends string>(namespace: T, prefix: U | null = null) => <V extends string>(...constants: V[]): Record<V, string> => (
  constants.reduce((result, constant) => ({
    [constant.toUpperCase()]: 
      `${namespace}/${(prefix) ? `${prefix.toUpperCase()}_` : ''}${constant.toUpperCase()}`,
    ...result,
  }), {} as Record<V, string>)
);

const test = createConstants('manual', 'SIDEBAR')('TOGGLE', 'OPEN', 'CLOSE')

See TypeScript Playground.

Sign up to request clarification or add additional context in comments.

2 Comments

This error means you are running an old TypeScript version. Try TypeScript Playground. It works as expected there.
i checked npm list typescript i m using 3.2.2. makes no sense. But thanks let me figure it out

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.