diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ffedd7..66a32ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ 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. +### Version 22.0.0 (unreleased) + +This release renames `fieldsUnion` to `taggedUnion` since it better describes what it is, and it goes along better with the `tag` function. + ### Version 21.0.0 (2023-10-30) This release renames `nullable` to `nullOr` to be consistent with `undefinedOr`. diff --git a/README.md b/README.md index c6ebb1e..effbebd 100644 --- a/README.md +++ b/README.md @@ -119,11 +119,11 @@ Here’s a summary of all codecs (with slightly simplified type annotations) and - Unions: - Of primitive literals: [primitiveUnion](#primitiveunion) - Of different types: [multi](#multi) - - Of tagged objects: [fieldsUnion](#fieldsunion) with [tag](#tag) + - Of tagged objects: [taggedUnion](#taggedunion) with [tag](#tag) - With undefined: [undefinedOr](#undefinedor) - With null: [nullOr](#nullOr) - Other unions: [untagged union example](examples/untagged-union.test.ts) -- Intersections: [intersection example](examples/fieldsUnion-with-common-fields.test.ts) +- Intersections: [intersection example](examples/taggedUnion-with-common-fields.test.ts) - Transformation: [map](#map), [flatMap](#flatmap) - Recursion: [recursive](#recursive) - Errors: [DecoderError](#decodererror), [format](#format), [repr](#repr) @@ -250,7 +250,7 @@ Here’s a summary of all codecs (with slightly simplified type annotations) and n/a, only used with fieldsAuto -fieldsUnion +taggedUnion
(
   decodedCommonField: string,
   variants: Array<
@@ -602,10 +602,10 @@ type Example = {
 >
 > All in all, you avoid a slight gotcha with optional fields and inferred types if you enable `exactOptionalPropertyTypes`.
 
-### fieldsUnion
+### taggedUnion
 
 ```ts
-function fieldsUnion<
+function taggedUnion<
   const DecodedCommonField extends keyof Variants[number],
   Variants extends readonly [
     Variant,
@@ -646,7 +646,7 @@ type Shape =
   | { tag: "Circle"; radius: number }
   | { tag: "Rectangle"; width: number; height: number };
 
-const shapeCodec: Codec = fieldsUnion("tag", [
+const shapeCodec: Codec = taggedUnion("tag", [
   {
     tag: tag("Circle"),
     radius: number,
@@ -664,7 +664,7 @@ The `allowExtraFields` option works just like for [fieldsAuto](#fieldsauto).
 See also these examples:
 
 - [Renaming union field](examples/renaming-union-field.test.ts)
-- [`fieldsUnion` with common fields](examples/fieldsUnion-with-common-fields.test.ts)
+- [`taggedUnion` with common fields](examples/taggedUnion-with-common-fields.test.ts)
 
 Note: If you use the same tag value twice, the last one wins. TypeScript infers a type with two variants with the same tag (which is a valid type), but tiny-decoders can’t tell them apart. Nothing will ever decode to the first one, only the last one will succeed. Trying to encode the first one might result in bad data.
 
@@ -693,13 +693,13 @@ function tag<
 type primitive = bigint | boolean | number | string | symbol | null | undefined;
 ```
 
-Used with [fieldsUnion](#fieldsunion), once for each variant of the union.
+Used with [taggedUnion](#taggedunion), once for each variant of the union.
 
-`tag("MyTag")` returns a `Field` with a codec 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.
+`tag("MyTag")` returns a `Field` with a codec that requires the input `"MyTag"` and returns `"MyTag"`. The metadata of the `Field` also advertises that the tag value is `"MyTag"`, which `taggedUnion` uses to know what to do.
 
 `tag("MyTag", { renameTagFrom: "my_tag" })` returns a `Field` with a codec that requires the input `"my_tag"` but returns `"MyTag"`.
 
-For `renameFieldFrom`, see [fieldsUnion](#fieldsunion).
+For `renameFieldFrom`, see [taggedUnion](#taggedunion).
 
 You will typically use string tags for your tagged unions, but other primitive types such as `boolean` and `number` are supported too.
 
@@ -942,7 +942,7 @@ type DecoderError = {
       got: number;
     }
   | {
-      tag: "unknown fieldsUnion tag";
+      tag: "unknown taggedUnion tag";
       knownTags: Array;
       got: unknown;
     }
@@ -1160,6 +1160,6 @@ function either(codec1: Codec, codec2: Codec): Codec;
 The decoder of this codec would try `codec1.decoder` first. If it fails, go on and try `codec2.decoder`. If that fails, present both errors. I consider this a blunt tool.
 
 - If you want either a string or a number, use [multi](#multi). This let’s you switch between any JSON types.
-- For objects that can be decoded in different ways, use [fieldsUnion](#fieldsunion). If that’s not possible, see the [untagged union example](examples/untagged-union.test.ts) for how you can approach the problem.
+- For objects that can be decoded in different ways, use [taggedUnion](#taggedunion). If that’s not possible, see the [untagged union example](examples/untagged-union.test.ts) for how you can approach the problem.
 
 The above approaches result in a much simpler [DecoderError](#decodererror) type, and also results in much better error messages, since there’s never a need to present something like “decoding failed in the following 2 ways: …”
diff --git a/examples/renaming-union-field.test.ts b/examples/renaming-union-field.test.ts
index 54d9ecf..5bb4e2e 100644
--- a/examples/renaming-union-field.test.ts
+++ b/examples/renaming-union-field.test.ts
@@ -1,12 +1,12 @@
 import { expectType, TypeEqual } from "ts-expect";
 import { expect, test } from "vitest";
 
-import { fieldsUnion, Infer, InferEncoded, number, tag } from "../";
+import { Infer, InferEncoded, number, tag, taggedUnion } from "../";
 
 test("using different tags in JSON and in TypeScript", () => {
   // Here’s how to use different keys and values in JSON and TypeScript.
   // For example, `"type": "circle"` → `tag: "Circle"`.
-  const shapeCodec = fieldsUnion("tag", [
+  const shapeCodec = taggedUnion("tag", [
     {
       tag: tag("Circle", { renameTagFrom: "circle", renameFieldFrom: "type" }),
       radius: number,
diff --git a/examples/fieldsUnion-fallback.test.ts b/examples/taggedUnion-fallback.test.ts
similarity index 83%
rename from examples/fieldsUnion-fallback.test.ts
rename to examples/taggedUnion-fallback.test.ts
index 25cbac9..bc93a26 100644
--- a/examples/fieldsUnion-fallback.test.ts
+++ b/examples/taggedUnion-fallback.test.ts
@@ -1,12 +1,12 @@
 import { expectType, TypeEqual } from "ts-expect";
 import { expect, test } from "vitest";
 
-import { Codec, fieldsUnion, Infer, number, tag } from "../";
+import { Codec, Infer, number, tag, taggedUnion } from "../";
 import { run } from "../tests/helpers";
 
-test("fieldsUnion with fallback for unknown tags", () => {
+test("taggedUnion with fallback for unknown tags", () => {
   // Here’s a helper function that takes a codec – which is supposed to be a
-  // `fieldsUnion` codec – and makes it return `undefined` if the tag is unknown.
+  // `taggedUnion` codec – and makes it return `undefined` if the tag is unknown.
   function handleUnknownTag(
     codec: Codec,
   ): Codec {
@@ -15,8 +15,8 @@ test("fieldsUnion with fallback for unknown tags", () => {
         const decoderResult = codec.decoder(value);
         switch (decoderResult.tag) {
           case "DecoderError":
-            return decoderResult.error.path.length === 1 && // Don’t match on nested `fieldsUnion`.
-              decoderResult.error.tag === "unknown fieldsUnion tag"
+            return decoderResult.error.path.length === 1 && // Don’t match on nested `taggedUnion`.
+              decoderResult.error.tag === "unknown taggedUnion tag"
               ? { tag: "Valid", value: undefined }
               : decoderResult;
           case "Valid":
@@ -28,12 +28,12 @@ test("fieldsUnion with fallback for unknown tags", () => {
     };
   }
 
-  const shapeCodec = fieldsUnion("tag", [
+  const shapeCodec = taggedUnion("tag", [
     { tag: tag("Circle"), radius: number },
     { tag: tag("Square"), side: number },
   ]);
 
-  const codec = fieldsUnion("tag", [
+  const codec = taggedUnion("tag", [
     { tag: tag("One") },
     { tag: tag("Two"), value: shapeCodec },
   ]);
@@ -74,7 +74,7 @@ test("fieldsUnion with fallback for unknown tags", () => {
   `);
   expect(run(codecWithFallback, { tag: "Three" })).toBeUndefined();
 
-  // A nested `fieldsUnion` still fails on unknown tags:
+  // A nested `taggedUnion` still fails on unknown tags:
   expect(run(codecWithFallback, { tag: "Two", value: { tag: "Rectangle" } }))
     .toMatchInlineSnapshot(`
     At root["value"]["tag"]:
diff --git a/examples/fieldsUnion-with-common-fields.test.ts b/examples/taggedUnion-with-common-fields.test.ts
similarity index 97%
rename from examples/fieldsUnion-with-common-fields.test.ts
rename to examples/taggedUnion-with-common-fields.test.ts
index c41d26d..c2da01f 100644
--- a/examples/fieldsUnion-with-common-fields.test.ts
+++ b/examples/taggedUnion-with-common-fields.test.ts
@@ -5,16 +5,16 @@ import {
   boolean,
   Codec,
   fieldsAuto,
-  fieldsUnion,
   Infer,
   InferEncoded,
   number,
   string,
   tag,
+  taggedUnion,
 } from "../";
 import { run } from "../tests/helpers";
 
-test("fieldsUnion with common fields", () => {
+test("taggedUnion with common fields", () => {
   // This function takes two codecs for object types and returns
   // a new codec which is the intersection of those.
   // This function is not part of the tiny-decoders package because it has some caveats:
@@ -56,7 +56,7 @@ test("fieldsUnion with common fields", () => {
   }
 
   type EventWithPayload = Infer;
-  const EventWithPayload = fieldsUnion("event", [
+  const EventWithPayload = taggedUnion("event", [
     {
       event: tag("opened"),
       payload: string,
diff --git a/examples/untagged-union.test.ts b/examples/untagged-union.test.ts
index d3e72c7..1a7f84f 100644
--- a/examples/untagged-union.test.ts
+++ b/examples/untagged-union.test.ts
@@ -6,12 +6,12 @@ import {
   Codec,
   field,
   fieldsAuto,
-  fieldsUnion,
   Infer,
   InferEncoded,
   number,
   string,
   tag,
+  taggedUnion,
   unknown,
 } from "../";
 import { run } from "../tests/helpers";
@@ -119,7 +119,7 @@ test("tagged tuples", () => {
     },
   };
 
-  // A function that takes a regular `fieldsUnion` codec, but makes it work on
+  // A function that takes a regular `taggedUnion` codec, but makes it work on
   // tagged tuples instead.
   function toArrayUnion<
     Decoded extends Record,
@@ -141,7 +141,7 @@ test("tagged tuples", () => {
 
   type Shape = Infer;
   const Shape = toArrayUnion(
-    fieldsUnion("tag", [
+    taggedUnion("tag", [
       {
         tag: tag("Circle", { renameFieldFrom: "0" }),
         radius: field(number, { renameFrom: "1" }),
diff --git a/index.ts b/index.ts
index 638958c..f253e6e 100644
--- a/index.ts
+++ b/index.ts
@@ -429,7 +429,7 @@ type Variant = Record<
 > &
   Record | Field>;
 
-export function fieldsUnion<
+export function taggedUnion<
   const DecodedCommonField extends keyof Variants[number],
   Variants extends readonly [
     Variant,
@@ -440,7 +440,7 @@ export function fieldsUnion<
     Variants[number]
   > extends never
     ? [
-        "fieldsUnion variants must have a field in common, and their encoded field names must be the same",
+        "taggedUnion variants must have a field in common, and their encoded field names must be the same",
         never,
       ]
     : DecodedCommonField,
@@ -451,7 +451,7 @@ export function fieldsUnion<
   InferEncodedFieldsUnion
 > {
   if (decodedCommonField === "__proto__") {
-    throw new Error("fieldsUnion: decoded common field cannot be __proto__");
+    throw new Error("taggedUnion: decoded common field cannot be __proto__");
   }
 
   type VariantCodec = Codec;
@@ -473,7 +473,7 @@ export function fieldsUnion<
       maybeEncodedCommonField = encodedFieldName;
     } else if (maybeEncodedCommonField !== encodedFieldName) {
       throw new Error(
-        `fieldsUnion: Variant at index ${index}: Key ${JSON.stringify(
+        `taggedUnion: Variant at index ${index}: Key ${JSON.stringify(
           decodedCommonField,
         )}: Got a different encoded field name (${JSON.stringify(
           encodedFieldName,
@@ -487,7 +487,7 @@ export function fieldsUnion<
 
   if (typeof maybeEncodedCommonField !== "string") {
     throw new Error(
-      `fieldsUnion: Got unusable encoded common field: ${repr(
+      `taggedUnion: Got unusable encoded common field: ${repr(
         maybeEncodedCommonField,
       )}`,
     );
@@ -509,7 +509,7 @@ export function fieldsUnion<
         return {
           tag: "DecoderError",
           error: {
-            tag: "unknown fieldsUnion tag",
+            tag: "unknown taggedUnion tag",
             knownTags: Array.from(decoderMap.keys()),
             got: encodedName,
             path: [encodedCommonField],
@@ -525,7 +525,7 @@ export function fieldsUnion<
       const encoder = encoderMap.get(decodedName);
       if (encoder === undefined) {
         throw new Error(
-          `fieldsUnion: Unexpectedly found no encoder for decoded variant name: ${JSON.stringify(
+          `taggedUnion: Unexpectedly found no encoder for decoded variant name: ${JSON.stringify(
             decodedName,
           )} at key ${JSON.stringify(decodedCommonField)}`,
         );
@@ -952,11 +952,6 @@ export type DecoderError = {
       expected: number;
       got: number;
     }
-  | {
-      tag: "unknown fieldsUnion tag";
-      knownTags: Array;
-      got: unknown;
-    }
   | {
       tag: "unknown multi type";
       knownTypes: Array<
@@ -975,6 +970,11 @@ export type DecoderError = {
       knownVariants: Array;
       got: unknown;
     }
+  | {
+      tag: "unknown taggedUnion tag";
+      knownTags: Array;
+      got: unknown;
+    }
   | {
       tag: "wrong tag";
       expected: primitive;
@@ -1039,7 +1039,7 @@ function formatDecoderErrorVariant(
           : variant.knownTypes.join(", ")
       }\nGot: ${formatGot(variant.got)}`;
 
-    case "unknown fieldsUnion tag":
+    case "unknown taggedUnion tag":
       return `Expected one of these tags:${primitiveList(
         variant.knownTags,
       )}\nGot: ${formatGot(variant.got)}`;
diff --git a/tests/codecs.test.ts b/tests/codecs.test.ts
index b0b7e37..939fc1c 100644
--- a/tests/codecs.test.ts
+++ b/tests/codecs.test.ts
@@ -9,7 +9,6 @@ import {
   DecoderResult,
   field,
   fieldsAuto,
-  fieldsUnion,
   flatMap,
   Infer,
   InferEncoded,
@@ -22,6 +21,7 @@ import {
   recursive,
   string,
   tag,
+  taggedUnion,
   tuple,
   undefinedOr,
   unknown,
@@ -978,10 +978,10 @@ describe("fieldsAuto", () => {
   });
 });
 
-describe("fieldsUnion", () => {
+describe("taggedUnion", () => {
   test("string tags", () => {
     type Shape = Infer;
-    const Shape = fieldsUnion("tag", [
+    const Shape = taggedUnion("tag", [
       {
         tag: tag("Circle"),
         radius: number,
@@ -1059,7 +1059,7 @@ describe("fieldsUnion", () => {
         Got: "Square"
       `);
 
-    expect(run(fieldsUnion("0", [{ "0": tag("a") }]), ["a"]))
+    expect(run(taggedUnion("0", [{ "0": tag("a") }]), ["a"]))
       .toMatchInlineSnapshot(`
       At root:
       Expected an object
@@ -1071,7 +1071,7 @@ describe("fieldsUnion", () => {
 
   test("boolean tags", () => {
     type User = Infer;
-    const User = fieldsUnion("isAdmin", [
+    const User = taggedUnion("isAdmin", [
       {
         isAdmin: tag(true),
         name: string,
@@ -1163,7 +1163,7 @@ describe("fieldsUnion", () => {
     const symbol2 = Symbol("symbol2");
 
     type Type = Infer;
-    const codec = fieldsUnion("tag", [
+    const codec = taggedUnion("tag", [
       { tag: tag(undefined) },
       { tag: tag(null) },
       { tag: tag(true) },
@@ -1240,7 +1240,7 @@ describe("fieldsUnion", () => {
 
     type Type = Infer;
     type EncodedType = InferEncoded;
-    const codec = fieldsUnion("tag", [
+    const codec = taggedUnion("tag", [
       { tag: tag("undefined", { renameTagFrom: undefined }) },
       { tag: tag("null", { renameTagFrom: null }) },
       { tag: tag("true", { renameTagFrom: true }) },
@@ -1335,9 +1335,9 @@ describe("fieldsUnion", () => {
 
   test("__proto__ is not allowed", () => {
     expect(() =>
-      fieldsUnion("__proto__", [{ __proto__: tag("Test") }]),
+      taggedUnion("__proto__", [{ __proto__: tag("Test") }]),
     ).toThrowErrorMatchingInlineSnapshot(
-      '"fieldsUnion: decoded common field cannot be __proto__"',
+      '"taggedUnion: decoded common field cannot be __proto__"',
     );
   });
 
@@ -1345,59 +1345,59 @@ describe("fieldsUnion", () => {
     expect(() =>
       // @ts-expect-error Argument of type '[]' is not assignable to parameter of type 'readonly [Variant<"tag">, ...Variant<"tag">[]]'.
       //   Source has 0 element(s) but target requires 1.
-      fieldsUnion("tag", []),
+      taggedUnion("tag", []),
     ).toThrowErrorMatchingInlineSnapshot(
-      '"fieldsUnion: Got unusable encoded common field: undefined"',
+      '"taggedUnion: Got unusable encoded common field: undefined"',
     );
   });
 
   test("decodedCommonField mismatch", () => {
     expect(() =>
       // @ts-expect-error Property 'tag' is missing in type '{ type: Field<"Test", { tag: { decoded: string; encoded: string; }; }>; }' but required in type 'Record<"tag", Field>'.
-      fieldsUnion("tag", [{ type: tag("Test") }]),
+      taggedUnion("tag", [{ type: tag("Test") }]),
     ).toThrow();
   });
 
   test("one variant uses wrong decodedCommonField", () => {
     expect(() =>
       // @ts-expect-error Property 'tag' is missing in type '{ type: Field<"B", { tag: { decoded: string; encoded: string; }; }>; }' but required in type 'Record<"tag", Field>'.
-      fieldsUnion("tag", [{ tag: tag("A") }, { type: tag("B") }]),
+      taggedUnion("tag", [{ tag: tag("A") }, { type: tag("B") }]),
     ).toThrow();
   });
 
   test("decodedCommonField does not use the tag function", () => {
     expect(() =>
       // @ts-expect-error Type '(value: unknown) => string' is not assignable to type 'Field'.
-      fieldsUnion("tag", [{ tag: string }]),
+      taggedUnion("tag", [{ tag: string }]),
     ).toThrow();
   });
 
   test("encodedCommonField mismatch", () => {
     expect(() =>
-      // @ts-expect-error Argument of type 'string' is not assignable to parameter of type '["fieldsUnion variants must have a field in common, and their encoded field names must be the same", never]'.
-      fieldsUnion("tag", [
+      // @ts-expect-error Argument of type 'string' is not assignable to parameter of type '["taggedUnion variants must have a field in common, and their encoded field names must be the same", never]'.
+      taggedUnion("tag", [
         { tag: tag("A") },
         { tag: tag("B", { renameFieldFrom: "type" }) },
       ]),
     ).toThrowErrorMatchingInlineSnapshot(
-      '"fieldsUnion: Variant at index 1: Key \\"tag\\": Got a different encoded field name (\\"type\\") than before (\\"tag\\")."',
+      '"taggedUnion: Variant at index 1: Key \\"tag\\": Got a different encoded field name (\\"type\\") than before (\\"tag\\")."',
     );
   });
 
   test("encodedCommonField mismatch 2", () => {
     expect(() =>
-      // @ts-expect-error Argument of type 'string' is not assignable to parameter of type '["fieldsUnion variants must have a field in common, and their encoded field names must be the same", never]'.
-      fieldsUnion("tag", [
+      // @ts-expect-error Argument of type 'string' is not assignable to parameter of type '["taggedUnion variants must have a field in common, and their encoded field names must be the same", never]'.
+      taggedUnion("tag", [
         { tag: tag("A", { renameFieldFrom: "other" }) },
         { tag: tag("B", { renameFieldFrom: "type" }) },
       ]),
     ).toThrowErrorMatchingInlineSnapshot(
-      '"fieldsUnion: Variant at index 1: Key \\"tag\\": Got a different encoded field name (\\"type\\") than before (\\"other\\")."',
+      '"taggedUnion: Variant at index 1: Key \\"tag\\": Got a different encoded field name (\\"type\\") than before (\\"other\\")."',
     );
   });
 
   test("same encodedCommonField correctly used on every variant", () => {
-    const codec = fieldsUnion("tag", [
+    const codec = taggedUnion("tag", [
       { tag: tag("A", { renameFieldFrom: "type" }) },
       { tag: tag("B", { renameFieldFrom: "type" }) },
     ]);
@@ -1418,7 +1418,7 @@ describe("fieldsUnion", () => {
 
   test("same tag used twice", () => {
     type Type = Infer;
-    const codec = fieldsUnion("tag", [
+    const codec = taggedUnion("tag", [
       { tag: tag("Test"), one: number },
       { tag: tag("Test"), two: string },
     ]);
@@ -1479,7 +1479,7 @@ describe("fieldsUnion", () => {
       okCodec: Codec,
       errCodec: Codec,
     ): Codec> =>
-      fieldsUnion("tag", [
+      taggedUnion("tag", [
         {
           tag: tag("Ok"),
           value: okCodec,
@@ -1533,7 +1533,7 @@ describe("fieldsUnion", () => {
       okCodec: Codec,
       errCodec: Codec,
     ): Codec, Result> =>
-      fieldsUnion("tag", [
+      taggedUnion("tag", [
         {
           tag: tag("Ok"),
           value: okCodec,
@@ -1567,7 +1567,7 @@ describe("fieldsUnion", () => {
   });
 
   test("always print the expected tags in full", () => {
-    const codec = fieldsUnion("tag", [
+    const codec = taggedUnion("tag", [
       { tag: tag("PrettyLongTagName1"), value: string },
       { tag: tag("PrettyLongTagName2"), value: string },
     ]);
@@ -1588,7 +1588,7 @@ describe("fieldsUnion", () => {
   });
 
   test("unexpectedly found no encoder for decoded variant name", () => {
-    const codec = fieldsUnion("tag", [
+    const codec = taggedUnion("tag", [
       { tag: tag("One") },
       { tag: tag("Two") },
     ]);
@@ -1597,7 +1597,7 @@ describe("fieldsUnion", () => {
       // @ts-expect-error Type '"Three"' is not assignable to type '"One" | "Two"'.
       codec.encoder({ tag: "Three" }),
     ).toThrowErrorMatchingInlineSnapshot(
-      '"fieldsUnion: Unexpectedly found no encoder for decoded variant name: \\"Three\\" at key \\"tag\\""',
+      '"taggedUnion: Unexpectedly found no encoder for decoded variant name: \\"Three\\" at key \\"tag\\""',
     );
   });
 
@@ -1605,7 +1605,7 @@ describe("fieldsUnion", () => {
     test("allows excess properties by default", () => {
       expect(
         run(
-          fieldsUnion("tag", [{ tag: tag("Test"), one: string, two: boolean }]),
+          taggedUnion("tag", [{ tag: tag("Test"), one: string, two: boolean }]),
           {
             tag: "Test",
             one: "a",
@@ -1618,7 +1618,7 @@ describe("fieldsUnion", () => {
 
       expect(
         run(
-          fieldsUnion(
+          taggedUnion(
             "tag",
             [{ tag: tag("Test"), one: string, two: boolean }],
             { allowExtraFields: true },
@@ -1633,7 +1633,7 @@ describe("fieldsUnion", () => {
         ),
       ).toStrictEqual({ tag: "Test", one: "a", two: true });
 
-      fieldsUnion("tag", [
+      taggedUnion("tag", [
         { tag: tag("Test"), one: string, two: boolean },
       ]).encoder({
         tag: "Test",
@@ -1648,7 +1648,7 @@ describe("fieldsUnion", () => {
     test("fail on excess properties", () => {
       expect(
         run(
-          fieldsUnion(
+          taggedUnion(
             "tag",
             [{ tag: tag("Test"), one: string, two: boolean }],
             { allowExtraFields: false },
@@ -1672,7 +1672,7 @@ describe("fieldsUnion", () => {
         "four"
     `);
 
-      fieldsUnion("tag", [{ tag: tag("Test"), one: string, two: boolean }], {
+      taggedUnion("tag", [{ tag: tag("Test"), one: string, two: boolean }], {
         allowExtraFields: false,
       }).encoder({
         tag: "Test",
@@ -1687,7 +1687,7 @@ describe("fieldsUnion", () => {
     test("large number of excess properties", () => {
       expect(
         run(
-          fieldsUnion(
+          taggedUnion(
             "tag",
             [{ tag: tag("Test"), "1": boolean, "2": boolean }],
             { allowExtraFields: false },
@@ -1716,7 +1716,7 @@ describe("fieldsUnion", () => {
     });
 
     test("always print the expected keys in full", () => {
-      const codec = fieldsUnion(
+      const codec = taggedUnion(
         "tag",
         [
           {