Reputation: 7679
I'd like to be able to define a type that takes in a generic parameter (that itself extends a type with 2 generic parameters) and define its constraints by using the nested generic parameters.
// Boiler plate for example setup:
type NodeCallback<T> = (err?: Error | void, result?: T) => void
type Handler<I, R> = (event: I, callback: NodeCallback<R>) => void
type StrToNumHandler = Handler<string, number>
// I end up having to do this:
type WorkaroundAsyncHandler<T extends Handler<I, R>, I, R> = (event: I) => Promise<R>
type WorkaroundStrToNumHandler = WorkaroundAsyncHandler<StrToNumHandler, string, number>
// I'd like to be able to just write this:
type AsyncHandler<T extends Handler<I, R>> = (event: I) => Promise<R> // This is a compiler error. Not sure how to write this in a valid way.
type AsyncStrToNumHandler = AsyncHandler<StrToNumHandler> // This is the line I'd ultimately like to write
The workaround I have compiles, but if I'm supplying the values for I
and R
, there isn't any value in supplying the Handler
, which I'd like to be able to do.
Upvotes: 4
Views: 601
Reputation: 51559
You can get pretty close with conditional types and type inference in conditional types
type AsyncHandler<T> = T extends Handler<infer I, infer R> ?
(event: I) => Promise<R>
: never
;
type AsyncStrToNumHandler = AsyncHandler<StrToNumHandler>
// inferred as AsyncStrToNumHandler = (event: string) => Promise<number>
The downside is that your type alias should provide some type even if T
is not actually Handler
. The usual solution is to return never
type. But the code that uses such alias can behave unexpectedly at compile time when it receives never
type.
Upvotes: 1