type AnyMiddleware = (() => any) | null;
type MiddlewareContext<TMiddleware extends AnyMiddleware> =
TMiddleware extends null
? { context?: never }
: { context: Awaited<ReturnType<TMiddleware>> };
// ^^^^^^^^^^^
// Type 'TMiddleware' does not satisfy the constraint '(...args: any) => any'.
// Type 'AnyMiddleware' is not assignable to type '(...args: any) => any'.
// Type 'null' is not assignable to type '(...args: any) => any'.
#Why does typescript not narrow the type down and how to fix this?
33 messages · Page 1 of 1 (latest)
@misty atlas Here's a shortened URL of your playground link! You can remove the full link from your message.
Preview:```ts
type AnyMiddleware = (() => any) | null
type MiddlewareContext<
TMiddleware extends AnyMiddleware
= TMiddleware extends null
? {context?: never}
: {context: Awaited<ReturnType<TMiddleware>>}```
You can choose specific lines to embed by selecting them before copying the link.
Issue is the | null
The smallest tweak would be to do Exclude<TMiddleware, null>
The first part of a conditional type works mostly like you'd expect
But the second part doesn't narrow the same way
i.e. T extends U ? /* You can treat T like U here */ : /* T won't be narrowed here, it won't be Exclude<T, U> */
Here's how I'd write this:
type MiddlewareOfType<T> = (() => T) | null;
type AnyMiddleware = MiddlewareOfType<any>;
type MiddlewareContext<
TMiddleware extends AnyMiddleware
> = TMiddleware extends MiddlewareOfType<infer R>
? { context: Awaited<R> }
: never;
Thanks for your answer!
I tried to implement it in my code, but did not work unfortunately
your link shortener is not working
The main difference would probably be the handling of the null case. I decided to omit it entirely because I believed your intent for { context?: never } was likely that it should error in such a case. I think you may be getting an unknown you did not want
but I need to see an actual playground link to know what's going on
(You shouldn't need a custom link shortener; just send a TS playground link as its own message and the bot will replace it)
If you want the same behaviour as before:
type MiddlewareOfType<T> = (() => T | Promise<T>) | null;
type AnyMiddleware = MiddlewareOfType<any>;
type MiddlewareContext<
TMiddleware extends AnyMiddleware
> = TMiddleware extends null
? { context?: never }
: TMiddleware extends MiddlewareOfType<infer R>
? { context: R }
: never
TS PLayground share link is too long
The Playground lets you write TypeScript or JavaScript online in a safe and sharable way.
Preview:```ts
import {z} from "zod"
export type AnyInput = z.ZodTypeAny | z.ZodNever
export type Middleware<
TInput extends AnyInput,
TOutput = any
= (params: {input: z.infer<TInput>}) => TOutput
export type AnyMiddleware = Middleware<never> | null
...```
You can choose specific lines to embed by selecting them before copying the link.
You can make a reproduction shorter like this next time
this is with the issue btw
I've not attempted to solve it yet, just pare it down
Thanks! will keep that in mind for next time
The easiest fix is to AnyDef
Change ```ts
export type AnyDef = Def<
AnyallowedMimeTypes,
AnyFileSizeLimit,
AnyInput,
AnyMiddleware,
AnyPath
;
to
export type AnyDef = Def<
AnyallowedMimeTypes,
AnyFileSizeLimit,
AnyInput,
AnyMiddleware,
any
>;
though I'd recommend using any even more in such cases
The issue you're running into is that AnyPath took one specific route through your conditional type
whereas any will instead properly take both sides of a conditional type (in most cases, you can still get it to only go through one branch)
and the issue was that TPath, being generic, could take either side of the conditional type whereas AnyPath is actually statically known to take a specific route
Avoiding any is admirable, I recommend it as much as possible, but you'll need it in cases like this where you're dealing with generic bounds that also interface with conditional types because being more concrete means it won't take both sides of the conditional type
Hmmm, Appreciate your thinking, but now I lose the path type anywhere in my app where I work with that path function... 😅
Are there any option with using Extract?
Got it working!