From 49d6f61298af7a1b470257d293e160694dcd1416 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Wed, 1 May 2019 01:49:58 +0900 Subject: [PATCH] Add ES2019 Object.fromEntries function (#30934) * add ES2019 Object.fromEntries function * add some comments * apply suggested changes * add readonly and general any --- src/compiler/commandLineParser.ts | 1 + src/lib/es2019.d.ts | 1 + src/lib/es2019.object.d.ts | 15 +++ src/lib/libs.json | 1 + .../unittests/config/commandLineParsing.ts | 6 +- .../baselines/reference/objectFromEntries.js | 20 ++++ .../reference/objectFromEntries.symbols | 48 ++++++++++ .../reference/objectFromEntries.types | 92 +++++++++++++++++++ tests/cases/compiler/objectFromEntries.ts | 11 +++ 9 files changed, 192 insertions(+), 3 deletions(-) create mode 100644 src/lib/es2019.object.d.ts create mode 100644 tests/baselines/reference/objectFromEntries.js create mode 100644 tests/baselines/reference/objectFromEntries.symbols create mode 100644 tests/baselines/reference/objectFromEntries.types create mode 100644 tests/cases/compiler/objectFromEntries.ts diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 1ec07912adaa6..104f3576e3a6d 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -45,6 +45,7 @@ namespace ts { ["es2018.promise", "lib.es2018.promise.d.ts"], ["es2018.regexp", "lib.es2018.regexp.d.ts"], ["es2019.array", "lib.es2019.array.d.ts"], + ["es2019.object", "lib.es2019.object.d.ts"], ["es2019.string", "lib.es2019.string.d.ts"], ["es2019.symbol", "lib.es2019.symbol.d.ts"], ["es2020.string", "lib.es2020.string.d.ts"], diff --git a/src/lib/es2019.d.ts b/src/lib/es2019.d.ts index b25f9e1d76af9..29212ecfe0f1b 100644 --- a/src/lib/es2019.d.ts +++ b/src/lib/es2019.d.ts @@ -1,4 +1,5 @@ /// /// +/// /// /// diff --git a/src/lib/es2019.object.d.ts b/src/lib/es2019.object.d.ts new file mode 100644 index 0000000000000..69b185d7ca91c --- /dev/null +++ b/src/lib/es2019.object.d.ts @@ -0,0 +1,15 @@ +/// + +interface ObjectConstructor { + /** + * Returns an object created by key-value entries for properties and methods + * @param entries An iterable object that contains key-value entries for properties and methods. + */ + fromEntries(entries: Iterable): { [k in PropertyKey]: T }; + + /** + * Returns an object created by key-value entries for properties and methods + * @param entries An iterable object that contains key-value entries for properties and methods. + */ + fromEntries(entries: Iterable): any; +} diff --git a/src/lib/libs.json b/src/lib/libs.json index 74611a938609c..ac2f2db5b6bb0 100644 --- a/src/lib/libs.json +++ b/src/lib/libs.json @@ -36,6 +36,7 @@ "es2018.promise", "es2018.intl", "es2019.array", + "es2019.object", "es2019.string", "es2019.symbol", "es2020.string", diff --git a/src/testRunner/unittests/config/commandLineParsing.ts b/src/testRunner/unittests/config/commandLineParsing.ts index 450b27e01ed4f..3c033d658ef6c 100644 --- a/src/testRunner/unittests/config/commandLineParsing.ts +++ b/src/testRunner/unittests/config/commandLineParsing.ts @@ -57,7 +57,7 @@ namespace ts { assertParseResult(["--lib", "es5,invalidOption", "0.ts"], { errors: [{ - 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'.", + 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'.", category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category, code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code, file: undefined, @@ -259,7 +259,7 @@ namespace ts { assertParseResult(["--lib", "es5,", "es7", "0.ts"], { errors: [{ - 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'.", + 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'.", category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category, code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code, file: undefined, @@ -278,7 +278,7 @@ namespace ts { assertParseResult(["--lib", "es5, ", "es7", "0.ts"], { errors: [{ - 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'.", + 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'.", category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category, code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code, file: undefined, diff --git a/tests/baselines/reference/objectFromEntries.js b/tests/baselines/reference/objectFromEntries.js new file mode 100644 index 0000000000000..fc5b9a107a3be --- /dev/null +++ b/tests/baselines/reference/objectFromEntries.js @@ -0,0 +1,20 @@ +//// [objectFromEntries.ts] +const o = Object.fromEntries([['a', 1], ['b', 2], ['c', 3]]); +const o2 = Object.fromEntries(new URLSearchParams()); +const o3 = Object.fromEntries(new Map([[Symbol("key"), "value"]])); + +const frozenArray = Object.freeze([['a', 1], ['b', 2], ['c', 3]]); +const o4 = Object.fromEntries(frozenArray); + +const frozenArray2: readonly [string, number][] = Object.freeze([['a', 1], ['b', 2], ['c', 3]]); +const o5 = Object.fromEntries(frozenArray2); + + +//// [objectFromEntries.js] +const o = Object.fromEntries([['a', 1], ['b', 2], ['c', 3]]); +const o2 = Object.fromEntries(new URLSearchParams()); +const o3 = Object.fromEntries(new Map([[Symbol("key"), "value"]])); +const frozenArray = Object.freeze([['a', 1], ['b', 2], ['c', 3]]); +const o4 = Object.fromEntries(frozenArray); +const frozenArray2 = Object.freeze([['a', 1], ['b', 2], ['c', 3]]); +const o5 = Object.fromEntries(frozenArray2); diff --git a/tests/baselines/reference/objectFromEntries.symbols b/tests/baselines/reference/objectFromEntries.symbols new file mode 100644 index 0000000000000..882b553eb558c --- /dev/null +++ b/tests/baselines/reference/objectFromEntries.symbols @@ -0,0 +1,48 @@ +=== tests/cases/compiler/objectFromEntries.ts === +const o = Object.fromEntries([['a', 1], ['b', 2], ['c', 3]]); +>o : Symbol(o, Decl(objectFromEntries.ts, 0, 5)) +>Object.fromEntries : Symbol(ObjectConstructor.fromEntries, Decl(lib.es2019.object.d.ts, --, --), Decl(lib.es2019.object.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>fromEntries : Symbol(ObjectConstructor.fromEntries, Decl(lib.es2019.object.d.ts, --, --), Decl(lib.es2019.object.d.ts, --, --)) + +const o2 = Object.fromEntries(new URLSearchParams()); +>o2 : Symbol(o2, Decl(objectFromEntries.ts, 1, 5)) +>Object.fromEntries : Symbol(ObjectConstructor.fromEntries, Decl(lib.es2019.object.d.ts, --, --), Decl(lib.es2019.object.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>fromEntries : Symbol(ObjectConstructor.fromEntries, Decl(lib.es2019.object.d.ts, --, --), Decl(lib.es2019.object.d.ts, --, --)) +>URLSearchParams : Symbol(URLSearchParams, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(lib.dom.iterable.d.ts, --, --)) + +const o3 = Object.fromEntries(new Map([[Symbol("key"), "value"]])); +>o3 : Symbol(o3, Decl(objectFromEntries.ts, 2, 5)) +>Object.fromEntries : Symbol(ObjectConstructor.fromEntries, Decl(lib.es2019.object.d.ts, --, --), Decl(lib.es2019.object.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>fromEntries : Symbol(ObjectConstructor.fromEntries, Decl(lib.es2019.object.d.ts, --, --), Decl(lib.es2019.object.d.ts, --, --)) +>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, --, --)) +>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, --, --)) + +const frozenArray = Object.freeze([['a', 1], ['b', 2], ['c', 3]]); +>frozenArray : Symbol(frozenArray, Decl(objectFromEntries.ts, 4, 5)) +>Object.freeze : Symbol(ObjectConstructor.freeze, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>freeze : Symbol(ObjectConstructor.freeze, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + +const o4 = Object.fromEntries(frozenArray); +>o4 : Symbol(o4, Decl(objectFromEntries.ts, 5, 5)) +>Object.fromEntries : Symbol(ObjectConstructor.fromEntries, Decl(lib.es2019.object.d.ts, --, --), Decl(lib.es2019.object.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>fromEntries : Symbol(ObjectConstructor.fromEntries, Decl(lib.es2019.object.d.ts, --, --), Decl(lib.es2019.object.d.ts, --, --)) +>frozenArray : Symbol(frozenArray, Decl(objectFromEntries.ts, 4, 5)) + +const frozenArray2: readonly [string, number][] = Object.freeze([['a', 1], ['b', 2], ['c', 3]]); +>frozenArray2 : Symbol(frozenArray2, Decl(objectFromEntries.ts, 7, 5)) +>Object.freeze : Symbol(ObjectConstructor.freeze, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>freeze : Symbol(ObjectConstructor.freeze, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + +const o5 = Object.fromEntries(frozenArray2); +>o5 : Symbol(o5, Decl(objectFromEntries.ts, 8, 5)) +>Object.fromEntries : Symbol(ObjectConstructor.fromEntries, Decl(lib.es2019.object.d.ts, --, --), Decl(lib.es2019.object.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>fromEntries : Symbol(ObjectConstructor.fromEntries, Decl(lib.es2019.object.d.ts, --, --), Decl(lib.es2019.object.d.ts, --, --)) +>frozenArray2 : Symbol(frozenArray2, Decl(objectFromEntries.ts, 7, 5)) + diff --git a/tests/baselines/reference/objectFromEntries.types b/tests/baselines/reference/objectFromEntries.types new file mode 100644 index 0000000000000..265cbd2d87813 --- /dev/null +++ b/tests/baselines/reference/objectFromEntries.types @@ -0,0 +1,92 @@ +=== tests/cases/compiler/objectFromEntries.ts === +const o = Object.fromEntries([['a', 1], ['b', 2], ['c', 3]]); +>o : { [x: string]: number; [x: number]: number; } +>Object.fromEntries([['a', 1], ['b', 2], ['c', 3]]) : { [x: string]: number; [x: number]: number; } +>Object.fromEntries : { (entries: Iterable): { [x: string]: T; [x: number]: T; }; (entries: Iterable): any; } +>Object : ObjectConstructor +>fromEntries : { (entries: Iterable): { [x: string]: T; [x: number]: T; }; (entries: Iterable): any; } +>[['a', 1], ['b', 2], ['c', 3]] : [string, number][] +>['a', 1] : [string, number] +>'a' : "a" +>1 : 1 +>['b', 2] : [string, number] +>'b' : "b" +>2 : 2 +>['c', 3] : [string, number] +>'c' : "c" +>3 : 3 + +const o2 = Object.fromEntries(new URLSearchParams()); +>o2 : { [x: string]: string; [x: number]: string; } +>Object.fromEntries(new URLSearchParams()) : { [x: string]: string; [x: number]: string; } +>Object.fromEntries : { (entries: Iterable): { [x: string]: T; [x: number]: T; }; (entries: Iterable): any; } +>Object : ObjectConstructor +>fromEntries : { (entries: Iterable): { [x: string]: T; [x: number]: T; }; (entries: Iterable): any; } +>new URLSearchParams() : URLSearchParams +>URLSearchParams : { new (init?: string | URLSearchParams | string[][] | Record): URLSearchParams; prototype: URLSearchParams; } + +const o3 = Object.fromEntries(new Map([[Symbol("key"), "value"]])); +>o3 : { [x: string]: string; [x: number]: string; } +>Object.fromEntries(new Map([[Symbol("key"), "value"]])) : { [x: string]: string; [x: number]: string; } +>Object.fromEntries : { (entries: Iterable): { [x: string]: T; [x: number]: T; }; (entries: Iterable): any; } +>Object : ObjectConstructor +>fromEntries : { (entries: Iterable): { [x: string]: T; [x: number]: T; }; (entries: Iterable): any; } +>new Map([[Symbol("key"), "value"]]) : Map +>Map : MapConstructor +>[[Symbol("key"), "value"]] : [symbol, string][] +>[Symbol("key"), "value"] : [symbol, string] +>Symbol("key") : symbol +>Symbol : SymbolConstructor +>"key" : "key" +>"value" : "value" + +const frozenArray = Object.freeze([['a', 1], ['b', 2], ['c', 3]]); +>frozenArray : readonly (string | number)[][] +>Object.freeze([['a', 1], ['b', 2], ['c', 3]]) : readonly (string | number)[][] +>Object.freeze : { (a: T[]): readonly T[]; (f: T): T; (o: T): Readonly; } +>Object : ObjectConstructor +>freeze : { (a: T[]): readonly T[]; (f: T): T; (o: T): Readonly; } +>[['a', 1], ['b', 2], ['c', 3]] : (string | number)[][] +>['a', 1] : (string | number)[] +>'a' : "a" +>1 : 1 +>['b', 2] : (string | number)[] +>'b' : "b" +>2 : 2 +>['c', 3] : (string | number)[] +>'c' : "c" +>3 : 3 + +const o4 = Object.fromEntries(frozenArray); +>o4 : any +>Object.fromEntries(frozenArray) : any +>Object.fromEntries : { (entries: Iterable): { [x: string]: T; [x: number]: T; }; (entries: Iterable): any; } +>Object : ObjectConstructor +>fromEntries : { (entries: Iterable): { [x: string]: T; [x: number]: T; }; (entries: Iterable): any; } +>frozenArray : readonly (string | number)[][] + +const frozenArray2: readonly [string, number][] = Object.freeze([['a', 1], ['b', 2], ['c', 3]]); +>frozenArray2 : readonly [string, number][] +>Object.freeze([['a', 1], ['b', 2], ['c', 3]]) : readonly [string, number][] +>Object.freeze : { (a: T[]): readonly T[]; (f: T): T; (o: T): Readonly; } +>Object : ObjectConstructor +>freeze : { (a: T[]): readonly T[]; (f: T): T; (o: T): Readonly; } +>[['a', 1], ['b', 2], ['c', 3]] : [string, number][] +>['a', 1] : [string, number] +>'a' : "a" +>1 : 1 +>['b', 2] : [string, number] +>'b' : "b" +>2 : 2 +>['c', 3] : [string, number] +>'c' : "c" +>3 : 3 + +const o5 = Object.fromEntries(frozenArray2); +>o5 : { [x: string]: number; [x: number]: number; } +>Object.fromEntries(frozenArray2) : { [x: string]: number; [x: number]: number; } +>Object.fromEntries : { (entries: Iterable): { [x: string]: T; [x: number]: T; }; (entries: Iterable): any; } +>Object : ObjectConstructor +>fromEntries : { (entries: Iterable): { [x: string]: T; [x: number]: T; }; (entries: Iterable): any; } +>frozenArray2 : readonly [string, number][] + diff --git a/tests/cases/compiler/objectFromEntries.ts b/tests/cases/compiler/objectFromEntries.ts new file mode 100644 index 0000000000000..9993edbf344ec --- /dev/null +++ b/tests/cases/compiler/objectFromEntries.ts @@ -0,0 +1,11 @@ +// @target: es2019 + +const o = Object.fromEntries([['a', 1], ['b', 2], ['c', 3]]); +const o2 = Object.fromEntries(new URLSearchParams()); +const o3 = Object.fromEntries(new Map([[Symbol("key"), "value"]])); + +const frozenArray = Object.freeze([['a', 1], ['b', 2], ['c', 3]]); +const o4 = Object.fromEntries(frozenArray); + +const frozenArray2: readonly [string, number][] = Object.freeze([['a', 1], ['b', 2], ['c', 3]]); +const o5 = Object.fromEntries(frozenArray2);