diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 38600b3fc14..4a600f5a62f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -186,7 +186,11 @@ namespace ts { }, isValidPropertyAccess: (node, propertyName) => { node = getParseTreeNode(node, isPropertyAccessOrQualifiedName); - return node ? isValidPropertyAccess(node, escapeLeadingUnderscores(propertyName)) : false; + return !!node && isValidPropertyAccess(node, escapeLeadingUnderscores(propertyName)); + }, + isValidPropertyAccessForCompletions: (node, type, property) => { + node = getParseTreeNode(node, isPropertyAccessExpression); + return !!node && isValidPropertyAccessForCompletions(node, type, property); }, getSignatureFromDeclaration: declaration => { declaration = getParseTreeNode(declaration, isFunctionLike); @@ -4678,6 +4682,7 @@ namespace ts { } else if (isJSDocPropertyTag(declaration) || isPropertyAccessExpression(declaration) + || isIdentifier(declaration) || isMethodDeclaration(declaration) && !isObjectLiteralMethod(declaration)) { // TODO: Mimics old behavior from incorrect usage of getWidenedTypeForVariableLikeDeclaration, but seems incorrect type = tryGetTypeFromEffectiveTypeNode(declaration) || anyType; @@ -16042,13 +16047,24 @@ namespace ts { } function isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: __String): boolean { - const left = node.kind === SyntaxKind.PropertyAccessExpression - ? (node).expression - : (node).left; - + const left = node.kind === SyntaxKind.PropertyAccessExpression ? node.expression : node.left; return isValidPropertyAccessWithType(node, left, propertyName, getWidenedType(checkExpression(left))); } + function isValidPropertyAccessForCompletions(node: PropertyAccessExpression, type: Type, property: Symbol): boolean { + return isValidPropertyAccessWithType(node, node.expression, property.escapedName, type) + && (!(property.flags & ts.SymbolFlags.Method) || isValidMethodAccess(property, type)); + } + function isValidMethodAccess(method: Symbol, type: Type) { + const propType = getTypeOfFuncClassEnumModule(method); + const signatures = getSignaturesOfType(propType, SignatureKind.Call); + Debug.assert(signatures.length !== 0); + return signatures.some(sig => { + const thisType = getThisTypeOfSignature(sig); + return !thisType || isTypeAssignableTo(type, thisType); + }); + } + function isValidPropertyAccessWithType( node: PropertyAccessExpression | QualifiedName, left: LeftHandSideExpression | QualifiedName, @@ -22724,7 +22740,12 @@ namespace ts { const t = getTypeFromTypeNode(typeRefNode); if (t !== unknownType) { if (isValidBaseType(t)) { - checkTypeAssignableTo(typeWithThis, getTypeWithThisArgument(t, type.thisType), node.name || node, Diagnostics.Class_0_incorrectly_implements_interface_1); + checkTypeAssignableTo(typeWithThis, + getTypeWithThisArgument(t, type.thisType), + node.name || node, + t.symbol.flags & SymbolFlags.Class ? + Diagnostics.Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass : + Diagnostics.Class_0_incorrectly_implements_interface_1); } else { error(typeRefNode, Diagnostics.A_class_may_only_implement_another_class_or_interface); diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 336def7ea52..826efa6994b 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2276,6 +2276,10 @@ "category": "Error", "code": 2719 }, + "Class '{0}' incorrectly implements class '{1}'. Did you mean to extend '{1}' and inherit its members as a subclass?": { + "category": "Error", + "code": 2720 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/src/compiler/program.ts b/src/compiler/program.ts index de106bae2cd..3274e81ce81 100755 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -241,22 +241,28 @@ namespace ts { return errorMessage; } - const redForegroundEscapeSequence = "\u001b[91m"; - const yellowForegroundEscapeSequence = "\u001b[93m"; - const blueForegroundEscapeSequence = "\u001b[93m"; + /** @internal */ + export enum ForegroundColorEscapeSequences { + Grey = "\u001b[90m", + Red = "\u001b[91m", + Yellow = "\u001b[93m", + Blue = "\u001b[94m", + Cyan = "\u001b[96m" + } const gutterStyleSequence = "\u001b[30;47m"; const gutterSeparator = " "; const resetEscapeSequence = "\u001b[0m"; const ellipsis = "..."; function getCategoryFormat(category: DiagnosticCategory): string { switch (category) { - case DiagnosticCategory.Warning: return yellowForegroundEscapeSequence; - case DiagnosticCategory.Error: return redForegroundEscapeSequence; - case DiagnosticCategory.Message: return blueForegroundEscapeSequence; + case DiagnosticCategory.Warning: return ForegroundColorEscapeSequences.Yellow; + case DiagnosticCategory.Error: return ForegroundColorEscapeSequences.Red; + case DiagnosticCategory.Message: return ForegroundColorEscapeSequences.Blue; } } - function formatAndReset(text: string, formatStyle: string) { + /** @internal */ + export function formatColorAndReset(text: string, formatStyle: string) { return formatStyle + text + resetEscapeSequence; } @@ -289,7 +295,7 @@ namespace ts { // If the error spans over 5 lines, we'll only show the first 2 and last 2 lines, // so we'll skip ahead to the second-to-last line. if (hasMoreThanFiveLines && firstLine + 1 < i && i < lastLine - 1) { - context += formatAndReset(padLeft(ellipsis, gutterWidth), gutterStyleSequence) + gutterSeparator + host.getNewLine(); + context += formatColorAndReset(padLeft(ellipsis, gutterWidth), gutterStyleSequence) + gutterSeparator + host.getNewLine(); i = lastLine - 1; } @@ -300,12 +306,12 @@ namespace ts { lineContent = lineContent.replace("\t", " "); // convert tabs to single spaces // Output the gutter and the actual contents of the line. - context += formatAndReset(padLeft(i + 1 + "", gutterWidth), gutterStyleSequence) + gutterSeparator; + context += formatColorAndReset(padLeft(i + 1 + "", gutterWidth), gutterStyleSequence) + gutterSeparator; context += lineContent + host.getNewLine(); // Output the gutter and the error span for the line using tildes. - context += formatAndReset(padLeft("", gutterWidth), gutterStyleSequence) + gutterSeparator; - context += redForegroundEscapeSequence; + context += formatColorAndReset(padLeft("", gutterWidth), gutterStyleSequence) + gutterSeparator; + context += ForegroundColorEscapeSequences.Red; if (i === firstLine) { // If we're on the last line, then limit it to the last character of the last line. // Otherwise, we'll just squiggle the rest of the line, giving 'slice' no end position. @@ -324,13 +330,19 @@ namespace ts { context += resetEscapeSequence; } - output += host.getNewLine(); - output += `${ relativeFileName }(${ firstLine + 1 },${ firstLineChar + 1 }): `; + output += formatColorAndReset(relativeFileName, ForegroundColorEscapeSequences.Cyan); + output += "("; + output += formatColorAndReset(`${ firstLine + 1 }`, ForegroundColorEscapeSequences.Yellow); + output += ","; + output += formatColorAndReset(`${ firstLineChar + 1 }`, ForegroundColorEscapeSequences.Yellow); + output += "): "; } const categoryColor = getCategoryFormat(diagnostic.category); const category = DiagnosticCategory[diagnostic.category].toLowerCase(); - output += `${ formatAndReset(category, categoryColor) } TS${ diagnostic.code }: ${ flattenDiagnosticMessageText(diagnostic.messageText, host.getNewLine()) }`; + output += formatColorAndReset(category, categoryColor); + output += formatColorAndReset(` TS${ diagnostic.code }: `, ForegroundColorEscapeSequences.Grey); + output += flattenDiagnosticMessageText(diagnostic.messageText, host.getNewLine()); if (diagnostic.file) { output += host.getNewLine(); @@ -339,7 +351,7 @@ namespace ts { output += host.getNewLine(); } - return output; + return output + host.getNewLine(); } export function flattenDiagnosticMessageText(messageText: string | DiagnosticMessageChain, newLine: string): string { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 83d70c90122..dfd6831be42 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2785,6 +2785,8 @@ namespace ts { getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): string | number | undefined; isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean; + /** Exclude accesses to private properties or methods with a `this` parameter that `type` doesn't satisfy. */ + /* @internal */ isValidPropertyAccessForCompletions(node: PropertyAccessExpression, type: Type, property: Symbol): boolean; /** Follow all aliases to get the original symbol. */ getAliasedSymbol(symbol: Symbol): Symbol; /** Follow a *single* alias to get the immediately aliased symbol. */ diff --git a/src/compiler/watch.ts b/src/compiler/watch.ts index 35692531d05..b4ed1c1ac1b 100644 --- a/src/compiler/watch.ts +++ b/src/compiler/watch.ts @@ -48,6 +48,15 @@ namespace ts { }; } + /** @internal */ + export function createWatchDiagnosticReporterWithColor(system = sys): DiagnosticReporter { + return diagnostic => { + let output = `[${ formatColorAndReset(new Date().toLocaleTimeString(), ForegroundColorEscapeSequences.Grey) }] `; + output += `${flattenDiagnosticMessageText(diagnostic.messageText, system.newLine)}${system.newLine + system.newLine + system.newLine}`; + system.write(output); + }; + } + export function reportDiagnostics(diagnostics: Diagnostic[], reportDiagnostic: DiagnosticReporter): void { for (const diagnostic of diagnostics) { reportDiagnostic(diagnostic); @@ -131,7 +140,7 @@ namespace ts { reportWatchDiagnostic?: DiagnosticReporter ): WatchingSystemHost { reportDiagnostic = reportDiagnostic || createDiagnosticReporter(system, pretty ? reportDiagnosticWithColorAndContext : reportDiagnosticSimply); - reportWatchDiagnostic = reportWatchDiagnostic || createWatchDiagnosticReporter(system); + reportWatchDiagnostic = reportWatchDiagnostic || pretty ? createWatchDiagnosticReporterWithColor(system) : createWatchDiagnosticReporter(system); parseConfigFile = parseConfigFile || ts.parseConfigFile; return { system, diff --git a/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl index 751c7b8a741..d0457b5595e 100644 --- a/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -154,7 +154,7 @@ - + @@ -1384,7 +1384,7 @@ - + diff --git a/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl index 1dc3c392642..701d3e15ced 100644 --- a/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -3247,7 +3247,7 @@ - + @@ -6646,7 +6646,7 @@ - + diff --git a/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl index 4f0153ab129..8131e17425e 100644 --- a/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -2191,7 +2191,7 @@ - + diff --git a/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl index 0ef3945d275..7bd660e8d68 100644 --- a/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -436,7 +436,7 @@ - + @@ -523,7 +523,7 @@ - + @@ -1420,7 +1420,7 @@ - + @@ -1432,7 +1432,7 @@ - + @@ -3465,15 +3465,6 @@ - - - - - - - - - diff --git a/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl index 17e755bb6f9..bc947f210ea 100644 --- a/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -1060,7 +1060,7 @@ - + @@ -1105,7 +1105,7 @@ - + @@ -1978,7 +1978,7 @@ - + @@ -2158,7 +2158,7 @@ - + @@ -2581,7 +2581,7 @@ - + @@ -2827,7 +2827,7 @@ - + @@ -2854,7 +2854,7 @@ - + @@ -2926,7 +2926,7 @@ - + @@ -2935,7 +2935,7 @@ - + @@ -2944,7 +2944,7 @@ - + @@ -3028,7 +3028,7 @@ - + @@ -3046,7 +3046,7 @@ - + @@ -3763,7 +3763,7 @@ - + @@ -3886,7 +3886,7 @@ - + @@ -3895,7 +3895,7 @@ - + @@ -3904,7 +3904,7 @@ - + @@ -6289,7 +6289,7 @@ - + @@ -7141,7 +7141,7 @@ - + @@ -8473,7 +8473,7 @@ - + @@ -8482,7 +8482,7 @@ - + diff --git a/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl index 9d34467e790..d1bb0c437ba 100644 --- a/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -418,7 +418,7 @@ - + @@ -1105,7 +1105,7 @@ - + @@ -2185,7 +2185,7 @@ - + @@ -2194,7 +2194,7 @@ - + @@ -2581,7 +2581,7 @@ - + @@ -2926,7 +2926,7 @@ - + @@ -2944,7 +2944,7 @@ - + @@ -3895,7 +3895,7 @@ - + @@ -4927,7 +4927,7 @@ - + @@ -5506,7 +5506,7 @@ - + @@ -8473,7 +8473,7 @@ - + @@ -8482,7 +8482,7 @@ - + @@ -8509,7 +8509,7 @@ - + diff --git a/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl index cbe3ce88321..0e5bddb2fc2 100644 --- a/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -1374,7 +1374,7 @@ - + @@ -1383,7 +1383,7 @@ - + diff --git a/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl index c43b4d8409b..957d3588185 100644 --- a/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -276,7 +276,7 @@ - + @@ -411,7 +411,7 @@ - + @@ -1050,7 +1050,7 @@ - + @@ -1095,7 +1095,7 @@ - + @@ -2184,7 +2184,7 @@ - + @@ -2907,7 +2907,7 @@ - + @@ -2916,7 +2916,7 @@ - + @@ -2925,7 +2925,7 @@ - + @@ -2934,7 +2934,7 @@ - + @@ -2943,7 +2943,7 @@ - + @@ -2955,7 +2955,7 @@ - + @@ -3876,7 +3876,7 @@ - + @@ -3885,7 +3885,7 @@ - + @@ -6936,7 +6936,7 @@ - + @@ -7074,7 +7074,7 @@ - + diff --git a/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl index 4aff7e0a2bd..2ad03fe4c41 100644 --- a/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -3036,7 +3036,7 @@ - + @@ -3455,15 +3455,6 @@ - - - - - - - - - diff --git a/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts index f7d5a4b9342..0236b0c79b7 100644 --- a/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts +++ b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts @@ -1,6 +1,7 @@ /* @internal */ namespace ts.codefix { - const errorCodes = [Diagnostics.Class_0_incorrectly_implements_interface_1.code]; + const errorCodes = [Diagnostics.Class_0_incorrectly_implements_interface_1.code, + Diagnostics.Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass.code]; const fixId = "fixClassIncorrectlyImplementsInterface"; // TODO: share a group with fixClassDoesntImplementInheritedAbstractMember? registerCodeFix({ errorCodes, diff --git a/src/services/completions.ts b/src/services/completions.ts index a264ad10bc7..51553a4a6b7 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -238,7 +238,7 @@ namespace ts.Completions { function getStringLiteralCompletionEntries(sourceFile: SourceFile, position: number, typeChecker: TypeChecker, compilerOptions: CompilerOptions, host: LanguageServiceHost, log: Log): CompletionInfo | undefined { const node = findPrecedingToken(position, sourceFile); - if (!node || node.kind !== SyntaxKind.StringLiteral) { + if (!node || (node.kind !== SyntaxKind.StringLiteral && node.kind !== SyntaxKind.NoSubstitutionTemplateLiteral)) { return undefined; } @@ -303,7 +303,7 @@ namespace ts.Completions { // Get completion for string literal from string literal type // i.e. var x: "hi" | "hello" = "/*completion position*/" - return getStringLiteralCompletionEntriesFromType(typeChecker.getContextualType(node), typeChecker); + return getStringLiteralCompletionEntriesFromType(typeChecker.getContextualType(node), typeChecker); } } @@ -918,9 +918,8 @@ namespace ts.Completions { symbols.push(...getPropertiesForCompletion(type, typeChecker, /*isForAccess*/ true)); } else { - // Filter private properties for (const symbol of type.getApparentProperties()) { - if (typeChecker.isValidPropertyAccess((node.parent), symbol.name)) { + if (typeChecker.isValidPropertyAccessForCompletions((node.parent), type, symbol)) { symbols.push(symbol); } } @@ -1761,7 +1760,10 @@ namespace ts.Completions { return true; } - return isDeclarationName(contextToken) && !isJsxAttribute(contextToken.parent); + return isDeclarationName(contextToken) + && !isJsxAttribute(contextToken.parent) + // Don't block completions if we're in `class C /**/`, because we're *past* the end of the identifier and might want to complete `extends`. + && !(isClassLike(contextToken.parent) && position > previousToken.end); } function isFunctionLikeButNotConstructor(kind: SyntaxKind) { @@ -2119,8 +2121,7 @@ namespace ts.Completions { /** * Gets all properties on a type, but if that type is a union of several types, - * tries to only include those types which declare properties, not methods. - * This ensures that we don't try providing completions for all the methods on e.g. Array. + * excludes array-like types or callable/constructable types. */ function getPropertiesForCompletion(type: Type, checker: TypeChecker, isForAccess: boolean): Symbol[] { if (!(type.flags & TypeFlags.Union)) { diff --git a/tests/baselines/reference/classImplementsClass2.errors.txt b/tests/baselines/reference/classImplementsClass2.errors.txt index 49eeed75fe0..4d82142e5ba 100644 --- a/tests/baselines/reference/classImplementsClass2.errors.txt +++ b/tests/baselines/reference/classImplementsClass2.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/classImplementsClass2.ts(2,7): error TS2420: Class 'C' incorrectly implements interface 'A'. +tests/cases/compiler/classImplementsClass2.ts(2,7): error TS2720: Class 'C' incorrectly implements class 'A'. Did you mean to extend 'A' and inherit its members as a subclass? Property 'foo' is missing in type 'C'. tests/cases/compiler/classImplementsClass2.ts(13,1): error TS2322: Type 'C' is not assignable to type 'C2'. Property 'foo' is missing in type 'C'. @@ -8,8 +8,8 @@ tests/cases/compiler/classImplementsClass2.ts(13,1): error TS2322: Type 'C' is n class A { foo(): number { return 1; } } class C implements A {} // error ~ -!!! error TS2420: Class 'C' incorrectly implements interface 'A'. -!!! error TS2420: Property 'foo' is missing in type 'C'. +!!! error TS2720: Class 'C' incorrectly implements class 'A'. Did you mean to extend 'A' and inherit its members as a subclass? +!!! error TS2720: Property 'foo' is missing in type 'C'. class C2 extends A { foo() { diff --git a/tests/baselines/reference/classImplementsClass4.errors.txt b/tests/baselines/reference/classImplementsClass4.errors.txt index ecc9d6d8582..2ac005ca40a 100644 --- a/tests/baselines/reference/classImplementsClass4.errors.txt +++ b/tests/baselines/reference/classImplementsClass4.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/classImplementsClass4.ts(5,7): error TS2420: Class 'C' incorrectly implements interface 'A'. +tests/cases/compiler/classImplementsClass4.ts(5,7): error TS2720: Class 'C' incorrectly implements class 'A'. Did you mean to extend 'A' and inherit its members as a subclass? Property 'x' is missing in type 'C'. tests/cases/compiler/classImplementsClass4.ts(16,1): error TS2322: Type 'C' is not assignable to type 'C2'. Property 'x' is missing in type 'C'. @@ -11,8 +11,8 @@ tests/cases/compiler/classImplementsClass4.ts(16,1): error TS2322: Type 'C' is n } class C implements A { ~ -!!! error TS2420: Class 'C' incorrectly implements interface 'A'. -!!! error TS2420: Property 'x' is missing in type 'C'. +!!! error TS2720: Class 'C' incorrectly implements class 'A'. Did you mean to extend 'A' and inherit its members as a subclass? +!!! error TS2720: Property 'x' is missing in type 'C'. foo() { return 1; } diff --git a/tests/baselines/reference/classImplementsClass5.errors.txt b/tests/baselines/reference/classImplementsClass5.errors.txt index 076120fdbaf..a291da15407 100644 --- a/tests/baselines/reference/classImplementsClass5.errors.txt +++ b/tests/baselines/reference/classImplementsClass5.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/classImplementsClass5.ts(5,7): error TS2420: Class 'C' incorrectly implements interface 'A'. +tests/cases/compiler/classImplementsClass5.ts(5,7): error TS2720: Class 'C' incorrectly implements class 'A'. Did you mean to extend 'A' and inherit its members as a subclass? Types have separate declarations of a private property 'x'. tests/cases/compiler/classImplementsClass5.ts(16,1): error TS2322: Type 'C2' is not assignable to type 'C'. Types have separate declarations of a private property 'x'. @@ -13,8 +13,8 @@ tests/cases/compiler/classImplementsClass5.ts(17,1): error TS2322: Type 'C' is n } class C implements A { ~ -!!! error TS2420: Class 'C' incorrectly implements interface 'A'. -!!! error TS2420: Types have separate declarations of a private property 'x'. +!!! error TS2720: Class 'C' incorrectly implements class 'A'. Did you mean to extend 'A' and inherit its members as a subclass? +!!! error TS2720: Types have separate declarations of a private property 'x'. private x = 1; foo() { return 1; diff --git a/tests/baselines/reference/classImplementsClass7.errors.txt b/tests/baselines/reference/classImplementsClass7.errors.txt new file mode 100644 index 00000000000..fef48518dc9 --- /dev/null +++ b/tests/baselines/reference/classImplementsClass7.errors.txt @@ -0,0 +1,14 @@ +tests/cases/compiler/classImplementsClass7.ts(5,7): error TS2720: Class 'B' incorrectly implements class 'A'. Did you mean to extend 'A' and inherit its members as a subclass? + Property 'x' is missing in type 'B'. + + +==== tests/cases/compiler/classImplementsClass7.ts (1 errors) ==== + class A { + private x: number; + } + + class B implements A {} + ~ +!!! error TS2720: Class 'B' incorrectly implements class 'A'. Did you mean to extend 'A' and inherit its members as a subclass? +!!! error TS2720: Property 'x' is missing in type 'B'. + \ No newline at end of file diff --git a/tests/baselines/reference/classImplementsClass7.js b/tests/baselines/reference/classImplementsClass7.js new file mode 100644 index 00000000000..bbb2fde3391 --- /dev/null +++ b/tests/baselines/reference/classImplementsClass7.js @@ -0,0 +1,19 @@ +//// [classImplementsClass7.ts] +class A { + private x: number; +} + +class B implements A {} + + +//// [classImplementsClass7.js] +var A = /** @class */ (function () { + function A() { + } + return A; +}()); +var B = /** @class */ (function () { + function B() { + } + return B; +}()); diff --git a/tests/baselines/reference/classImplementsClass7.symbols b/tests/baselines/reference/classImplementsClass7.symbols new file mode 100644 index 00000000000..b72e9dc049f --- /dev/null +++ b/tests/baselines/reference/classImplementsClass7.symbols @@ -0,0 +1,12 @@ +=== tests/cases/compiler/classImplementsClass7.ts === +class A { +>A : Symbol(A, Decl(classImplementsClass7.ts, 0, 0)) + + private x: number; +>x : Symbol(A.x, Decl(classImplementsClass7.ts, 0, 9)) +} + +class B implements A {} +>B : Symbol(B, Decl(classImplementsClass7.ts, 2, 1)) +>A : Symbol(A, Decl(classImplementsClass7.ts, 0, 0)) + diff --git a/tests/baselines/reference/classImplementsClass7.types b/tests/baselines/reference/classImplementsClass7.types new file mode 100644 index 00000000000..42def37193c --- /dev/null +++ b/tests/baselines/reference/classImplementsClass7.types @@ -0,0 +1,12 @@ +=== tests/cases/compiler/classImplementsClass7.ts === +class A { +>A : A + + private x: number; +>x : number +} + +class B implements A {} +>B : B +>A : A + diff --git a/tests/baselines/reference/classImplementsMergedClassInterface.errors.txt b/tests/baselines/reference/classImplementsMergedClassInterface.errors.txt index 3e62e72be84..3d2e721a955 100644 --- a/tests/baselines/reference/classImplementsMergedClassInterface.errors.txt +++ b/tests/baselines/reference/classImplementsMergedClassInterface.errors.txt @@ -1,8 +1,8 @@ -tests/cases/conformance/classes/classDeclarations/classImplementsMergedClassInterface.ts(9,7): error TS2420: Class 'C2' incorrectly implements interface 'C1'. +tests/cases/conformance/classes/classDeclarations/classImplementsMergedClassInterface.ts(9,7): error TS2720: Class 'C2' incorrectly implements class 'C1'. Did you mean to extend 'C1' and inherit its members as a subclass? Property 'x' is missing in type 'C2'. -tests/cases/conformance/classes/classDeclarations/classImplementsMergedClassInterface.ts(12,7): error TS2420: Class 'C3' incorrectly implements interface 'C1'. +tests/cases/conformance/classes/classDeclarations/classImplementsMergedClassInterface.ts(12,7): error TS2720: Class 'C3' incorrectly implements class 'C1'. Did you mean to extend 'C1' and inherit its members as a subclass? Property 'y' is missing in type 'C3'. -tests/cases/conformance/classes/classDeclarations/classImplementsMergedClassInterface.ts(16,7): error TS2420: Class 'C4' incorrectly implements interface 'C1'. +tests/cases/conformance/classes/classDeclarations/classImplementsMergedClassInterface.ts(16,7): error TS2720: Class 'C4' incorrectly implements class 'C1'. Did you mean to extend 'C1' and inherit its members as a subclass? Property 'x' is missing in type 'C4'. @@ -17,21 +17,21 @@ tests/cases/conformance/classes/classDeclarations/classImplementsMergedClassInte class C2 implements C1 { // error -- missing x ~~ -!!! error TS2420: Class 'C2' incorrectly implements interface 'C1'. -!!! error TS2420: Property 'x' is missing in type 'C2'. +!!! error TS2720: Class 'C2' incorrectly implements class 'C1'. Did you mean to extend 'C1' and inherit its members as a subclass? +!!! error TS2720: Property 'x' is missing in type 'C2'. } class C3 implements C1 { // error -- missing y ~~ -!!! error TS2420: Class 'C3' incorrectly implements interface 'C1'. -!!! error TS2420: Property 'y' is missing in type 'C3'. +!!! error TS2720: Class 'C3' incorrectly implements class 'C1'. Did you mean to extend 'C1' and inherit its members as a subclass? +!!! error TS2720: Property 'y' is missing in type 'C3'. x : number; } class C4 implements C1 { // error -- missing x ~~ -!!! error TS2420: Class 'C4' incorrectly implements interface 'C1'. -!!! error TS2420: Property 'x' is missing in type 'C4'. +!!! error TS2720: Class 'C4' incorrectly implements class 'C1'. Did you mean to extend 'C1' and inherit its members as a subclass? +!!! error TS2720: Property 'x' is missing in type 'C4'. y : number; } diff --git a/tests/baselines/reference/extendAndImplementTheSameBaseType2.errors.txt b/tests/baselines/reference/extendAndImplementTheSameBaseType2.errors.txt index a44c95377dc..799fc7bb8b0 100644 --- a/tests/baselines/reference/extendAndImplementTheSameBaseType2.errors.txt +++ b/tests/baselines/reference/extendAndImplementTheSameBaseType2.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/extendAndImplementTheSameBaseType2.ts(7,7): error TS2420: Class 'D' incorrectly implements interface 'C'. +tests/cases/compiler/extendAndImplementTheSameBaseType2.ts(7,7): error TS2720: Class 'D' incorrectly implements class 'C'. Did you mean to extend 'C' and inherit its members as a subclass? Types of property 'bar' are incompatible. Type '() => string' is not assignable to type '() => number'. Type 'string' is not assignable to type 'number'. @@ -15,10 +15,10 @@ tests/cases/compiler/extendAndImplementTheSameBaseType2.ts(16,5): error TS2322: } class D extends C implements C { ~ -!!! error TS2420: Class 'D' incorrectly implements interface 'C'. -!!! error TS2420: Types of property 'bar' are incompatible. -!!! error TS2420: Type '() => string' is not assignable to type '() => number'. -!!! error TS2420: Type 'string' is not assignable to type 'number'. +!!! error TS2720: Class 'D' incorrectly implements class 'C'. Did you mean to extend 'C' and inherit its members as a subclass? +!!! error TS2720: Types of property 'bar' are incompatible. +!!! error TS2720: Type '() => string' is not assignable to type '() => number'. +!!! error TS2720: Type 'string' is not assignable to type 'number'. baz() { } } diff --git a/tests/baselines/reference/genericSpecializations2.errors.txt b/tests/baselines/reference/genericSpecializations2.errors.txt index e570adb7912..99a6e2a6985 100644 --- a/tests/baselines/reference/genericSpecializations2.errors.txt +++ b/tests/baselines/reference/genericSpecializations2.errors.txt @@ -1,10 +1,10 @@ -tests/cases/compiler/genericSpecializations2.ts(7,7): error TS2420: Class 'IntFooBad' incorrectly implements interface 'IFoo'. +tests/cases/compiler/genericSpecializations2.ts(7,7): error TS2720: Class 'IntFooBad' incorrectly implements class 'IFoo'. Did you mean to extend 'IFoo' and inherit its members as a subclass? Types of property 'foo' are incompatible. Type '(x: string) => string' is not assignable to type '(x: T) => T'. Types of parameters 'x' and 'x' are incompatible. Type 'T' is not assignable to type 'string'. tests/cases/compiler/genericSpecializations2.ts(8,9): error TS2368: Type parameter name cannot be 'string'. -tests/cases/compiler/genericSpecializations2.ts(11,7): error TS2420: Class 'StringFoo2' incorrectly implements interface 'IFoo'. +tests/cases/compiler/genericSpecializations2.ts(11,7): error TS2720: Class 'StringFoo2' incorrectly implements class 'IFoo'. Did you mean to extend 'IFoo' and inherit its members as a subclass? Types of property 'foo' are incompatible. Type '(x: string) => string' is not assignable to type '(x: T) => T'. Types of parameters 'x' and 'x' are incompatible. @@ -21,11 +21,11 @@ tests/cases/compiler/genericSpecializations2.ts(12,9): error TS2368: Type parame class IntFooBad implements IFoo { ~~~~~~~~~ -!!! error TS2420: Class 'IntFooBad' incorrectly implements interface 'IFoo'. -!!! error TS2420: Types of property 'foo' are incompatible. -!!! error TS2420: Type '(x: string) => string' is not assignable to type '(x: T) => T'. -!!! error TS2420: Types of parameters 'x' and 'x' are incompatible. -!!! error TS2420: Type 'T' is not assignable to type 'string'. +!!! error TS2720: Class 'IntFooBad' incorrectly implements class 'IFoo'. Did you mean to extend 'IFoo' and inherit its members as a subclass? +!!! error TS2720: Types of property 'foo' are incompatible. +!!! error TS2720: Type '(x: string) => string' is not assignable to type '(x: T) => T'. +!!! error TS2720: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2720: Type 'T' is not assignable to type 'string'. foo(x: string): string { return null; } ~~~~~~ !!! error TS2368: Type parameter name cannot be 'string'. @@ -33,11 +33,11 @@ tests/cases/compiler/genericSpecializations2.ts(12,9): error TS2368: Type parame class StringFoo2 implements IFoo { ~~~~~~~~~~ -!!! error TS2420: Class 'StringFoo2' incorrectly implements interface 'IFoo'. -!!! error TS2420: Types of property 'foo' are incompatible. -!!! error TS2420: Type '(x: string) => string' is not assignable to type '(x: T) => T'. -!!! error TS2420: Types of parameters 'x' and 'x' are incompatible. -!!! error TS2420: Type 'T' is not assignable to type 'string'. +!!! error TS2720: Class 'StringFoo2' incorrectly implements class 'IFoo'. Did you mean to extend 'IFoo' and inherit its members as a subclass? +!!! error TS2720: Types of property 'foo' are incompatible. +!!! error TS2720: Type '(x: string) => string' is not assignable to type '(x: T) => T'. +!!! error TS2720: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2720: Type 'T' is not assignable to type 'string'. foo(x: string): string { return null; } ~~~~~~ !!! error TS2368: Type parameter name cannot be 'string'. diff --git a/tests/baselines/reference/prettyContextNotDebugAssertion.errors.txt b/tests/baselines/reference/prettyContextNotDebugAssertion.errors.txt index a621d52ebef..f03b87ba947 100644 --- a/tests/baselines/reference/prettyContextNotDebugAssertion.errors.txt +++ b/tests/baselines/reference/prettyContextNotDebugAssertion.errors.txt @@ -1,10 +1,10 @@ - -tests/cases/compiler/index.ts(2,1): error TS1005: '}' expected. +tests/cases/compiler/index.ts(2,1): error TS1005: '}' expected. 2    + ==== tests/cases/compiler/index.ts (1 errors) ==== if (true) { diff --git a/tests/baselines/reference/typeFromPropertyAssignmentOutOfOrder.symbols b/tests/baselines/reference/typeFromPropertyAssignmentOutOfOrder.symbols new file mode 100644 index 00000000000..fa526ebbe7d --- /dev/null +++ b/tests/baselines/reference/typeFromPropertyAssignmentOutOfOrder.symbols @@ -0,0 +1,28 @@ +=== tests/cases/conformance/salsa/index.js === +Common.Item = class I {} +>Common : Symbol(Common, Decl(index.js, 0, 0), Decl(roots.js, 0, 3)) +>I : Symbol(I, Decl(index.js, 0, 13)) + +Common.Object = class extends Common.Item {} +>Common : Symbol(Common, Decl(index.js, 0, 0), Decl(roots.js, 0, 3)) +>Common.Item : Symbol(Common.Item, Decl(index.js, 0, 0)) +>Common : Symbol(Common, Decl(index.js, 0, 0), Decl(roots.js, 0, 3)) +>Item : Symbol(Common.Item, Decl(index.js, 0, 0)) + +Workspace.Object = class extends Common.Object {} +>Workspace : Symbol(Workspace, Decl(index.js, 1, 44), Decl(roots.js, 1, 3)) +>Common.Object : Symbol(Common.Object, Decl(index.js, 0, 24)) +>Common : Symbol(Common, Decl(index.js, 0, 0), Decl(roots.js, 0, 3)) +>Object : Symbol(Common.Object, Decl(index.js, 0, 24)) + +/** @type {Workspace.Object} */ +var am; +>am : Symbol(am, Decl(index.js, 6, 3)) + +=== tests/cases/conformance/salsa/roots.js === +var Common = {}; +>Common : Symbol(Common, Decl(index.js, 0, 0), Decl(roots.js, 0, 3)) + +var Workspace = {}; +>Workspace : Symbol(Workspace, Decl(index.js, 1, 44), Decl(roots.js, 1, 3)) + diff --git a/tests/baselines/reference/typeFromPropertyAssignmentOutOfOrder.types b/tests/baselines/reference/typeFromPropertyAssignmentOutOfOrder.types new file mode 100644 index 00000000000..3fb6b6df1b4 --- /dev/null +++ b/tests/baselines/reference/typeFromPropertyAssignmentOutOfOrder.types @@ -0,0 +1,42 @@ +=== tests/cases/conformance/salsa/index.js === +Common.Item = class I {} +>Common.Item = class I {} : typeof I +>Common.Item : any +>Common : any +>Item : any +>class I {} : typeof I +>I : typeof I + +Common.Object = class extends Common.Item {} +>Common.Object = class extends Common.Item {} : typeof (Anonymous class) +>Common.Object : any +>Common : any +>Object : any +>class extends Common.Item {} : typeof (Anonymous class) +>Common.Item : any +>Common : any +>Item : any + +Workspace.Object = class extends Common.Object {} +>Workspace.Object = class extends Common.Object {} : typeof (Anonymous class) +>Workspace.Object : any +>Workspace : any +>Object : any +>class extends Common.Object {} : typeof (Anonymous class) +>Common.Object : any +>Common : any +>Object : any + +/** @type {Workspace.Object} */ +var am; +>am : (Anonymous class) + +=== tests/cases/conformance/salsa/roots.js === +var Common = {}; +>Common : any +>{} : { [x: string]: any; } + +var Workspace = {}; +>Workspace : any +>{} : { [x: string]: any; } + diff --git a/tests/baselines/reference/user/chrome-devtools-frontend.log b/tests/baselines/reference/user/chrome-devtools-frontend.log index c997005026f..ca43cccaa18 100644 --- a/tests/baselines/reference/user/chrome-devtools-frontend.log +++ b/tests/baselines/reference/user/chrome-devtools-frontend.log @@ -12,8 +12,8 @@ Standard output: ../../../../built/local/lib.dom.d.ts(9253,13): error TS2300: Duplicate identifier 'Request'. ../../../../built/local/lib.dom.d.ts(13511,11): error TS2300: Duplicate identifier 'Window'. ../../../../built/local/lib.dom.d.ts(13700,13): error TS2300: Duplicate identifier 'Window'. -../../../../built/local/lib.es5.d.ts(1322,11): error TS2300: Duplicate identifier 'ArrayLike'. -../../../../built/local/lib.es5.d.ts(1351,6): error TS2300: Duplicate identifier 'Record'. +../../../../built/local/lib.es5.d.ts(1321,11): error TS2300: Duplicate identifier 'ArrayLike'. +../../../../built/local/lib.es5.d.ts(1350,6): error TS2300: Duplicate identifier 'Record'. node_modules/chrome-devtools-frontend/front_end/Runtime.js(43,8): error TS2339: Property '_importScriptPathPrefix' does not exist on type 'Window'. node_modules/chrome-devtools-frontend/front_end/Runtime.js(95,28): error TS2339: Property 'response' does not exist on type 'EventTarget'. node_modules/chrome-devtools-frontend/front_end/Runtime.js(147,37): error TS2339: Property '_importScriptPathPrefix' does not exist on type 'Window'. diff --git a/tests/cases/compiler/classImplementsClass7.ts b/tests/cases/compiler/classImplementsClass7.ts new file mode 100644 index 00000000000..ab56cae56ce --- /dev/null +++ b/tests/cases/compiler/classImplementsClass7.ts @@ -0,0 +1,5 @@ +class A { + private x: number; +} + +class B implements A {} diff --git a/tests/cases/conformance/salsa/typeFromPropertyAssignmentOutOfOrder.ts b/tests/cases/conformance/salsa/typeFromPropertyAssignmentOutOfOrder.ts new file mode 100644 index 00000000000..d6f97375734 --- /dev/null +++ b/tests/cases/conformance/salsa/typeFromPropertyAssignmentOutOfOrder.ts @@ -0,0 +1,16 @@ +// @noEmit: true +// @allowJs: true +// @checkJs: true +// @target: es3 +// @filename: index.js +Common.Item = class I {} +Common.Object = class extends Common.Item {} + +Workspace.Object = class extends Common.Object {} + +/** @type {Workspace.Object} */ +var am; + +// @filename: roots.js +var Common = {}; +var Workspace = {}; diff --git a/tests/cases/fourslash/completionListAfterStringLiteralTypeWithNoSubstitutionTemplateLiteral.ts b/tests/cases/fourslash/completionListAfterStringLiteralTypeWithNoSubstitutionTemplateLiteral.ts new file mode 100644 index 00000000000..c5deac5123e --- /dev/null +++ b/tests/cases/fourslash/completionListAfterStringLiteralTypeWithNoSubstitutionTemplateLiteral.ts @@ -0,0 +1,8 @@ +/// + +////let count: 'one' | 'two'; +////count = `/**/` + +goTo.marker(); +verify.completionListContains('one'); +verify.completionListContains('two'); diff --git a/tests/cases/fourslash/completionsKeywordsExtends.ts b/tests/cases/fourslash/completionsKeywordsExtends.ts new file mode 100644 index 00000000000..065d30d1286 --- /dev/null +++ b/tests/cases/fourslash/completionsKeywordsExtends.ts @@ -0,0 +1,11 @@ +/// + +////class C/*a*/ /*b*/ { } + +// Tests that `isCompletionListBlocker` is true *at* the class name, but false *after* it. + +goTo.marker("a"); +verify.completionListIsEmpty(); + +goTo.marker("b"); +verify.completionListContains("extends"); diff --git a/tests/cases/fourslash/completionsMethodWithThisParameter.ts b/tests/cases/fourslash/completionsMethodWithThisParameter.ts new file mode 100644 index 00000000000..b455ba4f5b8 --- /dev/null +++ b/tests/cases/fourslash/completionsMethodWithThisParameter.ts @@ -0,0 +1,15 @@ +/// + +////class A { +//// value: T; // Make the type parameter actually matter +//// ms(this: A) {} +//// mo(this: A<{}>) {} +////} +//// +////const s = new A(); +////const n = new A(); +////s./*s*/; +////n./*n*/; + +verify.completionsAt("s", ["value", "ms", "mo"]); +verify.completionsAt("n", ["value", "mo"]); \ No newline at end of file