Type Inference does not work for generics with default types
jpkraemer opened this issue · 5 comments
TypeScript Version: 2.6.0-dev.201xxxxx
Code
type FormattedDataProvider<T, R = {}> = {
src: R,
format: (item: R) => T
}
let a: FormattedDataProvider<string> = {
src: { a: 23 },
format: v => String(v.a)
}
Expected behavior:
This should compile and infer that v is of type {a: number}
.
Actual behavior:
v is inferred to the default type {}, which results in an error:
error TS2339: Property 'a' does not exist on type '{}'.
Currently generic type inference happens only when no generic type arguments are provided. specifying at least one disables all generic inference.
#10571 tracks allowing partial generic inference for required parameters. I would say we will do the default automatic inference in the same change.
Thanks for the clarification, indeed the following example works:
function test<T, R>(param: FormattedDataProvider<T, R>) {
console.log(param);
}
test({
src: { a: 23 },
format: v => String(v.a)
})
This one however, does not. So even when not specifying any types, the defaults might disable inference, too, in some instances.
type FormattedDataProvider<T, R = {}> = {
src: R,
format: (item: R) => T
}
type UnformattedDataProvider<T> = {
src: T
}
type ConfiguredDataProvider<T> = FormattedDataProvider<T> | UnformattedDataProvider<T>;
function test<T>(param: ConfiguredDataProvider<T>) {
console.log(param);
}
test({
src: { a: 23 },
format: v => String(v.a)
})
in the above example, you have used FormattedDataProvider<T>
in the definition of ConfiguredDataProvider<T>
without a second argument. this is identical to FormattedDataProvider<T , {}>
.
if you wanted to propagate the optionality of the second argument you would write it as:
type FormattedDataProvider<T, R = {}> = {
src: R,
format: (item: R) => T
}
type UnformattedDataProvider<T> = {
src: T
}
type ConfiguredDataProvider<T, R = {}> = FormattedDataProvider<T, R> | UnformattedDataProvider<T>;
function test<T, R = {}>(param: ConfiguredDataProvider<T, R>) {
console.log(param);
}
Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.