@@ -68,6 +68,13 @@ export type DecoderOptions<ContextType = undefined> = Readonly<
68
68
* `null` is a special value to disable the use of the key decoder at all.
69
69
*/
70
70
keyDecoder: KeyDecoder | null;
71
+
72
+ /**
73
+ * A function to convert decoded map key to a valid JS key type.
74
+ *
75
+ * Defaults to a function that throws an error if the key is not a string or a number.
76
+ */
77
+ mapKeyConverter: (key: unknown) => MapKeyType;
71
78
}>
72
79
> &
73
80
ContextOf<ContextType>;
@@ -78,8 +85,11 @@ const STATE_MAP_VALUE = "map_value";
78
85
79
86
type MapKeyType = string | number;
80
87
81
- const isValidMapKeyType = (key: unknown): key is MapKeyType => {
82
- return typeof key === "string" || typeof key === "number";
88
+ const mapKeyConverter = (key: unknown): MapKeyType => {
89
+ if (typeof key === "string" || typeof key === "number") {
90
+ return key;
91
+ }
92
+ throw new DecodeError("The type of key must be string or number but " + typeof key);
83
93
};
84
94
85
95
type StackMapState = {
@@ -213,6 +223,7 @@ export class Decoder<ContextType = undefined> {
213
223
private readonly maxMapLength: number;
214
224
private readonly maxExtLength: number;
215
225
private readonly keyDecoder: KeyDecoder | null;
226
+ private readonly mapKeyConverter: (key: unknown) => MapKeyType;
216
227
217
228
private totalPos = 0;
218
229
private pos = 0;
@@ -236,6 +247,7 @@ export class Decoder<ContextType = undefined> {
236
247
this.maxMapLength = options?.maxMapLength ?? UINT32_MAX;
237
248
this.maxExtLength = options?.maxExtLength ?? UINT32_MAX;
238
249
this.keyDecoder = options?.keyDecoder !== undefined ? options.keyDecoder : sharedCachedKeyDecoder;
250
+ this.mapKeyConverter = options?.mapKeyConverter ?? mapKeyConverter;
239
251
}
240
252
241
253
private clone(): Decoder<ContextType> {
@@ -631,14 +643,11 @@ export class Decoder<ContextType = undefined> {
631
643
continue DECODE;
632
644
}
633
645
} else if (state.type === STATE_MAP_KEY) {
634
- if (!isValidMapKeyType(object)) {
635
- throw new DecodeError("The type of key must be string or number but " + typeof object);
636
- }
637
646
if (object === "__proto__") {
638
647
throw new DecodeError("The key __proto__ is not allowed");
639
648
}
640
649
641
- state.key = object;
650
+ state.key = this.mapKeyConverter( object) ;
642
651
state.type = STATE_MAP_VALUE;
643
652
continue DECODE;
644
653
} else {
0 commit comments