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

Incorrect type inference #27212

Closed
MichaelTamm opened this issue Sep 19, 2018 · 1 comment
Closed

Incorrect type inference #27212

MichaelTamm opened this issue Sep 19, 2018 · 1 comment
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed

Comments

@MichaelTamm
Copy link
Contributor

TypeScript Version: 3.1.0-rc.20180911

Search Terms:

TS2459

Code

function test_driver<F extends Object, R extends Object>({ arrange, act, assert }: {
    arrange: () => F
    act: (fixture: F) => R
    assert: (fixture_and_result: F & R) => void
}) {
    const f = arrange();
    const r = act(f);
    assert(Object.assign({}, f, r));
}

function test() {
    test_driver({
        arrange: () => ({ foo: "foo" }),
        act: ({ foo }) => ({bar: foo + "bar"}),
        assert: ({ foo, bar }) => {
            // foo is "foo" and bar is "foobar" here
        }
    });
}

... should be compiled with --target es2017 because of the Object.assign(...) statement

Expected behavior:
Should compile without error

Actual behavior:

...:15:25 - error TS2459: Type '{ foo: string; }' has no property 'bar' and no string index signature.

15         assert: ({ foo, bar }) => {
                           ~~~

Playground Link: Demo on TypeScript Playground

@ahejlsberg
Copy link
Member

This is a design limitation. Our type inference algorithm allows inferences to flow left to right between separate arguments, but not between properties in an object literal. Effectively, we can make an inference for F because the arrow function specified for the arrange property doesn't depend on anything, but then when it comes time to assign types to the parameters of the arrow functions specified for act and assert, we have not yet made an inference for R and so we end up with {}. It works if you add a type annotation in the second arrow function because we can then make inferences for both F and R before assigning types to the parameters in the last arrow function:

function test() {
    test_driver({
        arrange: () => ({ foo: "foo" }),
        act: ({ foo }: { foo: string }) => ({bar: foo + "bar"}),
        assert: ({ foo, bar }) => {
            // foo is "foo" and bar is "foobar" here
        }
    });
}

Also, your example works with no type annotations if you convert arrange, act, and assert to distinct parameters and use distinct arguments in the call to test_driver.

Would be nice to do better, but it isn't a simple fix.

@ahejlsberg ahejlsberg added the Design Limitation Constraints of the existing architecture prevent this from being fixed label Sep 19, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed
Projects
None yet
Development

No branches or pull requests

3 participants