grpc-web
grpc-web copied to clipboard
Incorrect TS type definition for protobuf enums
Protobuf enum
s are incorrectly types as TypeScript enum
s. This is incorrect because TS enums map from item name to value and from value to item name.
Example
Proto file:
enum Tag {
WORD = 0;
WORD_FOR_QMARK = 1;
WORD_FOR_STAR = 2;
}
Generated JS:
/**
* @enum {number}
*/
proto.Tag = {
WORD: 0,
WORD_FOR_QMARK: 1,
WORD_FOR_STAR: 2,
};
TypeScript definition (.d.ts
)
export enum Tag {
WORD = 0,
WORD_FOR_QMARK = 1,
WORD_FOR_STAR = 2,
}
However, the type definition actually means this:
export var Tag;
(function (Tag) {
Tag[Tag["WORD"] = 0] = "WORD";
Tag[Tag["WORD_FOR_QMARK"] = 1] = "WORD_FOR_QMARK";
Tag[Tag["WORD_FOR_STAR"] = 2] = "WORD_FOR_STAR";
})(Tag || (Tag = {}));
... which is equivalent to:
export var Tag = {
"0": "WORD",
"1": "WORD_FOR_QMARK",
"2": "WORD_FOR_STAR",
"WORD": 0,
"WORD_FOR_QMARK": 1,
"WORD_FOR_STAR": 2,
};
Possible solution
Use a type
for enums (same as for message
s):
export type Tag = {
WORD: 0,
WORD_FOR_QMARK: 1,
WORD_FOR_STAR: 2,
}
I also want to point out that const enum
s are not the solution since TS will insert the values of const enum
s at compile time. const enum
s are meant for purely internal usage only and not for APIs.
To be honest, I like the value/name and name/value mapping of a typescript enum. Instead of limiting the typings to name/value mapping only, I would prefer to patch protoc to extend the Javascript code to support the value/name mapping as well. It should be backward compatible and would fit the typescript enum.
As a workaround for now, I can add the missing mapping at runtime, whenever I need this. It is easily possible because of the type enum
in the generated d.ts file that allows this but would be impossible with the switch to the suggested solution that prefers type
instead of enum
.