Skip to content

lib.es5.d.ts: Default ArrayConstructor generic parameter to undefined #59379

Closed as not planned

Description

@karlhorky

⚙ Compilation target

ES2015

⚙ Library

lib.es5.d.ts

Missing / Incorrect Definition

The two constructor declaration lines without generics (new (arrayLength?: number): any[]; and (arrayLength?: number): any[];)

TypeScript/src/lib/es5.d.ts

Lines 1488 to 1497 in 903e82b

interface ArrayConstructor {
new (arrayLength?: number): any[];
new <T>(arrayLength: number): T[];
new <T>(...items: T[]): T[];
(arrayLength?: number): any[];
<T>(arrayLength: number): T[];
<T>(...items: T[]): T[];
isArray(arg: any): arg is any[];
readonly prototype: any[];
}

Suggestion:

interface ArrayConstructor {
-   new (arrayLength?: number): any[];
-   new <T>(arrayLength: number): T[];
+   new <T = undefined>(arrayLength: number): T[];
    new <T>(...items: T[]): T[];
-   (arrayLength?: number): any[];
-   <T>(arrayLength: number): T[];
+   <T = undefined>(arrayLength: number): T[];
    <T>(...items: T[]): T[];
    isArray(arg: any): arg is any[];
    readonly prototype: any[];
}

Sample Code

Using the @typescript-eslint/no-unsafe-assignment ESLint rule

const arr: undefined[] = Array(10); // 💥 Unsafe assignment of type `any[]` to a variable of type `undefined[]`. eslint (@typescript-eslint/no-unsafe-assignment)

Documentation Link

In some operations, empty slots behave as if they are filled with undefined.

const arr = [1, 2, , , 5]; // Create a sparse array

// Indexed access
console.log(arr[2]); // undefined

// For...of
for (const i of arr) {
  console.log(i);
}
// Logs: 1 2 undefined undefined 5

// Spreading
const another = [...arr]; // "another" is [ 1, 2, undefined, undefined, 5 ]

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Indexed_collections#sparse_arrays:~:text=In%20some%20operations%2C%20empty%20slots%20behave%20as%20if%20they%20are%20filled%20with%20undefined.

Since TypeScript does not have a primitive for "empty slot", undefined seems like the closest default.

cc Josh Ghoulberg 👻 (@JoshuaKGoldberg) Brad Zacher (@bradzacher)

Activity

  1. karlhorky commented on Jul 21, 2024

    @karlhorky
    ContributorAuthor

    Workaround

    To address the problem in the @typescript-eslint/no-unsafe-assignment ESLint rule without changing the lib.es5.d.ts declarations, pass in a generic type argument undefined to the Array constructor (which I'm arguing should be the default):

    const arr: undefined[] = Array<undefined>(10);
  2. MartinJohns commented on Jul 21, 2024

    @MartinJohns
    Contributor

    Somewhat related: #24834


    Your suggestion would be quite a breaking change.

    Since TypeScript does not have a primitive for "empty slot", undefined seems like the closest default.

    I don't see how this is relevant at all to your suggested change.

  3. RyanCavanaugh commented on Jul 29, 2024

    @RyanCavanaugh
    Member

    I don't see why someone would initialize an array with a length except in the rare case where they were about to fill it. This would break a number of cases, especially in JS where you can't easily specify type arguments.

  4. karlhorky commented on Jul 29, 2024

    @karlhorky
    ContributorAuthor

    My original motivation was actually that - spreading a newly-initialized array into a new array literal:

    typescript-eslint Playground

    [
      ...Array(5) // 💥 Unsafe spread of an `any` value in an array. ESLint @typescript-eslint/no-unsafe-assignment 
    ].map((val, index) => index)

    Screenshot 2024-07-29 at 22 07 46

    Providing the undefined type argument makes this problem disappear:

    typescript-eslint Playground

    [...Array<undefined>(5)].map((val, index) => index)

    Upon first thinking about it, it seemed like a logical default to me.

  5. typescript-bot commented on Aug 1, 2024

    @typescript-bot
    Contributor

    This issue has been marked as "Declined" and has seen no recent activity. It has been automatically closed for house-keeping purposes.

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