Skip to content

Rest binding element should contextually type initializer as a tuple #1824

Closed

Description

var [x, y, ...z] = [0, "", true, ""];

x and y are string | number | boolean because the rest element causes the contextual type to be an array. It seems like there is no reason for this. I think the contextual type here should be a tuple, so x would be number, y would be string, and z would be (string | boolean)[]

Activity

  1. added
    By DesignDeprecated - use "Working as Intended" or "Design Limitation" instead
    SuggestionAn idea for TypeScript
    and removed
    BugA bug in TypeScript
    By DesignDeprecated - use "Working as Intended" or "Design Limitation" instead
    on Jan 27, 2015
  2. ahejlsberg commented on Jan 27, 2015

    @ahejlsberg
    Member

    This will only matter when you're destructuring a tuple using spread operator--which, I contend, is going to be a very rare. Futhermore, if we did this sort of partial tuple destructuring, wouldn't you also expect z to be of type [boolean, string]? And wouldn't you expect to be able to put it back together as a tuple again by writing [x, y, ...z] as an expression?

    Right now we have a simple rule that says whenever spread or rest is involved, the result is an array. I think anything beyond that gets very muddled.

  3. JsonFreeman commented on Jan 28, 2015

    @JsonFreeman
    ContributorAuthor

    I agree that spread should make the result an array, because we don't know what you did to the array (lengthwise or elementwise) before you did the spread. However, rest seems different. I think with rest, there is no information lacking, that would cause it to be unsafe to consider the contextual type a tuple.

    To answer your questions about the above example:

    1. Yes, z should have the type [boolean, string]
    2. No, we should not allow the user to put the tuple back together using spread. We don't know what they did before the spread. So while it's intuitive, I don't think that's a good idea. Unless people are fine with that type hole, but I'd rather start without it.

    I think doing this for rest, but not spread, is a sensible option.

  4. ahejlsberg commented on Jan 28, 2015

    @ahejlsberg
    Member

    What about

    var [x, y, ...z] = [0, ""];

    Would we then switch and make z an array? So sometimes you get an array and sometimes a tuple. I think there is more complexity here than meets the eye for practically zero gain. I just don't think it is a meaningful real world scenario and I'd rather have the simple rule.

  5. JsonFreeman commented on Jan 28, 2015

    @JsonFreeman
    ContributorAuthor

    In that case, z would be a tuple of length 0, which happens to degenerate to undefined[], but I don't think there's anything wrong with that... provided we change our way of detecting tuple types so that it checks a bit, rather than relying on the presence of a property named 0. Also note that if we did that, x and y would not get penalized.

    I am not sure how anyone would gauge the benefits here. But the current rule about rest elements just doesn't seem to fit into our tuple story, and seems like changing it wouldn't cost us much.

  6. RyanCavanaugh commented on May 4, 2015

    @RyanCavanaugh
    Member

    Existing behavior matches general pattern of not inferring a tuple type when none was written

  7. added
    DeclinedThe issue was declined as something which matches the TypeScript vision
    and removed on May 4, 2015
  8. JsonFreeman commented on May 4, 2015

    @JsonFreeman
    ContributorAuthor

    Rereading this, I think we should actually do something different from what I mentioned. We should contextually type the RHS as a tuple, but then z should always be an array that matches the array being destructured. That way x and y have the expected types, and z behaves as it does today. What would be wrong with that?

  9. added and removed
    DeclinedThe issue was declined as something which matches the TypeScript vision
    on May 4, 2015
  10. RyanCavanaugh commented on May 4, 2015

    @RyanCavanaugh
    Member

    Open question over whether this is the right thing to do or not, versus its priority relative other things (and our inability to change this if we decide to do it later)

  11. JsonFreeman commented on May 5, 2015

    @JsonFreeman
    ContributorAuthor

    Thanks. I will also point out that this situation is not as rare as it may seem, if you consider that the binding pattern can be a parameter, and the array literal can be an argument.

  12. added
    DeclinedThe issue was declined as something which matches the TypeScript vision
    and removed on May 19, 2015
  13. RyanCavanaugh commented on May 19, 2015

    @RyanCavanaugh
    Member

    Doesn't seem to be coming up in real code.

  14. locked and limited conversation to collaborators on Jun 18, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    DeclinedThe issue was declined as something which matches the TypeScript visionSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions