Don’t create expando declarations on alias symbols (#39558)
* Don’t create expando declarations on alias symbols * Update other baseline * Fix brace nesting refactor mistake
This commit is contained in:
parent
629dd6487b
commit
583bd92bc4
|
@ -2980,6 +2980,9 @@ namespace ts {
|
|||
}
|
||||
|
||||
function bindPotentiallyMissingNamespaces(namespaceSymbol: Symbol | undefined, entityName: BindableStaticNameExpression, isToplevel: boolean, isPrototypeProperty: boolean, containerIsClass: boolean) {
|
||||
if (namespaceSymbol?.flags! & SymbolFlags.Alias) {
|
||||
return namespaceSymbol;
|
||||
}
|
||||
if (isToplevel && !isPrototypeProperty) {
|
||||
// make symbols or add declarations for intermediate containers
|
||||
const flags = SymbolFlags.Module | SymbolFlags.Assignment;
|
||||
|
|
|
@ -35217,39 +35217,36 @@ namespace ts {
|
|||
const target = resolveAlias(symbol);
|
||||
|
||||
if (target !== unknownSymbol) {
|
||||
const shouldSkipWithJSExpandoTargets = symbol.flags & SymbolFlags.Assignment;
|
||||
if (!shouldSkipWithJSExpandoTargets) {
|
||||
// For external modules symbol represents local symbol for an alias.
|
||||
// This local symbol will merge any other local declarations (excluding other aliases)
|
||||
// and symbol.flags will contains combined representation for all merged declaration.
|
||||
// Based on symbol.flags we can compute a set of excluded meanings (meaning that resolved alias should not have,
|
||||
// otherwise it will conflict with some local declaration). Note that in addition to normal flags we include matching SymbolFlags.Export*
|
||||
// in order to prevent collisions with declarations that were exported from the current module (they still contribute to local names).
|
||||
symbol = getMergedSymbol(symbol.exportSymbol || symbol);
|
||||
const excludedMeanings =
|
||||
(symbol.flags & (SymbolFlags.Value | SymbolFlags.ExportValue) ? SymbolFlags.Value : 0) |
|
||||
(symbol.flags & SymbolFlags.Type ? SymbolFlags.Type : 0) |
|
||||
(symbol.flags & SymbolFlags.Namespace ? SymbolFlags.Namespace : 0);
|
||||
if (target.flags & excludedMeanings) {
|
||||
const message = node.kind === SyntaxKind.ExportSpecifier ?
|
||||
Diagnostics.Export_declaration_conflicts_with_exported_declaration_of_0 :
|
||||
Diagnostics.Import_declaration_conflicts_with_local_declaration_of_0;
|
||||
error(node, message, symbolToString(symbol));
|
||||
}
|
||||
// For external modules, `symbol` represents the local symbol for an alias.
|
||||
// This local symbol will merge any other local declarations (excluding other aliases)
|
||||
// and symbol.flags will contains combined representation for all merged declaration.
|
||||
// Based on symbol.flags we can compute a set of excluded meanings (meaning that resolved alias should not have,
|
||||
// otherwise it will conflict with some local declaration). Note that in addition to normal flags we include matching SymbolFlags.Export*
|
||||
// in order to prevent collisions with declarations that were exported from the current module (they still contribute to local names).
|
||||
symbol = getMergedSymbol(symbol.exportSymbol || symbol);
|
||||
const excludedMeanings =
|
||||
(symbol.flags & (SymbolFlags.Value | SymbolFlags.ExportValue) ? SymbolFlags.Value : 0) |
|
||||
(symbol.flags & SymbolFlags.Type ? SymbolFlags.Type : 0) |
|
||||
(symbol.flags & SymbolFlags.Namespace ? SymbolFlags.Namespace : 0);
|
||||
if (target.flags & excludedMeanings) {
|
||||
const message = node.kind === SyntaxKind.ExportSpecifier ?
|
||||
Diagnostics.Export_declaration_conflicts_with_exported_declaration_of_0 :
|
||||
Diagnostics.Import_declaration_conflicts_with_local_declaration_of_0;
|
||||
error(node, message, symbolToString(symbol));
|
||||
}
|
||||
|
||||
// Don't allow to re-export something with no value side when `--isolatedModules` is set.
|
||||
if (compilerOptions.isolatedModules
|
||||
&& node.kind === SyntaxKind.ExportSpecifier
|
||||
&& !node.parent.parent.isTypeOnly
|
||||
&& !(target.flags & SymbolFlags.Value)
|
||||
&& !(node.flags & NodeFlags.Ambient)) {
|
||||
error(node, Diagnostics.Re_exporting_a_type_when_the_isolatedModules_flag_is_provided_requires_using_export_type);
|
||||
}
|
||||
// Don't allow to re-export something with no value side when `--isolatedModules` is set.
|
||||
if (compilerOptions.isolatedModules
|
||||
&& node.kind === SyntaxKind.ExportSpecifier
|
||||
&& !node.parent.parent.isTypeOnly
|
||||
&& !(target.flags & SymbolFlags.Value)
|
||||
&& !(node.flags & NodeFlags.Ambient)) {
|
||||
error(node, Diagnostics.Re_exporting_a_type_when_the_isolatedModules_flag_is_provided_requires_using_export_type);
|
||||
}
|
||||
|
||||
if (isImportSpecifier(node) &&
|
||||
(target.valueDeclaration && target.valueDeclaration.flags & NodeFlags.Deprecated
|
||||
|| every(target.declarations, d => !!(d.flags & NodeFlags.Deprecated)))) {
|
||||
|| every(target.declarations, d => !!(d.flags & NodeFlags.Deprecated)))) {
|
||||
errorOrSuggestion(/* isError */ false, node.name, Diagnostics._0_is_deprecated, symbol.escapedName as string);
|
||||
}
|
||||
}
|
||||
|
|
25
tests/baselines/reference/expandoOnAlias.errors.txt
Normal file
25
tests/baselines/reference/expandoOnAlias.errors.txt
Normal file
|
@ -0,0 +1,25 @@
|
|||
tests/cases/conformance/salsa/test.js(4,5): error TS2339: Property 'config' does not exist on type 'typeof Vue'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/salsa/vue.js (0 errors) ====
|
||||
export class Vue {}
|
||||
export const config = { x: 0 };
|
||||
|
||||
==== tests/cases/conformance/salsa/test.js (1 errors) ====
|
||||
import { Vue, config } from "./vue";
|
||||
|
||||
// Expando declarations aren't allowed on aliases.
|
||||
Vue.config = {};
|
||||
~~~~~~
|
||||
!!! error TS2339: Property 'config' does not exist on type 'typeof Vue'.
|
||||
new Vue();
|
||||
|
||||
// This is not an expando declaration; it's just a plain property assignment.
|
||||
config.x = 1;
|
||||
|
||||
// This is not an expando declaration; it works because non-strict JS allows
|
||||
// loosey goosey assignment on objects.
|
||||
config.y = {};
|
||||
config.x;
|
||||
config.y;
|
||||
|
33
tests/baselines/reference/expandoOnAlias.js
Normal file
33
tests/baselines/reference/expandoOnAlias.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
//// [tests/cases/conformance/salsa/expandoOnAlias.ts] ////
|
||||
|
||||
//// [vue.js]
|
||||
export class Vue {}
|
||||
export const config = { x: 0 };
|
||||
|
||||
//// [test.js]
|
||||
import { Vue, config } from "./vue";
|
||||
|
||||
// Expando declarations aren't allowed on aliases.
|
||||
Vue.config = {};
|
||||
new Vue();
|
||||
|
||||
// This is not an expando declaration; it's just a plain property assignment.
|
||||
config.x = 1;
|
||||
|
||||
// This is not an expando declaration; it works because non-strict JS allows
|
||||
// loosey goosey assignment on objects.
|
||||
config.y = {};
|
||||
config.x;
|
||||
config.y;
|
||||
|
||||
|
||||
|
||||
|
||||
//// [vue.d.ts]
|
||||
export class Vue {
|
||||
}
|
||||
export namespace config {
|
||||
const x: number;
|
||||
}
|
||||
//// [test.d.ts]
|
||||
export {};
|
39
tests/baselines/reference/expandoOnAlias.symbols
Normal file
39
tests/baselines/reference/expandoOnAlias.symbols
Normal file
|
@ -0,0 +1,39 @@
|
|||
=== tests/cases/conformance/salsa/vue.js ===
|
||||
export class Vue {}
|
||||
>Vue : Symbol(Vue, Decl(vue.js, 0, 0))
|
||||
|
||||
export const config = { x: 0 };
|
||||
>config : Symbol(config, Decl(vue.js, 1, 12))
|
||||
>x : Symbol(x, Decl(vue.js, 1, 23))
|
||||
|
||||
=== tests/cases/conformance/salsa/test.js ===
|
||||
import { Vue, config } from "./vue";
|
||||
>Vue : Symbol(Vue, Decl(test.js, 0, 8))
|
||||
>config : Symbol(config, Decl(test.js, 0, 13))
|
||||
|
||||
// Expando declarations aren't allowed on aliases.
|
||||
Vue.config = {};
|
||||
>Vue : Symbol(Vue, Decl(test.js, 0, 8))
|
||||
|
||||
new Vue();
|
||||
>Vue : Symbol(Vue, Decl(test.js, 0, 8))
|
||||
|
||||
// This is not an expando declaration; it's just a plain property assignment.
|
||||
config.x = 1;
|
||||
>config.x : Symbol(x, Decl(vue.js, 1, 23))
|
||||
>config : Symbol(config, Decl(test.js, 0, 13))
|
||||
>x : Symbol(x, Decl(vue.js, 1, 23))
|
||||
|
||||
// This is not an expando declaration; it works because non-strict JS allows
|
||||
// loosey goosey assignment on objects.
|
||||
config.y = {};
|
||||
>config : Symbol(config, Decl(test.js, 0, 13))
|
||||
|
||||
config.x;
|
||||
>config.x : Symbol(x, Decl(vue.js, 1, 23))
|
||||
>config : Symbol(config, Decl(test.js, 0, 13))
|
||||
>x : Symbol(x, Decl(vue.js, 1, 23))
|
||||
|
||||
config.y;
|
||||
>config : Symbol(config, Decl(test.js, 0, 13))
|
||||
|
54
tests/baselines/reference/expandoOnAlias.types
Normal file
54
tests/baselines/reference/expandoOnAlias.types
Normal file
|
@ -0,0 +1,54 @@
|
|||
=== tests/cases/conformance/salsa/vue.js ===
|
||||
export class Vue {}
|
||||
>Vue : Vue
|
||||
|
||||
export const config = { x: 0 };
|
||||
>config : { x: number; }
|
||||
>{ x: 0 } : { x: number; }
|
||||
>x : number
|
||||
>0 : 0
|
||||
|
||||
=== tests/cases/conformance/salsa/test.js ===
|
||||
import { Vue, config } from "./vue";
|
||||
>Vue : typeof Vue
|
||||
>config : { x: number; }
|
||||
|
||||
// Expando declarations aren't allowed on aliases.
|
||||
Vue.config = {};
|
||||
>Vue.config = {} : {}
|
||||
>Vue.config : any
|
||||
>Vue : typeof Vue
|
||||
>config : any
|
||||
>{} : {}
|
||||
|
||||
new Vue();
|
||||
>new Vue() : Vue
|
||||
>Vue : typeof Vue
|
||||
|
||||
// This is not an expando declaration; it's just a plain property assignment.
|
||||
config.x = 1;
|
||||
>config.x = 1 : 1
|
||||
>config.x : number
|
||||
>config : { x: number; }
|
||||
>x : number
|
||||
>1 : 1
|
||||
|
||||
// This is not an expando declaration; it works because non-strict JS allows
|
||||
// loosey goosey assignment on objects.
|
||||
config.y = {};
|
||||
>config.y = {} : {}
|
||||
>config.y : any
|
||||
>config : { x: number; }
|
||||
>y : any
|
||||
>{} : {}
|
||||
|
||||
config.x;
|
||||
>config.x : number
|
||||
>config : { x: number; }
|
||||
>x : number
|
||||
|
||||
config.y;
|
||||
>config.y : any
|
||||
>config : { x: number; }
|
||||
>y : any
|
||||
|
|
@ -7,10 +7,8 @@ export default Obj;
|
|||
|
||||
=== tests/cases/compiler/b.js ===
|
||||
import Obj from './a';
|
||||
>Obj : Symbol(Obj, Decl(b.js, 0, 6), Decl(b.js, 0, 22))
|
||||
>Obj : Symbol(Obj, Decl(b.js, 0, 6))
|
||||
|
||||
Obj.fn = function() {};
|
||||
>Obj.fn : Symbol(Obj.fn, Decl(b.js, 0, 22))
|
||||
>Obj : Symbol(Obj, Decl(b.js, 0, 6), Decl(b.js, 0, 22))
|
||||
>fn : Symbol(Obj.fn, Decl(b.js, 0, 22))
|
||||
>Obj : Symbol(Obj, Decl(b.js, 0, 6))
|
||||
|
||||
|
|
|
@ -8,12 +8,12 @@ export default Obj;
|
|||
|
||||
=== tests/cases/compiler/b.js ===
|
||||
import Obj from './a';
|
||||
>Obj : typeof Obj
|
||||
>Obj : {}
|
||||
|
||||
Obj.fn = function() {};
|
||||
>Obj.fn = function() {} : () => void
|
||||
>Obj.fn : () => void
|
||||
>Obj : typeof Obj
|
||||
>fn : () => void
|
||||
>Obj.fn : error
|
||||
>Obj : {}
|
||||
>fn : any
|
||||
>function() {} : () => void
|
||||
|
||||
|
|
|
@ -4,10 +4,8 @@ export var hurk = {}
|
|||
|
||||
=== tests/cases/conformance/salsa/bug24658.js ===
|
||||
import { hurk } from './mod1'
|
||||
>hurk : Symbol(hurk, Decl(bug24658.js, 0, 8), Decl(bug24658.js, 0, 29))
|
||||
>hurk : Symbol(hurk, Decl(bug24658.js, 0, 8))
|
||||
|
||||
hurk.expando = 4
|
||||
>hurk.expando : Symbol(hurk.expando, Decl(bug24658.js, 0, 29))
|
||||
>hurk : Symbol(hurk, Decl(bug24658.js, 0, 8), Decl(bug24658.js, 0, 29))
|
||||
>expando : Symbol(hurk.expando, Decl(bug24658.js, 0, 29))
|
||||
>hurk : Symbol(hurk, Decl(bug24658.js, 0, 8))
|
||||
|
||||
|
|
|
@ -5,12 +5,12 @@ export var hurk = {}
|
|||
|
||||
=== tests/cases/conformance/salsa/bug24658.js ===
|
||||
import { hurk } from './mod1'
|
||||
>hurk : typeof hurk
|
||||
>hurk : {}
|
||||
|
||||
hurk.expando = 4
|
||||
>hurk.expando = 4 : 4
|
||||
>hurk.expando : number
|
||||
>hurk : typeof hurk
|
||||
>expando : number
|
||||
>hurk.expando : any
|
||||
>hurk : {}
|
||||
>expando : any
|
||||
>4 : 4
|
||||
|
||||
|
|
24
tests/cases/conformance/salsa/expandoOnAlias.ts
Normal file
24
tests/cases/conformance/salsa/expandoOnAlias.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @declaration: true
|
||||
// @emitDeclarationOnly: true
|
||||
|
||||
// @Filename: vue.js
|
||||
export class Vue {}
|
||||
export const config = { x: 0 };
|
||||
|
||||
// @Filename: test.js
|
||||
import { Vue, config } from "./vue";
|
||||
|
||||
// Expando declarations aren't allowed on aliases.
|
||||
Vue.config = {};
|
||||
new Vue();
|
||||
|
||||
// This is not an expando declaration; it's just a plain property assignment.
|
||||
config.x = 1;
|
||||
|
||||
// This is not an expando declaration; it works because non-strict JS allows
|
||||
// loosey goosey assignment on objects.
|
||||
config.y = {};
|
||||
config.x;
|
||||
config.y;
|
Loading…
Reference in a new issue