Make Map constructor argument optional and nullable (#43396)

* Make Iterable Map constructor argument optional

Fixes #37779

* Change Map constructor in iterable to accept both null and undefined.

According to the spec (https://tc39.es/ecma262/#sec-map-iterable), the sole argument passed to Map is allowed to be null or undefined.

* Changed Map constructor to ensure new Map() still types as Map<any, any>.

* Add map constructor test.

This proves that the previous commit fixes #37779, as well as that new Map() still types as Map<any, any>.

* Update baseline.

Co-authored-by: Jared Neil <jaredneil@lucidchart.com>
This commit is contained in:
Pimm "de Chinchilla" Hogeling 2022-01-18 14:39:05 +01:00 committed by GitHub
parent 7490b329a7
commit cecd8c50a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 95 additions and 10 deletions

View File

@ -137,7 +137,8 @@ interface ReadonlyMap<K, V> {
}
interface MapConstructor {
new <K, V>(iterable: Iterable<readonly [K, V]>): Map<K, V>;
new(): Map<any, any>;
new <K, V>(iterable?: Iterable<readonly [K, V]> | null): Map<K, V>;
}
interface WeakMap<K extends object, V> { }

View File

@ -1,5 +1,5 @@
tests/cases/conformance/es6/for-ofStatements/for-of39.ts(1,11): error TS2769: No overload matches this call.
Overload 1 of 3, '(iterable: Iterable<readonly [string, boolean]>): Map<string, boolean>', gave the following error.
Overload 1 of 4, '(iterable?: Iterable<readonly [string, boolean]>): Map<string, boolean>', gave the following error.
Argument of type '([string, number] | [string, true])[]' is not assignable to parameter of type 'Iterable<readonly [string, boolean]>'.
The types returned by '[Symbol.iterator]().next(...)' are incompatible between these types.
Type 'IteratorResult<[string, number] | [string, true], any>' is not assignable to type 'IteratorResult<readonly [string, boolean], any>'.
@ -9,7 +9,7 @@ tests/cases/conformance/es6/for-ofStatements/for-of39.ts(1,11): error TS2769: No
Type '[string, number]' is not assignable to type 'readonly [string, boolean]'.
Type at position 1 in source is not compatible with type at position 1 in target.
Type 'number' is not assignable to type 'boolean'.
Overload 2 of 3, '(entries?: readonly (readonly [string, boolean])[]): Map<string, boolean>', gave the following error.
Overload 2 of 4, '(entries?: readonly (readonly [string, boolean])[]): Map<string, boolean>', gave the following error.
Type 'number' is not assignable to type 'boolean'.
@ -17,7 +17,7 @@ tests/cases/conformance/es6/for-ofStatements/for-of39.ts(1,11): error TS2769: No
var map = new Map([["", true], ["", 0]]);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2769: No overload matches this call.
!!! error TS2769: Overload 1 of 3, '(iterable: Iterable<readonly [string, boolean]>): Map<string, boolean>', gave the following error.
!!! error TS2769: Overload 1 of 4, '(iterable?: Iterable<readonly [string, boolean]>): Map<string, boolean>', gave the following error.
!!! error TS2769: Argument of type '([string, number] | [string, true])[]' is not assignable to parameter of type 'Iterable<readonly [string, boolean]>'.
!!! error TS2769: The types returned by '[Symbol.iterator]().next(...)' are incompatible between these types.
!!! error TS2769: Type 'IteratorResult<[string, number] | [string, true], any>' is not assignable to type 'IteratorResult<readonly [string, boolean], any>'.
@ -27,7 +27,7 @@ tests/cases/conformance/es6/for-ofStatements/for-of39.ts(1,11): error TS2769: No
!!! error TS2769: Type '[string, number]' is not assignable to type 'readonly [string, boolean]'.
!!! error TS2769: Type at position 1 in source is not compatible with type at position 1 in target.
!!! error TS2769: Type 'number' is not assignable to type 'boolean'.
!!! error TS2769: Overload 2 of 3, '(entries?: readonly (readonly [string, boolean])[]): Map<string, boolean>', gave the following error.
!!! error TS2769: Overload 2 of 4, '(entries?: readonly (readonly [string, boolean])[]): Map<string, boolean>', gave the following error.
!!! error TS2769: Type 'number' is not assignable to type 'boolean'.
for (var [k, v] of map) {
k;

View File

@ -1,5 +1,5 @@
tests/cases/conformance/es6/destructuring/iterableArrayPattern28.ts(2,24): error TS2769: No overload matches this call.
Overload 1 of 3, '(iterable: Iterable<readonly [string, number]>): Map<string, number>', gave the following error.
Overload 1 of 4, '(iterable?: Iterable<readonly [string, number]>): Map<string, number>', gave the following error.
Argument of type '([string, number] | [string, boolean])[]' is not assignable to parameter of type 'Iterable<readonly [string, number]>'.
The types returned by '[Symbol.iterator]().next(...)' are incompatible between these types.
Type 'IteratorResult<[string, number] | [string, boolean], any>' is not assignable to type 'IteratorResult<readonly [string, number], any>'.
@ -9,7 +9,7 @@ tests/cases/conformance/es6/destructuring/iterableArrayPattern28.ts(2,24): error
Type '[string, boolean]' is not assignable to type 'readonly [string, number]'.
Type at position 1 in source is not compatible with type at position 1 in target.
Type 'boolean' is not assignable to type 'number'.
Overload 2 of 3, '(entries?: readonly (readonly [string, number])[]): Map<string, number>', gave the following error.
Overload 2 of 4, '(entries?: readonly (readonly [string, number])[]): Map<string, number>', gave the following error.
Type 'boolean' is not assignable to type 'number'.
@ -18,7 +18,7 @@ tests/cases/conformance/es6/destructuring/iterableArrayPattern28.ts(2,24): error
takeFirstTwoEntries(...new Map([["", 0], ["hello", true]]));
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2769: No overload matches this call.
!!! error TS2769: Overload 1 of 3, '(iterable: Iterable<readonly [string, number]>): Map<string, number>', gave the following error.
!!! error TS2769: Overload 1 of 4, '(iterable?: Iterable<readonly [string, number]>): Map<string, number>', gave the following error.
!!! error TS2769: Argument of type '([string, number] | [string, boolean])[]' is not assignable to parameter of type 'Iterable<readonly [string, number]>'.
!!! error TS2769: The types returned by '[Symbol.iterator]().next(...)' are incompatible between these types.
!!! error TS2769: Type 'IteratorResult<[string, number] | [string, boolean], any>' is not assignable to type 'IteratorResult<readonly [string, number], any>'.
@ -28,5 +28,5 @@ tests/cases/conformance/es6/destructuring/iterableArrayPattern28.ts(2,24): error
!!! error TS2769: Type '[string, boolean]' is not assignable to type 'readonly [string, number]'.
!!! error TS2769: Type at position 1 in source is not compatible with type at position 1 in target.
!!! error TS2769: Type 'boolean' is not assignable to type 'number'.
!!! error TS2769: Overload 2 of 3, '(entries?: readonly (readonly [string, number])[]): Map<string, number>', gave the following error.
!!! error TS2769: Overload 2 of 4, '(entries?: readonly (readonly [string, number])[]): Map<string, number>', gave the following error.
!!! error TS2769: Type 'boolean' is not assignable to type 'number'.

View File

@ -0,0 +1,16 @@
//// [mapConstructor.ts]
new Map();
const potentiallyUndefinedIterable = [['1', 1], ['2', 2]] as Iterable<[string, number]> | undefined;
new Map(potentiallyUndefinedIterable);
const potentiallyNullIterable = [['1', 1], ['2', 2]] as Iterable<[string, number]> | null;
new Map(potentiallyNullIterable);
//// [mapConstructor.js]
"use strict";
new Map();
const potentiallyUndefinedIterable = [['1', 1], ['2', 2]];
new Map(potentiallyUndefinedIterable);
const potentiallyNullIterable = [['1', 1], ['2', 2]];
new Map(potentiallyNullIterable);

View File

@ -0,0 +1,20 @@
=== tests/cases/compiler/mapConstructor.ts ===
new Map();
>Map : Symbol(Map, Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
const potentiallyUndefinedIterable = [['1', 1], ['2', 2]] as Iterable<[string, number]> | undefined;
>potentiallyUndefinedIterable : Symbol(potentiallyUndefinedIterable, Decl(mapConstructor.ts, 2, 5))
>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --))
new Map(potentiallyUndefinedIterable);
>Map : Symbol(Map, Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
>potentiallyUndefinedIterable : Symbol(potentiallyUndefinedIterable, Decl(mapConstructor.ts, 2, 5))
const potentiallyNullIterable = [['1', 1], ['2', 2]] as Iterable<[string, number]> | null;
>potentiallyNullIterable : Symbol(potentiallyNullIterable, Decl(mapConstructor.ts, 5, 5))
>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --))
new Map(potentiallyNullIterable);
>Map : Symbol(Map, Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
>potentiallyNullIterable : Symbol(potentiallyNullIterable, Decl(mapConstructor.ts, 5, 5))

View File

@ -0,0 +1,38 @@
=== tests/cases/compiler/mapConstructor.ts ===
new Map();
>new Map() : Map<any, any>
>Map : MapConstructor
const potentiallyUndefinedIterable = [['1', 1], ['2', 2]] as Iterable<[string, number]> | undefined;
>potentiallyUndefinedIterable : Iterable<[string, number]> | undefined
>[['1', 1], ['2', 2]] as Iterable<[string, number]> | undefined : Iterable<[string, number]> | undefined
>[['1', 1], ['2', 2]] : [string, number][]
>['1', 1] : [string, number]
>'1' : "1"
>1 : 1
>['2', 2] : [string, number]
>'2' : "2"
>2 : 2
new Map(potentiallyUndefinedIterable);
>new Map(potentiallyUndefinedIterable) : Map<string, number>
>Map : MapConstructor
>potentiallyUndefinedIterable : Iterable<[string, number]> | undefined
const potentiallyNullIterable = [['1', 1], ['2', 2]] as Iterable<[string, number]> | null;
>potentiallyNullIterable : Iterable<[string, number]> | null
>[['1', 1], ['2', 2]] as Iterable<[string, number]> | null : Iterable<[string, number]> | null
>[['1', 1], ['2', 2]] : [string, number][]
>['1', 1] : [string, number]
>'1' : "1"
>1 : 1
>['2', 2] : [string, number]
>'2' : "2"
>2 : 2
>null : null
new Map(potentiallyNullIterable);
>new Map(potentiallyNullIterable) : Map<string, number>
>Map : MapConstructor
>potentiallyNullIterable : Iterable<[string, number]> | null

View File

@ -1,5 +1,5 @@
=== tests/cases/compiler/newMap.ts ===
new Map<string>();
>new Map<string>() : Map<string, unknown>
>new Map<string>() : Map<any, any>
>Map : MapConstructor

View File

@ -0,0 +1,10 @@
// @strict: true
// @target: es2015
new Map();
const potentiallyUndefinedIterable = [['1', 1], ['2', 2]] as Iterable<[string, number]> | undefined;
new Map(potentiallyUndefinedIterable);
const potentiallyNullIterable = [['1', 1], ['2', 2]] as Iterable<[string, number]> | null;
new Map(potentiallyNullIterable);