#Losing type inference somewhere

33 messages · Page 1 of 1 (latest)

drowsy spire
#

Hello! I have created a repro for an issue I am having. In our codebae, we have some method that creates a "definition". This definition has a property on it called "resolve", which is a function type that is based on the handler passed in. The issue is that at the very end, resolve's signature has erased the conditional logic.

upper niche
#

your repro is not self-contained. could you provide the definitions for LoggerPayload, Result, and BaseError?

#

actually seems like the logger is irrelevant and BaseError could be anything, so Result is the important one. i'm guessing it's an Eitherish thing?

drowsy spire
#

ya it is

#

i'm sorry you're right I didn't include those

#

but you can erase Result and BaseError and all that stuff and it should probably still do the same thing

upper niche
#

oh Parsable too i guess

upper niche
drowsy spire
#

Yeah I'll work on that shortly thanks

#

You just need zod installed I believe

upper niche
#

seems good, thanks

#

nah i only need the type definitions

#

which can be fetched automatically in the playground:

sonic sequoiaBOT
#
mkantor#0

Preview:```ts
import {z} from "zod"
import {SafeParseReturnType} from "zod"

interface S2SafeParsable<Input, Output> {
safeParse: (
input: unknown
) => SafeParseReturnType<Input, Output>
}

type Handler<Input, Output> = (props: {
input: Input
}) => Promise<Output>
...```

upper niche
#

at first glance i think the stuff like Parameters<H>[0]["input"] is probably not what you want to be doing, but i'll need to look closer to be specific

#

seems like you want def.resolve to itself be generic, right? the way you have it set up around line 26 it is not. it's just a concrete function type with H already applied via the original createDef call

#

should be like resolve: async <Something>(...) => ...

#

(i don't know what that Something should be yet)

drowsy spire
#

Yeah that's the trick

#

and btw the implementation can just throw

#

the signature is the important part

upper niche
#

right

#

i have to step away for a bit but i simplified the repro down to this, which might be easier to work through:

sonic sequoiaBOT
#
mkantor#0

Preview:```ts
type Handler<Input, Output> = (props: {
input: Input
}) => Promise<Output>

type ReturnValueOfPromise<T> = T extends Promise<
infer U

? U
: never

declare const createDef: <
H extends Handler<any, any>

(_: {
handler: H
}) => {
resolve: (
_: Parameters<H>[0]["input"]
) => Promise<ReturnValueOfPromise<ReturnType<H>>>
...```

upper niche
#

okay, back now (though i will have to leave again before too long)

#

how general-purpose do you need createDef to be? could it be set up such that resolve must always be a generic function with a single type parameter?

#

i ask because the most straightforward way to type it would be something like this:

sonic sequoiaBOT
#
mkantor#0

Preview:ts ... declare const createDef: (_: { handler: Handler<any, any> }) => { resolve: <TE extends Event>( _: TE ) => Promise<Res<TE>> } ...

upper niche
#

(tweaks may be needed when you go to implement it though)

drowsy spire
#

Hmm yeah I see what you mean. If I constrain Event and Result to both be unions of my app's possible values...

#

that probably would be fine honestly

#

I do the same for BaseError tbh