🤾‍♂️

TypeScriptで既存の型の一部を上書きする方法とAPI通信時の活用例

2022/02/23に公開

前書き

一部の日付の値がAPIへのリクエストとレスポンスでは、 string型 だが、フロント側では Date型 で値を持ちたい場面がありました。
そんな時にフロントでデータを持つ時の型をAPI通信時に上書きして型定義するというのが今回の話です。

やったこと

  • 既存の型を拡張する用の type を用意し、一部のプロパティの型を上書き 🛠
  • その型を使って、型変換処理を実装 💪

実例

APIのリクエスト用の型を変換する関数を定義して、Postの直前で変換してリクエストを投げます。
(変換部分はデザインパターンのAdapterパターンをイメージしてます。)

※Nuxt / Composition API / TypeScript使ってる前提で書いてます。

  • フロント側でデータを持つ際のBlogオブジェクトの型
type Blog = {
  id: string,
  titile: string,
  body: string,
  publishedAt: Date
}
  • 既存の型を拡張する用の type を用意
export type Weaken<T, K extends keyof T> = {
  [P in keyof T]: P extends K ? any : T[P];
};
  • 上書きしたAPIの型
// 既存の型を拡張する用の type を import する
import { Weaken } from '~/types/utils/weaken';
// 中略

export interface PostBlogParams extends Weaken<Blog, 'publishedAt'> {
  publishedAt: string; // YYYY/MM/DD
}
  • APIのリクエストとレスポンス用に型を変換する関数
import { PostBlogParams } from '~/api/blogs';
import { Blog } from '~/types/blogs';

export const adaptToPostBlogParams = (blog: Blog): PostBlogParams => {
  return {
    ...blog,
    publishedAt: // 割愛: blog.publishedAt を string型の 'YYYY/MM/DD'フォーマットに変換する処理
  };
};
  • setup関数内での使い方
// 型を変換する関数
import { adaptToPostBlogParams } from '~/utils/blogs/adaptToApi';
// 中略

export default defineComponent({
  name: 'BlogEditForm',
  setup() {
    const blog = reactive<Blog>({
      id: '',
      title: '',
      body: '',
      publishedAt: new Date(),
    });
  
    const { $axios } = useContext();
  
    // 中略
    const createBlog = async (): Promise<void> => {
      try {
        // 中略
        const params = adaptToPostBlogParams(blog); // ここで変換する!
        await $axios.post('/blogs', params);
        // 中略
      } catch (err) {
        // 例外処理
      }
    };
// 中略

まとめ

  • APIとフロントで持ちたいデータ型が異なる場面では、Adapterパターンに倣って型変換処理を噛ませることでバックエンドとフロントエンドの繋ぎ込みがスムーズになって良い👍

Discussion