gpt4 book ai didi

typescript - 如何键入参数化元组?

转载 作者:搜寻专家 更新时间:2023-10-30 20:42:54 24 4
gpt4 key购买 nike

我有一个元组,其中类型相互关联。在我的例子中,它是一个提取函数,提取一个值,该值又用作另一个函数的输入。

从概念上讲,我正在寻找的是这样的东西,但这不会编译:

const a: <T>[(v:any) => T, (t:T) => void] = [ ... ]

用例是这样的。我有一个 any 类型的传入 RPC 消息,以及一个具有众所周知参数类型的 API。我想构建一个采用两个参数的“布线计划”,一个提取器函数和相应的 API 函数。

export interface API = {
saveModel : (model:Model) => Promise<boolean>,
getModel : (modelID:string) => Promise<Model>,
}

const api: API = { ... }

// this is the tuple type where i'd like to define that
// there's a relation between the second and third member
// of the tuple.
type WirePlan = [[string, (msg:any) => T, (t:T) => Promise<any>]]

const wirePlan: WirePlan = [[
['saveModel', (msg:any) => <Model>msg.model , api.saveModel],
['getModel' , (msg:any) => <string>msg.modelID, api.getModel],
]

const handleMessage = (msg) => {
const handler = wirePlan.find((w) => w[0] === msg.name)
const extractedValue = handler[1](msg)
return handler[2](extractedValue)
}

我可以通过其他方式解决这个问题,我只是突然想到,关于元组可能有些我不理解的地方。

最佳答案

Conceptually what I'm looking for is something like this, but this doesn't compile:

const a: <T>[(v:any) => T, (t:T) => void] = [ ... ]

也就是说,事实上,您想要的相反。借助函数类型的直觉,a: <T>(t: T) => T意味着您拥有适用于所有 类型的函数。这是一个通用量词:a 的实现不知道什么T是; a 的用户可以设置T到他们想要的任何东西。对元组执行此操作将是灾难性的,因为内部函数需要输出 T 的值。不管怎样T是,因此他们唯一能做的就是错误输出/永远循环/以某种方式处于底部(他们必须返回 never )。

你想要existential quantification . a: ∃T. [(v:any) => T, (t:T) => void]意味着 a有某种类型 T与之相关。 a的执行知道它是什么,可以用它做任何想做的事,但是 a 的用户现在对此一无所知。实际上,与通用量化相比,它颠倒了角色。 TypeScript doesn't have support for existential types (甚至不是像 Java 的通配符那样的 super 基本形式),但它 can be simulated :

type WirePlanEntry = <R>(user: <T>(name: string, reader: (msg: any) => T, action: (t: T) => Promise<any>)) => R
type WirePlan = WirePlanEntry[]

是的,那是一口。可以分解为:

// Use universal quantification for the base type
type WirePlanEntry<T> = [string, (msg: any) => T, (t: T) => Promise<any>]
// A WirePlanEntryConsumer<R> takes WirePlanEntry<T> for any T, and outputs R
type WirePlanEntryConsumer<R> = <T>(plan: WirePlanEntry<T>) => R
// This consumer consumer consumes a consumer by giving it a `WirePlanEntry<T>`
// The type of an `EWirePlanEntry` doesn't give away what that `T` is, so now we have
// a `WirePlanEntry` of some unknown type `T` being passed to a consumer.
// This is the essence of existential quantification.
type EWirePlanEntry = <R>(consumer: WirePlanEntryConsumer<R>) => R
// this is an application of the fact that the statement
// "there exists a T for which the statement P(T) is true"
// implies that
// "not for every T is the statement P(T) false"

// Convert one way
function existentialize<T>(e: WirePlanEntry<T>): EWirePlanEntry {
return <R>(consumer: WirePlanEntryConsumer<R>) => consumer(e)
}

// Convert the other way
function lift<R>(consumer: WirePlanEntryConsumer<R>): (e: EWirePlanEntry) => R {
return (plan: EWirePlanEntry) => plan(consumer)
}

消费 EWirePlanEntry看起来像

plan(<T>(eT: WirePlanEntry<T>) => ...)
// without types
plan(eT => ...)

但是如果你只有这样的消费者

function consume<T>(plan: WirePlanEntry<T>): R // R is not a function of T

你会像这样使用它们

plan(consume) // Backwards!
lift(consume)(plan) // Forwards!

不过,现在您可以拥有制作人了。已经编写了最简单的此类生产者:existentialize .

这是您的其余代码:

type WirePlan = EWirePlanEntry[]
const wirePlan: WirePlan = [
existentialize(['saveModel', (msg:any) => <Model>msg.model , api.saveModel]),
existentialize(['getModel' , (msg:any) => <string>msg.modelID, api.getModel ]),
]

const handleMessage = (msg: any) => {
let entry = wirePlan.find(lift((w) => w[0] === msg.name))
if(entry) {
entry(handler => {
const extractedValue = handler[1](msg)
return handler[2](extractedValue)
})
}
}

In Action

关于typescript - 如何键入参数化元组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46185023/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com