9

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

3
  • 1
    Do you really need enums in this scenario? I think it'd be much easier to just use objects. I'd just make Constants and Potato const objects and I think TypeScript would be happy Commented Sep 30, 2020 at 21:29
  • @thelukaszns while that is something I would like, it's a little too late since this is how the entire codebase (>100 files) is structured. Commented Sep 30, 2020 at 22:47
  • This restriction appears to be lifted by typescript 5.1.3 (or earlier, haven't searched for when) Commented Nov 2, 2023 at 20:37

1 Answer 1

6

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;
Sign up to request clarification or add additional context in comments.

1 Comment

Just mentioning microsoft/TypeScript#40862 here by number so that searches for #40862 might find this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.