Typescript 枚举作为参数类型允许无效值

Posted

技术标签:

【中文标题】Typescript 枚举作为参数类型允许无效值【英文标题】:Typescript enum as a parameter type allows invalid values 【发布时间】:2020-08-05 23:26:12 【问题描述】:

在 TypeScript 中,我定义了一个 enum,然后我想要一个函数接受一个参数,其值为枚举值之一。但是,TypeScript 似乎不对值进行任何验证,并允许枚举之外的值。有没有办法做到这一点?

示例

enum myenum 
    hello = 1,
    world = 2,


const myfunc = (num:myenum):void => console.log(`num=$num`);

myfunc(1);            // num=1 (expected)
myfunc(myenum.hello); // num=1 (expected)

//THE ISSUE: I'm expecting next line to be a TS compile error, but it is not
myfunc(7); // num=7

另类

如果我使用 type 而不是 enum 我可以获得类似于我正在寻找的东西,但我失去了枚举的一些功能。

type mytype = 1|2;
const myfunc = (num:mytype):void => console.log(`num=$num`);

myfunc(1);
myfunc(7);  //TS Compile Error: Argument of type '7' is not assignable to a parameter of type 'mytype'

【问题讨论】:

您看过这个问题及其答案吗? ***.com/questions/43804805/… @JonahBishop 显然我有,因为我已经对问题和答案进行了投票。 :) 这对我帮助不大。我可以在我的函数中添加一个条件,比如if(!Object.values(myenum).includes(num)) throw('Illegal Argument');,但是当我宁愿它是打字稿可以在编译时识别的东西时,这会导致它成为运行时错误。 【参考方案1】:

您可能对 TS 中的枚举期望过高... :)

enum MyCoolEnum 
  A = 1,
  B = 2,


function test(data: MyCoolEnum) 
  console.log(`Test = $typeof data`)


test(1)
test(MyCoolEnum.A)
test(500)

如果您在上面运行此代码,您将看到所有行都打印number,这意味着在幕后它被转换为数字,这就是它接受所有内容的原因...枚举通常只是一个很好的做法避免使用幻数并使代码更具可读性

另一方面,如果您停止使用数字枚举并将 A 和 B 的值实际更改为字符串,您将得到:

TSError: ⨯ Unable to compile TypeScript:
dima.ts:10:6 - error TS2345: Argument of type '1' is not assignable to parameter of type 'MyCoolEnum'.

10 test(1)
        ~
dima.ts:12:6 - error TS2345: Argument of type '500' is not assignable to parameter of type 'MyCoolEnum'.

12 test(500)
        ~~~

    at createTSError (/Users/odinn/.nvm/versions/node/v10.15.1/lib/node_modules/ts-node/src/index.ts:423:12)
    at reportTSError (/Users/odinn/.nvm/versions/node/v10.15.1/lib/node_modules/ts-node/src/index.ts:427:19)
    at getOutput (/Users/odinn/.nvm/versions/node/v10.15.1/lib/node_modules/ts-node/src/index.ts:554:36)
    at Object.compile (/Users/odinn/.nvm/versions/node/v10.15.1/lib/node_modules/ts-node/src/index.ts:760:32)
    at Module.m._compile (/Users/odinn/.nvm/versions/node/v10.15.1/lib/node_modules/ts-node/src/index.ts:839:43)
    at Module._extensions..js (internal/modules/cjs/loader.js:700:10)
    at Object.require.extensions.(anonymous function) [as .ts] (/Users/odinn/.nvm/versions/node/v10.15.1/lib/node_modules/ts-node/src/index.ts:842:12)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
    at Function.Module._load (internal/modules/cjs/loader.js:530:3)

所以我想说的是,如果它是一个数字枚举,它只是装饰性的,它被视为一个数字,但如果你制作一个字符串枚举,那么它实际上是在尝试匹配类型

【讨论】:

谢谢,这一切都证实了我已经看到的。我正在使用一些代码,其中枚举是 2 年前定义的,并且在很多地方都使用过,所以我不能轻易地更改为一种类型。但是在我的新函数中,我希望能够让打字稿验证我传递的值实际上是在枚举中。有没有办法做到这一点,还是我运气不好? 不是我所知道的,我唯一能想到的就是添加一些验证逻辑......或者如果你更改枚举并向其添加一个字符串值,这将停止使其成为数字枚举,也许这可以帮助......虽然有点黑客攻击 目前看来这是“设计使然”-github.com/microsoft/TypeScript/issues/36756

以上是关于Typescript 枚举作为参数类型允许无效值的主要内容,如果未能解决你的问题,请参考以下文章

在方法的参数中使用动态枚举作为类型

如何使用 TypeScript 枚举值作为类型?

使用字符串类型参数访问枚举时出现 TypeScript TS7015 错误

Typescript 中的枚举类型是啥?

TypeScript深入学习

typedef 枚举类型作为 NSDictionary 的键?