Axiosでエラー
Axiosで外部APIを叩いてデータを取得したいと思い、下記のコードを書いたとします。
import axios, { AxiosPromise } from "axios";
interface CatApiResponse {
name: string;
age: number;
parents: string[];
}
const client = axios.create({
baseURL: "https://example.com/api/v2/",
headers: {
"Content-Type": "application/json"
}
});
const fetchAllCat = (): AxiosPromise<CatApiResponse> => client.get("cat");
const hoge = () => {
const data = fetchAllCat();
data.then((data) => {
data.data.parents.map((parent) => {
console.log(parent);
return "hoge";
});
});
};
IDEで型推定を確認すると、確かに CatApiResponse
になっている。
けど、実際はnullかもしれないし、 CatApiResponse
のinterfaceに則したデータ構造じゃないかもしれない。で、実際に変なデータを返すAPIを用意して実行すると、案の定 data.data.parents.map()
のところでコケる。でも、IDEにも怒られないし、コンパイル時にもツッコまれない。
カスタム型ガードでちゃんとチェックする
イマイチ釈然としないけど、型ガードでちゃんとデータをチェックしてから返却しよう というお話。
const isCatApiResnpose = (arg: any): arg is CatApiResponse => {
return (arg.name !== undefined
&& arg.age !== undefined
&& arg.parents !== undefined
&& Array.isArray(arg.parents))
}
こんな感じの型ガードを書いてあげて、 fetchAllCat()
で受け取ったPromiseをresolveしたときに、きちんとデータがCapApiResponseのinterfaceに準拠していることを確認してあげる必要がある。
const hoge = () => {
const data = fetchAllCat();
data.then((data) => {
if (isCatApiResnpose(data.data)) {
data.data.parents.map((parent) => {
console.log(parent);
return "hoge";
});
}
});
};
こうすることで、はちゃめちゃなデータが返ってきても安全に処理ができる(これでいいのか...?)。
実際はReactでデータをstateにsetしたりすることもあるが、その際はnullとか想定外のデータ構造だった場合は空のCatApiResponseを準備して返して上げれば単なる「データ無し」として扱える。
で、ここで面倒なのが、「空のhoge interfaceのデータ」を作ることで、構造が複雑だと一々手動でemptyHogeDataみたいなものを作らないといけない。ただ、その場合は該当するinterfaceを実装したclassを作っちゃって、そのconstructorで空を作らせるのも手かな と。
ということで、今回はtypescriptのお話でございました。