【Zod】v4.5の新機能とパフォーマンス改善をまとめて解説

【Zod】v4.5の新機能とパフォーマンス改善をまとめて解説

杉田侑祐
杉田侑祐20分で読めます
はてなブックマーク

はじめに

この記事の概要

こんにちは、株式会社TOKOSのスギタです!

Zod v4.5が2026年8月28日にリリースされました。
新機能とパフォーマンス改善、そしてアップグレードで挙動が変わる箇所をまとめます。

Zod 4.5

Zod 4.5 is now available, with z.compile() ahead-of-time compilation, up to 9x less memory per schema, and a batch of long-awaited features.

zod.dev

対象読者

  • すでにZodを業務で使っているTypeScript開発者の方
  • v4系を使っていて、v4.5へのアップグレードを検討している方
  • z.compile()を自分のプロジェクトで使えるか判断したい方

この記事で扱う内容、扱わない内容

扱う内容は下記です。

  • Zod v4.5で追加された機能
  • v4.4からのパフォーマンス改善点
  • アップグレードで挙動が変わる箇所

扱わない内容は下記です。

  • Zod自体の入門(スキーマ定義やparseの基本)
  • Zod v3からv4への移行
  • Zod Mini(Zod本体の軽量版)の詳細(z.compile()のバンドルサイズに関わる部分だけ触れます)
  • react-hook-formなど他ライブラリとの連携

Zod v4.5で入った変更の全体像

新機能の追加とパフォーマンスの改善、そして仕様をより正確にする破壊的変更が入っています。

その中でも気になるものだけ取り上げます!

変更点内容
z.compile()スキーマの検証を1本のJavaScript関数に書き出しておく新機能。キーの多いオブジェクトでparseが最大10.2倍速い
メモリ削減と失敗時の高速化内部構造の見直しによる改善で、コードの書き換えは不要。スキーマ1つが使うメモリが最大9.8分の1、失敗するsafeParse()は7.6倍速い
z.validate()値が通るかどうかだけを真偽値で返す型ガード。エラーを組み立てない分、不正な入力に対して.safeParse().successより最大16倍速い
z.toZod()先に決めた型とスキーマが一致するか検証。satisfies z.ZodType<T>では見逃していた余分なキーやz.any()を弾ける
文字列長がコードポイント単位に.min().max()の数え方がUTF-16のコードユニットからUnicodeのコードポイントへ変わり、絵文字を含む入力で結果が変わる

ここに入らなかった追加分は「その他の新機能」でまとめて扱います。
z.deepPartial()z.creditCard()、循環参照を含むデータのparseなどが該当します。

z.compile()

Zodはキーが増えるほど、parseに時間がかかります。
z.compile()は、この作業を先に済ませて1本のJavaScript関数に書き出しておく機能です。

z.compile()の基本
import * as z from "zod"
 
const Player = z.object({
  username: z.string(),
  bio: z.string(),
  xp: z.number(),
})
 
const CompiledPlayer = z.compile(Player)
 
CompiledPlayer.parse({ username: "billie", bio: "hello", xp: 100 })

z.compile()が返すのは元のスキーマと同じ型です。
呼び出し側のコードは変わりません。

使う上で押さえておきたいのは次の2点です!

  • エラーメッセージはコンパイルの有無で変わらない
  • 失敗するケースは速くならない

コンパイル済みの関数は、値が不正だと分かった時点で処理をやめます。
エラーを組み立てるのが元のパーサなので、メッセージは今までと変わりません。
書き出されるコードの中身は、公式ドキュメントを参照してください。

AOT compilation | Zod

Ahead-of-time schema compilation for hot validation paths

zod.dev

速度は公式のベンチマークが公開されています。

スキーマ標準コンパイル済み
20キーのオブジェクト301ns38ns
10要素のオブジェクト配列377ns68ns
10要素の文字列配列241ns33ns
3つのオブジェクトのunion190ns36ns
5キーのstrictObject117ns32ns
discriminatedUnion92ns27ns

キーが多いほど差が開きます!
50キーのオブジェクトでは10.2倍という数値も出ています。

コンパイルはチェーンの最後に

.refine().extend().optional()が返すスキーマはコンパイルされていません。
チェーンの途中でz.compile()を呼ぶと、その後に足したものは元のパーサで処理されます。

呼ぶ順番
const bad = z.compile(z.string()).refine((val) => val.length > 1) 
const good = z.compile(z.string().refine((val) => val.length > 1)) 

コンパイルできないスキーマ

すべてのスキーマがコンパイルできるわけではありません!
対応していない機能を含んでいても、z.compile()はエラーを投げずにそのまま返します。
{ strict: true }を渡しておくと、そのときにエラーを投げてくれます。

strictモードで確認する
z.compile(z.coerce.number(), { strict: true })
投げられるエラー
ZodCompileUnsupportedError: z.compile does not support coercion (z.coerce.number());
this schema must use the runtime parser

対応していないのは次のものです。

  • 非同期のrefinetransformcheck
  • z.xor()
  • 再帰スキーマ
  • z.coerce.*
  • whenを指定したcheck
  • コールバックを渡した.catch()

.catch("fallback")のように定数を渡す形はコンパイルできます。

非対応のものが混ざっていても、必ずスキーマ全体が諦められるわけではありません。
効く範囲は場所によって変わります。

  • objectarraytuplerecordintersectionの中なら、非対応のものだけが元のパーサに回り、外側はコンパイルされたまま
  • unionのメンバーに非対応のものがある場合、コールバック形式の.catch()、どこかに非同期処理がある場合は全体が元のパーサに戻る

バンドルサイズのトレードオフ

コンパイラそのものが、それなりの量のコードでできています。
z.compile()を呼ぶかzod/compileをimportした時点で、その分がバンドルに乗ります。

バンドルcompileなしcompileあり
Zod24.1KB31.1KB
Zod Mini4.6KB13.2KB

いずれもgzip後の数値です。
Zodでは約1.3倍増加ですが、Zod Miniでは2.9倍になります。
Zod Miniを選ぶ理由はサイズなので、Miniとcompileの組み合わせは噛み合いません!

一度も呼ばなければビルド時に丸ごと削られるので、使わないなら増加はゼロです!
サーバーサイドならバンドルサイズを気にせず採用できます。
クライアントで動かすバリデーションなら、7KB分の速度が得られるかを先に確かめたいところです。

スギタ
スギタ

ZodMiniの4.6KBが13.2KBになるのは、正直かなり厳しい数字だと感じました。Miniとcompileはどちらかひとつでいいという解釈をしています。

下記公式ブログで紹介されています!

Introducing z.compile()

z.compile() walks a schema once and produces a flat, loop-free JavaScript validator that runs far faster than the standard parser. Arrays, unions, and nested or wide objects parse 3 to 7x faster, with identical output and identical errors.

zod.dev

import "zod/compile"で全体に適用する

スキーマごとに毎回1つずつコンパイルするのでは無く、アプリケーション全体でコンパイルを有効にできます。

グローバルに有効化する
import "zod/compile" // スキーマを定義するモジュールより前に置く
import * as z from "zod"
 
const schema = z.object({ name: z.string() })
schema.parse({ name: "ok" }) // 初回のparseでコンパイルされる

import "zod/compile"は読み込む順番が重要です!
これより後に定義されたスキーマだけが、コンパイルの対象になります。
import文の並び順で保証しきれないときは、Node.jsの起動時に読み込みます。

起動時に読み込む
node --import zod/compile app.js

コンパイルされるのは、実際にparseしたスキーマだけです。
定義しただけで使っていないスキーマは対象外になります。
公式ドキュメントは「This import is for applications, not libraries.」と明記しています。
ライブラリから読み込むと、利用側のスキーマまで巻き込むためです。

CSP(Content Security Policy)でnew Functionを使えない環境では、コンパイルに失敗してそのまま元のパーサで動きます。
Cloudflare Workersなどが当てはまります。
はっきり無効にしたいときはz.config({ jitless: true })を設定してください。

何もしなくても速くなった部分

z.compile()は自分で呼んだときだけ効く機能です。
一方で、v4.5にはコードを変えなくても効く改善が入っています。

スキーマ1個あたりのメモリが最大9.8倍削減

スキーマ1つが使うメモリの比較です。

スキーマv4.4.3v4.5
10キーのオブジェクト82.0KB11.0KB
union17.5KB2.13KB
z.string().min(1)16.7KB3.37KB
record16.4KB2.64KB
z.string().optional()12.6KB1.50KB
z.string()7.53KB784B
z.number()4.44KB706B

メソッドの持ち方を変えたことによる効果のようです。
これまではスキーマを作った時点で、すべてのメソッドを1つずつ持たせていました。
v4.5では、実際に呼ばれたメソッドだけを後から持たせます。
一度も呼ばないメソッドの分は、まるごと不要になります!

書き方への影響はないので、次のような分割代入も引き続き動きます。

分割代入しても動く
const { parse } = z.string()
 
parse("some data")

Reducing Zod&#x27;s memory footprint by an order of magnitude with method memoization

A bare z.string() retained 7.5kb of heap in Zod 4.4. In Zod 4.5 it retains 784 bytes. One change to where a schema&#x27;s methods live accounts for nearly all of it.

zod.dev

safeParseの失敗が7.6倍速く

.safeParse()は失敗するたびにZodErrorを作り、スタックトレースまで取っていました。
v4.5でもZodError自体はその場で作られますが、重い処理が後ろにずれました。
エラー文面の組み立てはmessageを読むまで走らず、safeParse()ではスタックの記録も省かれます。
parse()が投げる場合はスタックが必要なので、そちらは今までどおり記録されます。

公式の計測では、失敗するsafeParseが6.3msから840nsになっています!
フォームのように入力途中で何度も失敗する画面なら、成功より失敗のほうが回数は多いはずです。

z.validate()

値が通るかどうかだけを知りたい場面で、.safeParse().successを使っていた方は多いはずです。
この書き方だと、失敗するたびにエラーオブジェクトを組み立てる処理が走ります。

v4.5で追加されたz.validate()は真偽値だけを返します。

z.validate()
z.validate(z.string(), "hi") // true
z.validate(z.string(), 42) // false

公式によると、不正な入力に対して.safeParse().successより最大16倍速くなります。
z.compile()を通したスキーマを渡すと、差はさらに開きます。
コンパイル時に真偽値だけを返す判定用の関数も作られていて、z.validate()はそれをそのまま呼ぶためです。
値を組み立てる処理を通らない分だけ速く終わります。

注意したいのは、絞り込まれる型です。

型ガードが効くのはinput側
const Age = z.string().transform((s) => Number(s))
const value: unknown = "3"
 
if (z.validate(Age, value)) {
  // ここでの value は string
  // transform 後の number ではない
}

z.validate()が絞り込むのは、変換した後の型ではなく変換する前の型です!
Zodの用語でいえばoutput<T>ではなくinput<T>側になります。

非同期のrefinetransformを含む場合はz.validateAsync()を使います。
TypeScriptでは非同期の型ガードを書けないため、こちらはPromise<boolean>を返すだけで型は絞り込まれません。

スギタ
スギタ

z.validate()output<T>ではなくinput<T>に対する型ガードです。そのため、transformを挟んだスキーマで使うときは、絞り込まれた型を一度確認しておくと安全です。

z.toZod()

先に型を定義して、それに合うスキーマを書く場面があります。
例えば、外部APIの型や共有パッケージの型に合わせてバリデーションを足すときなどです。

satisfiesでは防げないケース

これまでよく使われていたのはsatisfies z.ZodType<T>です。
ただしこれは「型として当てはまるかどうか」しか見ません。
必須キーの書き忘れは捕まえますが、余分なキーやz.any()はすり抜けてしまいます。

satisfiesはすり抜ける
type Player = { username: string; xp: number }
 
// 型に存在しない admin を足してもエラーにならない
z.object({
  username: z.string(),
  xp: z.number(),
  admin: z.boolean(),
}) satisfies z.ZodType<Player>
 
// z.any() でも通ってしまう
z.any() satisfies z.ZodType<Player>

この2つは手元のtscでもエラーになりませんでした!

z.toZod()なら弾ける

v4.5のz.toZod()は、型とスキーマがぴったり一致するかどうかを見ます。
2段階に分けて呼ぶ点だけ注意してください。

z.toZod()で書き直す
// 1段目: 合わせたい型を渡す
// 2段目: その型と一致するスキーマだけ受け付ける
const PlayerSchema = z.toZod<Player>()(
  z.object({
    username: z.string(),
    xp: z.number(),
    admin: z.boolean(), // Playerに無いキー → 型エラー
  }),
)
// z.any()も「Playerと一致しない」のでエラー
const AnyPlayer = z.toZod<Player>()(z.any())

先ほどと同じ内容ですが、今度は両方エラーになります!

tscの出力(抜粋)
error TS2345: Argument of type 'ZodObject<{ username: ZodString; xp: ZodNumber;
admin: ZodBoolean; }, $strip>' is not assignable to parameter of type
'$ZodObject<{ username: ZodString; xp: ZodNumber;
admin: ToZodKeyMismatch<never, boolean>; }, $strip>'.
  Property '"types do not match"' is missing in type '_ZodBoolean<...>'
 
error TS2345: Argument of type 'ZodAny' is not assignable to parameter of type
'ZodAny & ToZodMismatch<Player, ZodAny>'.
  Property '"types do not match"' is missing in type '_ZodType<$ZodAnyInternals>'

"types do not match"という文字列がエラーに現れるので、原因を追いやすくなっています。
adminというキー名まで出るのも助かります。

スキーマが正しい場合、z.toZod()は渡したスキーマをそのまま返します。
戻り値の.shapeもそのまま使えます。

スギタ
スギタ

z.toZod<Player>()(schema)という2段呼び出しは、初見だと書き間違いに見えます。それでもsatisfiesz.any()を弾けないと知ってしまうと、型定義に追従させたいスキーマはこちらへ寄せたくなりました。

その他の新機能

z.deepPartial()とexactPartial()

z.deepPartial()はZod 3にあったメソッドです。
v4でいったん削除され、v4.5で関数の形になって戻ってきました。
ネストしたオブジェクトのプロパティも再帰的にoptionalにします。

z.deepPartial()
const Post = z.object({
  title: z.string(),
  author: z.object({ name: z.string(), email: z.string() }),
})
 
const PartialPost = z.deepPartial(Post)
// { title?: string; author?: { name?: string; email?: string } }
 
PartialPost.parse({ author: {} }) // ✅

元のスキーマは変更されず、結果もZodObjectのままなので.shape.extend()が使えます。

ただし、どんなオブジェクトにも使えるわけではありません。
内部で.partial()を使うため、.refine()を持つオブジェクトに行き当たると例外を投げます。

refineを持つオブジェクトに使った場合
.partial() cannot be used on object schemas containing refinements

既存のスキーマに使うなら、.refine()z.deepPartial()のあとに付けてください。
discriminatedUnionに使うと、判別に使うキーまでoptionalになります。
判別できなくなるため、結果は通常のunionに変わります。

.exactPartial()は、各フィールドをz.optional()ではなくz.exactOptional()で包みます。
キーの省略は許しますが、はっきりundefinedを渡すと弾きます。

exactPartialとpartialの違い
const Recipe = z.object({ title: z.string(), servings: z.number() })
 
Recipe.exactPartial().parse({}) // ✅
Recipe.exactPartial().parse({ title: undefined }) // ❌
Recipe.partial().parse({ title: undefined }) // ✅

TypeScriptのexactOptionalPropertyTypesを有効にしているなら、こちらのほうが型と実行時の挙動が揃います。

スギタ
スギタ

exactOptionalPropertyTypesはTypeScriptのコンパイラオプションで、optionalなプロパティとundefinedを入れていいプロパティを区別する設定です。

z.properties()

クラスのインスタンスに対して、複数のプロパティをまとめて検証できます。

これまではz.property()を1つずつ並べる書き方でした。

v4.4まで
z.instanceof(URL).check(
  z.property("protocol", z.literal("https:" as string)),
  z.property("hostname", z.string().regex(z.regexes.domain)),
)

v4.5のz.properties()なら、オブジェクトで一度に渡せます。
戻り値が配列なので、.check()にはスプレッドで渡します。

v4.5から
const httpsUrl = z.instanceof(URL).check(
  ...z.properties({
    protocol: z.literal("https:" as string),
    hostname: z.string().regex(z.regexes.domain),
  }),
)
 
httpsUrl.parse(new URL("https://example.com")) // ✅
httpsUrl.parse(new URL("http://localhost")) // ❌ expected "https:"

as stringが要るのは、URL.protocolの型がstringのためです。
これを外すと、リテラル型と一致しないというエラーになります。

z.creditCard()

クレジットカード番号のフォーマットと、Luhnアルゴリズム(クレジットカード番号の検証アルゴリズム)によるチェックサムを検証します。

z.creditCard()
z.creditCard().parse("4111111111111111") // ✅
z.creditCard().parse("4111 1111 1111 1111") // ✅ 単一のスペース
z.creditCard().parse("4111-1111-1111-1111") // ✅ 単一のハイフン
z.creditCard().parse("4111  1111 1111 1111") // ❌ 区切りの連続は不可
z.creditCard().parse("4111111111111112") // ❌ チェックサム不一致

12桁から19桁を受け付けます。
区切り文字はスペースとハイフンだけで、連続はできません。
カードブランドの判別はしないので、どの発行元の番号でも通ります!

ブランドを絞りたい場合は、これまでどおり自前の判定を足すことになります。
z.creditCard()が見てくれるのは、桁数と区切りとチェックサムまでです。

循環参照を含むデータのparse

自分自身を含むデータを渡すと、v4.4まではエラーになっていました。

自分を含むデータ
const Category = z.object({
  name: z.string(),
  get subcategories() {
    return z.array(Category)
  },
})
 
type Category = z.infer<typeof Category>
 
const input: Category = { name: "root", subcategories: [] }
input.subcategories.push(input)
 
const result = Category.parse(input)

同じコードを2つのバージョンで走らせた結果です。

実行結果
zod@4.4.3
  RangeError: Maximum call stack size exceeded
 
zod@4.5.4
  result.subcategories[0] === result  // true

入力にあった循環は、そのまま結果にも残ります!
同じオブジェクトとして扱われるので、===での比較も成立します。

Zod本体では最初から有効になっています。
Zod Miniでは、スキーマを定義する前に登録します。

Zod Miniでの有効化
z.config({ memoizer: z.memoizer() })

z.input()とz.output()の関数版

z.inputz.outputはv4.4まで型だけでしたが、v4.5からは関数としても呼べます。
codecやpipeを含むスキーマから、片側だけを取り出せます。

codecの片側だけを検証する
const isoDate = z.codec(z.iso.datetime(), z.date(), {
  decode: (s) => new Date(s),
  encode: (d) => d.toISOString(),
})
 
const Event = z.object({ name: z.string(), at: isoDate })
 
z.input(Event).parse({ name: "launch", at: "2024-01-01T00:00:00Z" }) // ✅
z.output(Event).parse({ name: "launch", at: new Date() }) // ✅

型としての使い方はこれまでどおりです。

z.input()のほうは、codecに付けたcheckを引き継ぎません。
変換した後の値を縛る条件なので、変換前のスキーマには残らないからです。

codecやpipeを含まないスキーマなら、どちらを呼んでも何も変わりません。

z.getDiscriminatedOption()

discriminatedUnionから、特定のdiscriminatorを持つ選択肢を型安全に取り出せます。

z.getDiscriminatedOption()
const Fruit = z.object({ type: z.literal("fruit"), seeds: z.boolean() })
const Veg = z.object({ type: z.literal("vegetable"), leafy: z.boolean() })
const Produce = z.discriminatedUnion("type", [Fruit, Veg])
 
z.getDiscriminatedOption(Produce, "fruit") // typeof Fruit
z.getDiscriminatedOption(Produce, "meat") // ❌ TypeScriptのエラー

これまではProduce.optionsから.find()で探して、戻り値の型を手で指定していました。
存在しないdiscriminatorを渡すと、コンパイル時に落ちます。

この関数は公式ドキュメントのAPIページには見当たらず、現時点ではリリースノートだけに載っています。
手元では問題なく動きましたが、ドキュメントに載るまでは仕様が変わる可能性もありそうです。

そのほかの追加はドキュメントで

ここまでのほかにも、細かい追加があります。

  • z.object()のキーにsymbolを使えるようになった
  • z.nanoid()で長さを指定できるようになった
  • 対応言語が8言語増えた(ベンガル語・ヒンディー語・ブラジルポルトガル語など)

Defining schemas | Zod

Complete API reference for all Zod schema types, methods, and validation features

zod.dev

破壊的変更

リリースノートでは、これらをbug fixesとして扱っています。
どれも本来あるべき挙動に直す修正です。
そのため、これまでの挙動を前提にしていたスキーマでは、判定が変わるかもしれません。

文字列長がUnicodeコードポイント単位に

.min().max().length()の数え方が変わりました。
UTF-16のコードユニットではなく、Unicodeのコードポイントを数えます。

UTF-16とUnicodeの違いは下記を参考にしてください。

カオス過ぎる Unicode, UTF-8, UTF-16, UTF-32 の違い概要まとめ - Qiita

文字コードについて、Shift-JISもカオスながら、鳴り物入りで出来たUnicodeも色々あるようなので、要点をサクッとまとめ。 とりあえずこれだけ押さえておけばOK Unicode:文字コードの規格の名称。あらゆる国の文字コードを格納できる UCS-4:Unicod...

qiita.com
検証コード
z.string().max(5).parse("😀😀😀😀😀")
z.string().min(5).parse("😀😀😀")
zod@4.4.3
max(5) => ERROR too_big: expected string to have <=5 characters
min(5) => OK "😀😀😀"
zod@4.5.4
max(5) => OK "😀😀😀😀😀"
min(5) => ERROR too_small: expected string to have >=5 characters

挙動が逆転しています!
絵文字1つはUTF-16では2コードユニットなので、"😀😀😀".lengthは6でした。
v4.5はこれを3と数えます。

ほかの言語やデータベースに合わせるための変更です。
PostgreSQLやMySQL、GoやPythonは、長さの制限をコードポイントで数えます。
z.toJSONSchema()が出力するmaxLengthも同じです。

変わり方は.min().max()で逆です。

  • .max()は緩む方向にだけ動き、これまで弾いていた入力を通すようになる
  • .min()は厳しくなる方向にだけ動き、これまで通っていた入力を弾くようになる
  • .length()は指定した数によってどちらにも動く

ただし「見た目どおりの1文字」で数えてくれるわけではありません。
家族の絵文字のように複数の絵文字をつないだものは、今も複数文字として数えられます。

家族の絵文字
"👨‍👩‍👧‍👦".length     => 11
コードポイント数    => 7
z.string().max(1)   => ERROR too_big

見た目は1文字ですが、.max(1)は通りません!

.length()が両方向に動く例です。

絵文字1つに対する.length(n)
.length(1)  4.4.3 => ERROR    /  4.5.4 => OK
.length(2)  4.4.3 => OK       /  4.5.4 => ERROR

絵文字1つはコードユニットでは2、コードポイントでは1と数えるので、通る指定がそのままずれます。

スギタ
スギタ

v4.5でもっとも怖いのはこの変更だと思っています。仕様としては正しい方向への修正ですし、他の言語やデータベースに揃うのも納得なのですが、日本語のサービスだとニックネームや自己紹介で絵文字が普通に飛んできます。パッチバージョン感覚で上げると本番で気づくことになりかねません。

z.iso.datetime()

RFC 3339が秒を必須としているため、それに合わせる修正が入りました。

秒のないdatetime
z.iso.datetime().parse("2020-01-01T06:15Z")
 
zod@4.4.3 => OK "2020-01-01T06:15Z"
zod@4.5.4 => ERROR invalid_format: Invalid ISO datetime

秒を省いた形式も受け付けたい場合は、公式が回避策を示しています。

秒なしも許容する
z.union([z.iso.datetime(), z.iso.datetime({ precision: -1 })])

{ offset: true }を付けた場合も同じ変更が入ります。
{ local: true }のほうは2020-01-01T06:15を引き続き受け付けます。
タイムゾーンのない日時は、そもそもRFC 3339の対象外だからです。

そのほかの変更はリリースノートで

上の2つ以外にも、挙動の変わった箇所があります。

  • recordintersectionの組み合わせがTypeScriptの型どおりに動くようになった
  • .strict()に余分なキーと不正な値を同時に渡すと、issueが2件返るようになった
  • __proto__キーを常に除去するようになった
  • z.ulid()z.ipv6()z.httpUrl()z.emoji()の判定が厳しくなった

心当たりがあれば、リリースノートで詳細を確認してください。

Zod 4.5

Zod 4.5 is now available, with z.compile() ahead-of-time compilation, up to 9x less memory per schema, and a batch of long-awaited features.

zod.dev

さいごに

v4.5の変更は、自分で呼んで使うものと、上げるだけで効くものに分かれます。

z.compile()は前者です。
サーバーサイドで何度も呼ばれる処理なら、バンドルサイズを気にせず試せます。
クライアントで動かす場合は、7KBの増加と速度を比較して検討する必要がありそうです!
どちらの場合も、{ strict: true }で黙ってフォールバックしていないか確認しておくと確実だと思います!

メモリの削減と失敗時の高速化は後者です。
バージョンを上げるだけで効くので、まずはアップグレードして既存のテストを流してみてください。

この記事を書いた人

杉田侑祐
杉田侑祐

TOKOSのフロントエンドエンジニア兼UI/UXデザイナー。このブログではフロントエンドメインで投稿しています。HIPHOPとゲームが好きです✌️