@@ -25,7 +25,7 @@ class TypeWriterWalker {
25
25
26
26
private checker : ts . TypeChecker ;
27
27
28
- constructor ( private program : ts . Program , fullTypeCheck : boolean ) {
28
+ constructor ( private program : ts . Program , fullTypeCheck : boolean , private hadErrorBaseline : boolean ) {
29
29
// Consider getting both the diagnostics checker and the non-diagnostics checker to verify
30
30
// they are consistent.
31
31
this . checker = fullTypeCheck
@@ -69,6 +69,26 @@ class TypeWriterWalker {
69
69
}
70
70
}
71
71
72
+ private isImportStatementName ( node : ts . Node ) {
73
+ if ( ts . isImportSpecifier ( node . parent ) && ( node . parent . name === node || node . parent . propertyName === node ) ) return true ;
74
+ if ( ts . isImportClause ( node . parent ) && node . parent . name === node ) return true ;
75
+ if ( ts . isImportEqualsDeclaration ( node . parent ) && node . parent . name === node ) return true ;
76
+ return false ;
77
+ }
78
+
79
+ private isExportStatementName ( node : ts . Node ) {
80
+ if ( ts . isExportAssignment ( node . parent ) && node . parent . expression === node ) return true ;
81
+ if ( ts . isExportSpecifier ( node . parent ) && ( node . parent . name === node || node . parent . propertyName === node ) ) return true ;
82
+ return false ;
83
+ }
84
+
85
+ private isIntrinsicJsxTag ( node : ts . Node ) {
86
+ const p = node . parent ;
87
+ if ( ! ( ts . isJsxOpeningElement ( p ) || ts . isJsxClosingElement ( p ) || ts . isJsxSelfClosingElement ( p ) ) ) return false ;
88
+ if ( p . tagName !== node ) return false ;
89
+ return ts . isIntrinsicJsxName ( node . getText ( ) ) ;
90
+ }
91
+
72
92
private writeTypeOrSymbol ( node : ts . Node , isSymbolWalk : boolean ) : TypeWriterResult | undefined {
73
93
const actualPos = ts . skipTrivia ( this . currentSourceFile . text , node . pos ) ;
74
94
const lineAndCharacter = this . currentSourceFile . getLineAndCharacterOfPosition ( actualPos ) ;
@@ -85,7 +105,31 @@ class TypeWriterWalker {
85
105
// let type = this.checker.getTypeAtLocation(node);
86
106
let type = ts . isExpressionWithTypeArgumentsInClassExtendsClause ( node . parent ) ? this . checker . getTypeAtLocation ( node . parent ) : undefined ;
87
107
if ( ! type || type . flags & ts . TypeFlags . Any ) type = this . checker . getTypeAtLocation ( node ) ;
88
- const typeString = this . checker . typeToString ( type , node . parent , ts . TypeFormatFlags . NoTruncation | ts . TypeFormatFlags . AllowUniqueESSymbolType ) ;
108
+ const typeString =
109
+ // Distinguish `errorType`s from `any`s; but only if the file has no errors.
110
+ // Additionally,
111
+ // * the LHS of a qualified name
112
+ // * a binding pattern name
113
+ // * labels
114
+ // * the "global" in "declare global"
115
+ // * the "target" in "new.target"
116
+ // * names in import statements
117
+ // * type-only names in export statements
118
+ // * and intrinsic jsx tag names
119
+ // return `error`s via `getTypeAtLocation`
120
+ // But this is generally expected, so we don't call those out, either
121
+ ( ! this . hadErrorBaseline &&
122
+ type . flags & ts . TypeFlags . Any &&
123
+ ! ts . isBindingElement ( node . parent ) &&
124
+ ! ts . isPropertyAccessOrQualifiedName ( node . parent ) &&
125
+ ! ts . isLabelName ( node ) &&
126
+ ! ( ts . isModuleDeclaration ( node . parent ) && ts . isGlobalScopeAugmentation ( node . parent ) ) &&
127
+ ! ts . isMetaProperty ( node . parent ) &&
128
+ ! this . isImportStatementName ( node ) &&
129
+ ! this . isExportStatementName ( node ) &&
130
+ ! this . isIntrinsicJsxTag ( node ) ) ?
131
+ ( type as ts . IntrinsicType ) . intrinsicName :
132
+ this . checker . typeToString ( type , node . parent , ts . TypeFormatFlags . NoTruncation | ts . TypeFormatFlags . AllowUniqueESSymbolType ) ;
89
133
return {
90
134
line : lineAndCharacter . line ,
91
135
syntaxKind : node . kind ,
0 commit comments