Given a function that has an argument supposed to be an enum
. The enum
passed in can have different numbers of properties. How to fix the type of that argument ? enum
itself is not a type.
E.g. :
function (myEnum: mysteriousType){ //What is that mysteriousType ? }
Enums or enumerations are a new data type supported in TypeScript. Most object-oriented languages like Java and C# use enums. This is now available in TypeScript too. In simple words, enums allow us to declare a set of named constants i.e. a collection of related values that can be numeric or string values.
An enum type is a special data type that enables for a variable to be a set of predefined constants. The variable must be equal to one of the values that have been predefined for it. Common examples include compass directions (values of NORTH, SOUTH, EAST, and WEST) and the days of the week.
To get the value of enum we can simply typecast it to its type. In the first example, the default type is int so we have to typecast it to int. Also, we can get the string value of that enum by using the ToString() method as below.
Enums or Enumerated types are special data types that set variables as a set of predefined constants. In other languages enumerated data types are provided to use in this application. Javascript does not have enum types directly in it, but we can implement similar types like enums through javascript.
With what you've stated so far (needs to accept all string / numeric / heterogeneous enums), the closest I can do is something like this:
type Enum<E> = Record<keyof E, number | string> & { [k: number]: string }; function acceptEnum<E extends Enum<E>>( myEnum: E ): void { // do something with myEnum... what's your use case anyway? } enum E { X, Y, Z }; acceptEnum(E); // works
I'm not sure what you're going to do with myEnum
if all you know is that it's "some enum type", but I guess that's up to you to figure out.
How I came up with this: I examined a bunch of concrete enum
types, and they seem to have properties with string keys and string or numeric values (the forward mapping), as well as a numeric index key with string values (the reverse mapping for numeric values).
const works: { X: 0, Y: 1, Z: 2, [k: number]: string } = E; // works
The language designers might have constrained this further, since the reverse mapping will only produce the specific numeric keys and string values seen in the forward mapping, but for some reason it's not implemented like that:
const doesntWork: { X: 0, Y: 1, Z: 2, [k: number]: 'X' | 'Y' | 'Z' } = E; // error const alsoDoesntWork: { X: 0, Y: 1, Z: 2, 0: 'X', 1: 'Y', 2: 'Z' } = E; // error
So the tightest constraint I can put on an enum type is the above E extends Enum<E>
.
Note that this code does not work for const enum
types which don't really exist at runtime:
const enum F {U, V, W}; acceptEnum(F); // nope, can't refer to `F` by itself
And also note that the above type (E extends Enum<E>
) allows some things it maybe shouldn't:
acceptEnum({ foo: 1 }); // works
In the above, {foo: 1}
is plausibly a numeric enum similar to enum Foo {foo = 1}
but it doesn't have the reverse mapping, and if you rely on that things will blow up at runtime. Note that {foo: 1}
doesn't seem to have an index signature but it still matches an index signature implicitly. It wouldn't fail to match unless you added some explicit bad value:
acceptEnum({foo: 1, 2: 3}); // error, prop '2' not compatible with index signature
But there's nothing to be done here. As I mentioned above, the implementation of enum
typing currently does not constrain the numeric keys as much as it can, so there seems to be no way at compile time to distinguish between an enum with a good reverse mapping and one without one.
Hope that helps. Good luck!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With