簡體   English   中英

Typescript function object 參數更改返回類型

[英]Typescript function object parameter changes return type

我一直在努力嘗試使 object 參數影響 function 的返回類型。

主要問題

這是一個帶有createArray function 的示例,向您展示我的意思。

interface Selectable { selectable: boolean; }

interface SelectableReturn { selected: {value:any, index:number} }

interface Distant { distant: boolean; }

interface DistantReturn { distances: number[]; }

// All possible type combinations (all objects we can pass to the function)
type Possibilties = Distant | Selectable;

// Here we create the function definitions
declare function createArray(arr: any[], options?: undefined): any[];
declare function createArray(arr: any[], options?: Selectable): any[] & SelectableReturn;
declare function createArray(arr: any[], options?: Distant): any[] & DistantReturn;
declare function createArray(arr: any[], options?: Selectable & Distant): any[] & SelectableReturn & DistantReturn;

在未來,您可以想象為 object 添加新選項。 你能看出你會花多少時間來實現這個嗎? 如果我有 5 個選項,我必須有 5² = 25 function 聲明......

我想要的是根據選項類型自動將 append 屬性添加到返回的數組中。

第二個問題

如您所見,此代碼有效,但是當您像這樣創建數組時:

const arr = createArray([1,2,3], {selectable: true});

你沒有得到智能感知,這是因為“可能性”接口......有沒有辦法檢測“選項”類型,推斷返回類型並維護智能感知?

是 Typescript 游樂場的鏈接。

我在這里采用的方法是創建一個通用調用簽名,它使用options輸入參數的類型來生成所需形狀的 output 類型,這將是與options中每個鍵對應的結果類型的交集范圍。

這里有幫助的一件事是定義一個類型CreateArrayOptions表示輸入選項鍵到 output 返回類型的映射,以便我們可以以編程方式將結果類型確定為選項鍵的 function:

interface CreateArrayOptions {
  selectable: SelectableReturn;
  distant: DistantReturn;
}

而不是使用SelectableDistant類型,我們將只使用 map 的CreateArrayOptionsboolean屬性的鍵......好吧,實際上只是true ,因為我不想擔心甚至不支持有人將選項設置為false 理想情況下,您只是不包含該選項,而是將其設置為false ...如果您需要支持false ,這是可能的,但更復雜。

這意味着createArray()調用簽名將如下所示:

declare function createArray<K extends keyof CreateArrayOptions = never>(
  arr: any[], options?: Record<K, true> 
): any[] & Return<K>;

其中泛型類型參數Koptions鍵的聯合(如果未傳入options ,則never不會)。 Return<K>應該是對應的*Return類型的交集。

以下是計算方法:

type Return<K extends keyof CreateArrayOptions> =
  { [P in K]: (x: CreateArrayOptions[P]) => void }[K] extends
  (x: infer I) => void ? I : never

這會產生交叉點可能並不明顯。 如果你想要一個union ,你可以像CreateArrayOptions[K]一樣簡單地做到這一點,因為索引到一個帶有聯合鍵的接口會產生一個聯合值。 但是要從鍵的聯合中以編程方式進行交集,需要更多的類型雜耍。 當您在具有多個推理候選的逆變position 中的條件類型中使用infer時,會自動為您生成交點。 假設您使用的是--strictFunctionTypes編譯器選項(它也記錄了我所說的“逆變”的意思,但也可以在這里查看),其中一個這樣的 position 是 function 的參數。

對於傳入的鍵,我們創建一個映射類型,我們將相應的*Return類型放入逆變 position 中,然后infer這些類型的並集,這會產生一個交集。 這也是用於將並集轉換為交集的通用方法。


讓我們看看它是否有效:

const regularArray = createArray([]) // any[]
const alsoRegularArray = createArray([], {}) // any[]
const distantReturn = createArray([], { distant: true }) // any[] & DistantReturn
const selectableReturn = createArray([], { selectable: true }) 
  // any[] & SelectableReturn
const distantAndSelectableReturn = 
  createArray([], { selectable: true, distant: true }) 
  // any[] & SelectableReturn & DistantReturn

看起來不錯!

而且它很容易擴展; 您所要做的就是向CreateArrayOptions添加更多條目:

interface CreateArrayOptions {
  selectable: SelectableReturn;
  distant: DistantReturn;
  thirdThing: ThirdThingReturn;
}

const somethingElse = createArray([], { thirdThing: true, distant: true });
// const somethingElse: any[] & DistantReturn & ThirdThingReturn
somethingElse.monkeys // boolean
somethingElse.distances // number[]

對於您的最后一個問題,如果 IntelliSense 不適合您,這似乎是 TypeScript 中的錯誤或設計限制或缺少功能,其中泛型類型阻止生成合理的 IntelliSense 完成列表。 GitHub 中有很多關於 IntelliSense 缺點的問題,但我不知道我是否找到了正是這個問題的問題。 就像, microsoft/TypeScript#28662看起來相關但並不明顯相同。 無論如何,在microsoft/TypeScript#28470中,有一條注釋顯示了一種解決方法,在這里翻譯它會產生以下調用簽名:

declare function createArray<K extends keyof CreateArrayOptions = never>(
  arr: any[], 
  options?: Record<K, true> & Partial<Record<keyof CreateArrayOptions, true>>
): any[] & Return<K>;

我們希望將options視為可分配給Partial<Record<keyof CreateArrayOptions, true>> ,原始版本的CreateArrayOptions看起來像{selected?: true; distant?: true} {selected?: true; distant?: true}Partial<T>實用程序類型使所有屬性都是可選的),但仍然讓我們推斷K 那個路口對我們都有好處。

所以現在你應該得到一些 IntelliSense,它至少知道預期的鍵,它應該看起來像這樣:

// createArray([], { })
// ---------------> |
// ◾ distant   (property) distant?: true | undefined
// ◾ selectable (property) selectable?: true | undefined 

或者對於那些可以看到圖像的人:

在此處輸入圖像描述

萬歲!

Playground 代碼鏈接

暫無
暫無

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

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