Skip to content

Commit 9a7fdad

Browse files
authored
Fix crash in contextual typing of defaulted element access declarations (#33686)
1 parent 98cf317 commit 9a7fdad

7 files changed

+104
-12
lines changed

src/compiler/binder.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -2966,7 +2966,7 @@ namespace ts {
29662966
}
29672967
else {
29682968
const symbol = lookupSymbolForPropertyAccess(node.expression);
2969-
return symbol && symbol.exports && symbol.exports.get(escapeLeadingUnderscores(getElementOrPropertyAccessName(node)));
2969+
return symbol && symbol.exports && symbol.exports.get(getElementOrPropertyAccessName(node));
29702970
}
29712971
}
29722972

@@ -2979,7 +2979,7 @@ namespace ts {
29792979
}
29802980
else {
29812981
const s = forEachIdentifierInEntityName(e.expression, parent, action);
2982-
return action(getNameOrArgument(e), s && s.exports && s.exports.get(escapeLeadingUnderscores(getElementOrPropertyAccessName(e))), s);
2982+
return action(getNameOrArgument(e), s && s.exports && s.exports.get(getElementOrPropertyAccessName(e)), s);
29832983
}
29842984
}
29852985

src/compiler/checker.ts

+9-5
Original file line numberDiff line numberDiff line change
@@ -20940,7 +20940,7 @@ namespace ts {
2094020940
if (!decl) {
2094120941
return false;
2094220942
}
20943-
const lhs = binaryExpression.left as PropertyAccessExpression;
20943+
const lhs = cast(binaryExpression.left, isAccessExpression);
2094420944
const overallAnnotation = getEffectiveTypeAnnotationNode(decl);
2094520945
if (overallAnnotation) {
2094620946
return getTypeFromTypeNode(overallAnnotation);
@@ -20951,8 +20951,11 @@ namespace ts {
2095120951
if (parentSymbol) {
2095220952
const annotated = getEffectiveTypeAnnotationNode(parentSymbol.valueDeclaration);
2095320953
if (annotated) {
20954-
const type = getTypeOfPropertyOfContextualType(getTypeFromTypeNode(annotated), lhs.name.escapedText);
20955-
return type || false;
20954+
const nameStr = getElementOrPropertyAccessName(lhs);
20955+
if (nameStr !== undefined) {
20956+
const type = getTypeOfPropertyOfContextualType(getTypeFromTypeNode(annotated), nameStr);
20957+
return type || false;
20958+
}
2095620959
}
2095720960
return false;
2095820961
}
@@ -20972,12 +20975,13 @@ namespace ts {
2097220975
}
2097320976
}
2097420977
if (kind === AssignmentDeclarationKind.ModuleExports) return false;
20975-
const thisAccess = binaryExpression.left as PropertyAccessExpression;
20978+
const thisAccess = cast(binaryExpression.left, isAccessExpression);
2097620979
if (!isObjectLiteralMethod(getThisContainer(thisAccess.expression, /*includeArrowFunctions*/ false))) {
2097720980
return false;
2097820981
}
2097920982
const thisType = checkThisExpression(thisAccess.expression);
20980-
return thisType && getTypeOfPropertyOfContextualType(thisType, thisAccess.name.escapedText) || false;
20983+
const nameStr = getElementOrPropertyAccessName(thisAccess);
20984+
return nameStr !== undefined && thisType && getTypeOfPropertyOfContextualType(thisType, nameStr) || false;
2098120985
case AssignmentDeclarationKind.ObjectDefinePropertyValue:
2098220986
case AssignmentDeclarationKind.ObjectDefinePropertyExports:
2098320987
case AssignmentDeclarationKind.ObjectDefinePrototypeProperty:

src/compiler/utilities.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -2128,18 +2128,21 @@ namespace ts {
21282128
}
21292129

21302130
/* @internal */
2131-
export function getElementOrPropertyAccessName(node: LiteralLikeElementAccessExpression | PropertyAccessExpression): string;
2132-
export function getElementOrPropertyAccessName(node: AccessExpression): string | undefined;
2133-
export function getElementOrPropertyAccessName(node: AccessExpression): string | undefined {
2131+
export function getElementOrPropertyAccessName(node: LiteralLikeElementAccessExpression | PropertyAccessExpression): __String;
2132+
export function getElementOrPropertyAccessName(node: AccessExpression): __String | undefined;
2133+
export function getElementOrPropertyAccessName(node: AccessExpression): __String | undefined {
21342134
const name = getElementOrPropertyAccessArgumentExpressionOrName(node);
21352135
if (name) {
21362136
if (isIdentifier(name)) {
2137-
return idText(name);
2137+
return name.escapedText;
21382138
}
21392139
if (isStringLiteralLike(name) || isNumericLiteral(name)) {
2140-
return name.text;
2140+
return escapeLeadingUnderscores(name.text);
21412141
}
21422142
}
2143+
if (isElementAccessExpression(node) && isWellKnownSymbolSyntactically(node.argumentExpression)) {
2144+
return getPropertyNameForKnownSymbolName(idText((<PropertyAccessExpression>node.argumentExpression).name));
2145+
}
21432146
return undefined;
21442147
}
21452148

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
tests/cases/compiler/jsElementAccessNoContextualTypeCrash.js(2,1): error TS2741: Property 'localize' is missing in type '{}' but required in type 'typeof Common'.
2+
3+
4+
==== tests/cases/compiler/jsElementAccessNoContextualTypeCrash.js (1 errors) ====
5+
var Common = {};
6+
self['Common'] = self['Common'] || {};
7+
~~~~~~~~~~~~~~
8+
!!! error TS2741: Property 'localize' is missing in type '{}' but required in type 'typeof Common'.
9+
!!! related TS2728 tests/cases/compiler/jsElementAccessNoContextualTypeCrash.js:7:1: 'localize' is declared here.
10+
/**
11+
* @param {string} string
12+
* @return {string}
13+
*/
14+
Common.localize = function (string) {
15+
return string;
16+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
=== tests/cases/compiler/jsElementAccessNoContextualTypeCrash.js ===
2+
var Common = {};
3+
>Common : Symbol(Common, Decl(jsElementAccessNoContextualTypeCrash.js, 0, 3), Decl(jsElementAccessNoContextualTypeCrash.js, 1, 38))
4+
5+
self['Common'] = self['Common'] || {};
6+
>self : Symbol(self, Decl(lib.dom.d.ts, --, --), Decl(jsElementAccessNoContextualTypeCrash.js, 0, 16))
7+
>'Common' : Symbol(Common, Decl(jsElementAccessNoContextualTypeCrash.js, 0, 3), Decl(jsElementAccessNoContextualTypeCrash.js, 1, 38))
8+
>self : Symbol(self, Decl(lib.dom.d.ts, --, --), Decl(jsElementAccessNoContextualTypeCrash.js, 0, 16))
9+
>'Common' : Symbol(Common, Decl(jsElementAccessNoContextualTypeCrash.js, 0, 3), Decl(jsElementAccessNoContextualTypeCrash.js, 1, 38))
10+
11+
/**
12+
* @param {string} string
13+
* @return {string}
14+
*/
15+
Common.localize = function (string) {
16+
>Common.localize : Symbol(Common.localize, Decl(jsElementAccessNoContextualTypeCrash.js, 1, 38))
17+
>Common : Symbol(Common, Decl(jsElementAccessNoContextualTypeCrash.js, 0, 3), Decl(jsElementAccessNoContextualTypeCrash.js, 1, 38))
18+
>localize : Symbol(Common.localize, Decl(jsElementAccessNoContextualTypeCrash.js, 1, 38))
19+
>string : Symbol(string, Decl(jsElementAccessNoContextualTypeCrash.js, 6, 28))
20+
21+
return string;
22+
>string : Symbol(string, Decl(jsElementAccessNoContextualTypeCrash.js, 6, 28))
23+
24+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
=== tests/cases/compiler/jsElementAccessNoContextualTypeCrash.js ===
2+
var Common = {};
3+
>Common : typeof Common
4+
>{} : {}
5+
6+
self['Common'] = self['Common'] || {};
7+
>self['Common'] = self['Common'] || {} : {}
8+
>self['Common'] : typeof Common
9+
>self : Window & typeof globalThis
10+
>'Common' : "Common"
11+
>self['Common'] || {} : {}
12+
>self['Common'] : typeof Common
13+
>self : Window & typeof globalThis
14+
>'Common' : "Common"
15+
>{} : {}
16+
17+
/**
18+
* @param {string} string
19+
* @return {string}
20+
*/
21+
Common.localize = function (string) {
22+
>Common.localize = function (string) { return string;} : (string: string) => string
23+
>Common.localize : (string: string) => string
24+
>Common : typeof Common
25+
>localize : (string: string) => string
26+
>function (string) { return string;} : (string: string) => string
27+
>string : string
28+
29+
return string;
30+
>string : string
31+
32+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// @checkJs: true
2+
// @allowJs: true
3+
// @noEmit: true
4+
// @filename: jsElementAccessNoContextualTypeCrash.js
5+
var Common = {};
6+
self['Common'] = self['Common'] || {};
7+
/**
8+
* @param {string} string
9+
* @return {string}
10+
*/
11+
Common.localize = function (string) {
12+
return string;
13+
};

0 commit comments

Comments
 (0)