From 694a985b4990e2f9e9904e0bdfbb82809f70d76e Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 22 May 2018 13:06:59 -0700 Subject: [PATCH] For completions, treat a '// @ts-check' file like a TypeScript one (#24321) --- src/services/completions.ts | 18 ++++++++++++------ .../getJavaScriptCompletions_tsCheck.ts | 17 +++++++++++++++++ 2 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 tests/cases/fourslash/getJavaScriptCompletions_tsCheck.ts diff --git a/src/services/completions.ts b/src/services/completions.ts index d8b0bbc138d..98579fa890f 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -47,7 +47,7 @@ namespace ts.Completions { return getLabelCompletionAtPosition(contextToken.parent); } - const completionData = getCompletionData(program, log, sourceFile, position, preferences, /*detailsEntryId*/ undefined); + const completionData = getCompletionData(program, log, sourceFile, isUncheckedFile(sourceFile, compilerOptions), position, preferences, /*detailsEntryId*/ undefined); if (!completionData) { return undefined; } @@ -121,7 +121,7 @@ namespace ts.Completions { const entries: CompletionEntry[] = []; - if (isSourceFileJavaScript(sourceFile)) { + if (isUncheckedFile(sourceFile, compilerOptions)) { const uniqueNames = getCompletionEntriesFromSymbols(symbols, entries, location, sourceFile, typeChecker, compilerOptions.target, log, completionKind, preferences, propertyAccessToConvert, isJsxInitializer, recommendedCompletion, symbolToOriginInfoMap); getJavaScriptCompletionEntries(sourceFile, location.pos, uniqueNames, compilerOptions.target, entries); } @@ -146,6 +146,10 @@ namespace ts.Completions { return { isGlobalCompletion: isInSnippetScope, isMemberCompletion, isNewIdentifierLocation, entries }; } + function isUncheckedFile(sourceFile: SourceFile, compilerOptions: CompilerOptions): boolean { + return isSourceFileJavaScript(sourceFile) && !isCheckJsEnabledForFile(sourceFile, compilerOptions); + } + function isMemberCompletionKind(kind: CompletionKind): boolean { switch (kind) { case CompletionKind.ObjectPropertyDeclaration: @@ -488,7 +492,8 @@ namespace ts.Completions { } function getSymbolCompletionFromEntryId(program: Program, log: Log, sourceFile: SourceFile, position: number, entryId: CompletionEntryIdentifier, ): SymbolCompletion | { type: "request", request: Request } | { type: "none" } { - const completionData = getCompletionData(program, log, sourceFile, position, { includeCompletionsForModuleExports: true, includeCompletionsWithInsertText: true }, entryId); + const compilerOptions = program.getCompilerOptions(); + const completionData = getCompletionData(program, log, sourceFile, isUncheckedFile(sourceFile, compilerOptions), position, { includeCompletionsForModuleExports: true, includeCompletionsWithInsertText: true }, entryId); if (!completionData) { return { type: "none" }; } @@ -504,7 +509,7 @@ namespace ts.Completions { // completion entry. return firstDefined(symbols, (symbol): SymbolCompletion => { // TODO: Shouldn't need return type annotation (GH#12632) const origin = symbolToOriginInfoMap[getSymbolId(symbol)]; - const info = getCompletionEntryDisplayNameForSymbol(symbol, program.getCompilerOptions().target, origin, completionKind); + const info = getCompletionEntryDisplayNameForSymbol(symbol, compilerOptions.target, origin, completionKind); return info && info.name === entryId.name && getSourceFromOrigin(origin) === entryId.source ? { type: "symbol" as "symbol", symbol, location, symbolToOriginInfoMap, previousToken, isJsxInitializer } : undefined; @@ -759,6 +764,7 @@ namespace ts.Completions { program: Program, log: (message: string) => void, sourceFile: SourceFile, + isUncheckedFile: boolean, position: number, preferences: Pick, detailsEntryId: CompletionEntryIdentifier | undefined, @@ -1058,7 +1064,7 @@ namespace ts.Completions { function addTypeProperties(type: Type): void { isNewIdentifierLocation = hasIndexSignature(type); - if (isSourceFileJavaScript(sourceFile)) { + if (isUncheckedFile) { // In javascript files, for union types, we don't just get the members that // the individual types have in common, we also include all the members that // each individual type has. This is because we're going to add all identifiers @@ -1203,7 +1209,7 @@ namespace ts.Completions { // If some file is using ES6 modules, assume that it's OK to add more. if (programContainsEs6Modules(program)) return true; // For JS, stay on the safe side. - if (isSourceFileJavaScript(sourceFile)) return false; + if (isUncheckedFile) return false; // If module transpilation is enabled or we're targeting es6 or above, or not emitting, OK. return compilerOptionsIndicateEs6Modules(program.getCompilerOptions()); } diff --git a/tests/cases/fourslash/getJavaScriptCompletions_tsCheck.ts b/tests/cases/fourslash/getJavaScriptCompletions_tsCheck.ts new file mode 100644 index 00000000000..124445d0a11 --- /dev/null +++ b/tests/cases/fourslash/getJavaScriptCompletions_tsCheck.ts @@ -0,0 +1,17 @@ +/// + +// @allowJs: true + +// With 'ts-check' on, we return the same completions we do for TypeScript code. + +// @Filename: /a.js +////// @ts-check +////interface I { a: number; b: number; } +////interface J { b: number; c: number; } +////declare const ij: I | J; +////ij./**/ + +verify.completions({ + marker: "", + exact: ["b"], +});