Skip to content

Commit f3f42e7

Browse files
authored
Fix isolatedDeclarations emit of computed property names in interfaces (#1720)
1 parent ea6d53c commit f3f42e7

File tree

7 files changed

+110
-3
lines changed

7 files changed

+110
-3
lines changed

internal/checker/emitresolver.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,30 @@ func (r *emitResolver) IsImportRequiredByAugmentation(decl *ast.ImportDeclaratio
498498
return false
499499
}
500500

501+
func (r *emitResolver) IsDefinitelyReferenceToGlobalSymbolObject(node *ast.Node) bool {
502+
if !ast.IsPropertyAccessExpression(node) ||
503+
!ast.IsIdentifier(node.Name()) ||
504+
!ast.IsPropertyAccessExpression(node.Expression()) && !ast.IsIdentifier(node.Expression()) {
505+
return false
506+
}
507+
if node.Expression().Kind == ast.KindIdentifier {
508+
if node.Expression().AsIdentifier().Text != "Symbol" {
509+
return false
510+
}
511+
r.checkerMu.Lock()
512+
defer r.checkerMu.Unlock()
513+
// Exactly `Symbol.something` and `Symbol` either does not resolve or definitely resolves to the global Symbol
514+
return r.checker.getResolvedSymbol(node.Expression()) == r.checker.getGlobalSymbol("Symbol", ast.SymbolFlagsValue|ast.SymbolFlagsExportValue, nil /*diagnostic*/)
515+
}
516+
if node.Expression().Expression().Kind != ast.KindIdentifier || node.Expression().Expression().AsIdentifier().Text != "globalThis" || node.Expression().Name().Text() != "Symbol" {
517+
return false
518+
}
519+
r.checkerMu.Lock()
520+
defer r.checkerMu.Unlock()
521+
// Exactly `globalThis.Symbol.something` and `globalThis` resolves to the global `globalThis`
522+
return r.checker.getResolvedSymbol(node.Expression().Expression()) == r.checker.globalThisSymbol
523+
}
524+
501525
func (r *emitResolver) RequiresAddingImplicitUndefined(declaration *ast.Node, symbol *ast.Symbol, enclosingDeclaration *ast.Node) bool {
502526
if !ast.IsParseTreeNode(declaration) {
503527
return false

internal/printer/emitresolver.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ type EmitResolver interface {
5252
RequiresAddingImplicitUndefined(node *ast.Node, symbol *ast.Symbol, enclosingDeclaration *ast.Node) bool
5353
IsDeclarationVisible(node *ast.Node) bool
5454
IsImportRequiredByAugmentation(decl *ast.ImportDeclaration) bool
55+
IsDefinitelyReferenceToGlobalSymbolObject(node *ast.Node) bool
5556
IsImplementationOfOverload(node *ast.SignatureDeclaration) bool
5657
GetEnumMemberValue(node *ast.Node) evaluator.Result
5758
IsLateBound(node *ast.Node) bool

internal/transformers/declarations/transform.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,8 +384,20 @@ func (tx *DeclarationTransformer) visitDeclarationSubtree(input *ast.Node) *ast.
384384
}
385385
if ast.HasDynamicName(input) {
386386
if tx.state.isolatedDeclarations {
387-
// !!! isolatedDeclarations support
388-
return nil
387+
// Classes and object literals usually elide properties with computed names that are not of a literal type
388+
// In isolated declarations TSC needs to error on these as we don't know the type in a DTE.
389+
if !tx.resolver.IsDefinitelyReferenceToGlobalSymbolObject(input.Name().Expression()) {
390+
if ast.IsClassDeclaration(input.Parent) || ast.IsObjectLiteralExpression(input.Parent) {
391+
// !!! TODO: isolatedDeclarations diagnostics
392+
// context.addDiagnostic(createDiagnosticForNode(input, diagnostics.Computed_property_names_on_class_or_object_literals_cannot_be_inferred_with_isolatedDeclarations))
393+
return nil
394+
} else if (ast.IsInterfaceDeclaration(input.Parent) || ast.IsTypeLiteralNode(input.Parent)) && !ast.IsEntityNameExpression(input.Name().Expression()) {
395+
// Type declarations just need to double-check that the input computed name is an entity name expression
396+
// !!! TODO: isolatedDeclarations diagnostics
397+
// context.addDiagnostic(createDiagnosticForNode(input, diagnostics.Computed_properties_must_be_number_or_string_literals_variables_or_dotted_expressions_with_isolatedDeclarations))
398+
return nil
399+
}
400+
}
389401
} else if !tx.resolver.IsLateBound(tx.EmitContext().ParseNode(input)) || !ast.IsEntityNameExpression(input.Name().AsComputedPropertyName().Expression) {
390402
return nil
391403
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//// [tests/cases/compiler/enumMemberInterfacePropertyDeclarationEmit.ts] ////
2+
3+
//// [enum.ts]
4+
export enum WWMF{
5+
AAR = 'AAR',
6+
}
7+
8+
//// [base.ts]
9+
import type { WWMF } from "./enum";
10+
11+
interface WWMFMap {
12+
[WWMF.AAR]?: any;
13+
}
14+
15+
export const wwmfMap: WWMFMap = {};
16+
17+
18+
//// [enum.js]
19+
"use strict";
20+
Object.defineProperty(exports, "__esModule", { value: true });
21+
exports.WWMF = void 0;
22+
var WWMF;
23+
(function (WWMF) {
24+
WWMF["AAR"] = "AAR";
25+
})(WWMF || (exports.WWMF = WWMF = {}));
26+
//// [base.js]
27+
"use strict";
28+
Object.defineProperty(exports, "__esModule", { value: true });
29+
exports.wwmfMap = void 0;
30+
exports.wwmfMap = {};
31+
32+
33+
//// [enum.d.ts]
34+
export declare enum WWMF {
35+
AAR = "AAR"
36+
}
37+
//// [base.d.ts]
38+
import type { WWMF } from "./enum";
39+
interface WWMFMap {
40+
[WWMF.AAR]?: any;
41+
}
42+
export declare const wwmfMap: WWMFMap;
43+
export {};

testdata/baselines/reference/submodule/compiler/isolatedDeclarationErrorsClasses.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,14 @@ export declare class Cls {
112112
get getSetOk3(): number;
113113
set getSetOk3(value: number);
114114
}
115+
declare let noAnnotationStringName: string;
116+
declare const noAnnotationLiteralName = "noAnnotationLiteralName";
115117
export declare class C {
116118
[x: string]: any;
117119
[x: number]: number;
118120
}
119121
export interface I {
122+
[noAnnotationStringName]: 10;
123+
[noAnnotationLiteralName](): any;
120124
}
125+
export {};

testdata/baselines/reference/submodule/compiler/isolatedDeclarationErrorsClasses.js.diff

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,14 @@
2424
+ get getSetOk3(): number;
2525
+ set getSetOk3(value: number);
2626
+}
27+
+declare let noAnnotationStringName: string;
28+
+declare const noAnnotationLiteralName = "noAnnotationLiteralName";
2729
+export declare class C {
2830
+ [x: string]: any;
2931
+ [x: number]: number;
3032
+}
3133
+export interface I {
32-
+}
34+
+ [noAnnotationStringName]: 10;
35+
+ [noAnnotationLiteralName](): any;
36+
+}
37+
+export {};
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// @declaration: true
2+
// @noTypesAndSymbols: true
3+
// @isolatedDeclarations: true
4+
5+
// @Filename: enum.ts
6+
export enum WWMF{
7+
AAR = 'AAR',
8+
}
9+
10+
// @Filename: base.ts
11+
import type { WWMF } from "./enum";
12+
13+
interface WWMFMap {
14+
[WWMF.AAR]?: any;
15+
}
16+
17+
export const wwmfMap: WWMFMap = {};

0 commit comments

Comments
 (0)