I'm trying to map a number-based enum generated from a gRPC proto file into a string-based enum for use in my REST API.
The mapping works but TS complain, giving this error.
What have I done wrong, and how to fix?
types/mapping.ts:5:14 - error TS2739: Type '{ 3: OperationMode.LEARNING; 2: OperationMode.MAINTENANCE; 1: OperationMode.NORMAL; 4: OperationMode.TESTING; 0: undefined; }' is missing the following properties from type '{ 0: OperationMode | undefined; OPERATION_UNSPECIFIED: OperationMode | undefined; OPERATION_NORMAL: OperationMode | undefined; ... 6 more ...; 4: OperationMode | undefined; }': OPERATION_UNSPECIFIED, OPERATION_NORMAL, OPERATION_MAINTENANCE, OPERATION_LEARNING, OPERATION_TESTING
5 export const operationModeG2R: {[key in gRPCOperationMode]: OperationMode|undefined} = {
~~~~~~~~~~~~~~~~
Code generated by @grpc/proto
:
export const OperationMode = {
OPERATION_UNSPECIFIED: 0,
OPERATION_NORMAL: 1,
OPERATION_MAINTENANCE: 2,
OPERATION_LEARNING: 3,
OPERATION_TESTING: 4,
} as const;
Code defined in rest-api.ts
export enum OperationMode {
NORMAL = 'NORMAL',
MAINTENANCE = 'MAINTENANCE',
LEARNING = 'LEARNING',
TESTING = 'TESTING',
}
import { OperationMode as gRPCOperationMode } from "../proto/generated/companyname/control/OperationMode";
import { OperationMode } from "./rest-api";
export const operationModeG2R: {[key in gRPCOperationMode]: OperationMode|undefined} = {
[gRPCOperationMode.OPERATION_LEARNING]:OperationMode.LEARNING,
[gRPCOperationMode.OPERATION_MAINTENANCE]:OperationMode.MAINTENANCE,
[gRPCOperationMode.OPERATION_NORMAL]:OperationMode.NORMAL,
[gRPCOperationMode.OPERATION_TESTING]:OperationMode.TESTING,
[gRPCOperationMode.OPERATION_UNSPECIFIED]:undefined
}
CodePudding user response:
gRPCOperationMode
is a runtime value and can not be used inside of a mapped type because mapped types can only work with types.
You want to get the type of gRPCOperationMode
using typeof
and map over its keys with keyof
. But the keys of gRPCOperationMode
are string types. Since you want to get the number literal type of each key's value, you need to use key remapping to map each key K
into its corresponding type gRPCOperationMode[K]
.
export const operationModeG2R: {
[K in keyof typeof gRPCOperationMode as typeof gRPCOperationMode[K]]:
OperationMode | undefined
} = {
[gRPCOperationMode.OPERATION_LEARNING]:OperationMode.LEARNING,
[gRPCOperationMode.OPERATION_MAINTENANCE]:OperationMode.MAINTENANCE,
[gRPCOperationMode.OPERATION_NORMAL]:OperationMode.NORMAL,
[gRPCOperationMode.OPERATION_TESTING]:OperationMode.TESTING,
[gRPCOperationMode.OPERATION_UNSPECIFIED]:undefined
}
CodePudding user response:
The answer from @tobias-s is the correct answer to my particular question.
However, after taking a look in the generated file, I can see that there's already a shorthand type OperationMode__Output
for this case, which I want to share to anyone who come here by searching for the specific gRPC related issue:
// Original file: proto/autofuel.proto
export const OperationMode = {
OPERATION_UNSPECIFIED: 0,
OPERATION_NORMAL: 1,
OPERATION_MAINTENANCE: 2,
OPERATION_LEARNING: 3,
OPERATION_TESTING: 4,
} as const;
export type OperationMode =
| 'OPERATION_UNSPECIFIED'
| 0
| 'OPERATION_NORMAL'
| 1
| 'OPERATION_MAINTENANCE'
| 2
| 'OPERATION_LEARNING'
| 3
| 'OPERATION_TESTING'
| 4
export type OperationMode__Output = typeof OperationMode[keyof typeof OperationMode]
Which means I can do it like this:
import { OperationMode as GRPCOperationMode, OperationMode__Output } from "../proto/generated/companyname/control/OperationMode";
import { OperationMode } from "./rest-api";
export const operationModeG2R: {
[K in OperationMode__Output]:
OperationMode | undefined
} = {
[GRPCOperationMode.OPERATION_LEARNING]:OperationMode.LEARNING,
[GRPCOperationMode.OPERATION_MAINTENANCE]:OperationMode.MAINTENANCE,
[GRPCOperationMode.OPERATION_NORMAL]:OperationMode.NORMAL,
[GRPCOperationMode.OPERATION_TESTING]:OperationMode.TESTING,
[GRPCOperationMode.OPERATION_UNSPECIFIED]:undefined
}