Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

About the reverse inference in TypeScript

Tags:

typescript

this is my test code:

type Prop<T> = { new(...args: any[]): T } | { (): T }
declare function propTest<T>(t: Prop<T>): T

when i define a class, it will be ok:

class User {}
propTest(User) // User

But when i pass it with native constructors:

propTest(String) // String(not string)

The reason is String satisfy both call and constructor signature.

So my question is what should i do to get the compiler to infer the native type?

like image 342
jkchao Avatar asked Oct 19 '25 10:10

jkchao


1 Answers

So I take it you'd like T to be inferred from the callable signature (()=>T) before it gets inferred from the newable signature (new(...args: any[])=>T), but the compiler doesn't want to do that for you? I guess the newable signature always takes priority (it doesn't matter if you switch the order of the union constituents).

Luckily, there's a trick to lowering the priority of an inference site, mentioned by @RyanCavanaugh (one of the language maintainers) in a GitHub issue comment:

T & { } creates a "lower-priority" inference site for T by design. I would move this from the "definitely don't depend on this" column to the "it's probably going to work for the foreseeable future" column.

So the trick is to intersect something with the empty object type. Let's see if it works:

type Prop<T> = { (): T } | { new(...args: any[]): (T & {}) }

I've put the T & {} in the newable signature, to try to lower its priority. Here goes: 🤞

propTest(String) // string 🎉

And let's just make sure it still works for User:

propTest(User) // User

Okay, hope that helps. Good luck!

like image 53
jcalz Avatar answered Oct 21 '25 01:10

jcalz