@@ -203,75 +203,37 @@ export class Decoder<A> {
203203 /**
204204 * Decoder primitive that only matches on exact values.
205205 *
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]}> |
269230 * ```
270231 */
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 ) {
275237 return new Decoder (
276238 ( json : unknown ) =>
277239 isEqual ( json , value )
0 commit comments