frontendでも外部との境界で、仕様を満たした型に変換する
やりたいこと
frontendにおける外部との境界とはどこか?
formの入力
URL
serverとのアクセス
local storageなど(?)
どうしたいか
外部の汚いデータから、内部の綺麗なデータに変換する処理を一箇所にのみ書く
form部分の解決策
serverとのアクセス
実装を書きながら実例を集めている最中

良い感じにまとまったら、タイトルをもうちょい簡潔にしたい
zodという単語を含めることで、typescriptであることが前提出来る
ノリ
前準備
単純な例として、 OrderId
のようなものを考える
entityに以下のようなものを書く
OrderId
が満たすべき条件
features/order/entities.tsimport { OrderId } from './types';
import { z } from 'zod';
import { str2num } from 'app/src/utils/functions';
export const mkOrderId = (id: string | number): OrderId => {
const numId = typeof id === 'string' ? str2num(id) : id;
return validateOrderId.parse(numId);
};
/** @package */
export const validateOrderId = z.number().brand<'OrderId'>();
↑は内容が薄いが、ここに「 OrderId
が満たすべき条件」を全て列挙する
「OrderIdの仕様は何だっけ?」となったときにこのファイルを見れば完全に理解できる状態を目指す
typesには、entityのものから生成した型を書く
features/order/types.tsimport { z } from 'zod';
import { validateOrderId } from './entities';
export type OrderId = z.infer<typeof validateOrderId>;
相互依存になりうるが気にしない

zodは、どうしてもentity←typeという依存関係になってしまう
気持ちが悪いが仕方がない
URL部分の例
Next.jsのdynamic routingを使用したときに「このページのパラメータが欲しい」ということがよくある
なぜかNext.jsのそれは型がクソ雑なので、
例えば、 /order/[orderId]
のようなページで、 orderId
を取得すると
null | string | string[]
かなんかの型になる(忘れた)
そこのvalidationも自分でやれということだろう
tsimport { OrderId } from './types';
import { usePathname } from 'next/navigation';
import { mkOrderId } from './entities';
export const useCurrentOrderId = (): { orderId: OrderId } => {
const path = usePathname();
const orderId = path?.split('/')[2];
if (orderId == null) {
throw new Error('Order ID is not found in the URL');
}
return { orderId: mkOrderId(orderId) };
};
hooksの中でthrow Errorってしていいんだっけ
#??「URL」という外部から、値を中に持ち込むときにしっかりvalidationして、仕様を満たした型に変換する
ついでにこの辺を整理したい

zodとnewtype-tsを組み合わす例
ここまでするほどか?