Skip to content

Error if type node uses inaccessible type in isolated declarations #58620

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6085,6 +6085,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return result;
}
}
context.tracker.reportInferenceFallback(existing);
return undefined;
}

Expand Down Expand Up @@ -8301,6 +8302,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// If the symbol is found both in declaration scope and in current scope then it shoudl point to the same reference
(symAtLocation && sym && !getSymbolIfSameReference(getExportSymbolOfValueSymbolIfExported(symAtLocation), sym))
) {
// In isolated declaration we will not do rest parameter expansion so there is no need to report on these.
if (symAtLocation !== unknownSymbol) {
context.tracker.reportInferenceFallback(node);
}
introducesError = true;
return { introducesError, node, sym };
}
Expand All @@ -8321,6 +8326,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
!isDeclarationName(node) &&
isSymbolAccessible(sym, context.enclosingDeclaration, meaning, /*shouldComputeAliasesToMakeVisible*/ false).accessibility !== SymbolAccessibility.Accessible
) {
context.tracker.reportInferenceFallback(node);
introducesError = true;
}
else {
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -7018,6 +7018,10 @@
"category": "Error",
"code": 9038
},
"Type containing private name '{0}' can't be used with --isolatedDeclarations.": {
"category": "Error",
"code": 9039
},
"JSX attributes must only be assigned a non-empty 'expression'.": {
"category": "Error",
"code": 17000
Expand Down
52 changes: 36 additions & 16 deletions src/compiler/transformers/declarations/diagnostics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ import {
DiagnosticWithLocation,
ElementAccessExpression,
EmitResolver,
EntityNameOrEntityNameExpression,
ExportAssignment,
Expression,
ExpressionWithTypeArguments,
findAncestor,
FunctionDeclaration,
FunctionExpression,
FunctionLikeDeclaration,
GetAccessorDeclaration,
getAllAccessorDeclarations,
getNameOfDeclaration,
Expand All @@ -40,9 +42,12 @@ import {
isConstructorDeclaration,
isConstructSignatureDeclaration,
isElementAccessExpression,
isEntityName,
isEntityNameExpression,
isExportAssignment,
isExpressionWithTypeArguments,
isFunctionDeclaration,
isFunctionLikeDeclaration,
isGetAccessor,
isHeritageClause,
isImportEqualsDeclaration,
Expand All @@ -53,15 +58,18 @@ import {
isParameter,
isParameterPropertyDeclaration,
isParenthesizedExpression,
isPartOfTypeNode,
isPropertyAccessExpression,
isPropertyDeclaration,
isPropertySignature,
isReturnStatement,
isSetAccessor,
isStatement,
isStatic,
isTypeAliasDeclaration,
isTypeAssertionExpression,
isTypeParameterDeclaration,
isTypeQueryNode,
isVariableDeclaration,
JSDocCallbackTag,
JSDocEnumTag,
Expand Down Expand Up @@ -658,6 +666,9 @@ export function createGetIsolatedDeclarationErrors(resolver: EmitResolver) {
if (heritageClause) {
return createDiagnosticForNode(node, Diagnostics.Extends_clause_can_t_contain_an_expression_with_isolatedDeclarations);
}
if ((isPartOfTypeNode(node) || isTypeQueryNode(node.parent)) && (isEntityName(node) || isEntityNameExpression(node))) {
return createEntityInTypeNodeError(node);
}
Debug.type<WithIsolatedDeclarationDiagnostic>(node);
switch (node.kind) {
case SyntaxKind.GetAccessor:
Expand Down Expand Up @@ -694,8 +705,15 @@ export function createGetIsolatedDeclarationErrors(resolver: EmitResolver) {
}

function findNearestDeclaration(node: Node) {
const result = findAncestor(node, n => isExportAssignment(n) || (isStatement(n) ? "quit" : isVariableDeclaration(n) || isPropertyDeclaration(n) || isParameter(n)));
return result as VariableDeclaration | PropertyDeclaration | ParameterDeclaration | ExportAssignment | undefined;
const result = findAncestor(node, n => isExportAssignment(n) || isStatement(n) || isVariableDeclaration(n) || isPropertyDeclaration(n) || isParameter(n));
if (!result) return undefined;

if (isExportAssignment(result)) return result;

if (isReturnStatement(result)) {
return findAncestor(result, (n): n is Exclude<FunctionLikeDeclaration, ConstructorDeclaration> => isFunctionLikeDeclaration(n) && !isConstructorDeclaration(n));
}
return (isStatement(result) ? undefined : result) as VariableDeclaration | PropertyDeclaration | ParameterDeclaration | ExportAssignment | undefined;
}

function createAccessorTypeError(node: GetAccessorDeclaration | SetAccessorDeclaration) {
Expand All @@ -712,31 +730,27 @@ export function createGetIsolatedDeclarationErrors(resolver: EmitResolver) {
}
return diag;
}
function createObjectLiteralError(node: ShorthandPropertyAssignment | SpreadAssignment | ComputedPropertyName) {
const diag = createDiagnosticForNode(node, errorByDeclarationKind[node.kind]);
function addParentDeclarationRelatedInfo(node: Node, diag: DiagnosticWithLocation) {
const parentDeclaration = findNearestDeclaration(node);
if (parentDeclaration) {
const targetStr = isExportAssignment(parentDeclaration) ? "" : getTextOfNode(parentDeclaration.name, /*includeTrivia*/ false);
const targetStr = isExportAssignment(parentDeclaration) || !parentDeclaration.name ? "" : getTextOfNode(parentDeclaration.name, /*includeTrivia*/ false);
addRelatedInfo(diag, createDiagnosticForNode(parentDeclaration, relatedSuggestionByDeclarationKind[parentDeclaration.kind], targetStr));
}
return diag;
}
function createObjectLiteralError(node: ShorthandPropertyAssignment | SpreadAssignment | ComputedPropertyName) {
const diag = createDiagnosticForNode(node, errorByDeclarationKind[node.kind]);
addParentDeclarationRelatedInfo(node, diag);
return diag;
}
function createArrayLiteralError(node: ArrayLiteralExpression | SpreadElement) {
const diag = createDiagnosticForNode(node, errorByDeclarationKind[node.kind]);
const parentDeclaration = findNearestDeclaration(node);
if (parentDeclaration) {
const targetStr = isExportAssignment(parentDeclaration) ? "" : getTextOfNode(parentDeclaration.name, /*includeTrivia*/ false);
addRelatedInfo(diag, createDiagnosticForNode(parentDeclaration, relatedSuggestionByDeclarationKind[parentDeclaration.kind], targetStr));
}
addParentDeclarationRelatedInfo(node, diag);
return diag;
}
function createReturnTypeError(node: FunctionDeclaration | FunctionExpression | ArrowFunction | MethodDeclaration | ConstructSignatureDeclaration) {
const diag = createDiagnosticForNode(node, errorByDeclarationKind[node.kind]);
const parentDeclaration = findNearestDeclaration(node);
if (parentDeclaration) {
const targetStr = isExportAssignment(parentDeclaration) ? "" : getTextOfNode(parentDeclaration.name, /*includeTrivia*/ false);
addRelatedInfo(diag, createDiagnosticForNode(parentDeclaration, relatedSuggestionByDeclarationKind[parentDeclaration.kind], targetStr));
}
addParentDeclarationRelatedInfo(node, diag);
addRelatedInfo(diag, createDiagnosticForNode(node, relatedSuggestionByDeclarationKind[node.kind]));
return diag;
}
Expand Down Expand Up @@ -768,12 +782,18 @@ export function createGetIsolatedDeclarationErrors(resolver: EmitResolver) {
function createClassExpressionError(node: Expression) {
return createExpressionError(node, Diagnostics.Inference_from_class_expressions_is_not_supported_with_isolatedDeclarations);
}
function createEntityInTypeNodeError(node: EntityNameOrEntityNameExpression) {
const diag = createDiagnosticForNode(node, Diagnostics.Type_containing_private_name_0_can_t_be_used_with_isolatedDeclarations, getTextOfNode(node, /*includeTrivia*/ false));
addParentDeclarationRelatedInfo(node, diag);
return diag;
}
function createExpressionError(node: Expression, diagnosticMessage?: DiagnosticMessage) {
const parentDeclaration = findNearestDeclaration(node);
let diag: DiagnosticWithLocation;
if (parentDeclaration) {
const targetStr = isExportAssignment(parentDeclaration) ? "" : getTextOfNode(parentDeclaration.name, /*includeTrivia*/ false);
const targetStr = isExportAssignment(parentDeclaration) || !parentDeclaration.name ? "" : getTextOfNode(parentDeclaration.name, /*includeTrivia*/ false);
const parent = findAncestor(node.parent, n => isExportAssignment(n) || (isStatement(n) ? "quit" : !isParenthesizedExpression(n) && !isTypeAssertionExpression(n) && !isAsExpression(n)));

if (parentDeclaration === parent) {
diag = createDiagnosticForNode(node, diagnosticMessage ?? errorByDeclarationKind[parentDeclaration.kind]);
addRelatedInfo(diag, createDiagnosticForNode(parentDeclaration, relatedSuggestionByDeclarationKind[parentDeclaration.kind], targetStr));
Expand Down
4 changes: 3 additions & 1 deletion src/services/codefixes/fixMissingTypeAnnotationOnExports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ import {
isSpreadAssignment,
isSpreadElement,
isStatement,
isTypeNode,
isValueSignatureDeclaration,
isVariableDeclaration,
ModifierFlags,
Expand Down Expand Up @@ -132,6 +133,7 @@ const errorCodes = [
Diagnostics.Only_const_arrays_can_be_inferred_with_isolatedDeclarations.code,
Diagnostics.Assigning_properties_to_functions_without_declaring_them_is_not_supported_with_isolatedDeclarations_Add_an_explicit_declaration_for_the_properties_assigned_to_this_function.code,
Diagnostics.Declaration_emit_for_this_parameter_requires_implicitly_adding_undefined_to_it_s_type_This_is_not_supported_with_isolatedDeclarations.code,
Diagnostics.Type_containing_private_name_0_can_t_be_used_with_isolatedDeclarations.code,
Diagnostics.Add_satisfies_and_a_type_assertion_to_this_expression_satisfies_T_as_T_to_make_the_type_explicit.code,
];

Expand Down Expand Up @@ -352,7 +354,7 @@ function withContext<T>(
return undefined;
}
// No support for typeof in extends clauses
if (isExpressionTarget && findAncestor(targetNode, isHeritageClause)) {
if (isExpressionTarget && (findAncestor(targetNode, isHeritageClause) || findAncestor(targetNode, isTypeNode))) {
return undefined;
}
// Can't inline type spread elements. Whatever you do isolated declarations will not infer from them
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//// [variables.ts] ////
const x = "";
export function one() {
return {} as typeof x;
}

export function two() {
const y = "";
return {} as typeof y;
}

export function three() {
type Z = string;
return {} as Z;
}
//// [variables.d.ts] ////
declare const x = "";
export declare function one(): typeof x;
export declare function two(): "";
export declare function three(): string;
export {};


//// [Diagnostics reported]
variables.ts(8,25): error TS9039: Type containing private name 'y' can't be used with --isolatedDeclarations.
variables.ts(13,18): error TS9039: Type containing private name 'Z' can't be used with --isolatedDeclarations.


==== variables.ts (2 errors) ====
const x = "";
export function one() {
return {} as typeof x;
}

export function two() {
const y = "";
return {} as typeof y;
~
!!! error TS9039: Type containing private name 'y' can't be used with --isolatedDeclarations.
!!! related TS9031 variables.ts:6:17: Add a return type to the function declaration.
}

export function three() {
type Z = string;
return {} as Z;
~
!!! error TS9039: Type containing private name 'Z' can't be used with --isolatedDeclarations.
!!! related TS9031 variables.ts:11:17: Add a return type to the function declaration.
}
27 changes: 27 additions & 0 deletions tests/baselines/reference/transpile/declarationNotInScopeTypes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//// [variables.ts] ////
const x = "";
export function one() {
return {} as typeof x;
}

export function two() {
const y = "";
return {} as typeof y;
}

export function three() {
type Z = string;
return {} as Z;
}
//// [variables.js] ////
const x = "";
export function one() {
return {};
}
export function two() {
const y = "";
return {};
}
export function three() {
return {};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/// <reference path='fourslash.ts'/>

// @isolatedDeclarations: true
// @declaration: true
// @moduleResolution: node
// @target: es2018
// @jsx: react-jsx

////export function two() {
//// const y = "";
//// return {} as typeof y;
////}
////
////export function three() {
//// type Z = string;
//// return {} as Z;
////}

verify.codeFix({
description: "Add return type '\"\"'",
index: 0,
newFileContent:
`export function two(): "" {
const y = "";
return {} as typeof y;
}

export function three() {
type Z = string;
return {} as Z;
}`,
});


verify.codeFix({
description: "Add return type 'string'",
index: 1,
newFileContent:
`export function two() {
const y = "";
return {} as typeof y;
}

export function three(): string {
type Z = string;
return {} as Z;
}`,
});
17 changes: 17 additions & 0 deletions tests/cases/transpile/declarationNotInScopeTypes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// @declaration: true
// @target: es6
// @filename: variables.ts
const x = "";
export function one() {
return {} as typeof x;
}

export function two() {
const y = "";
return {} as typeof y;
}

export function three() {
type Z = string;
return {} as Z;
}