首页 > 解决方案 > How can I pass an enum, with keys of another string enum, into a function that accepts a string?

问题描述

I am trying to pass a string enum into a function that expects a string. The catch is that this string enum has to be assigned from a (global) constants enum that holds all the constants in our repository.

enum Constants {
    hello = "Hello"
}

enum Potato {
    h = Constants.hello
}

function takesAString(s: string) {
    console.log(s + ", world!");
}
takesAString(Potato.h);
// ERROR: Argument of type 'Potato' is not assignable to parameter of type 'string'

While one would expect that Potato.h is of type string (since it is being assigned a string from the string enum Constants), in fact it errors out, with the error that 'Potato' is not assignable to parameter of type string. This implies to me that the Typescript compiler cannot infer that Potato.h is a string.

Things that work:

enum Potato {
    h = "Hello"
}

function takesAString(s: string) {
    console.log(s + ", world!");
}
takesAString(Potato.h);
// OK
enum Constants {
    hello = "Hello"
}

enum Potato {
    h = Constants.hello
}

function takesAString(s: string) {
    console.log(s + ", world!");
}
takesAString(Potato.h.toString());
// OK: toString() causes "Hello, world!" to be printed

I'm working with Typescript version 3.8.3

Playground Link

标签: typescript

解决方案


This looks like a bug in typescript, I raised a bug report here It looks like typescript is typing the Potato enum as being numbers which is obviously wrong.

string enums aren't allowed to have computed members, for instance if you do this:

declare function returnsString(): string;
enum Test {
    a = returnsString();
} 

you get this error:

Only numeric enums can have computed members, but this expression has type 'string'. If you do not need exhaustiveness checks, consider using an object literal instead.

So you probably want to use object literals, it won't require rewriting the whole codebase just changing the enums to something like this:

type Constants = typeof Constants[keyof typeof Constants]
const Constants = {
    hello: "Hello"
} as const

type Potato = typeof Potato[keyof typeof Potato]
const Potato = {
    h: Constants.hello
} as const;

推荐阅读