From 4e8f5ee54a0403326d128e53cba4484e81cc1468 Mon Sep 17 00:00:00 2001 From: Ethan Resnick Date: Mon, 14 Nov 2016 20:51:28 -0500 Subject: [PATCH] Object.entries() types: fixup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Special case array. Because array instances are typed as implementing an interface that lists all their public methods, `keyof Array` returns all those method names as keys…even though they’re not actually enumerable at runtime. 2. Intersect keyof T with string, because `keyof T` can return `number | string` in some cases, whereas the entries’ keys will always be strings. --- src/lib/es2017.object.d.ts | 3 +- .../reference/useObjectValuesAndEntries1.js | 14 +++--- .../useObjectValuesAndEntries1.symbols | 28 ++++++----- .../useObjectValuesAndEntries1.types | 46 ++++++++++++------- .../useObjectValuesAndEntries4.symbols | 4 +- .../useObjectValuesAndEntries4.types | 8 ++-- .../es2017/useObjectValuesAndEntries1.ts | 7 +-- 7 files changed, 66 insertions(+), 44 deletions(-) diff --git a/src/lib/es2017.object.d.ts b/src/lib/es2017.object.d.ts index c219f467ac985..1bae8513b4ed2 100644 --- a/src/lib/es2017.object.d.ts +++ b/src/lib/es2017.object.d.ts @@ -9,6 +9,7 @@ interface ObjectConstructor { * Returns an array of key/values of the enumerable properties of an object * @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object. */ - entries(o: T): [keyof T, T[K]][]; + entries(o: Array): [string, T][]; + entries(o: T): [keyof T & string, T[K]][]; entries(o: any): [string, any][]; } diff --git a/tests/baselines/reference/useObjectValuesAndEntries1.js b/tests/baselines/reference/useObjectValuesAndEntries1.js index 728e14e746363..7a6db37351f06 100644 --- a/tests/baselines/reference/useObjectValuesAndEntries1.js +++ b/tests/baselines/reference/useObjectValuesAndEntries1.js @@ -6,10 +6,11 @@ for (var x of Object.values(o)) { let y = x; } -var entries = Object.entries(o); // <-- entries: ['a' | 'b', number][] +var entries = Object.entries(o); // <-- entries: [('a' & string) | ('b' & string), number][] var entries1 = Object.entries(1); // <-- entries: [string, any][] -var entries2 = Object.entries({a: true, b: 2}) // ['a' | 'b', number | boolean][] -var entries3 = Object.entries({}) // [never, any][] +var entries2 = Object.entries({a: true, b: 2}) // [('a' & string) | ('b' & string), number | boolean][] +var entries3 = Object.entries({}) // [string, any][] +var entries4 = Object.entries([1, 2, 3, 4]); // [string, number][] //// [useObjectValuesAndEntries1.js] @@ -18,7 +19,8 @@ for (var _i = 0, _a = Object.values(o); _i < _a.length; _i++) { var x = _a[_i]; var y = x; } -var entries = Object.entries(o); // <-- entries: ['a' | 'b', number][] +var entries = Object.entries(o); // <-- entries: [('a' & string) | ('b' & string), number][] var entries1 = Object.entries(1); // <-- entries: [string, any][] -var entries2 = Object.entries({ a: true, b: 2 }); // ['a' | 'b', number | boolean][] -var entries3 = Object.entries({}); // [never, any][] +var entries2 = Object.entries({ a: true, b: 2 }); // [('a' & string) | ('b' & string), number | boolean][] +var entries3 = Object.entries({}); // [string, any][] +var entries4 = Object.entries([1, 2, 3, 4]); // [string, number][] diff --git a/tests/baselines/reference/useObjectValuesAndEntries1.symbols b/tests/baselines/reference/useObjectValuesAndEntries1.symbols index 521d3ae722eb3..15f4c0f393e41 100644 --- a/tests/baselines/reference/useObjectValuesAndEntries1.symbols +++ b/tests/baselines/reference/useObjectValuesAndEntries1.symbols @@ -17,30 +17,36 @@ for (var x of Object.values(o)) { >x : Symbol(x, Decl(useObjectValuesAndEntries1.ts, 3, 8)) } -var entries = Object.entries(o); // <-- entries: ['a' | 'b', number][] +var entries = Object.entries(o); // <-- entries: [('a' & string) | ('b' & string), number][] >entries : Symbol(entries, Decl(useObjectValuesAndEntries1.ts, 7, 3)) ->Object.entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) +>Object.entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) >Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) +>entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) >o : Symbol(o, Decl(useObjectValuesAndEntries1.ts, 1, 3)) var entries1 = Object.entries(1); // <-- entries: [string, any][] >entries1 : Symbol(entries1, Decl(useObjectValuesAndEntries1.ts, 8, 3)) ->Object.entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) +>Object.entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) >Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) +>entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) -var entries2 = Object.entries({a: true, b: 2}) // ['a' | 'b', number | boolean][] +var entries2 = Object.entries({a: true, b: 2}) // [('a' & string) | ('b' & string), number | boolean][] >entries2 : Symbol(entries2, Decl(useObjectValuesAndEntries1.ts, 9, 3)) ->Object.entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) +>Object.entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) >Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) +>entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) >a : Symbol(a, Decl(useObjectValuesAndEntries1.ts, 9, 31)) >b : Symbol(b, Decl(useObjectValuesAndEntries1.ts, 9, 39)) -var entries3 = Object.entries({}) // [never, any][] +var entries3 = Object.entries({}) // [string, any][] >entries3 : Symbol(entries3, Decl(useObjectValuesAndEntries1.ts, 10, 3)) ->Object.entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) +>Object.entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) >Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) +>entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) + +var entries4 = Object.entries([1, 2, 3, 4]); // [string, number][] +>entries4 : Symbol(entries4, Decl(useObjectValuesAndEntries1.ts, 11, 3)) +>Object.entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) diff --git a/tests/baselines/reference/useObjectValuesAndEntries1.types b/tests/baselines/reference/useObjectValuesAndEntries1.types index f04201450c00f..c3166deab2509 100644 --- a/tests/baselines/reference/useObjectValuesAndEntries1.types +++ b/tests/baselines/reference/useObjectValuesAndEntries1.types @@ -21,39 +21,51 @@ for (var x of Object.values(o)) { >x : number } -var entries = Object.entries(o); // <-- entries: ['a' | 'b', number][] ->entries : ["a" | "b", number][] ->Object.entries(o) : ["a" | "b", number][] ->Object.entries : { (o: T): [keyof T, T[K]][]; (o: any): [string, any][]; } +var entries = Object.entries(o); // <-- entries: [('a' & string) | ('b' & string), number][] +>entries : [("a" & string) | ("b" & string), number][] +>Object.entries(o) : [("a" & string) | ("b" & string), number][] +>Object.entries : { (o: T[]): [string, T][]; (o: T): [keyof T & string, T[K]][]; (o: any): [string, any][]; } >Object : ObjectConstructor ->entries : { (o: T): [keyof T, T[K]][]; (o: any): [string, any][]; } +>entries : { (o: T[]): [string, T][]; (o: T): [keyof T & string, T[K]][]; (o: any): [string, any][]; } >o : { a: number; b: number; } var entries1 = Object.entries(1); // <-- entries: [string, any][] >entries1 : [string, any][] >Object.entries(1) : [string, any][] ->Object.entries : { (o: T): [keyof T, T[K]][]; (o: any): [string, any][]; } +>Object.entries : { (o: T[]): [string, T][]; (o: T): [keyof T & string, T[K]][]; (o: any): [string, any][]; } >Object : ObjectConstructor ->entries : { (o: T): [keyof T, T[K]][]; (o: any): [string, any][]; } +>entries : { (o: T[]): [string, T][]; (o: T): [keyof T & string, T[K]][]; (o: any): [string, any][]; } >1 : 1 -var entries2 = Object.entries({a: true, b: 2}) // ['a' | 'b', number | boolean][] ->entries2 : ["a" | "b", number | boolean][] ->Object.entries({a: true, b: 2}) : ["a" | "b", number | boolean][] ->Object.entries : { (o: T): [keyof T, T[K]][]; (o: any): [string, any][]; } +var entries2 = Object.entries({a: true, b: 2}) // [('a' & string) | ('b' & string), number | boolean][] +>entries2 : [("a" & string) | ("b" & string), number | boolean][] +>Object.entries({a: true, b: 2}) : [("a" & string) | ("b" & string), number | boolean][] +>Object.entries : { (o: T[]): [string, T][]; (o: T): [keyof T & string, T[K]][]; (o: any): [string, any][]; } >Object : ObjectConstructor ->entries : { (o: T): [keyof T, T[K]][]; (o: any): [string, any][]; } +>entries : { (o: T[]): [string, T][]; (o: T): [keyof T & string, T[K]][]; (o: any): [string, any][]; } >{a: true, b: 2} : { a: true; b: number; } >a : boolean >true : true >b : number >2 : 2 -var entries3 = Object.entries({}) // [never, any][] ->entries3 : [never, any][] ->Object.entries({}) : [never, any][] ->Object.entries : { (o: T): [keyof T, T[K]][]; (o: any): [string, any][]; } +var entries3 = Object.entries({}) // [string, any][] +>entries3 : [string, any][] +>Object.entries({}) : [string, any][] +>Object.entries : { (o: T[]): [string, T][]; (o: T): [keyof T & string, T[K]][]; (o: any): [string, any][]; } >Object : ObjectConstructor ->entries : { (o: T): [keyof T, T[K]][]; (o: any): [string, any][]; } +>entries : { (o: T[]): [string, T][]; (o: T): [keyof T & string, T[K]][]; (o: any): [string, any][]; } >{} : {} +var entries4 = Object.entries([1, 2, 3, 4]); // [string, number][] +>entries4 : [string, number][] +>Object.entries([1, 2, 3, 4]) : [string, number][] +>Object.entries : { (o: T[]): [string, T][]; (o: T): [keyof T & string, T[K]][]; (o: any): [string, any][]; } +>Object : ObjectConstructor +>entries : { (o: T[]): [string, T][]; (o: T): [keyof T & string, T[K]][]; (o: any): [string, any][]; } +>[1, 2, 3, 4] : number[] +>1 : 1 +>2 : 2 +>3 : 3 +>4 : 4 + diff --git a/tests/baselines/reference/useObjectValuesAndEntries4.symbols b/tests/baselines/reference/useObjectValuesAndEntries4.symbols index 5edf23790cd92..479dc842bc301 100644 --- a/tests/baselines/reference/useObjectValuesAndEntries4.symbols +++ b/tests/baselines/reference/useObjectValuesAndEntries4.symbols @@ -19,8 +19,8 @@ for (var x of Object.values(o)) { var entries = Object.entries(o); >entries : Symbol(entries, Decl(useObjectValuesAndEntries4.ts, 7, 3)) ->Object.entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) +>Object.entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) >Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) ->entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) +>entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) >o : Symbol(o, Decl(useObjectValuesAndEntries4.ts, 1, 3)) diff --git a/tests/baselines/reference/useObjectValuesAndEntries4.types b/tests/baselines/reference/useObjectValuesAndEntries4.types index d68193993e2b6..a1f70681033b3 100644 --- a/tests/baselines/reference/useObjectValuesAndEntries4.types +++ b/tests/baselines/reference/useObjectValuesAndEntries4.types @@ -22,10 +22,10 @@ for (var x of Object.values(o)) { } var entries = Object.entries(o); ->entries : ["a" | "b", number][] ->Object.entries(o) : ["a" | "b", number][] ->Object.entries : { (o: T): [keyof T, T[K]][]; (o: any): [string, any][]; } +>entries : [("a" & string) | ("b" & string), number][] +>Object.entries(o) : [("a" & string) | ("b" & string), number][] +>Object.entries : { (o: T[]): [string, T][]; (o: T): [keyof T & string, T[K]][]; (o: any): [string, any][]; } >Object : ObjectConstructor ->entries : { (o: T): [keyof T, T[K]][]; (o: any): [string, any][]; } +>entries : { (o: T[]): [string, T][]; (o: T): [keyof T & string, T[K]][]; (o: any): [string, any][]; } >o : { a: number; b: number; } diff --git a/tests/cases/conformance/es2017/useObjectValuesAndEntries1.ts b/tests/cases/conformance/es2017/useObjectValuesAndEntries1.ts index 60099bb1c0f6d..56db8a5df7d23 100644 --- a/tests/cases/conformance/es2017/useObjectValuesAndEntries1.ts +++ b/tests/cases/conformance/es2017/useObjectValuesAndEntries1.ts @@ -7,7 +7,8 @@ for (var x of Object.values(o)) { let y = x; } -var entries = Object.entries(o); // <-- entries: ['a' | 'b', number][] +var entries = Object.entries(o); // <-- entries: [('a' & string) | ('b' & string), number][] var entries1 = Object.entries(1); // <-- entries: [string, any][] -var entries2 = Object.entries({a: true, b: 2}) // ['a' | 'b', number | boolean][] -var entries3 = Object.entries({}) // [never, any][] +var entries2 = Object.entries({a: true, b: 2}) // [('a' & string) | ('b' & string), number | boolean][] +var entries3 = Object.entries({}) // [string, any][] +var entries4 = Object.entries([1, 2, 3, 4]); // [string, number][]