Skip to content

Commit 49d6f61

Browse files
saschanazRyanCavanaugh
authored andcommitted
Add ES2019 Object.fromEntries function (#30934)
* add ES2019 Object.fromEntries function * add some comments * apply suggested changes * add readonly and general any
1 parent 1d83982 commit 49d6f61

File tree

9 files changed

+192
-3
lines changed

9 files changed

+192
-3
lines changed

src/compiler/commandLineParser.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ namespace ts {
4545
["es2018.promise", "lib.es2018.promise.d.ts"],
4646
["es2018.regexp", "lib.es2018.regexp.d.ts"],
4747
["es2019.array", "lib.es2019.array.d.ts"],
48+
["es2019.object", "lib.es2019.object.d.ts"],
4849
["es2019.string", "lib.es2019.string.d.ts"],
4950
["es2019.symbol", "lib.es2019.symbol.d.ts"],
5051
["es2020.string", "lib.es2020.string.d.ts"],

src/lib/es2019.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/// <reference lib="es2018" />
22
/// <reference lib="es2019.array" />
3+
/// <reference lib="es2019.object" />
34
/// <reference lib="es2019.string" />
45
/// <reference lib="es2019.symbol" />

src/lib/es2019.object.d.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/// <reference lib="es2015.iterable" />
2+
3+
interface ObjectConstructor {
4+
/**
5+
* Returns an object created by key-value entries for properties and methods
6+
* @param entries An iterable object that contains key-value entries for properties and methods.
7+
*/
8+
fromEntries<T = any>(entries: Iterable<readonly [PropertyKey, T]>): { [k in PropertyKey]: T };
9+
10+
/**
11+
* Returns an object created by key-value entries for properties and methods
12+
* @param entries An iterable object that contains key-value entries for properties and methods.
13+
*/
14+
fromEntries(entries: Iterable<readonly any[]>): any;
15+
}

src/lib/libs.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"es2018.promise",
3737
"es2018.intl",
3838
"es2019.array",
39+
"es2019.object",
3940
"es2019.string",
4041
"es2019.symbol",
4142
"es2020.string",

src/testRunner/unittests/config/commandLineParsing.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ namespace ts {
5757
assertParseResult(["--lib", "es5,invalidOption", "0.ts"],
5858
{
5959
errors: [{
60-
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.string', 'es2019.symbol', 'es2020.string', 'es2020.symbol.wellknown', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
60+
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.object', 'es2019.string', 'es2019.symbol', 'es2020.string', 'es2020.symbol.wellknown', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
6161
category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category,
6262
code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
6363
file: undefined,
@@ -259,7 +259,7 @@ namespace ts {
259259
assertParseResult(["--lib", "es5,", "es7", "0.ts"],
260260
{
261261
errors: [{
262-
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.string', 'es2019.symbol', 'es2020.string', 'es2020.symbol.wellknown', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
262+
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.object', 'es2019.string', 'es2019.symbol', 'es2020.string', 'es2020.symbol.wellknown', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
263263
category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category,
264264
code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
265265
file: undefined,
@@ -278,7 +278,7 @@ namespace ts {
278278
assertParseResult(["--lib", "es5, ", "es7", "0.ts"],
279279
{
280280
errors: [{
281-
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.string', 'es2019.symbol', 'es2020.string', 'es2020.symbol.wellknown', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
281+
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.object', 'es2019.string', 'es2019.symbol', 'es2020.string', 'es2020.symbol.wellknown', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
282282
category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category,
283283
code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
284284
file: undefined,
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//// [objectFromEntries.ts]
2+
const o = Object.fromEntries([['a', 1], ['b', 2], ['c', 3]]);
3+
const o2 = Object.fromEntries(new URLSearchParams());
4+
const o3 = Object.fromEntries(new Map([[Symbol("key"), "value"]]));
5+
6+
const frozenArray = Object.freeze([['a', 1], ['b', 2], ['c', 3]]);
7+
const o4 = Object.fromEntries(frozenArray);
8+
9+
const frozenArray2: readonly [string, number][] = Object.freeze([['a', 1], ['b', 2], ['c', 3]]);
10+
const o5 = Object.fromEntries(frozenArray2);
11+
12+
13+
//// [objectFromEntries.js]
14+
const o = Object.fromEntries([['a', 1], ['b', 2], ['c', 3]]);
15+
const o2 = Object.fromEntries(new URLSearchParams());
16+
const o3 = Object.fromEntries(new Map([[Symbol("key"), "value"]]));
17+
const frozenArray = Object.freeze([['a', 1], ['b', 2], ['c', 3]]);
18+
const o4 = Object.fromEntries(frozenArray);
19+
const frozenArray2 = Object.freeze([['a', 1], ['b', 2], ['c', 3]]);
20+
const o5 = Object.fromEntries(frozenArray2);
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
=== tests/cases/compiler/objectFromEntries.ts ===
2+
const o = Object.fromEntries([['a', 1], ['b', 2], ['c', 3]]);
3+
>o : Symbol(o, Decl(objectFromEntries.ts, 0, 5))
4+
>Object.fromEntries : Symbol(ObjectConstructor.fromEntries, Decl(lib.es2019.object.d.ts, --, --), Decl(lib.es2019.object.d.ts, --, --))
5+
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
6+
>fromEntries : Symbol(ObjectConstructor.fromEntries, Decl(lib.es2019.object.d.ts, --, --), Decl(lib.es2019.object.d.ts, --, --))
7+
8+
const o2 = Object.fromEntries(new URLSearchParams());
9+
>o2 : Symbol(o2, Decl(objectFromEntries.ts, 1, 5))
10+
>Object.fromEntries : Symbol(ObjectConstructor.fromEntries, Decl(lib.es2019.object.d.ts, --, --), Decl(lib.es2019.object.d.ts, --, --))
11+
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
12+
>fromEntries : Symbol(ObjectConstructor.fromEntries, Decl(lib.es2019.object.d.ts, --, --), Decl(lib.es2019.object.d.ts, --, --))
13+
>URLSearchParams : Symbol(URLSearchParams, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(lib.dom.iterable.d.ts, --, --))
14+
15+
const o3 = Object.fromEntries(new Map([[Symbol("key"), "value"]]));
16+
>o3 : Symbol(o3, Decl(objectFromEntries.ts, 2, 5))
17+
>Object.fromEntries : Symbol(ObjectConstructor.fromEntries, Decl(lib.es2019.object.d.ts, --, --), Decl(lib.es2019.object.d.ts, --, --))
18+
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
19+
>fromEntries : Symbol(ObjectConstructor.fromEntries, Decl(lib.es2019.object.d.ts, --, --), Decl(lib.es2019.object.d.ts, --, --))
20+
>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, --, --))
21+
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --))
22+
23+
const frozenArray = Object.freeze([['a', 1], ['b', 2], ['c', 3]]);
24+
>frozenArray : Symbol(frozenArray, Decl(objectFromEntries.ts, 4, 5))
25+
>Object.freeze : Symbol(ObjectConstructor.freeze, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
26+
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
27+
>freeze : Symbol(ObjectConstructor.freeze, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
28+
29+
const o4 = Object.fromEntries(frozenArray);
30+
>o4 : Symbol(o4, Decl(objectFromEntries.ts, 5, 5))
31+
>Object.fromEntries : Symbol(ObjectConstructor.fromEntries, Decl(lib.es2019.object.d.ts, --, --), Decl(lib.es2019.object.d.ts, --, --))
32+
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
33+
>fromEntries : Symbol(ObjectConstructor.fromEntries, Decl(lib.es2019.object.d.ts, --, --), Decl(lib.es2019.object.d.ts, --, --))
34+
>frozenArray : Symbol(frozenArray, Decl(objectFromEntries.ts, 4, 5))
35+
36+
const frozenArray2: readonly [string, number][] = Object.freeze([['a', 1], ['b', 2], ['c', 3]]);
37+
>frozenArray2 : Symbol(frozenArray2, Decl(objectFromEntries.ts, 7, 5))
38+
>Object.freeze : Symbol(ObjectConstructor.freeze, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
39+
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
40+
>freeze : Symbol(ObjectConstructor.freeze, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
41+
42+
const o5 = Object.fromEntries(frozenArray2);
43+
>o5 : Symbol(o5, Decl(objectFromEntries.ts, 8, 5))
44+
>Object.fromEntries : Symbol(ObjectConstructor.fromEntries, Decl(lib.es2019.object.d.ts, --, --), Decl(lib.es2019.object.d.ts, --, --))
45+
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
46+
>fromEntries : Symbol(ObjectConstructor.fromEntries, Decl(lib.es2019.object.d.ts, --, --), Decl(lib.es2019.object.d.ts, --, --))
47+
>frozenArray2 : Symbol(frozenArray2, Decl(objectFromEntries.ts, 7, 5))
48+
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
=== tests/cases/compiler/objectFromEntries.ts ===
2+
const o = Object.fromEntries([['a', 1], ['b', 2], ['c', 3]]);
3+
>o : { [x: string]: number; [x: number]: number; }
4+
>Object.fromEntries([['a', 1], ['b', 2], ['c', 3]]) : { [x: string]: number; [x: number]: number; }
5+
>Object.fromEntries : { <T = any>(entries: Iterable<readonly [string | number | symbol, T]>): { [x: string]: T; [x: number]: T; }; (entries: Iterable<readonly any[]>): any; }
6+
>Object : ObjectConstructor
7+
>fromEntries : { <T = any>(entries: Iterable<readonly [string | number | symbol, T]>): { [x: string]: T; [x: number]: T; }; (entries: Iterable<readonly any[]>): any; }
8+
>[['a', 1], ['b', 2], ['c', 3]] : [string, number][]
9+
>['a', 1] : [string, number]
10+
>'a' : "a"
11+
>1 : 1
12+
>['b', 2] : [string, number]
13+
>'b' : "b"
14+
>2 : 2
15+
>['c', 3] : [string, number]
16+
>'c' : "c"
17+
>3 : 3
18+
19+
const o2 = Object.fromEntries(new URLSearchParams());
20+
>o2 : { [x: string]: string; [x: number]: string; }
21+
>Object.fromEntries(new URLSearchParams()) : { [x: string]: string; [x: number]: string; }
22+
>Object.fromEntries : { <T = any>(entries: Iterable<readonly [string | number | symbol, T]>): { [x: string]: T; [x: number]: T; }; (entries: Iterable<readonly any[]>): any; }
23+
>Object : ObjectConstructor
24+
>fromEntries : { <T = any>(entries: Iterable<readonly [string | number | symbol, T]>): { [x: string]: T; [x: number]: T; }; (entries: Iterable<readonly any[]>): any; }
25+
>new URLSearchParams() : URLSearchParams
26+
>URLSearchParams : { new (init?: string | URLSearchParams | string[][] | Record<string, string>): URLSearchParams; prototype: URLSearchParams; }
27+
28+
const o3 = Object.fromEntries(new Map([[Symbol("key"), "value"]]));
29+
>o3 : { [x: string]: string; [x: number]: string; }
30+
>Object.fromEntries(new Map([[Symbol("key"), "value"]])) : { [x: string]: string; [x: number]: string; }
31+
>Object.fromEntries : { <T = any>(entries: Iterable<readonly [string | number | symbol, T]>): { [x: string]: T; [x: number]: T; }; (entries: Iterable<readonly any[]>): any; }
32+
>Object : ObjectConstructor
33+
>fromEntries : { <T = any>(entries: Iterable<readonly [string | number | symbol, T]>): { [x: string]: T; [x: number]: T; }; (entries: Iterable<readonly any[]>): any; }
34+
>new Map([[Symbol("key"), "value"]]) : Map<symbol, string>
35+
>Map : MapConstructor
36+
>[[Symbol("key"), "value"]] : [symbol, string][]
37+
>[Symbol("key"), "value"] : [symbol, string]
38+
>Symbol("key") : symbol
39+
>Symbol : SymbolConstructor
40+
>"key" : "key"
41+
>"value" : "value"
42+
43+
const frozenArray = Object.freeze([['a', 1], ['b', 2], ['c', 3]]);
44+
>frozenArray : readonly (string | number)[][]
45+
>Object.freeze([['a', 1], ['b', 2], ['c', 3]]) : readonly (string | number)[][]
46+
>Object.freeze : { <T>(a: T[]): readonly T[]; <T extends Function>(f: T): T; <T>(o: T): Readonly<T>; }
47+
>Object : ObjectConstructor
48+
>freeze : { <T>(a: T[]): readonly T[]; <T extends Function>(f: T): T; <T>(o: T): Readonly<T>; }
49+
>[['a', 1], ['b', 2], ['c', 3]] : (string | number)[][]
50+
>['a', 1] : (string | number)[]
51+
>'a' : "a"
52+
>1 : 1
53+
>['b', 2] : (string | number)[]
54+
>'b' : "b"
55+
>2 : 2
56+
>['c', 3] : (string | number)[]
57+
>'c' : "c"
58+
>3 : 3
59+
60+
const o4 = Object.fromEntries(frozenArray);
61+
>o4 : any
62+
>Object.fromEntries(frozenArray) : any
63+
>Object.fromEntries : { <T = any>(entries: Iterable<readonly [string | number | symbol, T]>): { [x: string]: T; [x: number]: T; }; (entries: Iterable<readonly any[]>): any; }
64+
>Object : ObjectConstructor
65+
>fromEntries : { <T = any>(entries: Iterable<readonly [string | number | symbol, T]>): { [x: string]: T; [x: number]: T; }; (entries: Iterable<readonly any[]>): any; }
66+
>frozenArray : readonly (string | number)[][]
67+
68+
const frozenArray2: readonly [string, number][] = Object.freeze([['a', 1], ['b', 2], ['c', 3]]);
69+
>frozenArray2 : readonly [string, number][]
70+
>Object.freeze([['a', 1], ['b', 2], ['c', 3]]) : readonly [string, number][]
71+
>Object.freeze : { <T>(a: T[]): readonly T[]; <T extends Function>(f: T): T; <T>(o: T): Readonly<T>; }
72+
>Object : ObjectConstructor
73+
>freeze : { <T>(a: T[]): readonly T[]; <T extends Function>(f: T): T; <T>(o: T): Readonly<T>; }
74+
>[['a', 1], ['b', 2], ['c', 3]] : [string, number][]
75+
>['a', 1] : [string, number]
76+
>'a' : "a"
77+
>1 : 1
78+
>['b', 2] : [string, number]
79+
>'b' : "b"
80+
>2 : 2
81+
>['c', 3] : [string, number]
82+
>'c' : "c"
83+
>3 : 3
84+
85+
const o5 = Object.fromEntries(frozenArray2);
86+
>o5 : { [x: string]: number; [x: number]: number; }
87+
>Object.fromEntries(frozenArray2) : { [x: string]: number; [x: number]: number; }
88+
>Object.fromEntries : { <T = any>(entries: Iterable<readonly [string | number | symbol, T]>): { [x: string]: T; [x: number]: T; }; (entries: Iterable<readonly any[]>): any; }
89+
>Object : ObjectConstructor
90+
>fromEntries : { <T = any>(entries: Iterable<readonly [string | number | symbol, T]>): { [x: string]: T; [x: number]: T; }; (entries: Iterable<readonly any[]>): any; }
91+
>frozenArray2 : readonly [string, number][]
92+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// @target: es2019
2+
3+
const o = Object.fromEntries([['a', 1], ['b', 2], ['c', 3]]);
4+
const o2 = Object.fromEntries(new URLSearchParams());
5+
const o3 = Object.fromEntries(new Map([[Symbol("key"), "value"]]));
6+
7+
const frozenArray = Object.freeze([['a', 1], ['b', 2], ['c', 3]]);
8+
const o4 = Object.fromEntries(frozenArray);
9+
10+
const frozenArray2: readonly [string, number][] = Object.freeze([['a', 1], ['b', 2], ['c', 3]]);
11+
const o5 = Object.fromEntries(frozenArray2);

0 commit comments

Comments
 (0)