跳至主要内容

泛型與非同步的處理

什麼是泛型 (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}`);
})()