Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type Inference does not work for generics with default types #19205

Closed
jpkraemer opened this issue Oct 16, 2017 · 5 comments
Closed

Type Inference does not work for generics with default types #19205

jpkraemer opened this issue Oct 16, 2017 · 5 comments
Labels
Duplicate An existing issue was already created

Comments

@jpkraemer
Copy link

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 '{}'.

@mhegazy
Copy link
Contributor

mhegazy commented Oct 16, 2017

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.

@mhegazy
Copy link
Contributor

mhegazy commented Oct 16, 2017

closing in favor of #10571

@mhegazy mhegazy added the Duplicate An existing issue was already created label Oct 16, 2017
@jpkraemer
Copy link
Author

jpkraemer commented Oct 17, 2017

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)
})

@mhegazy
Copy link
Contributor

mhegazy commented Oct 17, 2017

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);
}

@mhegazy
Copy link
Contributor

mhegazy commented Oct 31, 2017

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

2 participants