From 75f4e95e8571305db0f66e637cf2818cb242d418 Mon Sep 17 00:00:00 2001 From: Harsheet Kakar <42893005+HarsheetKakar@users.noreply.github.com> Date: Wed, 1 Jun 2022 05:17:07 +0530 Subject: [PATCH] Fix46246 (#46357) * changed error message for interface extending primitive type * moved interface check to different function * changed part of interface declaration to is extended by interface Co-authored-by: harsheetkakar Co-authored-by: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> --- src/compiler/checker.ts | 18 +++++++++++++++++- src/compiler/diagnosticMessages.json | 4 ++++ ...rorLocationForInterfaceExtension.errors.txt | 4 ++-- .../interfacedeclWithIndexerErrors.errors.txt | 15 ++++++++++++++- .../interfacedeclWithIndexerErrors.js | 7 +++++++ .../interfacedeclWithIndexerErrors.symbols | 17 ++++++++++++++--- .../interfacedeclWithIndexerErrors.types | 9 +++++++++ .../compiler/interfacedeclWithIndexerErrors.ts | 7 +++++++ 8 files changed, 74 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8ae4c79370c..e5f226a37b9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2478,7 +2478,12 @@ namespace ts { function checkAndReportErrorForUsingTypeAsValue(errorLocation: Node, name: __String, meaning: SymbolFlags): boolean { if (meaning & (SymbolFlags.Value & ~SymbolFlags.NamespaceModule)) { if (isPrimitiveTypeName(name)) { - error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here, unescapeLeadingUnderscores(name)); + if (isExtendedByInterface(errorLocation)) { + error(errorLocation, Diagnostics.An_interface_cannot_extend_a_primitive_type_like_0_an_interface_can_only_extend_named_types_and_classes, unescapeLeadingUnderscores(name)); + } + else { + error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here, unescapeLeadingUnderscores(name)); + } return true; } const symbol = resolveSymbol(resolveName(errorLocation, name, SymbolFlags.Type & ~SymbolFlags.Value, /*nameNotFoundMessage*/undefined, /*nameArg*/ undefined, /*isUse*/ false)); @@ -2499,6 +2504,17 @@ namespace ts { return false; } + function isExtendedByInterface(node: Node): boolean { + const grandparent = node.parent.parent; + const parentOfGrandparent = grandparent.parent; + if(grandparent && parentOfGrandparent){ + const isExtending = isHeritageClause(grandparent) && grandparent.token === SyntaxKind.ExtendsKeyword; + const isInterface = isInterfaceDeclaration(parentOfGrandparent); + return isExtending && isInterface; + } + return false; + } + function maybeMappedType(node: Node, symbol: Symbol) { const container = findAncestor(node.parent, n => isComputedPropertyName(n) || isPropertySignature(n) ? false : isTypeLiteralNode(n) || "quit") as TypeLiteralNode | undefined; diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 0bf7b8b3eb5..05717148ebc 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3475,6 +3475,10 @@ "category": "Error", "code": 2839 }, + "An interface cannot extend a primitive type like '{0}'; an interface can only extend named types and classes": { + "category": "Error", + "code": 2840 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/tests/baselines/reference/errorLocationForInterfaceExtension.errors.txt b/tests/baselines/reference/errorLocationForInterfaceExtension.errors.txt index 6ed1517335d..24a6309e129 100644 --- a/tests/baselines/reference/errorLocationForInterfaceExtension.errors.txt +++ b/tests/baselines/reference/errorLocationForInterfaceExtension.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/errorLocationForInterfaceExtension.ts(3,21): error TS2693: 'string' only refers to a type, but is being used as a value here. +tests/cases/compiler/errorLocationForInterfaceExtension.ts(3,21): error TS2840: An interface cannot extend a primitive type like 'string'; an interface can only extend named types and classes ==== tests/cases/compiler/errorLocationForInterfaceExtension.ts (1 errors) ==== @@ -6,5 +6,5 @@ tests/cases/compiler/errorLocationForInterfaceExtension.ts(3,21): error TS2693: interface x extends string { } ~~~~~~ -!!! error TS2693: 'string' only refers to a type, but is being used as a value here. +!!! error TS2840: An interface cannot extend a primitive type like 'string'; an interface can only extend named types and classes \ No newline at end of file diff --git a/tests/baselines/reference/interfacedeclWithIndexerErrors.errors.txt b/tests/baselines/reference/interfacedeclWithIndexerErrors.errors.txt index 2939a04948a..6aebe8a31f1 100644 --- a/tests/baselines/reference/interfacedeclWithIndexerErrors.errors.txt +++ b/tests/baselines/reference/interfacedeclWithIndexerErrors.errors.txt @@ -3,9 +3,11 @@ tests/cases/compiler/interfacedeclWithIndexerErrors.ts(14,5): error TS2411: Prop tests/cases/compiler/interfacedeclWithIndexerErrors.ts(15,5): error TS2411: Property 'p5' of type '(s: number) => string' is not assignable to 'string' index type '() => string'. tests/cases/compiler/interfacedeclWithIndexerErrors.ts(19,5): error TS2411: Property 'f3' of type '(a: string) => number' is not assignable to 'string' index type '() => string'. tests/cases/compiler/interfacedeclWithIndexerErrors.ts(20,5): error TS2411: Property 'f4' of type '(s: number) => string' is not assignable to 'string' index type '() => string'. +tests/cases/compiler/interfacedeclWithIndexerErrors.ts(44,21): error TS2840: An interface cannot extend a primitive type like 'number'; an interface can only extend named types and classes +tests/cases/compiler/interfacedeclWithIndexerErrors.ts(48,18): error TS2693: 'string' only refers to a type, but is being used as a value here. -==== tests/cases/compiler/interfacedeclWithIndexerErrors.ts (5 errors) ==== +==== tests/cases/compiler/interfacedeclWithIndexerErrors.ts (7 errors) ==== interface a0 { (): string; (a, b, c?: string): number; @@ -59,6 +61,17 @@ tests/cases/compiler/interfacedeclWithIndexerErrors.ts(20,5): error TS2411: Prop interface d extends a { } + interface e extends number { + ~~~~~~ +!!! error TS2840: An interface cannot extend a primitive type like 'number'; an interface can only extend named types and classes + } + + interface f { + prop: typeof string; + ~~~~~~ +!!! error TS2693: 'string' only refers to a type, but is being used as a value here. + } + class c1 implements a { } var instance2 = new c1(); \ No newline at end of file diff --git a/tests/baselines/reference/interfacedeclWithIndexerErrors.js b/tests/baselines/reference/interfacedeclWithIndexerErrors.js index 776d43b940d..599ac30590a 100644 --- a/tests/baselines/reference/interfacedeclWithIndexerErrors.js +++ b/tests/baselines/reference/interfacedeclWithIndexerErrors.js @@ -42,6 +42,13 @@ interface c extends a, b { interface d extends a { } +interface e extends number { +} + +interface f { + prop: typeof string; +} + class c1 implements a { } var instance2 = new c1(); diff --git a/tests/baselines/reference/interfacedeclWithIndexerErrors.symbols b/tests/baselines/reference/interfacedeclWithIndexerErrors.symbols index 32880f2cb91..1ae6cf85950 100644 --- a/tests/baselines/reference/interfacedeclWithIndexerErrors.symbols +++ b/tests/baselines/reference/interfacedeclWithIndexerErrors.symbols @@ -84,11 +84,22 @@ interface d extends a { >a : Symbol(a, Decl(interfacedeclWithIndexerErrors.ts, 29, 1)) } +interface e extends number { +>e : Symbol(e, Decl(interfacedeclWithIndexerErrors.ts, 41, 1)) +} + +interface f { +>f : Symbol(f, Decl(interfacedeclWithIndexerErrors.ts, 44, 1)) + + prop: typeof string; +>prop : Symbol(f.prop, Decl(interfacedeclWithIndexerErrors.ts, 46, 13)) +} + class c1 implements a { ->c1 : Symbol(c1, Decl(interfacedeclWithIndexerErrors.ts, 41, 1)) +>c1 : Symbol(c1, Decl(interfacedeclWithIndexerErrors.ts, 48, 1)) >a : Symbol(a, Decl(interfacedeclWithIndexerErrors.ts, 29, 1)) } var instance2 = new c1(); ->instance2 : Symbol(instance2, Decl(interfacedeclWithIndexerErrors.ts, 45, 3)) ->c1 : Symbol(c1, Decl(interfacedeclWithIndexerErrors.ts, 41, 1)) +>instance2 : Symbol(instance2, Decl(interfacedeclWithIndexerErrors.ts, 52, 3)) +>c1 : Symbol(c1, Decl(interfacedeclWithIndexerErrors.ts, 48, 1)) diff --git a/tests/baselines/reference/interfacedeclWithIndexerErrors.types b/tests/baselines/reference/interfacedeclWithIndexerErrors.types index 67259ae88b8..a2f9964449d 100644 --- a/tests/baselines/reference/interfacedeclWithIndexerErrors.types +++ b/tests/baselines/reference/interfacedeclWithIndexerErrors.types @@ -70,6 +70,15 @@ interface c extends a, b { interface d extends a { } +interface e extends number { +} + +interface f { + prop: typeof string; +>prop : any +>string : any +} + class c1 implements a { >c1 : c1 } diff --git a/tests/cases/compiler/interfacedeclWithIndexerErrors.ts b/tests/cases/compiler/interfacedeclWithIndexerErrors.ts index 4b836247796..054d5e044ac 100644 --- a/tests/cases/compiler/interfacedeclWithIndexerErrors.ts +++ b/tests/cases/compiler/interfacedeclWithIndexerErrors.ts @@ -41,6 +41,13 @@ interface c extends a, b { interface d extends a { } +interface e extends number { +} + +interface f { + prop: typeof string; +} + class c1 implements a { } var instance2 = new c1(); \ No newline at end of file