Skip to content

Commit 822cb3a

Browse files
TypeScript Botelibarzilay
TypeScript Bot
andauthored
Cherry-pick PR #42766 into release-4.2 (#42950)
Component commits: ed26816 Avoid getting undefined `callSignatures`/`constructSignatures` in `getPropertyOfType` e350c35 (#40228) introduced a subtle bug: it switched the flags to an alias, dropping `SymbolFlags.Property` --- and that makes `symbolIsValue()` get to the `resolveAlias(symbol)` call, which leads to `getPropertyOfType()` with`resolved.callSignatures`+`constructSignatures` being `undefined`. So initialize them in `setStructuredTypeMembers` before calling `getNamedMembers()`. Fixes #42350 Co-authored-by: Eli Barzilay <eli@barzilay.org>
1 parent e213b2a commit 822cb3a

9 files changed

+108
-7
lines changed

src/compiler/checker.ts

+10-7
Original file line numberDiff line numberDiff line change
@@ -3846,13 +3846,16 @@ namespace ts {
38463846
}
38473847

38483848
function setStructuredTypeMembers(type: StructuredType, members: SymbolTable, callSignatures: readonly Signature[], constructSignatures: readonly Signature[], stringIndexInfo: IndexInfo | undefined, numberIndexInfo: IndexInfo | undefined): ResolvedType {
3849-
(<ResolvedType>type).members = members;
3850-
(<ResolvedType>type).properties = members === emptySymbols ? emptyArray : getNamedMembers(members);
3851-
(<ResolvedType>type).callSignatures = callSignatures;
3852-
(<ResolvedType>type).constructSignatures = constructSignatures;
3853-
(<ResolvedType>type).stringIndexInfo = stringIndexInfo;
3854-
(<ResolvedType>type).numberIndexInfo = numberIndexInfo;
3855-
return <ResolvedType>type;
3849+
const resolved = <ResolvedType>type;
3850+
resolved.members = members;
3851+
resolved.properties = emptyArray;
3852+
resolved.callSignatures = callSignatures;
3853+
resolved.constructSignatures = constructSignatures;
3854+
resolved.stringIndexInfo = stringIndexInfo;
3855+
resolved.numberIndexInfo = numberIndexInfo;
3856+
// This can loop back to getPropertyOfType() which would crash if `callSignatures` & `constructSignatures` are not initialized.
3857+
if (members !== emptySymbols) resolved.properties = getNamedMembers(members);
3858+
return resolved;
38563859
}
38573860

38583861
function createAnonymousType(symbol: Symbol | undefined, members: SymbolTable, callSignatures: readonly Signature[], constructSignatures: readonly Signature[], stringIndexInfo: IndexInfo | undefined, numberIndexInfo: IndexInfo | undefined): ResolvedType {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
tests/cases/conformance/salsa/x.js(1,9): error TS2339: Property 'fn1' does not exist on type 'typeof import("tests/cases/conformance/salsa/x")'.
2+
3+
4+
==== tests/cases/conformance/salsa/x.js (1 errors) ====
5+
exports.fn1();
6+
~~~
7+
!!! error TS2339: Property 'fn1' does not exist on type 'typeof import("tests/cases/conformance/salsa/x")'.
8+
exports.fn2 = Math.min;
9+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
=== tests/cases/conformance/salsa/x.js ===
2+
exports.fn1();
3+
>exports : Symbol("tests/cases/conformance/salsa/x", Decl(x.js, 0, 0))
4+
5+
exports.fn2 = Math.min;
6+
>exports.fn2 : Symbol(fn2, Decl(x.js, 0, 14))
7+
>exports : Symbol(fn2, Decl(x.js, 0, 14))
8+
>fn2 : Symbol(fn2, Decl(x.js, 0, 14))
9+
>Math.min : Symbol(fn2, Decl(lib.es5.d.ts, --, --))
10+
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
11+
>min : Symbol(fn2, Decl(lib.es5.d.ts, --, --))
12+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
=== tests/cases/conformance/salsa/x.js ===
2+
exports.fn1();
3+
>exports.fn1() : any
4+
>exports.fn1 : any
5+
>exports : typeof import("tests/cases/conformance/salsa/x")
6+
>fn1 : any
7+
8+
exports.fn2 = Math.min;
9+
>exports.fn2 = Math.min : (...values: number[]) => number
10+
>exports.fn2 : (...values: number[]) => number
11+
>exports : typeof import("tests/cases/conformance/salsa/x")
12+
>fn2 : (...values: number[]) => number
13+
>Math.min : (...values: number[]) => number
14+
>Math : Math
15+
>min : (...values: number[]) => number
16+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
tests/cases/conformance/salsa/x.js(2,9): error TS2339: Property 'fn1' does not exist on type 'typeof import("tests/cases/conformance/salsa/x")'.
2+
3+
4+
==== tests/cases/conformance/salsa/x.js (1 errors) ====
5+
const Foo = { min: 3 };
6+
exports.fn1();
7+
~~~
8+
!!! error TS2339: Property 'fn1' does not exist on type 'typeof import("tests/cases/conformance/salsa/x")'.
9+
exports.fn2 = Foo.min;
10+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
=== tests/cases/conformance/salsa/x.js ===
2+
const Foo = { min: 3 };
3+
>Foo : Symbol(Foo, Decl(x.js, 0, 5))
4+
>min : Symbol(min, Decl(x.js, 0, 13))
5+
6+
exports.fn1();
7+
>exports : Symbol("tests/cases/conformance/salsa/x", Decl(x.js, 0, 0))
8+
9+
exports.fn2 = Foo.min;
10+
>exports.fn2 : Symbol(fn2, Decl(x.js, 1, 14))
11+
>exports : Symbol(fn2, Decl(x.js, 1, 14))
12+
>fn2 : Symbol(fn2, Decl(x.js, 1, 14))
13+
>Foo.min : Symbol(fn2, Decl(x.js, 0, 13))
14+
>Foo : Symbol(Foo, Decl(x.js, 0, 5))
15+
>min : Symbol(fn2, Decl(x.js, 0, 13))
16+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
=== tests/cases/conformance/salsa/x.js ===
2+
const Foo = { min: 3 };
3+
>Foo : { min: number; }
4+
>{ min: 3 } : { min: number; }
5+
>min : number
6+
>3 : 3
7+
8+
exports.fn1();
9+
>exports.fn1() : any
10+
>exports.fn1 : any
11+
>exports : typeof import("tests/cases/conformance/salsa/x")
12+
>fn1 : any
13+
14+
exports.fn2 = Foo.min;
15+
>exports.fn2 = Foo.min : number
16+
>exports.fn2 : number
17+
>exports : typeof import("tests/cases/conformance/salsa/x")
18+
>fn2 : number
19+
>Foo.min : number
20+
>Foo : { min: number; }
21+
>min : number
22+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// @noEmit: true
2+
// @allowJs: true
3+
// @checkJs: true
4+
// @filename: x.js
5+
exports.fn1();
6+
exports.fn2 = Math.min;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// @noEmit: true
2+
// @allowJs: true
3+
// @checkJs: true
4+
// @filename: x.js
5+
const Foo = { min: 3 };
6+
exports.fn1();
7+
exports.fn2 = Foo.min;

0 commit comments

Comments
 (0)