TypeScript 4.9 でリリースされた satisfies をサンプルオブジェクトに活用できたはなし
Leaner 開発チームの phigasui です。
先日 TypeScript 4.9 がリリースされましたね。
開発チームのみんなで Announcing TypeScript 4.9 - TypeScript を見ていたのですが
satisfies
が気になりつつも実際コードでどこで活用できるかイメージできていませんでした。
今回、テストコード向けに用意しているサンプルのオブジェクトでの活用例を紹介します。
今回紹介するケース
弊プロダクトではフロントエンドのテスト用のダミーデータのオブジェクトを定義して使っています。
フロントエンドは SPA になっており、API リクエストのレスポンスをモックしてそのオブジェクトを返すようにしています。
例えばユーザーのデータなら下記のように定義しています。
type User = {
id: number
email: string
name?: string
}
export const user: User = {
id: 1,
email: 'user1@example.com',
name: 'user1',
}
例として、ユーザー編集ページでのフロントエンドのスモークテストでは下記のように確認しています。
ユーザー編集のために既存の情報を取得してフォームに入力されている状態を検証しています。
const user = examples.user // 上記で定義したサンプルのオブジェクト
expect(await screen.findByText(user.name)).toBeVisible()
発生する問題
tsc でエラーになっている様子
No overload matches this call.
Overload 1 of 2, '(id: Matcher, options?: SelectorMatcherOptions | undefined, waitForElementOptions?: waitForOptions | undefined): Promise<HTMLElement>', gave the following error.
Argument of type 'string | undefined' is not assignable to parameter of type 'Matcher'.
Type 'undefined' is not assignable to type 'Matcher'.
Overload 2 of 2, '(id: Matcher, options?: SelectorMatcherOptions | undefined, waitForElementOptions?: waitForOptions | undefined): Promise<HTMLElement>', gave the following error.
Argument of type 'string | undefined' is not assignable to parameter of type 'Matcher'. [2769]
この時、findByText
の引数は undefined
を期待しておらず、User['name']
は string | undefined
のため、型が合いません。
そのため、Non-null assertion operator を使うなど、undefined
を回避する必要がありました。
expect(await screen.findByText(user.name!)).toBeVisible()
現実として(型として)はたしかに、undefined
になりうるものの、テストで使う値は決まっているのに undefined
になりうることを考慮したコードにしないといけないのはすこしネックでした。
satisfies
というソリューション
そこで user
に対して User
で型づけするのでなく satisfies
Operator を活用します。
export const user = {
id: 1,
email: 'user1@example.com',
name: 'user1',
} satisfies User
そうすると user
は定義されたオブジェクトのインターフェイスのまま推論できるため
name
は string | undefined
でなく string
で推論されます。
なのでテストコードで undefined
を回避する必要がなくなります。
tsc でおこられなくなった様子
expect(await screen.findByText(user.name)).toBeVisible()
かつ user
のオブジェクトは User
の type に合っているかがチェックされるので User
type が変更されてサンプルのオブジェクトが更新できていない、なんて時にも検知できるので型安全にできます。
感想
TypeScript 4.9 でリリースされた satisfies
とても便利で役にたちました。
リリースしてすぐチームでキャッチアップし活用できている状態も良いチームだなという気持ちです。
そして、今回の活用例をコードレビューでチームメンバーが気付いてくれたので非常に感謝しております🙏
宣伝
Leaner では最新技術でコードを改善していきたいエンジニアを募集しています🙌
Discussion