客戶端應用程序的開發人員每天與API打交道。根據操作的成功與否或業務邏輯,標準化API響應是一個好習慣。通常,響應包括狀態、錯誤等標準字段。

有了這些標準字段,開發人員可以對操作的狀態做出反應,并構建與應用程序的進一步用戶交互。如果注冊成功,應該關閉表單并顯示成功消息。然而,如果數據格式不正確,驗證錯誤應該在表單中顯示。

這就提出了如何在項目中方便、快速和靈活地描述響應類型的問題。

遇到的問題

有時,項目中的響應類型僅用一種類型描述,帶有多個可選參數。在大多數情況下,這可能足夠了,TypeScript在編寫代碼時會建議這些參數,但需要額外檢查這些參數的存在。下面是一個這樣的類型的示例:

export enum ApiStatus {
OK = ok, ERROR = error, FORM_ERRORS = form_errors, REDIRECT = redirect, } export type ApiData = { status: ApiStatus error?: string errors?: Record<string, string> url?: string }

這種方法的唯一優點是它的簡單性。我們可以將ApiData類型添加到任何響應類型中,這樣就足夠了。

export type UserProfile = {
id: number
name: string
last_name: string
birthday: string
city: string
}

export type UserProfileResponse = ApiData & {
user: UserProfile
}

// to simulate an API call
const updateProfileAPI = async(data: Partial<UserProfile>): Promise<UserProfileResponse> => {
return Promise.resolve({} as UserProfileResponse)
}

然而,我認為這種單一的優勢被一個顯著的劣勢所抵消。這種方法的缺點是缺乏透明度。

此外,通過向響應類型添加這樣的類型,你永遠無法確切知道特定請求的響應將是什么。想象一下,對于一個POST請求,你可以從API獲得有限數量的響應場景。

場景可能是以下之一:

結果表明,我們不能僅僅通過查看響應類型就了解我們確切的響應選項。要了解所有可能的響應變體,你需要打開執行請求和處理響應的函數的代碼。

響應類型的實用類型

上述缺點可以通過自定義實用類型來解決。每個場景都有單獨的類型:成功操作、服務器錯誤、驗證錯誤或強制重定向。

這些類型可以單獨使用或組合使用,以反映特定響應的所有可能響應選項。每種類型都有一個通用類型,允許傳遞對應于該響應的數據類型的數據。

export enum ApiStatus {
OK = ok, ERROR = error, FORM_ERRORS = form_errors, REDIRECT = redirect, } export type ApiSuccess<T extends Record<string, unknown> | unknown = unknown> = T & { status: ApiStatus.OK, } export type ApiError<T extends Record<string, unknown> = { error: string } > = T & { status: ApiStatus.ERROR, } export type ApiFormErrors<T extends Record<string, unknown> = { errors: Record<string, string> }> = T & { status: ApiStatus.FORM_ERRORS, } export type ApiRedirect<T extends Record<string, unknown> = { url: string }> = T & { status: ApiStatus.REDIRECT, } export type ApiResponse<T extends Record<string, unknown> | unknown = unknown, K extends Record<string, unknown> = { error: string }, R extends Record<string, unknown> = { errors: Record<string, string> }> = ApiSuccess<T> | ApiError<K> | ApiFormErrors<R>

此外,我還創建了一個通用的ApiResponse類型,它包括幾個實用類型。這將節省為每個POST請求添加所有場景的時間。

以下是針對不同場景使用這些實用類型的示例:

export type FetchUserProfile = ApiSuccess<{
user: UserProfile
}>

export type FetchUserConfig = ApiSuccess<{
config: Record<string, string | number | boolean>
}> | ApiError

export type AddUserSocialNetworkAsLoginMethod = ApiResponse<{
social_network: string,
is_active: boolean
}, { message: string }> | ApiRedirect<{ redirect_url: string }>

實際差異

下面是一個用戶個人資料的類型示例,以及用戶個人資料更新功能返回的響應類型。

const updateProfile = async(): Promise<void> => {
try {
const data = await updateProfileAPI({ name: 'New name' })

// [!!!] Typescript does not highlight that the 'user' property could not exist on the 'data' property
// In the case when data.status === ApiStatus.ERROR|FORM_ERRORS|REDIRECT
console.log(data.user.id)

if (data.status === ApiStatus.OK) {
updatedProfileState(data.user)
return
}

if (data.status === ApiStatus.ERROR) {
// Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
// Type 'undefined' is not assignable to type 'string'.
showNotification('danger', data.error)
return
}

if (data.status === ApiStatus.FORM_ERRORS) {
// Argument of type 'Record<string, string> | undefined' is not assignable to parameter of type 'Record<string, string>'.
// Type 'undefined' is not assignable to type 'Record<string, string>'.
showValidationErrors(data.errors)
return
}

if (data.status === ApiStatus.REDIRECT) {
// Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
// Type 'undefined' is not assignable to type 'string'.
redirect(data.url)
return
}

throw new Error('Something went wrong...')
} catch (err) {
console.error('User: updateProfile - ', err)
}
}

這是一張TypeScript如何檢查這段代碼的圖片:

在圖片中,你可以看到TypeScript突出顯示了一些標準響應的預期值,如error、errors或url。這是因為linter(代碼檢查器)認為這些值可能是未定義的。這個問題可以通過在狀態檢查時增加額外的檢查來輕松解決,但它已經展示了這種方法的問題。

另外,請注意,在console.log(data.user.id)這一行中,user值沒有被突出顯示為可能未定義。如果我們收到的響應類型不是成功的,這是我們會遇到的情況。

使用ApiResponse等實用類型,我們就不會遇到這樣的問題。

export type UserProfileResponseV2 = ApiResponse<{
user: UserProfile
}> | ApiRedirect

const newUpdateProfileAPI = async(data: Partial<UserProfile>): Promise<UserProfileResponseV2> => {
return Promise.resolve({} as UserProfileResponseV2)
}

這是一張展示TypeScript如何對這段代碼進行lint檢查的圖片:

在這種情況下,一切工作正常進行:

TypeScript理解對于相應的狀態,將會有相應的標準字段。
它指出,在除了成功的響應之外的所有響應類型中,user值可能是未定義的。然而,在檢查響應的成功狀態后,這個值不再被突出顯示,并且是已定義的。

結論

在項目中實現這些實用類型后,開發人員體驗顯著提升。現在,類型完全對應于API可以提供的可能響應場景。

這也有助于避免在某些響應類型中不可用值的使用潛在錯誤,就像user值的例子一樣。

此外,不需要查看代碼中的響應處理實現就能理解實際的響應類型。你可以立即看到完整的情況。

如果你對這些實用類型是如何工作的感興趣,你可以查看TypeScript Playground頁面。

如何找到更多同類API?

冪簡集成是國內領先的API集成管理平臺,專注于為開發者提供全面、高效、易用的API集成解決方案。冪簡API平臺可以通過以下兩種方式找到所需API:通過關鍵詞搜索API、或者從API Hub分類頁進入尋找。

原文鏈接:https://itnext.io/how-to-write-api-response-types-with-typescript-f8152ddd43dd

熱門推薦
一個賬號試用1000+ API
助力AI無縫鏈接物理世界 · 無需多次注冊
3000+提示詞助力AI大模型
和專業工程師共享工作效率翻倍的秘密
返回頂部
上一篇
使用 Python 和 Flask 開發 RESTful API
下一篇
Open API 微信推送開發詳解:代碼示例與最佳實踐
国内精品久久久久影院日本,日本中文字幕视频,99久久精品99999久久,又粗又大又黄又硬又爽毛片
国产精品区一区二区三| 国产精品久久久久婷婷| 久久成人18免费观看| 国产一区 二区 三区一级| 亚洲精品国产无天堂网2021| 国产精品色在线| 国产一区二区视频在线| 在线一区二区三区四区五区 | 99精品久久免费看蜜臀剧情介绍| 国产麻豆精品久久一二三| 色婷婷综合在线| 国产在线视视频有精品| 精品国产一区二区三区久久影院| 91视频在线观看| 国产成人丝袜美腿| 91亚洲永久精品| 国产精品久久久久久久久久久免费看 | 91福利社在线观看| 欧美一区二区三区在线观看视频| 日韩不卡手机在线v区| 亚洲婷婷综合久久一本伊一区| 国产成人在线视频网址| 美女网站在线免费欧美精品| 亚洲免费看黄网站| 欧美精品一区二区三区久久久| 中文字幕二三区不卡| 国产成人亚洲综合a∨婷婷图片| 日韩黄色小视频| 亚洲最色的网站| 欧美精品国产精品| 成人动漫一区二区在线| 天天爽夜夜爽夜夜爽精品视频| 欧美成人女星排行榜| 日本视频一区二区三区| 成人免费视频caoporn| wwww国产精品欧美| 国产一区在线不卡| 青青草伊人久久| 亚洲精品在线三区| 欧美日韩一区二区欧美激情| 欧美成人a∨高清免费观看| 亚洲一二三专区| 日韩高清不卡一区二区三区| 亚洲伊人色欲综合网| 日本不卡视频在线观看| 首页国产欧美久久| 五月天激情小说综合| 一区二区三区小说| 蜜臀久久99精品久久久久宅男| 亚洲免费观看高清完整| 国产精品欧美久久久久无广告 | 久久久国产精品麻豆| 欧美一激情一区二区三区| 国产精品一二三四五| 午夜天堂影视香蕉久久| 三级一区在线视频先锋 | 亚洲国产sm捆绑调教视频| 国产调教视频一区| 26uuu色噜噜精品一区| 欧美无乱码久久久免费午夜一区| 高清国产一区二区三区| 日韩av中文字幕一区二区| 欧美一区二区大片| 亚洲一区二区三区自拍| 亚洲免费观看在线观看| 视频一区免费在线观看| 在线亚洲人成电影网站色www| 国产亲近乱来精品视频| 国产精品九色蝌蚪自拍| 国产亚洲欧美日韩俺去了| 九九**精品视频免费播放| 制服丝袜亚洲色图| 免费观看30秒视频久久| 日韩欧美国产一区二区在线播放 | 国产一区二区不卡在线| 欧美色手机在线观看| 97se亚洲国产综合自在线不卡| 亚洲视频狠狠干| 日韩女优制服丝袜电影| 亚洲欧洲综合另类| 高清不卡一二三区| 亚洲欧美日韩国产综合在线| 久久婷婷国产综合精品青草 | 亚洲欧洲99久久| 亚洲在线视频一区| 91久久精品网| 日韩在线一区二区| 精品日韩欧美在线| 韩国v欧美v日本v亚洲v| 国产日韩精品一区二区三区| 久久99国产精品久久99| 日韩一区二区三区免费观看| 麻豆视频一区二区| 日韩女同互慰一区二区| 国产精品伊人色| 亚洲欧美一区二区三区国产精品 | 色综合久久中文字幕| 亚洲色图另类专区| 国产经典欧美精品| 亚洲不卡av一区二区三区| 91麻豆成人久久精品二区三区| 中文子幕无线码一区tr| 欧美一区二区三区婷婷月色| 另类综合日韩欧美亚洲| 久久久www成人免费毛片麻豆 | 成人污视频在线观看| 肉丝袜脚交视频一区二区| 欧美激情一二三区| 91视频在线看| 国内精品伊人久久久久影院对白| av在线这里只有精品| 亚洲va欧美va人人爽午夜| 日韩欧美一级在线播放| 99riav久久精品riav| 亚洲小说欧美激情另类| 国产婷婷一区二区| 欧美日韩国产色站一区二区三区| 成人av电影免费观看| 91蜜桃网址入口| 欧美日韩精品一区二区三区| 综合网在线视频| 欧美日韩免费高清一区色橹橹| 五月婷婷综合在线| 精品粉嫩aⅴ一区二区三区四区| 欧美96一区二区免费视频| 欧美精品一区男女天堂| 99久久精品国产毛片| 天天亚洲美女在线视频| 一区二区三区在线视频观看58| 欧美国产国产综合| 午夜欧美在线一二页| av不卡免费在线观看| 欧美另类高清zo欧美| 久久精品日产第一区二区三区高清版| 日韩欧美激情一区| 中文字幕制服丝袜一区二区三区| 国产精品高潮呻吟| 亚洲最新视频在线观看| 一区二区理论电影在线观看| 亚洲成av人片在线| 亚洲国产欧美另类丝袜| 久久99在线观看| 67194成人在线观看| 日本一区二区综合亚洲| 欧美性xxxxx极品少妇| 久久久亚洲精品石原莉奈| 亚洲精品国产视频| 久久嫩草精品久久久精品 | 日韩欧美的一区二区| 欧美高清dvd| 日韩情涩欧美日韩视频| 91 com成人网| 国产欧美日韩一区二区三区在线观看| 精品精品国产高清a毛片牛牛| 欧美一级片免费看| 国产精品久久久久久久久免费相片| 国产亚洲精久久久久久| 综合色中文字幕| 免费成人性网站| 成人少妇影院yyyy| 91久久人澡人人添人人爽欧美| 欧美色综合网站| 国产精品每日更新在线播放网址| 一区二区中文字幕在线| 日本麻豆一区二区三区视频| 免费成人av在线播放| 欧美电视剧免费观看| av在线不卡免费看| 亚洲激情一二三区| 色婷婷狠狠综合| 国产成a人亚洲| 91精品国产综合久久精品app| 日韩精品一级中文字幕精品视频免费观看 | 欧美日韩国产精选| 欧美一区二区黄| 亚洲欧洲日产国产综合网| 婷婷丁香激情综合| 国产精品二区一区二区aⅴ污介绍| 日韩影院在线观看| 日韩欧美国产精品| 欧美精品123区| av中文字幕一区| 九九视频精品免费| 波多野结衣欧美| 91免费视频大全| 91尤物视频在线观看| 国产成人av一区二区三区在线| 亚洲精品欧美二区三区中文字幕| 欧美日韩电影在线播放| 国产成人啪免费观看软件| 成人综合在线观看| 日韩欧美亚洲另类制服综合在线| 成人做爰69片免费看网站| 69p69国产精品| 综合激情成人伊人| www.亚洲人| 日韩中文字幕麻豆| 亚洲国产精品av| 色哦色哦哦色天天综合| 国产老妇另类xxxxx|