Skip to content

Conflicting definitions for Set constructor causes unexpected default generic in TS 3.5 #31990

Description

@evmar

TypeScript Version: 3.4.5 vs versions after 3.5

Search Terms: set constructor setconstructor unknown

Code

let s = new Set();

Expected behavior:

In TS 3.4: we expect the default chosen param to give us a Set<{}>.
In TS 3.5: we expect a Set<unknown>.
That change was an intended change in TS 3.5.

Or, if Set has a default generic arg, I expect the same default chosen in 3.4 and 3.5.

Actual behavior:

In TS 3.4, this actually was a Set<any>!

It appears there are multiple overloads of the Set constructor.

lib.es2015.collection.d.ts says:

    new <T = any>(values?: ReadonlyArray<T> | null): Set<T>;

while lib.es2105.iterable.d.ts says:

    new <T>(iterable?: Iterable<T> | null): Set<T>;

Note that one has T = any and the other doesn't.

So somehow TS 3.4 vs TS 3.5 decided to change whether to obey the any default, I think?

Activity

  1. evmar commented on Jun 19, 2019

    @evmar
    ContributorAuthor

    Wesley Wigham (@weswigham) I think this might be unintended fallout of your default type parameter constraints change, maybe? #30637

    I think the two constructors should at least be consistent, but I'm not sure which is preferred, probably the any-less one?

  2. weswigham commented on Jun 20, 2019

    @weswigham
    Member

    I'm not sure which is preferred, probably the any-less one?

    Yeah, I'm not sure why we even have a version of the constructor that defaults to any - the's obviously quite unsafe.

  3. fatcerberus commented on Jun 20, 2019

    @fatcerberus

    Array has that problem too:

    let arr1 = new Array(10);  // any[] - bad
    let arr2 = new Array<number>(10);  // number[] - good
  4. weswigham commented on Jun 20, 2019

    @weswigham
    Member

    Daniel Rosenwasser (@DanielRosenwasser) do we want to change our behavior here? I think we last looked at it some time around #25374

  5. evmar commented on Jun 21, 2019

    @evmar
    ContributorAuthor

    Perhaps related, I notice in 3.4->3.5, SetConstructor changed from

       new <T>(iterable: Iterable<T>): Set<T>;
    

    to

        new <T>(iterable?: Iterable<T> | null): Set<T>;
    

    So perhaps that is changing which overload is selected when.

  6. DanielRosenwasser commented on Jun 21, 2019

    @DanielRosenwasser
    Member

    Yeah, it's unsafe, but it would be incredibly annoying to break people.

    This sort of comes back to the "I want this to be an 'implicit any' for the noImplicitAny scenarios."

  7. fatcerberus commented on Jun 21, 2019

    @fatcerberus

    I guess it can’t really be unknown[] since then it wouldn’t be assignable to anything but it also can’t reasonably be never[] because then you can’t put stuff in it (unless it could be made to work like evolving array types).

  8. evmar commented on Jun 23, 2019

    @evmar
    ContributorAuthor

    Just to restate, what I am concerned about here is whether "new Set()" is supposed to give you a Set<any> or a Set<unknown>, given the conflicting definitions in the typings.

    I believe the intention was for 3.5 change it to <unknown> and for that to break apps -- that is at least what 3.5 did in practice -- but I think the resolution of this bug is to make the typings express that intent more clearly.

  9. evmar commented on Jul 25, 2019

    @evmar
    ContributorAuthor

    Circling back on this -- I think maybe I failed to communicate the bug here.

    In practice, TS3.4 => TS3.5 changed what new Set() gives you, from Set<any> to Set<unknown>. (That is too late to undo, though massively annoying for us to upgrade through.)

    But the actual bug here is that I think you didn't change the definition of Set! It still says any in the typings, something else must be going wrong.

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

    In DiscussionNot yet reached consensusSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions