泛型與非同步的處理
什麼是泛型 (Generics)
有時候在定義函式或 type 時,無法確定會接收到什麼資料,而無法定義型別,此時就可以使用『泛型』T 來佔位,等到使用時再指定實際型別,達到安全與可重用性。
- 型別安全:不需使用
any來處理 - 可重用:一次定義,多種型別
- 輸入與輸出間的型別關聯性 (輸入什麼型別,輸出也是什麼型別)
例
function identity (value) {
return value;
}
const a = identity("hi");
const b = identity(123);
使用泛型
function identity<T> (value: T): T {
return value;
}
const a = identity<string>("hi");
const b = identity<number>(123);
在非同步 (axios) 時怎麼處理泛型?
先來複習一下 GET 請求
async function getAllPosts() {
try {
const url = 'https://jsonplaceholder.typicode.com/posts';
const res = await axios.get(url)
console.log(res.data)
} catch(error) {
console.error(error.message)
}
}
接著使用泛型來處理
import axios, { AxiosResponse } from 'axios';
type TPost = {
userId: number;
id: number;
title: string;
body: string;
}
async function getAllPosts(): Promise<AxiosResponse<TPost[]> | undefined> {
try {
const url = 'https://jsonplaceholder.typicode.com/posts';
const res: AxiosResponse<TPost[]> = await axios.get<TPost[]>(url)
console.log('資料取得成功');
return res;
} catch(error) {
console.error('API 請求錯誤', error.message)
return undefined;
}
}
getAllPosts(): Promise<AxiosResponse<TPost[]> | undefined> 發生了什麼?- 這裡我們試著取得完整的物件: axios 有包裝好的型別
AxiosResponse,這時候就可以直接引用 - 在呼叫
getAllPosts()函式時,會得到一個 Promise,成功時會回傳一個TPost[]資料的AxiosResponse,否則就回傳undefined備註:取得的資料格式會長這樣[{Tpost}, {Tpost}, {Tpos}]所以寫成TPost[]
const res: AxiosResponse<TPost[]> = await axios.get<TPost[]>(url) 發生了什麼?- 在
res: AxiosResponse<TPost[]>告訴 TS 變數res的類型必需是AxiosResponse裡面包著的資料類型是TPost[] - 接著
axios.get<TPost[]>在 get 後面是告訴 axios 和 TS 預期 Response Data 會是TPost[]類型 - 只寫
get<TPost[]>TS 也是可以推導出res的類型,但都寫好寫滿更嚴謹
提示
在 tsconfig.json 如果啟用了 verbatimModuleSyntax: true
要求導出/導入語法必須明確區分值與型別,
- 型別必須明確的使用
import type/export type - 一般的值(函式、變數…) 則使用
import/export
寫 import axios, { AxiosResponse } from 'axios'; 就會報錯;
要改寫成 import type {AxiosResponse} from 'axios'
來練習看看
GET 回應資料型別
目標:用泛型指定回應資料為 User,取得 data: User。
點擊查看解答
type TUser = {
id: number;
name: string;
username: string;
};
async function getUser(): Promise<TUser[]> {
const res = await axios.get<TUser[]>("https://jsonplaceholder.typicode.com/users");
return res.data;
}
// 使用
(async () => {
const userList = await getUser();
console.log(`成功取得 ${userList.length} 位使用者。`);
console.log(`第一位使用者名稱:${userList[0].name}`);
})()