You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CHANGELOG.md
+72Lines changed: 72 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,5 +1,77 @@
1
1
Note: I’m currently working on several breaking changes to tiny-decoders, but I’m trying out releasing them piece by piece. The idea is that you can either upgrade version by version only having to deal with one or a few breaking changes at a time, or wait and do a bunch of them at the same time.
2
2
3
+
### Version 12.0.0 (unreleased)
4
+
5
+
This release changes how `fieldsUnion` works. The new way should be easier to use, and it looks more similar to the type definition of a tagged union.
6
+
7
+
- Changed: The first argument to `fieldsUnion` is no longer the common field name used in the JSON, but the common field name used in TypeScript. This doesn’t matter if you use the same common field name in both JSON and TypeScript. But if you did use different names – don’t worry, you’ll get TypeScript errors so you won’t forget to update something.
8
+
9
+
- Changed: The second argument to `fieldsUnion` is now an array of objects, instead of an object with decoders. The objects in the array are “`fieldsAuto` objects” – they fit when passed to `fieldsAuto` as well. All of those objects must have the first argument to `fieldsUnion` as a key, and use the new `tag` function on that key.
10
+
11
+
- Added: The `tag` function. Used with `fieldsUnion`, once for each variant of the union. `tag("MyTag")` returns a `Field` with a decoder that requires the input `"MyTag"` and returns `"MyTag"`. The metadata of the `Field` also advertises that the tag value is `"MyTag"`, which `fieldsUnion` uses to know what to do. The `tag` function also lets you use a different common field in JSON than in TypeScript (similar to the `field` function for other fields).
This release deprecates `fields`, and makes `fieldsAuto` more powerful so that it can do most of what only `fields` could before. Removing `fields` unlocks further changes that will come in future releases. It’s also nice to have just one way of decoding objects (`fieldsAuto`), instead of having two. Finally, the changes to `fieldsAuto` gets rid of a flawed design choice which solves several reported bugs: [#22](https://github.com/lydell/tiny-decoders/issues/22) and [#24](https://github.com/lydell/tiny-decoders/issues/24).
@@ -484,12 +492,12 @@ The `exact` option let’s you choose between ignoring extraneous data and makin
484
492
See also the [Extra fields](examples/extra-fields.test.ts) example.
485
493
486
494
> **Warning**
487
-
> Temporary behavior: If a field is missing and _not_ marked as optional, `fieldsAuto` still _tries_ the decoder at the field (passing `undefined` to it). If the decoder succeeds (because it allows `undefined` or succeeds for any input), that value is used. If it fails, the regular “missing field” error is thrown. This means that `fieldsAuto({ name: undefinedOr(string) })` successfully produces `{ name: undefined }` if given `{}` as input. It is supposed to fail in that case (because a required field is missing), but temporarily it does not fail. This is to support how `fieldsUnion`is used currently. When`fieldsUnion`is updated to a new API in an upcoming version of tiny-decoders, this temporary behavior in `fieldsAuto` will be removed.
495
+
> Temporary behavior: If a field is missing and _not_ marked as optional, `fieldsAuto` still _tries_ the decoder at the field (passing `undefined` to it). If the decoder succeeds (because it allows `undefined` or succeeds for any input), that value is used. If it fails, the regular “missing field” error is thrown. This means that `fieldsAuto({ name: undefinedOr(string) })` successfully produces `{ name: undefined }` if given `{}` as input. It is supposed to fail in that case (because a required field is missing), but temporarily it does not fail. This is to support how a previous version of `fieldsUnion`was used. Now`fieldsUnion`has been updated to a new API, so this temporary behavior in `fieldsAuto` will be removed in an upcoming version of tiny-decoders.
488
496
489
497
### field
490
498
491
499
```ts
492
-
function field<Decoded, constMetaextendsFieldMeta>(
500
+
function field<Decoded, constMetaextendsOmit<FieldMeta, "tag">>(
493
501
decoder:Decoder<Decoded>,
494
502
meta:Meta,
495
503
):Field<Decoded, Meta>;
@@ -501,6 +509,7 @@ type Field<Decoded, Meta extends FieldMeta> = Meta & {
@@ -512,6 +521,8 @@ This function takes a decoder and lets you:
512
521
513
522
Use it with [fieldsAuto](#fieldsAuto).
514
523
524
+
The `tag` thing is handled by the [tag](#tag) function. It’s not something you’ll set manually using `field`. (That’s why the type annotation says `Omit<FieldMeta, "tag">`.)
525
+
515
526
Here’s an example illustrating the difference between `field(string, { optional: true })` and `undefinedOr(string)`:
// See `fieldsAuto` for the definitions of `Field`, `FieldMeta` and `FieldsMapping`.
592
616
```
593
617
594
618
Decodes JSON objects with a common string field (that tells them apart) into a TypeScript union type.
595
619
596
-
The `key` is the name of the common string field.
620
+
The `decodedCommonField` is the name of the common string field.
597
621
598
-
The `mapping` is an object where the keys are the strings of the `key` field and the values are decoders. The decoders are usually `fields` or `fieldsAuto`. The keys must be strings (not numbers) and you must provide at least one key.
599
-
600
-
You _can_ use [fields](#fields) to accomplish the same thing, but it’s easier with `fieldsUnion`. You also get better error messages and type inference with `fieldsUnion`.
622
+
`variants` is an array of objects. Those objects are “`fieldsAuto` objects” – they fit when passed to `fieldsAuto` as well. All of those objects must have `decodedCommonField` as a key, and use the [tag](#tag) function on that key.
See also the [renaming union field example](examples/renaming-union-field.test.ts).
621
643
644
+
### tag
645
+
646
+
```ts
647
+
exportfunction tag<
648
+
constDecodedextendsstring,
649
+
constEncodedextendsstring,
650
+
constEncodedFieldNameextendsstring,
651
+
>(
652
+
decoded:Decoded,
653
+
{
654
+
renameTagFrom=decoded,
655
+
renameFieldFrom,
656
+
}: {
657
+
renameTagFrom?:Encoded;
658
+
renameFieldFrom?:EncodedFieldName;
659
+
} = {},
660
+
):Field<
661
+
Decoded,
662
+
{
663
+
renameFrom:EncodedFieldName|undefined;
664
+
tag: { decoded:string; encoded:string };
665
+
}
666
+
>;
667
+
```
668
+
669
+
Used with [fieldsUnion](#fieldsunion), once for each variant of the union.
670
+
671
+
`tag("MyTag")` returns a `Field` with a decoder that requires the input `"MyTag"` and returns `"MyTag"`. The metadata of the `Field` also advertises that the tag value is `"MyTag"`, which `fieldsUnion` uses to know what to do.
672
+
673
+
`tag("MyTag", { renameTagFrom: "my_tag" })` returns a `Field` with a decoder that requires the input `"my_tag"` but returns `"MyTag"`.
674
+
675
+
For `renameFieldFrom`, see [fieldsUnion](#fieldsunion).
0 commit comments