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

inference strangeness - 3 #6037

Closed
zpdDG4gta8XKpMCd opened this issue Dec 10, 2015 · 7 comments
Closed

inference strangeness - 3 #6037

zpdDG4gta8XKpMCd opened this issue Dec 10, 2015 · 7 comments
Labels
By Design Deprecated - use "Working as Intended" or "Design Limitation" instead

Comments

@zpdDG4gta8XKpMCd
Copy link

Overheard conversation on the street:

Q: Can I assign an array literal to a tuple in TypeScript?
A: Yes, sometimes you can.

let value : [string, string];
value = ['hey', 'nay']; // <-- works, an array literal can be assigned to a tuple  

function fold<a, r>(values: a[], result: r, fold: (result: r, value: a) => r) : r {
    for (let value of values) {
        result = fold(result, value);
    }
    return result;
}

function append<a>(values: a[], value: a) : a[] {
    values.push(value);
    return values;
}


fold(
    [1, 2, 3],
    <[string, string][]>[],
    (result, value) => append( // <-- doesn't work, an array literal is not assignable to tuple 
        result,
        ['', '']
    )
);

image

@DanielRosenwasser
Copy link
Member

Just to make sure, you meant value where you last wrote values right?

Sorry, when you wrote values, did you mean result?

@zpdDG4gta8XKpMCd
Copy link
Author

I did. Good catch. Fixed.

@DanielRosenwasser
Copy link
Member

Okay, so here's what's happening, cutting to the important parts.

  1. fold infers its r as a [string, string] thanks to the type assertion.
  2. result gets inferred the type [string, string] as expected, due to contextual typing.
  3. append now needs to infer its type arguments. Its candidates are:
    • [string, string] from the type of result
    • string[] from the type of ['', '']. this is where things go wrong
  4. Between its two candidates, we choose the type that is the more general of the two. This is string[].

So given the one-at-a-time directionality of each inference process (type argument inference and contextual typing), I'm not sure how this could be modeled appropriately.

@zpdDG4gta8XKpMCd
Copy link
Author

Glad we found a corner case.

@DanielRosenwasser
Copy link
Member

Hey, guess what - thanks to @ahejlsberg's current work on allowing type parameters to extend each other (#5949), you should be able to do this in TypeScript 1.8! You'll just need to write append as follows:

function append<a, b extends a>(values: a[], value: b): a[] {
    values.push(value);
    return values;
}

Here's the full example:

let value: [string, string];
value = ['hey', 'nay']; // <-- works, an array literal can be assigned to a tuple  

function fold<a, r>(values: a[], result: r, fold: (result: r, value: a) => r): r {
    for (let value of values) {
        result = fold(result, value);
    }
    return result;
}

function append<a, b extends a>(values: a[], value: b): a[] {
    values.push(value);
    return values;
}


fold(
    [1, 2, 3],
    [] as [string, string][],
    (result, value) => append(
        result,
        ['', '']
    )
);

@DanielRosenwasser DanielRosenwasser added the By Design Deprecated - use "Working as Intended" or "Design Limitation" instead label Dec 10, 2015
@DanielRosenwasser
Copy link
Member

So while I'm marking this as by design, you should have a (more correct) workaround.

@zpdDG4gta8XKpMCd
Copy link
Author

looks like working, the language service in VS doesn't complain about, however I cannot verify 100% because of the --declaration argument problem that I reported: #5949 (comment)

will be waiting for that branch to be merged and available in nightly builds

thanks!

@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
By Design Deprecated - use "Working as Intended" or "Design Limitation" instead
Projects
None yet
Development

No branches or pull requests

2 participants