簡體   English   中英

Typescript generics 類型推斷

[英]Typescript generics type inferring

我通過實現強類型 rest 請求機制來玩 typescript。

讓代碼說話:

使用這種類型,我想定義路由和相關對象類型之間的映射:

export interface RoutesMapping {
    api1: {
        users: UserApiModel
        products: ProductApiModel,
    }
    api2: {
        "other-route": OtherModel1,
        "another-one-route": OtherModel2
    }
}

export type ApiScope = keyof RoutesMapping

下面的 function 是我願意用來發出 POST 請求的那個

export type RestApiPostResponse<T = any> = {
    result: boolean
    data: T
}

export function restPost<S extends keyof RoutesMapping = "api1", T extends keyof RoutesMapping[S] = keyof RoutesMapping[S]>(
  route: T,
  // nervermind this object, is out of scope for the question
  options: ApiRequestOptions<S, any> = {}
): Promise<RestApiPostResponse<RoutesMapping[S][T]>> {
  const url = apiUtils.buildUrl(route as string, options)
  const { payload, headers, isProtected } = options
  return post({
    url,
    isProtected,
    payload,
    headers
  });
}

我希望通過以下方式調用這個 function

const data = await restPost("users")

一個 make typescript 通過 scope 和路由推斷返回類型。

實際上,將它與默認類型參數一起使用,它可以工作:

在此處輸入圖像描述

問題是當我想以這種方式調用另一個 api 時:

const data = await restPost<"api2">("other-route")

不幸的是,它不起作用,它推斷出所有可能的類型

在此處輸入圖像描述

解決問題的唯一方法是顯式添加第二個類型參數

在此處輸入圖像描述

如何在不需要在第二種情況下添加第二個類型參數的情況下使用所有這些?

這是一個typescript 操場

如果您推斷出 api-key 類型參數,您實際上可以構建一個滿足您需求的解決方案:

type Model<Route> = // Returns the model value for key Route in RoutesMapping
  keyof RoutesMapping extends infer Api
  ? Api extends keyof RoutesMapping 
    ? Route extends keyof RoutesMapping[Api]
      ? RoutesMapping[Api][Route]
      : never
    : never
  : never

type Routes<Api> = Api extends {} ? keyof Api  : never // Helper to distribute keyof over a union of objects
type AllRoutes = Routes<RoutesMapping[keyof RoutesMapping]> // Union of all route keys: 'users' | 'products' | 'other-route' | 'another-one-route'

export function restPost<Route extends AllRoutes>(
  route: Route,
  options?:{url:string,payload:any}
): Promise<RestApiPostResponse<Model<Route>>> {
 ..
}

當應用於路由字符串時,會推斷出restPost的正確返回類型,而無需指定任何類型參數:

const data = await restPost("users") // data: RestApiPostResponse<UserApiModel>
const data2 = await restPost("other-route") // data2: RestApiPostResponse<OtherModel1>

TypeScript操場

請注意,這假設路由鍵是唯一的,這似乎是因為 api 鍵未傳遞給restPost 我也不確定引入所有這些復雜性是否明智,但至少這是可能的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM