【问题标题】:TypeScript: Generics check for enum typeTypeScript:泛型检查枚举类型
【发布时间】:2019-12-30 03:57:56
【问题描述】:

进程有一个枚举。它们有不同的步骤,也表示为枚举,如下所示。

enum Process {
  Simple = "simple",
  Advanced = "advanced"
}

enum SimpleStep {
  A = "A",
  B = "B"
}

enum AdvancedStep {
  A = "A",
  B = "B",
  C = "C"
}

通过以下语句,我创建了一系列步骤。

const SIMPLE_STEPS = Object.keys(SimpleStep).map(
  (k: string) => SimpleStep[k]
);

const ADVANCED_STEPS = Object.keys(AdvancedStep).map(
  k => AdvancedStep[k]
);

const ALL_STEPS = {
  [Process.Simple]: SIMPLE_STEPS,
  [Process.Advanced]: ADVANCED_STEPS
};

我写了以下函数来获取步数。

// ???: Check if S is a step of Process
const getStepNumber = <P extends Process, S>(process: P, step: S) => {
  return ALL_STEPS[process].indexOf(step) + 1;
};

// returns 2, which is correct
console.log('step number of B', getStepNumber(Process.Advanced, AdvancedStep.B)); 

// returns 0. Is it possible to prevent at compile-time?
console.log('step number of C', getStepNumber(Process.Simple, AdvancedStep.C));

正如您在代码示例中看到的那样,是否可以在编译时使用泛型防止以错误的步骤调用函数?

这里是操场,如果您想尝试整个示例:TS Playground

【问题讨论】:

    标签: typescript generics typescript-typings typescript-generics


    【解决方案1】:

    一种选择是引入一个条件类型,允许您根据提供给函数的Process 推断需要步骤枚举(即SimpleStepAdvancedStep)。这可以按如下方式完成:

    type StepFromProcess<P extends Process> =
        P extends Process.Simple ? SimpleStep : AdvancedStep
    

    然后您可以更改您的函数以使用该类型:

    const getStepNumber = <P extends Process>(process: P, step: StepFromProcess<P>) => ...
    

    编译器现在将阻止您进行此(无效)调用:

    console.log('step number of C', getStepNumber(Process.Simple, AdvancedStep.C));
    

    【讨论】:

    • 哇,这真的很酷。谢谢。如果有超过 2 个进程,是否有类似打字的 switch-case?还是应该用三元条件表达式来完成?
    • 不,我不相信有开关盒。您需要使用嵌套的三元运算符。您可以在 TypeScript 文档中看到一个示例 here(查看他们的 TypeName 示例)。
    猜你喜欢
    • 2018-10-31
    • 1970-01-01
    • 2013-03-20
    • 2018-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多