Skip to content

fix: support record in Object.keys #28899

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/lib.es5.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ interface ObjectConstructor {
* Returns the names of the enumerable properties and methods 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.
*/
keys<K extends string>(o: Record<K, any>): K[];
keys(o: {}): string[];
}

Expand Down
3 changes: 2 additions & 1 deletion src/lib/es5.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ interface ObjectConstructor {
* Returns the names of the enumerable properties and methods 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.
*/
keys<K extends string>(o: Record<K, any>): K[];
keys(o: {}): string[];
}

Expand Down Expand Up @@ -577,7 +578,7 @@ interface TemplateStringsArray extends ReadonlyArray<string> {

/**
* The type of `import.meta`.
*
*
* If you need to declare that a given property exists on `import.meta`,
* this type may be augmented via interface merging.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -403,9 +403,9 @@ export enum PubSubRecordIsStoredInRedisAsA {
fields: () => new Set(Object.keys(soFar) as (keyof SO_FAR)[]),
>fields : Symbol(fields, Decl(conditionalTypeDoesntSpinForever.ts, 94, 18))
>Set : Symbol(Set, 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, --, --))
>Object.keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --))
>Object.keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --))
>keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>soFar : Symbol(soFar, Decl(conditionalTypeDoesntSpinForever.ts, 92, 29))
>SO_FAR : Symbol(SO_FAR, Decl(conditionalTypeDoesntSpinForever.ts, 92, 21))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -409,10 +409,10 @@ export enum PubSubRecordIsStoredInRedisAsA {
>new Set(Object.keys(soFar) as (keyof SO_FAR)[]) : Set<keyof SO_FAR>
>Set : SetConstructor
>Object.keys(soFar) as (keyof SO_FAR)[] : (keyof SO_FAR)[]
>Object.keys(soFar) : string[]
>Object.keys : (o: {}) => string[]
>Object.keys(soFar) : never[]
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did this changed to never ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{} has no properties, so keyof will return the empty union (i.e. `never)

>Object.keys : { <K extends string>(o: Record<K, any>): K[]; (o: {}): string[]; }
>Object : ObjectConstructor
>keys : (o: {}) => string[]
>keys : { <K extends string>(o: Record<K, any>): K[]; (o: {}): string[]; }
>soFar : SO_FAR

hasField: (fieldName: string | number | symbol) => fieldName in soFar
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ export default class Operation {

for(const parameterLocation of Object.keys(parameterValues)) {
>parameterLocation : Symbol(parameterLocation, Decl(contextualExpressionTypecheckingDoesntBlowStack.ts, 8, 17))
>Object.keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --))
>Object.keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --))
>keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>parameterValues : Symbol(parameterValues, Decl(contextualExpressionTypecheckingDoesntBlowStack.ts, 6, 23))

const parameter: any = (this as any).getParameter();;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ export default class Operation {
for(const parameterLocation of Object.keys(parameterValues)) {
>parameterLocation : string
>Object.keys(parameterValues) : string[]
>Object.keys : (o: {}) => string[]
>Object.keys : { <K extends string>(o: Record<K, any>): K[]; (o: {}): string[]; }
>Object : ObjectConstructor
>keys : (o: {}) => string[]
>keys : { <K extends string>(o: Record<K, any>): K[]; (o: {}): string[]; }
>parameterValues : any

const parameter: any = (this as any).getParameter();;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration4.ts(
a1(...array2); // Error parameter type is (number|string)[]
~~~~~~
!!! error TS2552: Cannot find name 'array2'. Did you mean 'Array'?
!!! related TS2728 /.ts/lib.es5.d.ts:1358:15: 'Array' is declared here.
!!! related TS2728 /.ts/lib.es5.d.ts:1359:15: 'Array' is declared here.
a5([1, 2, "string", false, true]); // Error, parameter type is [any, any, [[any]]]
~~~~~~~~
!!! error TS2322: Type 'string' is not assignable to type '[[any]]'.
Expand Down
8 changes: 4 additions & 4 deletions tests/baselines/reference/externModule.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -69,20 +69,20 @@ tests/cases/compiler/externModule.ts(37,3): error TS2552: Cannot find name 'XDat
var d=new XDate();
~~~~~
!!! error TS2552: Cannot find name 'XDate'. Did you mean 'Date'?
!!! related TS2728 /.ts/lib.es5.d.ts:897:15: 'Date' is declared here.
!!! related TS2728 /.ts/lib.es5.d.ts:898:15: 'Date' is declared here.
d.getDay();
d=new XDate(1978,2);
~~~~~
!!! error TS2552: Cannot find name 'XDate'. Did you mean 'Date'?
!!! related TS2728 /.ts/lib.es5.d.ts:897:15: 'Date' is declared here.
!!! related TS2728 /.ts/lib.es5.d.ts:898:15: 'Date' is declared here.
d.getXDate();
var n=XDate.parse("3/2/2004");
~~~~~
!!! error TS2552: Cannot find name 'XDate'. Did you mean 'Date'?
!!! related TS2728 /.ts/lib.es5.d.ts:897:15: 'Date' is declared here.
!!! related TS2728 /.ts/lib.es5.d.ts:898:15: 'Date' is declared here.
n=XDate.UTC(1964,2,1);
~~~~~
!!! error TS2552: Cannot find name 'XDate'. Did you mean 'Date'?
!!! related TS2728 /.ts/lib.es5.d.ts:897:15: 'Date' is declared here.
!!! related TS2728 /.ts/lib.es5.d.ts:898:15: 'Date' is declared here.


Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ export const createService = <T>(
) => {
Object.keys(ServiceCtr).forEach(key => {
>Object.keys(ServiceCtr).forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --))
>Object.keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --))
>Object.keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --))
>keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>ServiceCtr : Symbol(ServiceCtr, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 11, 33))
>forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --))
>key : Symbol(key, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 14, 36))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ export const createService = <T>(
>Object.keys(ServiceCtr).forEach(key => { const method = (ServiceCtr)[key as keyof T]; const {__$daemonMode, __$action, id} = method; }) : void
>Object.keys(ServiceCtr).forEach : (callbackfn: (value: string, index: number, array: string[]) => void, thisArg?: any) => void
>Object.keys(ServiceCtr) : string[]
>Object.keys : (o: {}) => string[]
>Object.keys : { <K extends string>(o: Record<K, any>): K[]; (o: {}): string[]; }
>Object : ObjectConstructor
>keys : (o: {}) => string[]
>keys : { <K extends string>(o: Record<K, any>): K[]; (o: {}): string[]; }
>ServiceCtr : ExtendedService<T> & Service<T>
>forEach : (callbackfn: (value: string, index: number, array: string[]) => void, thisArg?: any) => void
>key => { const method = (ServiceCtr)[key as keyof T]; const {__$daemonMode, __$action, id} = method; } : (key: string) => void
Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/invalidTypeOfTarget.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ tests/cases/conformance/types/specifyingTypes/typeQueries/invalidTypeOfTarget.ts
var x7: typeof function f() { };
~~~~~~~~
!!! error TS2552: Cannot find name 'function'. Did you mean 'Function'?
!!! related TS2728 /.ts/lib.es5.d.ts:316:15: 'Function' is declared here.
!!! related TS2728 /.ts/lib.es5.d.ts:317:15: 'Function' is declared here.
~
!!! error TS1005: ',' expected.
~
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/literalTypeWidening.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -366,9 +366,9 @@ export function keys<K extends string, V>(obj: Record<K, V>): K[] {
>K : Symbol(K, Decl(literalTypeWidening.ts, 118, 21))

return Object.keys(obj) as K[]
>Object.keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --))
>Object.keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --))
>keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>obj : Symbol(obj, Decl(literalTypeWidening.ts, 118, 42))
>K : Symbol(K, Decl(literalTypeWidening.ts, 118, 21))
}
Expand Down
6 changes: 3 additions & 3 deletions tests/baselines/reference/literalTypeWidening.types
Original file line number Diff line number Diff line change
Expand Up @@ -390,10 +390,10 @@ export function keys<K extends string, V>(obj: Record<K, V>): K[] {

return Object.keys(obj) as K[]
>Object.keys(obj) as K[] : K[]
>Object.keys(obj) : string[]
>Object.keys : (o: {}) => string[]
>Object.keys(obj) : K[]
>Object.keys : { <K extends string>(o: Record<K, any>): K[]; (o: {}): string[]; }
>Object : ObjectConstructor
>keys : (o: {}) => string[]
>keys : { <K extends string>(o: Record<K, any>): K[]; (o: {}): string[]; }
>obj : Record<K, V>
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ tests/cases/compiler/modularizeLibrary_ErrorFromUsingES6FeaturesWithOnlyES5Lib.t
Math.sign(1);
~~~~
!!! error TS2551: Property 'sign' does not exist on type 'Math'. Did you mean 'sin'?
!!! related TS2728 /.ts/lib.es5.d.ts:703:5: 'sin' is declared here.
!!! related TS2728 /.ts/lib.es5.d.ts:704:5: 'sin' is declared here.

// Using ES6 object
var o = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ tests/cases/conformance/types/any/narrowExceptionVariableInCatchClause.ts(16,17)
err.massage; // ERROR: Property 'massage' does not exist on type 'Error'
~~~~~~~
!!! error TS2551: Property 'massage' does not exist on type 'Error'. Did you mean 'message'?
!!! related TS2728 /.ts/lib.es5.d.ts:964:5: 'message' is declared here.
!!! related TS2728 /.ts/lib.es5.d.ts:965:5: 'message' is declared here.
}

else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ tests/cases/conformance/types/any/narrowFromAnyWithInstanceof.ts(22,7): error TS
x.mesage;
~~~~~~
!!! error TS2551: Property 'mesage' does not exist on type 'Error'. Did you mean 'message'?
!!! related TS2728 /.ts/lib.es5.d.ts:964:5: 'message' is declared here.
!!! related TS2728 /.ts/lib.es5.d.ts:965:5: 'message' is declared here.
}

if (x instanceof Date) {
x.getDate();
x.getHuors();
~~~~~~~~
!!! error TS2551: Property 'getHuors' does not exist on type 'Date'. Did you mean 'getHours'?
!!! related TS2728 /.ts/lib.es5.d.ts:753:5: 'getHours' is declared here.
!!! related TS2728 /.ts/lib.es5.d.ts:754:5: 'getHours' is declared here.
}

Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ tests/cases/conformance/types/any/narrowFromAnyWithTypePredicate.ts(33,7): error
x.mesage;
~~~~~~
!!! error TS2551: Property 'mesage' does not exist on type 'Error'. Did you mean 'message'?
!!! related TS2728 /.ts/lib.es5.d.ts:964:5: 'message' is declared here.
!!! related TS2728 /.ts/lib.es5.d.ts:965:5: 'message' is declared here.
}

if (isDate(x)) {
x.getDate();
x.getHuors();
~~~~~~~~
!!! error TS2551: Property 'getHuors' does not exist on type 'Date'. Did you mean 'getHours'?
!!! related TS2728 /.ts/lib.es5.d.ts:753:5: 'getHours' is declared here.
!!! related TS2728 /.ts/lib.es5.d.ts:754:5: 'getHours' is declared here.
}

13 changes: 13 additions & 0 deletions tests/baselines/reference/objectKeysWithRecord.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//// [objectKeysWithRecord.ts]
type K = 'foo' | 'bar'
const record: Record<K, boolean> = { foo: true, bar: false };

Object.keys(record).forEach((key: K) => {

});


//// [objectKeysWithRecord.js]
var record = { foo: true, bar: false };
Object.keys(record).forEach(function (key) {
});
23 changes: 23 additions & 0 deletions tests/baselines/reference/objectKeysWithRecord.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
=== tests/cases/compiler/objectKeysWithRecord.ts ===
type K = 'foo' | 'bar'
>K : Symbol(K, Decl(objectKeysWithRecord.ts, 0, 0))

const record: Record<K, boolean> = { foo: true, bar: false };
>record : Symbol(record, Decl(objectKeysWithRecord.ts, 1, 5))
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
>K : Symbol(K, Decl(objectKeysWithRecord.ts, 0, 0))
>foo : Symbol(foo, Decl(objectKeysWithRecord.ts, 1, 36))
>bar : Symbol(bar, Decl(objectKeysWithRecord.ts, 1, 47))

Object.keys(record).forEach((key: K) => {
>Object.keys(record).forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --))
>Object.keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>record : Symbol(record, Decl(objectKeysWithRecord.ts, 1, 5))
>forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --))
>key : Symbol(key, Decl(objectKeysWithRecord.ts, 3, 29))
>K : Symbol(K, Decl(objectKeysWithRecord.ts, 0, 0))

});

26 changes: 26 additions & 0 deletions tests/baselines/reference/objectKeysWithRecord.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
=== tests/cases/compiler/objectKeysWithRecord.ts ===
type K = 'foo' | 'bar'
>K : K

const record: Record<K, boolean> = { foo: true, bar: false };
>record : Record<K, boolean>
>{ foo: true, bar: false } : { foo: true; bar: false; }
>foo : true
>true : true
>bar : false
>false : false

Object.keys(record).forEach((key: K) => {
>Object.keys(record).forEach((key: K) => {}) : void
>Object.keys(record).forEach : (callbackfn: (value: K, index: number, array: K[]) => void, thisArg?: any) => void
>Object.keys(record) : K[]
>Object.keys : { <K extends string>(o: Record<K, any>): K[]; (o: {}): string[]; }
>Object : ObjectConstructor
>keys : { <K extends string>(o: Record<K, any>): K[]; (o: {}): string[]; }
>record : Record<K, boolean>
>forEach : (callbackfn: (value: K, index: number, array: K[]) => void, thisArg?: any) => void
>(key: K) => {} : (key: K) => void
>key : K

});

Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ tests/cases/conformance/parser/ecmascript5/Expressions/parserMemberAccessAfterPo
!!! error TS1005: ';' expected.
~~~~~~~~
!!! error TS2552: Cannot find name 'toString'. Did you mean 'String'?
!!! related TS2728 /.ts/lib.es5.d.ts:517:15: 'String' is declared here.
!!! related TS2728 /.ts/lib.es5.d.ts:518:15: 'String' is declared here.
4 changes: 2 additions & 2 deletions tests/baselines/reference/parserS7.2_A1.5_T2.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ tests/cases/conformance/parser/ecmascript5/parserS7.2_A1.5_T2.ts(20,3): error TS
$ERROR('#1: eval("\\u00A0var x\\u00A0= 1\\u00A0"); x === 1. Actual: ' + (x));
~~~~~~
!!! error TS2552: Cannot find name '$ERROR'. Did you mean 'Error'?
!!! related TS2728 /.ts/lib.es5.d.ts:974:15: 'Error' is declared here.
!!! related TS2728 /.ts/lib.es5.d.ts:975:15: 'Error' is declared here.
}

//CHECK#2
Expand All @@ -28,7 +28,7 @@ tests/cases/conformance/parser/ecmascript5/parserS7.2_A1.5_T2.ts(20,3): error TS
$ERROR('#2:  var x = 1 ; x === 1. Actual: ' + (x));
~~~~~~
!!! error TS2552: Cannot find name '$ERROR'. Did you mean 'Error'?
!!! related TS2728 /.ts/lib.es5.d.ts:974:15: 'Error' is declared here.
!!! related TS2728 /.ts/lib.es5.d.ts:975:15: 'Error' is declared here.
}


Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/parserS7.3_A1.1_T2.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ tests/cases/conformance/parser/ecmascript5/parserS7.3_A1.1_T2.ts(17,3): error TS
$ERROR('#1: var\\nx\\n=\\n1\\n; x === 1. Actual: ' + (x));
~~~~~~
!!! error TS2552: Cannot find name '$ERROR'. Did you mean 'Error'?
!!! related TS2728 /.ts/lib.es5.d.ts:974:15: 'Error' is declared here.
!!! related TS2728 /.ts/lib.es5.d.ts:975:15: 'Error' is declared here.
}


Loading