简体   繁体   English

需要帮助转换 typescript 助手

[英]Need help to convert typescript helper

I have a helper I'm exporting and importing into multiple files which is working fine, however I want to change it slightly and I'm struggling to figure this one out:我有一个助手,我正在导出和导入多个工作正常的文件,但是我想稍微改变它,我正在努力解决这个问题:

// utils.ts
export enum RequestTypes {
  Request,
  Success,
  Failure,
}

type CombineEnums<P, C> = {
  [KP in keyof P]: {
    [KC in keyof C]: KP extends string ? KC extends string ? `${KP}${KC}` : never : never;
  };
};

export function createActions <P, C>(actionTypes: P, requestTypes: C): CombineEnums<P, C> {
  const result: any = {};
  for (const keyP of Object.keys(actionTypes)) {
    result[keyP] = {};
    for (const keyC of Object.keys(requestTypes)) {
      result[keyP][keyC] = `${keyP}${keyC}`;
    }
  }
  return result;
}

Now in another file I'm importing the createActions method & RequestTypes and using it like so:现在在另一个文件中,我正在导入 createActions 方法和 RequestTypes 并像这样使用它:

// module.ts
import { createActions, RequestTypes } from './utils.ts';
enum Actions {
   Find,
   Create
}
const actions = createActions(Actions, RequestTypes);
// actions.Find.Request -> 'FindRequest'
// actions.Find.Success -> 'FindSuccess'
// actions.Create.Failure -> 'CreateFailure'

This all works fine, however RequestTypes will rarely change, i want to make it an optional argument, but still able to pass through other RequestTypes if needed.这一切都很好,但是RequestTypes很少会改变,我想让它成为一个可选参数,但如果需要,仍然能够通过其他 RequestTypes。

So idealy by default I'd like the above solution but the usage will be:因此,默认情况下,我希望使用上述解决方案,但用法如下:

const actions = createActions(Actions) with the same output. const actions = createActions(Actions)与 output 相同。

And if need be, pass through different RequestTypes:如果需要,通过不同的 RequestTypes:

enum TabRequests {
   Open,
   Close
}
enum TabActions {
   Tab
}
const actions = createActions(TabActions, TabRequests);
// actions.Tab.Open -> 'TabOpen'
// actions.Tab.Close -> 'TabClose'

I've tried everything i can think of but can't seem to figure out the typescript side of this!我已经尝试了我能想到的一切,但似乎无法弄清楚 typescript 的一面!

You can use typescript overload signatures , also see the playground :您可以使用 typescript 重载签名,另请参阅操场

// signature for only one argument
export function createActions <P>(actionTypes: P): CombineEnums<P, typeof RequestTypes>;

// signature for two arguments
export function createActions <P, C>(actionTypes: P, requestTypes: C): CombineEnums<P, C>;

// actual implementation with default value for second argument
export function createActions <P>(actionTypes: P, requestTypes: any = RequestTypes): CombineEnums<P, any> {
  const result: any = {};
  for (const keyP of Object.keys(actionTypes)) {
    result[keyP] = {};
    for (const keyC of Object.keys(requestTypes)) {
      result[keyP][keyC] = `${keyP}${keyC}`;
    }
  }
  return result;
}

// If you want you could also use the following line as implementation signature
// export function createActions <P, C>(actionTypes: P, requestTypes: C | typeof RequestTypes = RequestTypes): CombineEnums<P, C | typeof RequestTypes> {


// Now you can use both signatures, typesafe.
const actionsWithRequestTypeArgument = createActions(Actions, RequestTypes);
const actionsWithoutRequestTypeArgument = createActions(Actions);

Here's how you can use the overloaded function from the other answer in a separate module:以下是如何在单独的模块中使用来自其他答案的重载 function :

TS Playground link TS Playground 链接

// utils.ts

type StringEnum = Record<string, string>;

export type NestedCombinedStringEnum<
  P extends StringEnum,
  C extends StringEnum,
> = {
  [KP in keyof P]: {
    [KC in keyof C]: KP extends string ? KC extends string ? `${KP}${KC}` : never : never;
  };
};

export function nestAndCombineStringEnums <
  P extends StringEnum,
  C extends StringEnum,
>(enumParent: P, enumChild: C): NestedCombinedStringEnum<P, C> {
  const result: any = {};

  for (const keyP of Object.keys(enumParent)) {
    result[keyP] = {};
    for (const keyC of Object.keys(enumChild)) {
      result[keyP][keyC] = `${keyP}${keyC}`;
    }
  }

  return result;
}

export enum RequestType {
  Request = 'Request',
  Success = 'Success',
  Failure = 'Failure',
}

export function createActions <
  P extends StringEnum,
  C extends StringEnum,
>(enumParent: P, enumChild: C): NestedCombinedStringEnum<P, C>;
export function createActions <P extends StringEnum>(enumParent: P): NestedCombinedStringEnum<P, typeof RequestType>;
export function createActions <
  P extends StringEnum,
  C extends StringEnum,
>(enumParent: P, enumChild?: C) {
  return nestAndCombineStringEnums(enumParent, enumChild ?? RequestType);
}

// module.ts

import {createActions, RequestType} from './utils.ts';

enum ActionType {
  Find = 'Find',
  Update = 'Update',
  Create = 'Create',
}

const actions = createActions(ActionType); // same as createActions(ActionType, RequestType);
console.log(actions.Create.Success); // "CreateSuccess"
console.log(actions); // the expected result object in your question

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM