<aside> 💡
チャプター完了時点のソースコード
https://github.com/craftgear/api_handson/tree/ch03
</aside>
zod https://zod.dev/
zodをインストール
npm i zod
/src/todo/domain.ts
を作成、zodを使ってバリデーションスキーマと型を定義
import { z } from 'zod';
export const TodoSchema = z.object({
id: z.number().brand('TodoId'),
title: z.string(),
done: z.coerce.boolean().default(false),
doneAt: z.coerce.date().nullish(),
});
export type Todo = z.infer<typeof TodoSchema>;
export type TodoId = Todo['id'];
JSONのパース関数を追加
export const parseTodo = (data: unknown): Todo => TodoSchema.parse(data);
export const parseTodoId = (id: number): TodoId => TodoSchema.shape.id.parse(id);
新しく追加するTodoには id
がないので、 NewTodo
という型を追加する。
export type NewTodo = Omit<Todo, 'id'>;
export const parseNewTodo = (data: unknown): NewTodo => TodoSchema.omit({ id: true }).parse(data);
vitestをインストール
npm i -D vitest
テスト作成 /src/todo/domain.spec.ts
import { describe, it, expect, expectTypeOf } from 'vitest';
import {
parseTodo,
parseTodoId,
parseNewTodo,
Todo,
TodoId,
NewTodo,
} from './domain';
describe('parseTodo', () => {
it('parse a valid todo', () => {
const result = parseTodo({ id: 1, title: "Buy milk" });
expect(result).toEqual({
id: 1,
title: "Buy milk",
done: false,
});
expectTypeOf(result).toEqualTypeOf<Todo>();
const now = new Date();
expect(parseTodo({ id: 1, title: 'Buy milk done', done: true, doneAt: now })).toEqual({
id: 1,
title: 'Buy milk done',
done: true,
doneAt: now,
});
});
});
describe('parseTodoId', () => {
it('parse a valid todo id', () => {
const todoId = parseTodoId(1);
expectTypeOf(todoId).toEqualTypeOf<TodoId>();
});
});
describe('parseNewTodo', () => {
it('parse a valid new todo', () => {
const result = parseNewTodo({ title: "Buy milk" });
expect(result).toEqual({
title: "Buy milk",
done: false,
});
expectTypeOf(result).toEqualTypeOf<NewTodo>();
});
});
package.json
に test
コマンドを追加
テスト実行
npm test