Skip to content

Commit 8537bb7

Browse files
Error if type node uses inaccessible type in isolated declarations (#58620)
1 parent f2aebff commit 8537bb7

File tree

8 files changed

+190
-17
lines changed

8 files changed

+190
-17
lines changed

src/compiler/checker.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6085,6 +6085,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
60856085
return result;
60866086
}
60876087
}
6088+
context.tracker.reportInferenceFallback(existing);
60886089
return undefined;
60896090
}
60906091

@@ -8301,6 +8302,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
83018302
// If the symbol is found both in declaration scope and in current scope then it shoudl point to the same reference
83028303
(symAtLocation && sym && !getSymbolIfSameReference(getExportSymbolOfValueSymbolIfExported(symAtLocation), sym))
83038304
) {
8305+
// In isolated declaration we will not do rest parameter expansion so there is no need to report on these.
8306+
if (symAtLocation !== unknownSymbol) {
8307+
context.tracker.reportInferenceFallback(node);
8308+
}
83048309
introducesError = true;
83058310
return { introducesError, node, sym };
83068311
}
@@ -8321,6 +8326,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
83218326
!isDeclarationName(node) &&
83228327
isSymbolAccessible(sym, context.enclosingDeclaration, meaning, /*shouldComputeAliasesToMakeVisible*/ false).accessibility !== SymbolAccessibility.Accessible
83238328
) {
8329+
context.tracker.reportInferenceFallback(node);
83248330
introducesError = true;
83258331
}
83268332
else {

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7018,6 +7018,10 @@
70187018
"category": "Error",
70197019
"code": 9038
70207020
},
7021+
"Type containing private name '{0}' can't be used with --isolatedDeclarations.": {
7022+
"category": "Error",
7023+
"code": 9039
7024+
},
70217025
"JSX attributes must only be assigned a non-empty 'expression'.": {
70227026
"category": "Error",
70237027
"code": 17000

src/compiler/transformers/declarations/diagnostics.ts

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@ import {
1919
DiagnosticWithLocation,
2020
ElementAccessExpression,
2121
EmitResolver,
22+
EntityNameOrEntityNameExpression,
2223
ExportAssignment,
2324
Expression,
2425
ExpressionWithTypeArguments,
2526
findAncestor,
2627
FunctionDeclaration,
2728
FunctionExpression,
29+
FunctionLikeDeclaration,
2830
GetAccessorDeclaration,
2931
getAllAccessorDeclarations,
3032
getNameOfDeclaration,
@@ -40,9 +42,12 @@ import {
4042
isConstructorDeclaration,
4143
isConstructSignatureDeclaration,
4244
isElementAccessExpression,
45+
isEntityName,
46+
isEntityNameExpression,
4347
isExportAssignment,
4448
isExpressionWithTypeArguments,
4549
isFunctionDeclaration,
50+
isFunctionLikeDeclaration,
4651
isGetAccessor,
4752
isHeritageClause,
4853
isImportEqualsDeclaration,
@@ -53,15 +58,18 @@ import {
5358
isParameter,
5459
isParameterPropertyDeclaration,
5560
isParenthesizedExpression,
61+
isPartOfTypeNode,
5662
isPropertyAccessExpression,
5763
isPropertyDeclaration,
5864
isPropertySignature,
65+
isReturnStatement,
5966
isSetAccessor,
6067
isStatement,
6168
isStatic,
6269
isTypeAliasDeclaration,
6370
isTypeAssertionExpression,
6471
isTypeParameterDeclaration,
72+
isTypeQueryNode,
6573
isVariableDeclaration,
6674
JSDocCallbackTag,
6775
JSDocEnumTag,
@@ -658,6 +666,9 @@ export function createGetIsolatedDeclarationErrors(resolver: EmitResolver) {
658666
if (heritageClause) {
659667
return createDiagnosticForNode(node, Diagnostics.Extends_clause_can_t_contain_an_expression_with_isolatedDeclarations);
660668
}
669+
if ((isPartOfTypeNode(node) || isTypeQueryNode(node.parent)) && (isEntityName(node) || isEntityNameExpression(node))) {
670+
return createEntityInTypeNodeError(node);
671+
}
661672
Debug.type<WithIsolatedDeclarationDiagnostic>(node);
662673
switch (node.kind) {
663674
case SyntaxKind.GetAccessor:
@@ -694,8 +705,15 @@ export function createGetIsolatedDeclarationErrors(resolver: EmitResolver) {
694705
}
695706

696707
function findNearestDeclaration(node: Node) {
697-
const result = findAncestor(node, n => isExportAssignment(n) || (isStatement(n) ? "quit" : isVariableDeclaration(n) || isPropertyDeclaration(n) || isParameter(n)));
698-
return result as VariableDeclaration | PropertyDeclaration | ParameterDeclaration | ExportAssignment | undefined;
708+
const result = findAncestor(node, n => isExportAssignment(n) || isStatement(n) || isVariableDeclaration(n) || isPropertyDeclaration(n) || isParameter(n));
709+
if (!result) return undefined;
710+
711+
if (isExportAssignment(result)) return result;
712+
713+
if (isReturnStatement(result)) {
714+
return findAncestor(result, (n): n is Exclude<FunctionLikeDeclaration, ConstructorDeclaration> => isFunctionLikeDeclaration(n) && !isConstructorDeclaration(n));
715+
}
716+
return (isStatement(result) ? undefined : result) as VariableDeclaration | PropertyDeclaration | ParameterDeclaration | ExportAssignment | undefined;
699717
}
700718

701719
function createAccessorTypeError(node: GetAccessorDeclaration | SetAccessorDeclaration) {
@@ -712,31 +730,27 @@ export function createGetIsolatedDeclarationErrors(resolver: EmitResolver) {
712730
}
713731
return diag;
714732
}
715-
function createObjectLiteralError(node: ShorthandPropertyAssignment | SpreadAssignment | ComputedPropertyName) {
716-
const diag = createDiagnosticForNode(node, errorByDeclarationKind[node.kind]);
733+
function addParentDeclarationRelatedInfo(node: Node, diag: DiagnosticWithLocation) {
717734
const parentDeclaration = findNearestDeclaration(node);
718735
if (parentDeclaration) {
719-
const targetStr = isExportAssignment(parentDeclaration) ? "" : getTextOfNode(parentDeclaration.name, /*includeTrivia*/ false);
736+
const targetStr = isExportAssignment(parentDeclaration) || !parentDeclaration.name ? "" : getTextOfNode(parentDeclaration.name, /*includeTrivia*/ false);
720737
addRelatedInfo(diag, createDiagnosticForNode(parentDeclaration, relatedSuggestionByDeclarationKind[parentDeclaration.kind], targetStr));
721738
}
722739
return diag;
723740
}
741+
function createObjectLiteralError(node: ShorthandPropertyAssignment | SpreadAssignment | ComputedPropertyName) {
742+
const diag = createDiagnosticForNode(node, errorByDeclarationKind[node.kind]);
743+
addParentDeclarationRelatedInfo(node, diag);
744+
return diag;
745+
}
724746
function createArrayLiteralError(node: ArrayLiteralExpression | SpreadElement) {
725747
const diag = createDiagnosticForNode(node, errorByDeclarationKind[node.kind]);
726-
const parentDeclaration = findNearestDeclaration(node);
727-
if (parentDeclaration) {
728-
const targetStr = isExportAssignment(parentDeclaration) ? "" : getTextOfNode(parentDeclaration.name, /*includeTrivia*/ false);
729-
addRelatedInfo(diag, createDiagnosticForNode(parentDeclaration, relatedSuggestionByDeclarationKind[parentDeclaration.kind], targetStr));
730-
}
748+
addParentDeclarationRelatedInfo(node, diag);
731749
return diag;
732750
}
733751
function createReturnTypeError(node: FunctionDeclaration | FunctionExpression | ArrowFunction | MethodDeclaration | ConstructSignatureDeclaration) {
734752
const diag = createDiagnosticForNode(node, errorByDeclarationKind[node.kind]);
735-
const parentDeclaration = findNearestDeclaration(node);
736-
if (parentDeclaration) {
737-
const targetStr = isExportAssignment(parentDeclaration) ? "" : getTextOfNode(parentDeclaration.name, /*includeTrivia*/ false);
738-
addRelatedInfo(diag, createDiagnosticForNode(parentDeclaration, relatedSuggestionByDeclarationKind[parentDeclaration.kind], targetStr));
739-
}
753+
addParentDeclarationRelatedInfo(node, diag);
740754
addRelatedInfo(diag, createDiagnosticForNode(node, relatedSuggestionByDeclarationKind[node.kind]));
741755
return diag;
742756
}
@@ -768,12 +782,18 @@ export function createGetIsolatedDeclarationErrors(resolver: EmitResolver) {
768782
function createClassExpressionError(node: Expression) {
769783
return createExpressionError(node, Diagnostics.Inference_from_class_expressions_is_not_supported_with_isolatedDeclarations);
770784
}
785+
function createEntityInTypeNodeError(node: EntityNameOrEntityNameExpression) {
786+
const diag = createDiagnosticForNode(node, Diagnostics.Type_containing_private_name_0_can_t_be_used_with_isolatedDeclarations, getTextOfNode(node, /*includeTrivia*/ false));
787+
addParentDeclarationRelatedInfo(node, diag);
788+
return diag;
789+
}
771790
function createExpressionError(node: Expression, diagnosticMessage?: DiagnosticMessage) {
772791
const parentDeclaration = findNearestDeclaration(node);
773792
let diag: DiagnosticWithLocation;
774793
if (parentDeclaration) {
775-
const targetStr = isExportAssignment(parentDeclaration) ? "" : getTextOfNode(parentDeclaration.name, /*includeTrivia*/ false);
794+
const targetStr = isExportAssignment(parentDeclaration) || !parentDeclaration.name ? "" : getTextOfNode(parentDeclaration.name, /*includeTrivia*/ false);
776795
const parent = findAncestor(node.parent, n => isExportAssignment(n) || (isStatement(n) ? "quit" : !isParenthesizedExpression(n) && !isTypeAssertionExpression(n) && !isAsExpression(n)));
796+
777797
if (parentDeclaration === parent) {
778798
diag = createDiagnosticForNode(node, diagnosticMessage ?? errorByDeclarationKind[parentDeclaration.kind]);
779799
addRelatedInfo(diag, createDiagnosticForNode(parentDeclaration, relatedSuggestionByDeclarationKind[parentDeclaration.kind], targetStr));

src/services/codefixes/fixMissingTypeAnnotationOnExports.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ import {
6565
isSpreadAssignment,
6666
isSpreadElement,
6767
isStatement,
68+
isTypeNode,
6869
isValueSignatureDeclaration,
6970
isVariableDeclaration,
7071
ModifierFlags,
@@ -132,6 +133,7 @@ const errorCodes = [
132133
Diagnostics.Only_const_arrays_can_be_inferred_with_isolatedDeclarations.code,
133134
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,
134135
Diagnostics.Declaration_emit_for_this_parameter_requires_implicitly_adding_undefined_to_it_s_type_This_is_not_supported_with_isolatedDeclarations.code,
136+
Diagnostics.Type_containing_private_name_0_can_t_be_used_with_isolatedDeclarations.code,
135137
Diagnostics.Add_satisfies_and_a_type_assertion_to_this_expression_satisfies_T_as_T_to_make_the_type_explicit.code,
136138
];
137139

@@ -352,7 +354,7 @@ function withContext<T>(
352354
return undefined;
353355
}
354356
// No support for typeof in extends clauses
355-
if (isExpressionTarget && findAncestor(targetNode, isHeritageClause)) {
357+
if (isExpressionTarget && (findAncestor(targetNode, isHeritageClause) || findAncestor(targetNode, isTypeNode))) {
356358
return undefined;
357359
}
358360
// Can't inline type spread elements. Whatever you do isolated declarations will not infer from them
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//// [variables.ts] ////
2+
const x = "";
3+
export function one() {
4+
return {} as typeof x;
5+
}
6+
7+
export function two() {
8+
const y = "";
9+
return {} as typeof y;
10+
}
11+
12+
export function three() {
13+
type Z = string;
14+
return {} as Z;
15+
}
16+
//// [variables.d.ts] ////
17+
declare const x = "";
18+
export declare function one(): typeof x;
19+
export declare function two(): "";
20+
export declare function three(): string;
21+
export {};
22+
23+
24+
//// [Diagnostics reported]
25+
variables.ts(8,25): error TS9039: Type containing private name 'y' can't be used with --isolatedDeclarations.
26+
variables.ts(13,18): error TS9039: Type containing private name 'Z' can't be used with --isolatedDeclarations.
27+
28+
29+
==== variables.ts (2 errors) ====
30+
const x = "";
31+
export function one() {
32+
return {} as typeof x;
33+
}
34+
35+
export function two() {
36+
const y = "";
37+
return {} as typeof y;
38+
~
39+
!!! error TS9039: Type containing private name 'y' can't be used with --isolatedDeclarations.
40+
!!! related TS9031 variables.ts:6:17: Add a return type to the function declaration.
41+
}
42+
43+
export function three() {
44+
type Z = string;
45+
return {} as Z;
46+
~
47+
!!! error TS9039: Type containing private name 'Z' can't be used with --isolatedDeclarations.
48+
!!! related TS9031 variables.ts:11:17: Add a return type to the function declaration.
49+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//// [variables.ts] ////
2+
const x = "";
3+
export function one() {
4+
return {} as typeof x;
5+
}
6+
7+
export function two() {
8+
const y = "";
9+
return {} as typeof y;
10+
}
11+
12+
export function three() {
13+
type Z = string;
14+
return {} as Z;
15+
}
16+
//// [variables.js] ////
17+
const x = "";
18+
export function one() {
19+
return {};
20+
}
21+
export function two() {
22+
const y = "";
23+
return {};
24+
}
25+
export function three() {
26+
return {};
27+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/// <reference path='fourslash.ts'/>
2+
3+
// @isolatedDeclarations: true
4+
// @declaration: true
5+
// @moduleResolution: node
6+
// @target: es2018
7+
// @jsx: react-jsx
8+
9+
////export function two() {
10+
//// const y = "";
11+
//// return {} as typeof y;
12+
////}
13+
////
14+
////export function three() {
15+
//// type Z = string;
16+
//// return {} as Z;
17+
////}
18+
19+
verify.codeFix({
20+
description: "Add return type '\"\"'",
21+
index: 0,
22+
newFileContent:
23+
`export function two(): "" {
24+
const y = "";
25+
return {} as typeof y;
26+
}
27+
28+
export function three() {
29+
type Z = string;
30+
return {} as Z;
31+
}`,
32+
});
33+
34+
35+
verify.codeFix({
36+
description: "Add return type 'string'",
37+
index: 1,
38+
newFileContent:
39+
`export function two() {
40+
const y = "";
41+
return {} as typeof y;
42+
}
43+
44+
export function three(): string {
45+
type Z = string;
46+
return {} as Z;
47+
}`,
48+
});
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// @declaration: true
2+
// @target: es6
3+
// @filename: variables.ts
4+
const x = "";
5+
export function one() {
6+
return {} as typeof x;
7+
}
8+
9+
export function two() {
10+
const y = "";
11+
return {} as typeof y;
12+
}
13+
14+
export function three() {
15+
type Z = string;
16+
return {} as Z;
17+
}

0 commit comments

Comments
 (0)