Skip to content

Commit 4567fc4

Browse files
authored
Ensure computed property names are always checked (#37307)
1 parent 6c1e8aa commit 4567fc4

File tree

5 files changed

+242
-0
lines changed

5 files changed

+242
-0
lines changed

src/compiler/checker.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22808,6 +22808,15 @@ namespace ts {
2280822808
let hasComputedStringProperty = false;
2280922809
let hasComputedNumberProperty = false;
2281022810

22811+
// Spreads may cause an early bail; ensure computed names are always checked (this is cached)
22812+
// As otherwise they may not be checked until exports for the type at this position are retrieved,
22813+
// which may never occur.
22814+
for (const elem of node.properties) {
22815+
if (elem.name && isComputedPropertyName(elem.name) && !isWellKnownSymbolSyntactically(elem.name)) {
22816+
checkComputedPropertyName(elem.name);
22817+
}
22818+
}
22819+
2281122820
let offset = 0;
2281222821
for (let i = 0; i < node.properties.length; i++) {
2281322822
const memberDecl = node.properties[i];
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//// [tests/cases/compiler/jsFileImportPreservedWhenUsed.ts] ////
2+
3+
//// [dash.d.ts]
4+
type ObjectIterator<TObject, TResult> = (value: TObject[keyof TObject], key: string, collection: TObject) => TResult;
5+
6+
interface LoDashStatic {
7+
mapValues<T extends object, TResult>(obj: T | null | undefined, callback: ObjectIterator<T, TResult>): { [P in keyof T]: TResult };
8+
}
9+
declare const _: LoDashStatic;
10+
export = _;
11+
//// [Consts.ts]
12+
export const INDEX_FIELD = '__INDEX';
13+
//// [index.js]
14+
import * as _ from './dash';
15+
import { INDEX_FIELD } from './Consts';
16+
17+
export class Test {
18+
/**
19+
* @param {object} obj
20+
* @param {object} vm
21+
*/
22+
test(obj, vm) {
23+
let index = 0;
24+
vm.objects = _.mapValues(
25+
obj,
26+
object => ({ ...object, [INDEX_FIELD]: index++ }),
27+
);
28+
}
29+
}
30+
31+
//// [Consts.js]
32+
export const INDEX_FIELD = '__INDEX';
33+
//// [index.js]
34+
import * as _ from './dash';
35+
import { INDEX_FIELD } from './Consts';
36+
export class Test {
37+
/**
38+
* @param {object} obj
39+
* @param {object} vm
40+
*/
41+
test(obj, vm) {
42+
let index = 0;
43+
vm.objects = _.mapValues(obj, object => ({ ...object, [INDEX_FIELD]: index++ }));
44+
}
45+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
=== tests/cases/compiler/dash.d.ts ===
2+
type ObjectIterator<TObject, TResult> = (value: TObject[keyof TObject], key: string, collection: TObject) => TResult;
3+
>ObjectIterator : Symbol(ObjectIterator, Decl(dash.d.ts, 0, 0))
4+
>TObject : Symbol(TObject, Decl(dash.d.ts, 0, 20))
5+
>TResult : Symbol(TResult, Decl(dash.d.ts, 0, 28))
6+
>value : Symbol(value, Decl(dash.d.ts, 0, 41))
7+
>TObject : Symbol(TObject, Decl(dash.d.ts, 0, 20))
8+
>TObject : Symbol(TObject, Decl(dash.d.ts, 0, 20))
9+
>key : Symbol(key, Decl(dash.d.ts, 0, 71))
10+
>collection : Symbol(collection, Decl(dash.d.ts, 0, 84))
11+
>TObject : Symbol(TObject, Decl(dash.d.ts, 0, 20))
12+
>TResult : Symbol(TResult, Decl(dash.d.ts, 0, 28))
13+
14+
interface LoDashStatic {
15+
>LoDashStatic : Symbol(LoDashStatic, Decl(dash.d.ts, 0, 117))
16+
17+
mapValues<T extends object, TResult>(obj: T | null | undefined, callback: ObjectIterator<T, TResult>): { [P in keyof T]: TResult };
18+
>mapValues : Symbol(LoDashStatic.mapValues, Decl(dash.d.ts, 2, 24))
19+
>T : Symbol(T, Decl(dash.d.ts, 3, 14))
20+
>TResult : Symbol(TResult, Decl(dash.d.ts, 3, 31))
21+
>obj : Symbol(obj, Decl(dash.d.ts, 3, 41))
22+
>T : Symbol(T, Decl(dash.d.ts, 3, 14))
23+
>callback : Symbol(callback, Decl(dash.d.ts, 3, 67))
24+
>ObjectIterator : Symbol(ObjectIterator, Decl(dash.d.ts, 0, 0))
25+
>T : Symbol(T, Decl(dash.d.ts, 3, 14))
26+
>TResult : Symbol(TResult, Decl(dash.d.ts, 3, 31))
27+
>P : Symbol(P, Decl(dash.d.ts, 3, 110))
28+
>T : Symbol(T, Decl(dash.d.ts, 3, 14))
29+
>TResult : Symbol(TResult, Decl(dash.d.ts, 3, 31))
30+
}
31+
declare const _: LoDashStatic;
32+
>_ : Symbol(_, Decl(dash.d.ts, 5, 13))
33+
>LoDashStatic : Symbol(LoDashStatic, Decl(dash.d.ts, 0, 117))
34+
35+
export = _;
36+
>_ : Symbol(_, Decl(dash.d.ts, 5, 13))
37+
38+
=== tests/cases/compiler/Consts.ts ===
39+
export const INDEX_FIELD = '__INDEX';
40+
>INDEX_FIELD : Symbol(INDEX_FIELD, Decl(Consts.ts, 0, 12))
41+
42+
=== tests/cases/compiler/index.js ===
43+
import * as _ from './dash';
44+
>_ : Symbol(_, Decl(index.js, 0, 6))
45+
46+
import { INDEX_FIELD } from './Consts';
47+
>INDEX_FIELD : Symbol(INDEX_FIELD, Decl(index.js, 1, 8))
48+
49+
export class Test {
50+
>Test : Symbol(Test, Decl(index.js, 1, 39))
51+
52+
/**
53+
* @param {object} obj
54+
* @param {object} vm
55+
*/
56+
test(obj, vm) {
57+
>test : Symbol(Test.test, Decl(index.js, 3, 19))
58+
>obj : Symbol(obj, Decl(index.js, 8, 9))
59+
>vm : Symbol(vm, Decl(index.js, 8, 13))
60+
61+
let index = 0;
62+
>index : Symbol(index, Decl(index.js, 9, 11))
63+
64+
vm.objects = _.mapValues(
65+
>vm : Symbol(vm, Decl(index.js, 8, 13))
66+
>_.mapValues : Symbol(LoDashStatic.mapValues, Decl(dash.d.ts, 2, 24))
67+
>_ : Symbol(_, Decl(index.js, 0, 6))
68+
>mapValues : Symbol(LoDashStatic.mapValues, Decl(dash.d.ts, 2, 24))
69+
70+
obj,
71+
>obj : Symbol(obj, Decl(index.js, 8, 9))
72+
73+
object => ({ ...object, [INDEX_FIELD]: index++ }),
74+
>object : Symbol(object, Decl(index.js, 11, 16))
75+
>object : Symbol(object, Decl(index.js, 11, 16))
76+
>[INDEX_FIELD] : Symbol([INDEX_FIELD], Decl(index.js, 12, 35))
77+
>INDEX_FIELD : Symbol(INDEX_FIELD, Decl(index.js, 1, 8))
78+
>index : Symbol(index, Decl(index.js, 9, 11))
79+
80+
);
81+
}
82+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
=== tests/cases/compiler/dash.d.ts ===
2+
type ObjectIterator<TObject, TResult> = (value: TObject[keyof TObject], key: string, collection: TObject) => TResult;
3+
>ObjectIterator : ObjectIterator<TObject, TResult>
4+
>value : TObject[keyof TObject]
5+
>key : string
6+
>collection : TObject
7+
8+
interface LoDashStatic {
9+
mapValues<T extends object, TResult>(obj: T | null | undefined, callback: ObjectIterator<T, TResult>): { [P in keyof T]: TResult };
10+
>mapValues : <T extends object, TResult>(obj: T | null | undefined, callback: ObjectIterator<T, TResult>) => { [P in keyof T]: TResult; }
11+
>obj : T | null | undefined
12+
>null : null
13+
>callback : ObjectIterator<T, TResult>
14+
}
15+
declare const _: LoDashStatic;
16+
>_ : LoDashStatic
17+
18+
export = _;
19+
>_ : LoDashStatic
20+
21+
=== tests/cases/compiler/Consts.ts ===
22+
export const INDEX_FIELD = '__INDEX';
23+
>INDEX_FIELD : "__INDEX"
24+
>'__INDEX' : "__INDEX"
25+
26+
=== tests/cases/compiler/index.js ===
27+
import * as _ from './dash';
28+
>_ : LoDashStatic
29+
30+
import { INDEX_FIELD } from './Consts';
31+
>INDEX_FIELD : "__INDEX"
32+
33+
export class Test {
34+
>Test : Test
35+
36+
/**
37+
* @param {object} obj
38+
* @param {object} vm
39+
*/
40+
test(obj, vm) {
41+
>test : (obj: object, vm: object) => void
42+
>obj : object
43+
>vm : object
44+
45+
let index = 0;
46+
>index : number
47+
>0 : 0
48+
49+
vm.objects = _.mapValues(
50+
>vm.objects = _.mapValues( obj, object => ({ ...object, [INDEX_FIELD]: index++ }), ) : object
51+
>vm.objects : error
52+
>vm : object
53+
>objects : any
54+
>_.mapValues( obj, object => ({ ...object, [INDEX_FIELD]: index++ }), ) : object
55+
>_.mapValues : <T extends object, TResult>(obj: T | null | undefined, callback: (value: T[keyof T], key: string, collection: T) => TResult) => { [P in keyof T]: TResult; }
56+
>_ : LoDashStatic
57+
>mapValues : <T extends object, TResult>(obj: T | null | undefined, callback: (value: T[keyof T], key: string, collection: T) => TResult) => { [P in keyof T]: TResult; }
58+
59+
obj,
60+
>obj : object
61+
62+
object => ({ ...object, [INDEX_FIELD]: index++ }),
63+
>object => ({ ...object, [INDEX_FIELD]: index++ }) : (object: never) => any
64+
>object : never
65+
>({ ...object, [INDEX_FIELD]: index++ }) : error
66+
>{ ...object, [INDEX_FIELD]: index++ } : error
67+
>object : never
68+
>[INDEX_FIELD] : number
69+
>INDEX_FIELD : "__INDEX"
70+
>index++ : number
71+
>index : number
72+
73+
);
74+
}
75+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// @target: esnext
2+
// @allowJs: true
3+
// @strict: true
4+
// @outDir: ./out
5+
// @filename: dash.d.ts
6+
type ObjectIterator<TObject, TResult> = (value: TObject[keyof TObject], key: string, collection: TObject) => TResult;
7+
8+
interface LoDashStatic {
9+
mapValues<T extends object, TResult>(obj: T | null | undefined, callback: ObjectIterator<T, TResult>): { [P in keyof T]: TResult };
10+
}
11+
declare const _: LoDashStatic;
12+
export = _;
13+
// @filename: Consts.ts
14+
export const INDEX_FIELD = '__INDEX';
15+
// @filename: index.js
16+
import * as _ from './dash';
17+
import { INDEX_FIELD } from './Consts';
18+
19+
export class Test {
20+
/**
21+
* @param {object} obj
22+
* @param {object} vm
23+
*/
24+
test(obj, vm) {
25+
let index = 0;
26+
vm.objects = _.mapValues(
27+
obj,
28+
object => ({ ...object, [INDEX_FIELD]: index++ }),
29+
);
30+
}
31+
}

0 commit comments

Comments
 (0)