TypeScriptでunknownを扱うの、つらくない?
みなさん、こんにちは!
オランダでも花粉症に悩まされてるフロントエンドエンジニアの @nyaomaru です!
APIレスポンス、フォーム入力、外部データ・・・
TypeScriptでは最終的に 「unknown」をどう扱うかが、実務のストレスになることが多いですよね・・・

そう、unknown は宇宙のような吸引力を持ってます。
でも、型を適切に扱いたいとき、ありますよね?
そんなときに使えるのが、型ガードを組み立てるライブラリ is-kit です!

Zodのように「schemaを定義する」アプローチもありますが、
is-kitは 既存のコードの中で自然に型を絞り込む ことにフォーカスしています。
つまり、「バリデーションを書く」のではなく、普段のif文の延長で型を扱えるイメージです。
Zodが「境界(API / 入力)で使うもの」なら、
is-kitは「アプリケーションの中で使うもの」です。
例えば、「3文字以下の文字列」を何度もチェックするようなケースでは、
条件を1箇所にまとめて再利用できます:
import { define, isString } from "is-kit";
const isShortString = define<string>( // narrowing先の型を明示
(value) => isString(value) && value.length <= 3,
);
import { isShortString } from "~/utils/is";
declare const input: unknown;
// before → 毎回条件を書く必要がある
if (typeof input === "string" && input.length <= 3) {
input.toUpperCase();
}
// after (is-kit) → guardを再利用できる
if (isShortString(input)) {
input.toUpperCase();
}

このスタイルは、filter / map / if文など、既存のロジックにそのまま組み込めるのが特徴です。
🐾 is-kit はどう進化してきたか
時が経つのは早いもんで、is-kit の v1.0 のリリースから半年がたちました。
is-kit の v1.0 は、define / and / or / struct / arrayOf のような基本ガードを揃えた、軽量な type guard ライブラリとして出発しました。
そこから現在の v1.6 系までの軌跡を見ると、単に「型ガードを作れる」から、「unknown な入力を現場で扱いやすい」ライブラリへ向かってきているのが分かるかと思います。
今回は大きな変更点である 5 点について、振り返ってみようと思います。
ほんなら、一緒に見ていこな!
🪄 1. struct が「missing」と「undefined」を分けて書けるようになったで!
APIレスポンスでよくあるのが、
- キーが存在しない
- キーはあるが undefined
この違いをちゃんと扱いたいケース。
そこで、v1.5.0 で追加された optionalKey(...) は、ええ感じの改修やで!
これまで struct では、「キーが存在しない」のか、「キーはあるが値が undefined なのか」を表現しづらい場面があった。
optional(...) は値側の話で、キーそのものの省略とは意味がちゃう。
せやから、optionalKey(...) が入ったことで、その差を schema で素直に書けるようになってんな。
import { isString, optional, optionalKey, struct } from "is-kit";
const isUser = struct({
id: isString,
nickname: optionalKey(isString), // key は optional として扱える
displayName: optionalKey(optional(isString)), // key も value も optional として扱える
});
この追加は地味に見えて、API レスポンスやフォーム入力のような「プロパティが来ないこと自体に意味がある」データではかなり効く。
v1.0 の struct は便利やったけど、v1.5 以降はより現実の payload に近い書き方ができるようになってるで~!
🔑 2. hasKey / hasKeys / narrowKeyTo で、オブジェクトの絞り込みがかなり自然になったで!
v1.1.13 で hasKey、v1.4.0 で hasKeys、その流れで narrowKeyTo も加わって、オブジェクトの一部キーを軸にした narrowing がめっちゃ書きやすくなってん。
import {
hasKeys,
narrowKeyTo,
oneOfValues,
struct,
isString,
isNumber,
} from "is-kit";
const isUser = struct({
id: isString,
age: isNumber,
role: oneOfValues("admin", "guest", "trial"),
});
const hasRoleAndId = hasKeys("role", "id"); // 複数の key を持っているかどうかを判別できる
const byRole = narrowKeyTo(isUser, "role"); // key を起点にさらに型の絞り込みができる
const isGuest = byRole("guest");
この系統の API が便利なんは、struct を毎回細かく再定義せんでも、既存ガードの上に「このキーがある」「このキーがこの値」といった条件を自然に積めることやな。
特に discriminated union 的なオブジェクトや、イベント payload を扱うコードではかなり相性がええ。
v1.0 の時点でも object guard はあったけど、v1.4 で「キーを起点にした使い勝手」が一段上がってるで~!
🧪 3. assert が入って、guard を fail-fast にも使えるようになったで!
v1.2.0 の assert 追加は、個人的な推しポイントや。
safeParse のような結果オブジェクト型も便利やけど、実際のアプリでは「ここで落としていい」「ここを通るなら型を確定させたい」という場所も多い。assert はそこにぴったりはまる。
import { assert, isString } from "is-kit";
declare const input: unknown;
assert(isString, input, "input must be a string");
input.toUpperCase();
この API のええとこは、is-kit がもともと持っていた guard-first な設計を崩さずに、実行時の失敗戦略だけを足していること。
Zod / Valibot のような大きな validation framework に寄せるんやなくて、**「既存の guard をそのまま assert にも使える」**というのが、この改修のええとこやと思ってる。
✨ 4. setOf と mapOf で、コレクション対応が一段広がったで!
v1.6.0 では setOf と mapOf を追加したで。
import { mapOf, setOf, isString, isNumber } from "is-kit";
const isTags = setOf(isString);
const isScores = mapOf(isString, isNumber);
v1.0 でも arrayOf、tupleOf、recordOf はあってんけど、実務で扱う collection は配列だけやない。
Set や Map を型安全に扱いたいケースは、キャッシュ、集計、タグ集合、辞書構造などでザラにある。
ここが揃ったことで、is-kit は「小さな guard を組み立てる道具箱」から、「日常的な JavaScript のデータ構造を一通りカバーする guard kit」に近づいたんちゃうかな。
🥏 5. 数値の細かい edge case を直接扱えるようになったで!
v1.1.7 と v1.1.8 では数値ガードがかなり増えた。
isInteger、isSafeInteger、isPositive、isNegative、isNaN、isInfiniteNumber、isZero などやな。
これが便利なのは、「number ではあるが、欲しい number ではない」を guard の段階で表現できることや。
たとえば NaN、Infinity、-0 は JavaScript では地味に厄介やねんけど、そこを専用 API で拾えるようになった。
v1.0 でも isNumber は提供しててんけど、v1.1.8 以降は「数値の質」を guard で表現できるようになったのがデカいな。
🌟 ほかにもいろいろ更新してるで!
この記事では細かいこと説明せえへんけど、他にもいろいろ便利なもん追加しとるから、気になる人は document 眺めてみてな!
🎯 まとめ
v1.0 の is-kit は、軽くて composable な type guard ライブラリやった。
そこから v1.6 系までで特に良くなったのは、unknown な値を実務で扱うときの具体的な手触りや。
-
optionalKeyで object schema が現実寄りになった -
hasKey系でキー起点の narrowing がしやすくなった -
assertで fail-fast な使い方ができるようになった -
setOf/mapOfで collection 対応が広がった - 数値ガード群で JavaScript の edge case に直接向き合えるようになった
つまり、v1.0 からの is-kit は「型ガードを作るための小さな道具」だけやなく、 「アプリケーションコードの中で unknown を扱いやすくする実践的な道具箱」 へ進化してきてる。
ほんで、これからも is-kit は 「型安全なコードを気持ちよく書ける」 ように、少しずつ育てていこうと思ってるで。
もし使ってみて気になる点や、「こういう guard があると嬉しい」というアイデアがあれば、ぜひ気軽に教えてな!
ほな、また次の記事で!
Discussion