Reputation: 9702
Today, I came across this type:
interface Base {
one: number;
two: number;
}
export type SelectSubset<T, U> = {
[key in keyof T]: key extends keyof U ? T[key] : never
}
type TQuestion = <T extends Base>(args: SelectSubset<T, Base>) => void
const example: TQuestion = (obj) => {}
I'm extremely unsure why the type of the generic T
can be inferred in this example. I see that T
is constrained to Base but would assume that I'd have to pass a default value for the compiler to figure out what T resolves to. I'm assuming that the compiler simply assumes T
has the type of Base
of no explicit type is passed?
Upvotes: 0
Views: 53
Reputation: 5615
In the snippet you've posted, there's no real inferring needed to be done by the compiler.
In this line-
const example: TQuestion = (obj) => {};
you've merely defined a function of type TQuestion
, no inferring needs to be done here. Since no type is explicitly mentioned on the obj
parameter, it's picked up from the TQuestion
type. This is equivalent to-
function example<T extends Base>(obj: SelectSubset<T, Base>): void {}
If you did-
const example = (obj) => {};
The compiler would complain about obj
is missing a type and has an implicit any
type (assuming you have the "no implicit any" setting set to true). Here, a type is completely missing, but when you declare example
to be of type TQuestion
, the function you store in it should be of type TQuestion
, which is why the obj
parameter automatically gets the type SelectSubset<T, Base>
The actual inferring and type checking of these constraints only come into play once you actually call the function.
Upvotes: 1