簡體   English   中英

Typescript 類型推斷與元組類型的聯合

[英]Typescript type inference with union of tuple types

給定以下類型

type Tool = 'network_query' | 'cluster'
type Network = 'one' | 'two' | 'three'

class QueryOneParams {...}
class QueryTwoParams {...}
class QueryThreeParams {...}
class ClusterParams {...}

我正在嘗試定義ToolNetwork組合之間的映射,以便我可以編寫如下內容:

const queryParamsLookup = {
    'one': QueryOneParams,
    'two': QueryTwoParams,
    'three': QueryThreeParams
}

type Job<Tool, Network> = {
    id: string,
    params: JobParams<Tool, Network>
}

在哪里

  • JobParams<'network_query', 'one'>解析為QueryOneParams
  • JobParams<'network_query', 'two'>解析為QueryTwoParams
  • JobParams<'network_query', 'three'>解析為QueryThreeParams
  • JobParams<'cluster'>解析為ClusterParams
  • JobParams<'cluster', 'one'> , JobParams<'cluster', 'two'>JobParams<'cluster', 'three'>無效

這將需要我以某種方式定義第二個通用參數'one' | 'two' | 'three' 'one' | 'two' | 'three' 'one' | 'two' | 'three'僅在第一個參數是'network_query'時才使用和必需。 Afaik,Typescript 不支持基於另一個參數類型的可選定義的泛型參數。

那是對的嗎? 我很想在這里犯錯:)

作為替代方案,我定義了一個輔助類型,如下所示:

type NetworkQueryJobType = {
    [N in keyof typeof queryParamsLookup]: ['network_query', N]
}[keyof typeof queryParamsLookup]
// ['network_query', 'one'] | ['network_query', 'two'] | ['network_query', 'three']

type JobType = NetworkQueryJobType | ['cluster']
// ['network_query', 'one'] | ['network_query', 'two'] | ['network_query', 'three'] | ['cluster']

並將Job的定義更改為

type Job<JobType> = {
    id: string,
    params: JobParams<JobType>
}

使用這種方法,我無法讓類型推斷在映射器類型JobParams中正常工作:

type JobParams<T extends JobType> = T extends ['network_query', infer N] ?
typeof queryParamsLookup[N] // Error: N is not compatible with 'one' | 'two' | 'three'
: ClusterParams

我可以通過以下方式解決類型推斷問題:

type JobParams<T extends JobType> = T extends ['network_query', infer N] ?
N extends Network ?
    typeof queryParamsLookup[N] // No error
    : ClusterParams
: ClusterParams

然而,所有這些仍然讓我在鍵入時自動完成性能很差,例如:

const params: JobParams<['

VSCode 不會建議'cluster' | 'network_query' 'cluster' | 'network_query'

總而言之,我覺得在這里打一場失敗的戰斗。 我在做一些根本錯誤的事情嗎?

游樂場鏈接

您可以使用通用參數默認值和中性類型,例如null來匹配提供的行為。

我對您的代碼做了一些假設,如果我解釋不正確,請糾正我。

首先, queryParamsLookup是一個類型QueryParamsLookup

type QueryParamsLookup = {
    'one': QueryOneParams,
    'two': QueryTwoParams,
    'three': QueryThreeParams
}

定義問題中定義的 object 會將類型解析為提供的 class 構造函數的類型,這可能不是預期的,因為這將非常罕見。

JobParams類型可以定義為:

type JobParams<T extends Tool, N extends T extends "network_query" ? Network : null = T extends "network_query" ? Network : null> =
    N extends Network ? QueryParamsLookup[N] : ClusterParams

這將滿足以下要求:

// valid cases
const one: JobParams<"network_query", "one"> = new QueryOneParams()
const two: JobParams<"network_query", "two"> = new QueryTwoParams()
const three: JobParams<"network_query", "three"> = new QueryThreeParams()
const cluster: JobParams<"cluster"> = new ClusterParams()

// invalid cases
const inv1: JobParams<"cluster", "one"> = new QueryOneParams()
const inv2: JobParams<"cluster", "two"> = new QueryTwoParams()
const inv3: JobParams<"cluster", "three"> = new QueryThreeParams()

當提供聯合作為其第一個參數時, JobParams的此定義是悲觀的,這意味着它將把聯合視為不是network_query 這種行為可以通過翻轉三元運算符來反轉。

帶有解決方案的游樂場的鏈接。

雖然這也完全可以用元組泛型來完成,但在我看來它是非常過分的並且不是很直觀。

暫無
暫無

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

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