Repository: karen-irc/option-t
Pull request #1256 (2022-04-07 09:13:16)

Fill unused field for shape stability of `PlainResult<T, E>` type with `null` instead of `undefined`
This is just **Breaking Change**.

## Motivation

With Next.js v12.1, we cannot use `PlainResult` type as the returned type for `getServerSideProps()` by following error.

```
Server Error

Error: Error serializing `.val` returned from `getServerSideProps` in "/path/[bafoo]".
Reason: `undefined` cannot be serialized as JSON. Please use `null` or omit this value.
This error happened while generating the page. Any console logs will be displayed in the terminal window.
```

To avoid this error, an user need to re-implement `createOk`/`createErr`.

Next.js is emerging web development framework and I think it's important for next 3~5 years.

So we should fix them.

## Possible Performance Impact

I confirmed what this change impacts on JSVM's internal shape (SM)/hidden class (V8)/structure (JSC).
I tested JavaScriptCore (for Safari 15.4), SpiderMonkey (for Firefox v99), and V8 9.9.
They are now used a single shape.

So I conclude this would cause a serious performance problem.

### Test code

#### Shared Part

<details>

```javascript
const FILL_VALUE = null;

function ok(val) {
    return { ok, val, err: FILL_VALUE };
}

function err(err) {
    return { ok, val: FILL_VALUE, err };
}

const VALUES = [
    0,
    1,
    -1,
    BigInt(1),
    true,
    false,
    "test",
    null,
    undefined,
    [],
    {},
    function () {},
    Symbol(''),
];

function getTypeof(v) {
    return v === null ? 'null' : typeof v;
}


for (const left of VALUES) {
    for (const right of VALUES) {
        const a = ok(left);
        const b = err(right);
        const label = `left=${getTypeof(left)}, right=${getTypeof(right)}: `
        // TEST CODE
    }
}
```

</details>

### V8

<details>

```diff
      for (const right of VALUES) {
          const a = ok(left);
          const b = err(right);
          const label = `left=${getTypeof(left)}, right=${getTypeof(right)}: `
+         print(label +  %HaveSameMap( a, b ) );
      }
```

</details>

### JavaScriptCore

<details>

```diff
      for (const right of VALUES) {
          const a = ok(left);
          const b = err(right);
          const label = `left=${getTypeof(left)}, right=${getTypeof(right)}: `
+         print(label);
+         print(describe(a));
+         print(describe(b));
      }
```

</details>

### SpiderMonkey

<details>

```diff
      for (const right of VALUES) {
          const a = ok(left);
          const b = err(right);
          const label = `left=${getTypeof(left)}, right=${getTypeof(right)}: `
+         print(label + (shapeOf(a) === shapeOf(b)));
      }
```

</details>


## User Impact

This change these fields types to `null` or `undefined`.

- `PlainResult`
    - `Ok.err`
    - `Err.val`
- `PlainOption`
    - `None.val`

If user touch these field directly and use them, then the user code may be broken by this change.
We need to recommend to use`unwrap()` or other similar methods.

The following case is typical problem:

```ts
// This function is expected that if `result` is Ok, return number. Otherwise, return `undefined`.
function bar(result: Result<number, Error>) {
    return result.val;
}

// This `foo` was `number | undefned` previously.
// But now `foo` is `number | null | undefined`.
const foo = bar(result);

// Previously, this dumped `undefined` if result is Err.
// But now, this dump `null` or `undefined`.
console.log(foo);
```

In this case, if user specify the return type of `bar()`, then we would catch this pattern easily.
But if user does not specify types explicitly and use type inference aggressively, catching this problem would be a bit hard.


Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 0681e521..2833e0d5 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -39,7 +39,7 @@ jobs:
               run: echo "::set-output name=dir::$(yarn cache dir)"
             - name: Restore dependencies from cache
               id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
-              uses: actions/cache@v3.0.1
+              uses: actions/cache@v2.1.7
               with:
                   path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
                   key: v0-${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
@@ -69,7 +69,7 @@ jobs:
               run: echo "::set-output name=dir::$(yarn cache dir)"
             - name: Restore dependencies from cache
               id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
-              uses: actions/cache@v3.0.1
+              uses: actions/cache@v2.1.7
               with:
                   path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
                   key: v0-${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
@@ -100,7 +100,7 @@ jobs:
               run: echo "::set-output name=dir::$(yarn cache dir)"
             - name: Restore dependencies from cache
               id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
-              uses: actions/cache@v3.0.1
+              uses: actions/cache@v2.1.7
               with:
                   path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
                   key: v0-${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
@@ -131,7 +131,7 @@ jobs:
               run: echo "::set-output name=dir::$(yarn cache dir)"
             - name: Restore dependencies from cache
               id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
-              uses: actions/cache@v3.0.1
+              uses: actions/cache@v2.1.7
               with:
                   path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
                   key: v0-${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
@@ -163,7 +163,7 @@ jobs:
               run: echo "::set-output name=dir::$(yarn cache dir)"
             - name: Restore dependencies from cache
               id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
-              uses: actions/cache@v3.0.1
+              uses: actions/cache@v2.1.7
               with:
                   path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
                   key: v0-${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
@@ -195,7 +195,7 @@ jobs:
               run: echo "::set-output name=dir::$(yarn cache dir)"
             - name: Restore dependencies from cache
               id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
-              uses: actions/cache@v3.0.1
+              uses: actions/cache@v2.1.7
               with:
                   path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
                   key: v0-${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
@@ -227,7 +227,7 @@ jobs:
               run: echo "::set-output name=dir::$(yarn cache dir)"
             - name: Restore dependencies from cache
               id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
-              uses: actions/cache@v3.0.1
+              uses: actions/cache@v2.1.7
               with:
                   path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
                   key: v0-${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
@@ -259,7 +259,7 @@ jobs:
               run: echo "::set-output name=dir::$(yarn cache dir)"
             - name: Restore dependencies from cache
               id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
-              uses: actions/cache@v3.0.1
+              uses: actions/cache@v2.1.7
               with:
                   path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
                   key: v0-${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
diff --git a/package.json b/package.json
index 28c3a4b8..5070b25e 100644
--- a/package.json
+++ b/package.json
@@ -55,14 +55,14 @@
     "@babel/cli": "^7.17.6",
     "@babel/core": "^7.17.8",
     "@babel/preset-env": "^7.16.11",
-    "@typescript-eslint/eslint-plugin": "^5.17.0",
-    "@typescript-eslint/parser": "^5.17.0",
+    "@typescript-eslint/eslint-plugin": "^5.15.0",
+    "@typescript-eslint/parser": "^5.15.0",
     "ava": "^4.1.0",
     "del-cli": "^4.0.1",
-    "eslint": "^8.12.0",
+    "eslint": "^8.11.0",
     "eslint-config-prettier": "^8.5.0",
     "picomatch": "^2.3.1",
-    "prettier": "^2.6.2",
+    "prettier": "^2.6.0",
     "typescript": "^4.5.5"
   },
   "sideEffects": false,
diff --git a/src/PlainOption/Option.ts b/src/PlainOption/Option.ts
index 370a865e..e8fefb3c 100644
--- a/src/PlainOption/Option.ts
+++ b/src/PlainOption/Option.ts
@@ -48,13 +48,12 @@ export interface None {
     // I tested a shape transition for some engines. By their results,
     // I concluded `Some` and `None` should have same properties to make to use the same shape.
     //
-    //  - V8 used an another hidden class if `val` is `number` or others.
+    //  - Modern JSVMs in web engines used a single shape.
+    //      - Inline cache would be monomorphic.
+    //      - I tested JavaScriptCore (for Safari 15.4), SpiderMonkey (for Firefox v99), and V8 9.9.
+    //  - Old V8 used an another hidden class if `val` is `number` or others.
     //      - Inline cache for an object taking this type would be polymorphic.
     //      - But we can assume that it will not be megamorphic by the observation.
-    //  - JavaScriptCore used single structure, not like as V8.
-    //      - Inline cache would be monomorphic.
-    //  - SpiderMonkey, I did not test it. But I assumed it would behave similary with other engines.
-    //      - I had not known how I trace for SM casually...
     //
     // Of course, this decision has some drawbacks for users of this package.
     //
@@ -63,12 +62,11 @@ export interface None {
     //     However, we don't think it is a common operation for user because we provide `is~~()` function
     //     and user will not do their operations generally for a "container" object like this type.
     //
-    //  2. If user will use `const { ok, val }` = None;`, then val will be `undefined`.
-    //     it's will not be a problem because `val` would be `undefined` if this type is `None`.
+    //  2. If user will use `const { ok, val }` = None;`, then val will be `null`.
     //
     // By these reasons, we should not recommend to create this object without this factory function.
     // User can create this object by hand. But it's fragile for the future change. So We should not recommend it.
-    readonly val?: undefined;
+    readonly val?: null;
 }
 
 export function isNone<T>(input: Option<T>): input is None {
@@ -78,7 +76,7 @@ export function isNone<T>(input: Option<T>): input is None {
 export function createNone(): None {
     const r: None = {
         ok: false,
-        val: undefined,
+        val: null,
     };
     return r;
 }
diff --git a/src/PlainResult/Result.ts b/src/PlainResult/Result.ts
index 81cd7807..74f126b6 100644
--- a/src/PlainResult/Result.ts
+++ b/src/PlainResult/Result.ts
@@ -32,13 +32,12 @@ export interface Ok<T> {
     // I tested a shape transition for some engines. By their results,
     // I concluded `Ok` and `Err` should have same properties to make to use the same shape.
     //
-    //  - V8 used an another hidden class if `val` is `number` or others.
+    //  - Modern JSVMs in web engines used a single shape.
+    //      - Inline cache would be monomorphic.
+    //      - I tested JavaScriptCore (for Safari 15.4), SpiderMonkey (for Firefox v99), and V8 9.9.
+    //  - Old V8 used an another hidden class if `val` is `number` or others.
     //      - Inline cache for an object taking this type would be polymorphic.
     //      - But we can assume that it will not be megamorphic by the observation.
-    //  - JavaScriptCore used single structure, not like as V8.
-    //      - Inline cache would be monomorphic.
-    //  - SpiderMonkey, I did not test it. But I assumed it would behave similary with other engines.
-    //      - I had not known how I trace for SM casually...
     //
     // Of course, this decision has some drawbacks for users of this package.
     //
@@ -47,13 +46,12 @@ export interface Ok<T> {
     //     However, we don't think it is a common operation for user because we provide `is~~()` function
     //     and user will not do their operations generally for a "container" object like this type.
     //
-    //  2. If user will use `const { ok, err }` = Ok;`, then val will be `undefined`.
-    //     it's will not be a problem because `err` would be `undefined` if this type is `Ok`.
+    //  2. If user will use `const { ok, err }` = Ok;`, then val will be `null`.
     //     We can say same thing for `Err`.
     //
     // By these reasons, we should not recommend to create this object without this factory function.
     // User can create this object by hand. But it's fragile for the future change. So We should not recommend it.
-    readonly err?: undefined;
+    readonly err?: null;
 }
 
 export function isOk<T, E>(input: Result<T, E>): input is Ok<T> {
@@ -64,7 +62,7 @@ export function createOk<T>(val: T): Ok<T> {
     const r: Ok<T> = {
         ok: true,
         val,
-        err: undefined,
+        err: null,
     };
     return r;
 }
@@ -79,13 +77,12 @@ export interface Err<E> {
     // I tested a shape transition for some engines. By their results,
     // I concluded `Ok` and `Err` should have same properties to make to use the same shape.
     //
-    //  - V8 used an another hidden class if `val` is `number` or others.
+    //  - Modern JSVMs in web engines used a single shape.
+    //      - Inline cache would be monomorphic.
+    //      - I tested JavaScriptCore (for Safari 15.4), SpiderMonkey (for Firefox v99), and V8 9.9.
+    //  - Old V8 used an another hidden class if `val` is `number` or others.
     //      - Inline cache for an object taking this type would be polymorphic.
     //      - But we can assume that it will not be megamorphic by the observation.
-    //  - JavaScriptCore used a single structure, not like as V8.
-    //      - Inline cache would be monomorphic.
-    //  - SpiderMonkey, I did not test it. But I assumed it would behave similary with other engines.
-    //      - I had not known how I trace for SM casually...
     //
     // Of course, this decision has some drawbacks for users of this package.
     //
@@ -94,13 +91,12 @@ export interface Err<E> {
     //     However, we don't think it is a common operation for user because we provide `is~~()` function
     //     and user will not do their operations generally for a "container" object like this type.
     //
-    //  2. If user will use `const { ok, err }` = Ok;`, then val will be `undefined`.
-    //     it's will not be a problem because `err` would be `undefined` if this type is `Ok`.
+    //  2. If user will use `const { ok, err }` = Ok;`, then val will be `null`.
     //     We can say same thing for `Err`.
     //
     // By these reasons, we should not recommend to create this object without this factory function.
     // User can create this object by hand. But it's fragile for the future change. So We should not recommend it.
-    readonly val?: undefined;
+    readonly val?: null;
 
     readonly err: E;
 }
@@ -112,8 +108,8 @@ export function isErr<T, E>(input: Result<T, E>): input is Err<E> {
 export function createErr<E>(err: E): Err<E> {
     const r: Err<E> = {
         ok: false,
-        val: undefined,
-        err: err,
+        val: null,
+        err,
     };
     return r;
 }
diff --git a/yarn.lock b/yarn.lock
index c2373120..accfdea9 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1046,14 +1046,14 @@
   resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301"
   integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==
 
-"@typescript-eslint/eslint-plugin@^5.17.0":
-  version "5.17.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.17.0.tgz#704eb4e75039000531255672bf1c85ee85cf1d67"
-  integrity sha512-qVstvQilEd89HJk3qcbKt/zZrfBZ+9h2ynpAGlWjWiizA7m/MtLT9RoX6gjtpE500vfIg8jogAkDzdCxbsFASQ==
-  dependencies:
-    "@typescript-eslint/scope-manager" "5.17.0"
-    "@typescript-eslint/type-utils" "5.17.0"
-    "@typescript-eslint/utils" "5.17.0"
+"@typescript-eslint/eslint-plugin@^5.15.0":
+  version "5.15.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.15.0.tgz#c28ef7f2e688066db0b6a9d95fb74185c114fb9a"
+  integrity sha512-u6Db5JfF0Esn3tiAKELvoU5TpXVSkOpZ78cEGn/wXtT2RVqs2vkt4ge6N8cRCyw7YVKhmmLDbwI2pg92mlv7cA==
+  dependencies:
+    "@typescript-eslint/scope-manager" "5.15.0"
+    "@typescript-eslint/type-utils" "5.15.0"
+    "@typescript-eslint/utils" "5.15.0"
     debug "^4.3.2"
     functional-red-black-tree "^1.0.1"
     ignore "^5.1.8"
@@ -1061,69 +1061,69 @@
     semver "^7.3.5"
     tsutils "^3.21.0"
 
-"@typescript-eslint/parser@^5.17.0":
-  version "5.17.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.17.0.tgz#7def77d5bcd8458d12d52909118cf3f0a45f89d5"
-  integrity sha512-aRzW9Jg5Rlj2t2/crzhA2f23SIYFlF9mchGudyP0uiD6SenIxzKoLjwzHbafgHn39dNV/TV7xwQkLfFTZlJ4ig==
+"@typescript-eslint/parser@^5.15.0":
+  version "5.15.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.15.0.tgz#95f603f8fe6eca7952a99bfeef9b85992972e728"
+  integrity sha512-NGAYP/+RDM2sVfmKiKOCgJYPstAO40vPAgACoWPO/+yoYKSgAXIFaBKsV8P0Cc7fwKgvj27SjRNX4L7f4/jCKQ==
   dependencies:
-    "@typescript-eslint/scope-manager" "5.17.0"
-    "@typescript-eslint/types" "5.17.0"
-    "@typescript-eslint/typescript-estree" "5.17.0"
+    "@typescript-eslint/scope-manager" "5.15.0"
+    "@typescript-eslint/types" "5.15.0"
+    "@typescript-eslint/typescript-estree" "5.15.0"
     debug "^4.3.2"
 
-"@typescript-eslint/scope-manager@5.17.0":
-  version "5.17.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.17.0.tgz#4cea7d0e0bc0e79eb60cad431c89120987c3f952"
-  integrity sha512-062iCYQF/doQ9T2WWfJohQKKN1zmmXVfAcS3xaiialiw8ZUGy05Em6QVNYJGO34/sU1a7a+90U3dUNfqUDHr3w==
+"@typescript-eslint/scope-manager@5.15.0":
+  version "5.15.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.15.0.tgz#d97afab5e0abf4018d1289bd711be21676cdd0ee"
+  integrity sha512-EFiZcSKrHh4kWk0pZaa+YNJosvKE50EnmN4IfgjkA3bTHElPtYcd2U37QQkNTqwMCS7LXeDeZzEqnsOH8chjSg==
   dependencies:
-    "@typescript-eslint/types" "5.17.0"
-    "@typescript-eslint/visitor-keys" "5.17.0"
+    "@typescript-eslint/types" "5.15.0"
+    "@typescript-eslint/visitor-keys" "5.15.0"
 
-"@typescript-eslint/type-utils@5.17.0":
-  version "5.17.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.17.0.tgz#1c4549d68c89877662224aabb29fbbebf5fc9672"
-  integrity sha512-3hU0RynUIlEuqMJA7dragb0/75gZmwNwFf/QJokWzPehTZousP/MNifVSgjxNcDCkM5HI2K22TjQWUmmHUINSg==
+"@typescript-eslint/type-utils@5.15.0":
+  version "5.15.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.15.0.tgz#d2c02eb2bdf54d0a645ba3a173ceda78346cf248"
+  integrity sha512-KGeDoEQ7gHieLydujGEFLyLofipe9PIzfvA/41urz4hv+xVxPEbmMQonKSynZ0Ks2xDhJQ4VYjB3DnRiywvKDA==
   dependencies:
-    "@typescript-eslint/utils" "5.17.0"
+    "@typescript-eslint/utils" "5.15.0"
     debug "^4.3.2"
     tsutils "^3.21.0"
 
-"@typescript-eslint/types@5.17.0":
-  version "5.17.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.17.0.tgz#861ec9e669ffa2aa9b873dd4d28d9b1ce26d216f"
-  integrity sha512-AgQ4rWzmCxOZLioFEjlzOI3Ch8giDWx8aUDxyNw9iOeCvD3GEYAB7dxWGQy4T/rPVe8iPmu73jPHuaSqcjKvxw==
+"@typescript-eslint/types@5.15.0":
+  version "5.15.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.15.0.tgz#c7bdd103843b1abae97b5518219d3e2a0d79a501"
+  integrity sha512-yEiTN4MDy23vvsIksrShjNwQl2vl6kJeG9YkVJXjXZnkJElzVK8nfPsWKYxcsGWG8GhurYXP4/KGj3aZAxbeOA==
 
-"@typescript-eslint/typescript-estree@5.17.0":
-  version "5.17.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.17.0.tgz#a7cba7dfc8f9cc2ac78c18584e684507df4f2488"
-  integrity sha512-X1gtjEcmM7Je+qJRhq7ZAAaNXYhTgqMkR10euC4Si6PIjb+kwEQHSxGazXUQXFyqfEXdkGf6JijUu5R0uceQzg==
+"@typescript-eslint/typescript-estree@5.15.0":
+  version "5.15.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.15.0.tgz#81513a742a9c657587ad1ddbca88e76c6efb0aac"
+  integrity sha512-Hb0e3dGc35b75xLzixM3cSbG1sSbrTBQDfIScqdyvrfJZVEi4XWAT+UL/HMxEdrJNB8Yk28SKxPLtAhfCbBInA==
   dependencies:
-    "@typescript-eslint/types" "5.17.0"
-    "@typescript-eslint/visitor-keys" "5.17.0"
+    "@typescript-eslint/types" "5.15.0"
+    "@typescript-eslint/visitor-keys" "5.15.0"
     debug "^4.3.2"
     globby "^11.0.4"
     is-glob "^4.0.3"
     semver "^7.3.5"
     tsutils "^3.21.0"
 
-"@typescript-eslint/utils@5.17.0":
-  version "5.17.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.17.0.tgz#549a9e1d491c6ccd3624bc3c1b098f5cfb45f306"
-  integrity sha512-DVvndq1QoxQH+hFv+MUQHrrWZ7gQ5KcJzyjhzcqB1Y2Xes1UQQkTRPUfRpqhS8mhTWsSb2+iyvDW1Lef5DD7vA==
+"@typescript-eslint/utils@5.15.0":
+  version "5.15.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.15.0.tgz#468510a0974d3ced8342f37e6c662778c277f136"
+  integrity sha512-081rWu2IPKOgTOhHUk/QfxuFog8m4wxW43sXNOMSCdh578tGJ1PAaWPsj42LOa7pguh173tNlMigsbrHvh/mtA==
   dependencies:
     "@types/json-schema" "^7.0.9"
-    "@typescript-eslint/scope-manager" "5.17.0"
-    "@typescript-eslint/types" "5.17.0"
-    "@typescript-eslint/typescript-estree" "5.17.0"
+    "@typescript-eslint/scope-manager" "5.15.0"
+    "@typescript-eslint/types" "5.15.0"
+    "@typescript-eslint/typescript-estree" "5.15.0"
     eslint-scope "^5.1.1"
     eslint-utils "^3.0.0"
 
-"@typescript-eslint/visitor-keys@5.17.0":
-  version "5.17.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.17.0.tgz#52daae45c61b0211b4c81b53a71841911e479128"
-  integrity sha512-6K/zlc4OfCagUu7Am/BD5k8PSWQOgh34Nrv9Rxe2tBzlJ7uOeJ/h7ugCGDCeEZHT6k2CJBhbk9IsbkPI0uvUkA==
+"@typescript-eslint/visitor-keys@5.15.0":
+  version "5.15.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.15.0.tgz#5669739fbf516df060f978be6a6dce75855a8027"
+  integrity sha512-+vX5FKtgvyHbmIJdxMJ2jKm9z2BIlXJiuewI8dsDYMp5LzPUcuTT78Ya5iwvQg3VqSVdmxyM8Anj1Jeq7733ZQ==
   dependencies:
-    "@typescript-eslint/types" "5.17.0"
+    "@typescript-eslint/types" "5.15.0"
     eslint-visitor-keys "^3.0.0"
 
 acorn-jsx@^5.3.1:
@@ -1782,10 +1782,10 @@ eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.3.0:
   resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826"
   integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==
 
-eslint@^8.12.0:
-  version "8.12.0"
-  resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.12.0.tgz#c7a5bd1cfa09079aae64c9076c07eada66a46e8e"
-  integrity sha512-it1oBL9alZg1S8UycLm5YDMAkIhtH6FtAzuZs6YvoGVldWjbS08BkAdb/ymP9LlAyq8koANu32U7Ib/w+UNh8Q==
+eslint@^8.11.0:
+  version "8.11.0"
+  resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.11.0.tgz#88b91cfba1356fc10bb9eb592958457dfe09fb37"
+  integrity sha512-/KRpd9mIRg2raGxHRGwW9ZywYNAClZrHjdueHcrVDuO3a6bj83eoTirCCk0M0yPwOjWYKHwRVRid+xK4F/GHgA==
   dependencies:
     "@eslint/eslintrc" "^1.2.1"
     "@humanwhocodes/config-array" "^0.9.2"
@@ -2468,9 +2468,9 @@ minimist-options@4.1.0:
     kind-of "^6.0.3"
 
 minimist@^1.2.5:
-  version "1.2.6"
-  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
-  integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
+  version "1.2.5"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
+  integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
 
 ms@2.1.2:
   version "2.1.2"
@@ -2692,10 +2692,10 @@ prelude-ls@^1.2.1:
   resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
   integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
 
-prettier@^2.6.2:
-  version "2.6.2"
-  resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.2.tgz#e26d71a18a74c3d0f0597f55f01fb6c06c206032"
-  integrity sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==
+prettier@^2.6.0:
+  version "2.6.0"
+  resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.0.tgz#12f8f504c4d8ddb76475f441337542fa799207d4"
+  integrity sha512-m2FgJibYrBGGgQXNzfd0PuDGShJgRavjUoRCw1mZERIWVSXF0iLzLm+aOqTAbLnC3n6JzUhAA8uZnFVghHJ86A==
 
 pretty-ms@^7.0.1:
   version "7.0.1"


Test patch:
diff --git a/__tests__/PlainOption/object_shape.test.mjs b/__tests__/PlainOption/object_shape.test.mjs
index a6529c85..b17e8f8c 100644
--- a/__tests__/PlainOption/object_shape.test.mjs
+++ b/__tests__/PlainOption/object_shape.test.mjs
@@ -13,7 +13,7 @@ test('The shape of PlainOption::Some', (t) => {
 test('The shape of PlainOption::None', (t) => {
     const actual = createNone();
     t.false(actual.ok, 'None.ok');
-    t.is(actual.val, undefined, 'None.val');
+    t.is(actual.val, null, 'None.val');
 
     t.true(
         // eslint-disable-next-line no-prototype-builtins
diff --git a/__tests__/PlainResult/object_shape.test.mjs b/__tests__/PlainResult/object_shape.test.mjs
index 780922ce..1f0b2dd6 100644
--- a/__tests__/PlainResult/object_shape.test.mjs
+++ b/__tests__/PlainResult/object_shape.test.mjs
@@ -9,7 +9,7 @@ test('The shape of PlainResult::Ok', (t) => {
 
     t.true(actual.ok, 'Ok.ok');
     t.is(actual.val, INNER_VAL, 'Ok.val');
-    t.is(actual.err, undefined, 'Ok.err');
+    t.is(actual.err, null, 'Ok.err');
 
     t.true(
         // eslint-disable-next-line no-prototype-builtins
@@ -24,7 +24,7 @@ test('The shape of PlainResult::Err', (t) => {
     const actual = createErr(INNER_VAL);
 
     t.false(actual.ok, 'Err.ok');
-    t.is(actual.val, undefined, 'Err.val');
+    t.is(actual.val, null, 'Err.val');
 
     t.true(
         // eslint-disable-next-line no-prototype-builtins