@@ -203,75 +203,37 @@ export class Decoder<A> {
203
203
/**
204
204
* Decoder primitive that only matches on exact values.
205
205
*
206
- * Note that `constant('string to match')` returns a `Decoder<string>` which
207
- * fails if the input is not equal to `'string to match'`. In many cases this
208
- * is sufficient, but in some situations typescript requires that the decoder
209
- * type be a type-literal. In such a case you must provide the type parameter,
210
- * which looks like `constant<'string to match'>('string to match')`.
211
- *
212
- * Providing the type parameter is only necessary for type-literal strings
213
- * and numbers, as detailed by this table:
214
- *
215
- * ```
216
- * | Decoder | Type |
217
- * | ---------------------------- | ---------------------|
218
- * | constant(true) | Decoder<true> |
219
- * | constant(false) | Decoder<false> |
220
- * | constant(null) | Decoder<null> |
221
- * | constant('alaska') | Decoder<string> |
222
- * | constant<'alaska'>('alaska') | Decoder<'alaska'> |
223
- * | constant(50) | Decoder<number> |
224
- * | constant<50>(50) | Decoder<50> |
225
- * | constant([1,2,3]) | Decoder<number[]> |
226
- * | constant<[1,2,3]>([1,2,3]) | Decoder<[1,2,3]> |
227
- * | constant({x: 't'}) | Decoder<{x: string}> |
228
- * | constant<{x: 't'}>({x: 't'}) | Decoder<{x: 't'}> |
229
- * ```
230
- *
231
- *
232
- * One place where this happens is when a type-literal is in an interface:
233
- * ```
234
- * interface Bear {
235
- * kind: 'bear';
236
- * isBig: boolean;
237
- * }
238
- *
239
- * const bearDecoder1: Decoder<Bear> = object({
240
- * kind: constant('bear'),
241
- * isBig: boolean()
242
- * });
243
- * // Type 'Decoder<{ kind: string; isBig: boolean; }>' is not assignable to
244
- * // type 'Decoder<Bear>'. Type 'string' is not assignable to type '"bear"'.
245
- *
246
- * const bearDecoder2: Decoder<Bear> = object({
247
- * kind: constant<'bear'>('bear'),
248
- * isBig: boolean()
249
- * });
250
- * // no compiler errors
251
- * ```
252
- *
253
- * Another is in type-literal unions:
254
- * ```
255
- * type animal = 'bird' | 'bear';
256
- *
257
- * const animalDecoder1: Decoder<animal> = union(
258
- * constant('bird'),
259
- * constant('bear')
260
- * );
261
- * // Type 'Decoder<string>' is not assignable to type 'Decoder<animal>'.
262
- * // Type 'string' is not assignable to type 'animal'.
263
- *
264
- * const animalDecoder2: Decoder<animal> = union(
265
- * constant<'bird'>('bird'),
266
- * constant<'bear'>('bear')
267
- * );
268
- * // no compiler errors
206
+ * For primitive values and shallow structures of primitive values `constant`
207
+ * will infer an exact literal type:
208
+ * ```
209
+ * | Decoder | Type |
210
+ * | ---------------------------- | ------------------------------|
211
+ * | constant(true) | Decoder<true> |
212
+ * | constant(false) | Decoder<false> |
213
+ * | constant(null) | Decoder<null> |
214
+ * | constant(undefined) | Decoder<undefined> |
215
+ * | constant('alaska') | Decoder<'alaska'> |
216
+ * | constant(50) | Decoder<50> |
217
+ * | constant([1,2,3]) | Decoder<[1,2,3]> |
218
+ * | constant({x: 't'}) | Decoder<{x: 't'}> |
219
+ * ```
220
+ *
221
+ * Inference breaks on nested structures, which require an annotation to get
222
+ * the literal type:
223
+ * ```
224
+ * | Decoder | Type |
225
+ * | -----------------------------|-------------------------------|
226
+ * | constant([1,[2]]) | Decoder<(number|number[])[]> |
227
+ * | constant<[1,[2]]>([1,[2]]) | Decoder<[1,[2]]> |
228
+ * | constant({x: [1]}) | Decoder<{x: number[]}> |
229
+ * | constant<{x: [1]}>({x: [1]}) | Decoder<{x: [1]}> |
269
230
* ```
270
231
*/
271
- static constant ( value : true ) : Decoder < true > ;
272
- static constant ( value : false ) : Decoder < false > ;
273
- static constant < A > ( value : A ) : Decoder < A > ;
274
- static constant ( value : any ) : Decoder < any > {
232
+ static constant < T extends string | number | boolean | [ ] > ( value : T ) : Decoder < T > ;
233
+ static constant < T extends string | number | boolean , U extends [ T , ...T [ ] ] > ( value : U ) : Decoder < U > ;
234
+ static constant < T extends string | number | boolean , U extends Record < string , T > > ( value : U ) : Decoder < U > ;
235
+ static constant < T > ( value : T ) : Decoder < T > ;
236
+ static constant ( value : any ) {
275
237
return new Decoder (
276
238
( json : unknown ) =>
277
239
isEqual ( json , value )
0 commit comments