ChatGPT解决这个技术问题 Extra ChatGPT

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

我是 TypeScript 的新手,我不明白我需要做什么来修复生成 TS7015 错误的行(使用字符串变量引用枚举成员),因为紧随其后的行没有错误(引用枚举成员使用字符串文字):

enum State {
    Happy = 0,
    Sad = 1,
    Drunk = 2
}

function Emote(enumKey:string) {
    console.log(State[enumKey]); // error TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'.
    console.log(State["Happy"]); // no error
}

"noImplicitAny": true设置在项目的tsconfig.json中检测到错误

"noImplictAny": false 设置在项目的 tsconfig.json 中未检测到错误

我正在使用 "ntypescript": "^1.201603060104.1" 进行编译

我现在正在使用 "tsc": "1.8.10" 进行编译

C:>npm install -g typescript

`-- typescript@1.8.10

验证安装:

C:\>tsc --version

Version 1.8.10

这是我的 tsconfig.json 文件:

{
  "compileOnSave": true,
  "compilerOptions": {
    "target": "ES5",
    "module": "System",
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": true,
    "noImplicitAny": true,
    "sourceMap": true,
    "mapRoot": "map/",
    "diagnostics": true
  },
  "exclude": [
    "node_modules",
    "typings"
  ]
}

这是编译器输出:

C:\>tsc

test.ts(8,17): error TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'.
你在寻找什么样的答案?您已经注意到将 noImplicitAny 设置为 false 会使错误消失...
我不想关闭 noImplicitAny 检查,而是想修复代码以使其通过 noImplicitAny 检查。但更重要的是我不明白为什么第一个引用错误,第二个引用通过(类型上两个枚举引用的类型是相同的......或者他们真的不是,我只是错过了一些东西(可能很明显) )
您使用的是什么版本的打字稿?我没有得到该代码的隐式任何类型错误。
"noImplicitAny": true,版本 1.8.2,没有错误,State[enumKey]
ntypescript 看起来它主要面向希望直接使用 TypeScript 编译器 API 的人。我想你想要 typescript...

S
Steven Barnett

如果您使用的是 TypeScript 2.1+,您可以将 enumKey 的类型更改为 keyof typeof State,如下所示:

function Emote(enumKey: keyof typeof State) {...}

或者,如果函数的输入需要是 string,则:

var state : State = State[enumKey as keyof typeof State];

解释:

因为 enumKey 是任意的 string,TypeScript 不知道 enumKey 是否是 State 的成员的名称,因此会产生错误。 TypeScript 2.1 引入了 keyof 运算符,它返回一个类型的已知公共属性名称的联合。使用 keyof 允许我们断言该属性确实在目标对象中。

但是,当您创建枚举时,TypeScript 实际上会同时生成 type(通常是 number 的子类型)和 value(您可以引用的枚举对象在表达式中)。当您编写 keyof State 时,您实际上将获得 number 的文字属性名称的并集。要获取枚举对象的属性名称,您可以使用 keyof typeof State

资料来源:

https://github.com/Microsoft/TypeScript/issues/13775#issuecomment-276381229 https://www.typescriptlang.org/docs/handbook/enums.html#enums-at-compile-time


我更喜欢这个,而不是我们必须提供 TS 好处的其他解决方案。使用此 public rateType: keyof typeof RegularTypeEnum | BlockedTypeEnum;,任何人都可以理解该属性的可能值。谢谢。
你的回答太好了,应该在官方文档里。
我很欣赏这个答案,但令人恼火的是,类型安全总是找到一种方法将非常简单和明显的代码变成类型声明的混淆。
哇,这个答案对我有用,但看着这个让我头疼:State[enumKey as keyof typeof State]
K
Ken Smith

我怀疑这与 TS 1.8.x 在这些情况下对字符串文字的新支持有关。 TS 碰巧知道“Happy”是一个有效的字符串索引,但它不知道 enumKey 是否会是。您可以通过将其转换为 <any> 来修复它,如下所示:

function Emote(enumKey:string) {
    console.log(State[enumKey]); // error TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'.
    console.log(State["Melancholy"]); // error TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'.
    console.log(State["Happy"]); // no error
    console.log(State[<any>enumKey]); // no error
    console.log(State[<any>"Melancholy"]); // no error
}

(顺便说一句,我认为这是新的:我无法用 1.8.9 重现此错误,但一旦我升级到 1.8.10,我就可以了。)

同样有趣的是,我本来希望这可以在没有错误的情况下工作,但事实并非如此:

function TypedEmote(enumKey:'Happy'|'Sad'|'Drunk'){
    console.log(State[enumKey]);
}

一定是关于我不理解的 TS 规范的一些东西,或者他们可能还没有解决这个问题。


有趣的是,“Melancholy”也表现出错误——让我怀疑编译器推断出有一个(未命名的)派生类型的字符串,并且仅限于“Happy”、“Sad”和“Drunk”——也许我可以显式定义这种类型并使用它...
@Neoheurist - 这或多或少是我在上面的 TypedEmote() 方法中尝试用 'Happy'|'Sad'|'Drunk' 类型做的事情。就像我说的,是的,我认为它应该有效,但似乎没有。很想知道你是否能找到一种方法来做到这一点。
state: State = State[<any>"Happy"] 也不起作用 - “类型 'string' 不可分配给类型 'State'”
@AlexOkrushko 不幸的是,在这种情况下,它似乎需要两边都有一个 any 类型,就像我在这里所做的那样 if(<any>this.gravity === GravityType[<any>dir]) 或者,看看 Sharpiro's answer,它有点更优雅。
H
HolgerJeromin

您可以使用编译器选项来防止此错误,而不会丢失整个严格的空检查

"suppressImplicitAnyIndexErrors": true

https://www.typescriptlang.org/tsconfig#suppressImplicitAnyIndexErrors


s
senshin
var stateName = "Happy"
var state = <State>parseInt(State[<any>stateName]);

这就是我必须做的让编译器满意


它有效,但它很丑......史蒂文的解决方案要好得多。 (但请注意,它只是 TS 2.1+,所以 YMMV)