[英]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 {...}
我正在尝试定义Tool
和Network
组合之间的映射,以便我可以编写如下内容:
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.