Skip to content
9 changes: 9 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ import {
getNamespaceDeclarationNode,
getNewTargetContainer,
getNonAugmentationDeclaration,
getNonModifierTokenPosOfNode,
getNormalizedAbsolutePath,
getObjectFlags,
getOriginalNode,
Expand Down Expand Up @@ -46886,6 +46887,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {

if (isIdentifier(node.name)) {
checkCollisionsForDeclarationName(node, node.name);
if (!(node.flags & (NodeFlags.Namespace | NodeFlags.GlobalAugmentation))) {
const sourceFile = getSourceFileOfNode(node);
const pos = getNonModifierTokenPosOfNode(node);
const span = getSpanOfTokenAtPosition(sourceFile, pos);
suggestionDiagnostics.add(
createFileDiagnostic(sourceFile, span.start, span.length, Diagnostics.A_namespace_declaration_should_not_be_declared_using_the_module_keyword_Please_use_the_namespace_keyword_instead),
);
}
}

checkExportsOnMergedDeclarations(node);
Expand Down
5 changes: 5 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -1813,6 +1813,11 @@
"category": "Error",
"code": 1539
},
"A 'namespace' declaration should not be declared using the 'module' keyword. Please use the 'namespace' keyword instead.": {
"category": "Suggestion",
"code": 1540,
"reportsDeprecated": true
},

"The types of '{0}' are incompatible between these types.": {
"category": "Error",
Expand Down
10 changes: 10 additions & 0 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1259,6 +1259,16 @@ export function getNonDecoratorTokenPosOfNode(node: Node, sourceFile?: SourceFil
return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, lastDecorator.end);
}

/** @internal */
export function getNonModifierTokenPosOfNode(node: Node, sourceFile?: SourceFileLike): number {
const lastModifier = !nodeIsMissing(node) && canHaveModifiers(node) && node.modifiers ? last(node.modifiers) : undefined;
if (!lastModifier) {
return getTokenPosOfNode(node, sourceFile);
}

return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, lastModifier.end);
}

/** @internal */
export function getSourceTextOfNodeFromSourceFile(sourceFile: SourceFile, node: Node, includeTrivia = false): string {
return getTextOfNodeFromSourceText(sourceFile.text, node, includeTrivia);
Expand Down
30 changes: 30 additions & 0 deletions tests/cases/fourslash/moduleDeclarationDeprecated_suggestion1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
///<reference path="fourslash.ts" />
// @Filename: a.ts
////[|module|] mod1 { export let x: number }
////declare [|module|] mod2 { export let x: number }
////export [|module|] mod3 { export let x: number }
////export declare [|module|] mod4 { export let x: number }
////namespace mod5 { export let x: number }
////declare namespace mod6 { export let x: number }
////declare module "module-augmentation" {}
////declare global {}
////mod1.x = 1;
////mod2.x = 1;
////mod5.x = 1;
////mod6.x = 1;

// @Filename: b.ts
////module "global-ambient-module" {}

goTo.file("a.ts")
const diagnostics = test.ranges().map(range => ({
code: 1540,
message: "A 'namespace' declaration should not be declared using the 'module' keyword. Please use the 'namespace' keyword instead.",
reportsDeprecated: true,
range,
}));
verify.getSuggestionDiagnostics(diagnostics)

goTo.file("b.ts")
verify.getSuggestionDiagnostics([])

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
///<reference path="fourslash.ts" />
// @Filename: a.ts
////declare module

const ranges = test.ranges();
verify.getSuggestionDiagnostics([])