1/* @internal */ 2namespace ts { 3 const ambientModuleSymbolRegex = /^".+"$/; 4 const anon = "(anonymous)" as __String & string; 5 6 let nextSymbolId = 1; 7 let nextNodeId = 1; 8 let nextMergeId = 1; 9 let nextFlowId = 1; 10 11 const enum IterationUse { 12 AllowsSyncIterablesFlag = 1 << 0, 13 AllowsAsyncIterablesFlag = 1 << 1, 14 AllowsStringInputFlag = 1 << 2, 15 ForOfFlag = 1 << 3, 16 YieldStarFlag = 1 << 4, 17 SpreadFlag = 1 << 5, 18 DestructuringFlag = 1 << 6, 19 PossiblyOutOfBounds = 1 << 7, 20 21 // Spread, Destructuring, Array element assignment 22 Element = AllowsSyncIterablesFlag, 23 Spread = AllowsSyncIterablesFlag | SpreadFlag, 24 Destructuring = AllowsSyncIterablesFlag | DestructuringFlag, 25 26 ForOf = AllowsSyncIterablesFlag | AllowsStringInputFlag | ForOfFlag, 27 ForAwaitOf = AllowsSyncIterablesFlag | AllowsAsyncIterablesFlag | AllowsStringInputFlag | ForOfFlag, 28 29 YieldStar = AllowsSyncIterablesFlag | YieldStarFlag, 30 AsyncYieldStar = AllowsSyncIterablesFlag | AllowsAsyncIterablesFlag | YieldStarFlag, 31 32 GeneratorReturnType = AllowsSyncIterablesFlag, 33 AsyncGeneratorReturnType = AllowsAsyncIterablesFlag, 34 35 } 36 37 const enum IterationTypeKind { 38 Yield, 39 Return, 40 Next, 41 } 42 43 interface IterationTypesResolver { 44 iterableCacheKey: "iterationTypesOfAsyncIterable" | "iterationTypesOfIterable"; 45 iteratorCacheKey: "iterationTypesOfAsyncIterator" | "iterationTypesOfIterator"; 46 iteratorSymbolName: "asyncIterator" | "iterator"; 47 getGlobalIteratorType: (reportErrors: boolean) => GenericType; 48 getGlobalIterableType: (reportErrors: boolean) => GenericType; 49 getGlobalIterableIteratorType: (reportErrors: boolean) => GenericType; 50 getGlobalGeneratorType: (reportErrors: boolean) => GenericType; 51 resolveIterationType: (type: Type, errorNode: Node | undefined) => Type | undefined; 52 mustHaveANextMethodDiagnostic: DiagnosticMessage; 53 mustBeAMethodDiagnostic: DiagnosticMessage; 54 mustHaveAValueDiagnostic: DiagnosticMessage; 55 } 56 57 const enum WideningKind { 58 Normal, 59 FunctionReturn, 60 GeneratorNext, 61 GeneratorYield, 62 } 63 64 export const enum TypeFacts { 65 None = 0, 66 TypeofEQString = 1 << 0, // typeof x === "string" 67 TypeofEQNumber = 1 << 1, // typeof x === "number" 68 TypeofEQBigInt = 1 << 2, // typeof x === "bigint" 69 TypeofEQBoolean = 1 << 3, // typeof x === "boolean" 70 TypeofEQSymbol = 1 << 4, // typeof x === "symbol" 71 TypeofEQObject = 1 << 5, // typeof x === "object" 72 TypeofEQFunction = 1 << 6, // typeof x === "function" 73 TypeofEQHostObject = 1 << 7, // typeof x === "xxx" 74 TypeofNEString = 1 << 8, // typeof x !== "string" 75 TypeofNENumber = 1 << 9, // typeof x !== "number" 76 TypeofNEBigInt = 1 << 10, // typeof x !== "bigint" 77 TypeofNEBoolean = 1 << 11, // typeof x !== "boolean" 78 TypeofNESymbol = 1 << 12, // typeof x !== "symbol" 79 TypeofNEObject = 1 << 13, // typeof x !== "object" 80 TypeofNEFunction = 1 << 14, // typeof x !== "function" 81 TypeofNEHostObject = 1 << 15, // typeof x !== "xxx" 82 EQUndefined = 1 << 16, // x === undefined 83 EQNull = 1 << 17, // x === null 84 EQUndefinedOrNull = 1 << 18, // x === undefined / x === null 85 NEUndefined = 1 << 19, // x !== undefined 86 NENull = 1 << 20, // x !== null 87 NEUndefinedOrNull = 1 << 21, // x != undefined / x != null 88 Truthy = 1 << 22, // x 89 Falsy = 1 << 23, // !x 90 IsUndefined = 1 << 24, // Contains undefined or intersection with undefined 91 IsNull = 1 << 25, // Contains null or intersection with null 92 IsUndefinedOrNull = IsUndefined | IsNull, 93 All = (1 << 27) - 1, 94 // The following members encode facts about particular kinds of types for use in the getTypeFacts function. 95 // The presence of a particular fact means that the given test is true for some (and possibly all) values 96 // of that kind of type. 97 BaseStringStrictFacts = TypeofEQString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull, 98 BaseStringFacts = BaseStringStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, 99 StringStrictFacts = BaseStringStrictFacts | Truthy | Falsy, 100 StringFacts = BaseStringFacts | Truthy, 101 EmptyStringStrictFacts = BaseStringStrictFacts | Falsy, 102 EmptyStringFacts = BaseStringFacts, 103 NonEmptyStringStrictFacts = BaseStringStrictFacts | Truthy, 104 NonEmptyStringFacts = BaseStringFacts | Truthy, 105 BaseNumberStrictFacts = TypeofEQNumber | TypeofNEString | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull, 106 BaseNumberFacts = BaseNumberStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, 107 NumberStrictFacts = BaseNumberStrictFacts | Truthy | Falsy, 108 NumberFacts = BaseNumberFacts | Truthy, 109 ZeroNumberStrictFacts = BaseNumberStrictFacts | Falsy, 110 ZeroNumberFacts = BaseNumberFacts, 111 NonZeroNumberStrictFacts = BaseNumberStrictFacts | Truthy, 112 NonZeroNumberFacts = BaseNumberFacts | Truthy, 113 BaseBigIntStrictFacts = TypeofEQBigInt | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull, 114 BaseBigIntFacts = BaseBigIntStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, 115 BigIntStrictFacts = BaseBigIntStrictFacts | Truthy | Falsy, 116 BigIntFacts = BaseBigIntFacts | Truthy, 117 ZeroBigIntStrictFacts = BaseBigIntStrictFacts | Falsy, 118 ZeroBigIntFacts = BaseBigIntFacts, 119 NonZeroBigIntStrictFacts = BaseBigIntStrictFacts | Truthy, 120 NonZeroBigIntFacts = BaseBigIntFacts | Truthy, 121 BaseBooleanStrictFacts = TypeofEQBoolean | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull, 122 BaseBooleanFacts = BaseBooleanStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, 123 BooleanStrictFacts = BaseBooleanStrictFacts | Truthy | Falsy, 124 BooleanFacts = BaseBooleanFacts | Truthy, 125 FalseStrictFacts = BaseBooleanStrictFacts | Falsy, 126 FalseFacts = BaseBooleanFacts, 127 TrueStrictFacts = BaseBooleanStrictFacts | Truthy, 128 TrueFacts = BaseBooleanFacts | Truthy, 129 SymbolStrictFacts = TypeofEQSymbol | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy, 130 SymbolFacts = SymbolStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, 131 ObjectStrictFacts = TypeofEQObject | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | NEUndefined | NENull | NEUndefinedOrNull | Truthy, 132 ObjectFacts = ObjectStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, 133 FunctionStrictFacts = TypeofEQFunction | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy, 134 FunctionFacts = FunctionStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, 135 VoidFacts = TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | EQUndefined | EQUndefinedOrNull | NENull | Falsy, 136 UndefinedFacts = TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | EQUndefined | EQUndefinedOrNull | NENull | Falsy | IsUndefined, 137 NullFacts = TypeofEQObject | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | TypeofNEHostObject | EQNull | EQUndefinedOrNull | NEUndefined | Falsy | IsNull, 138 EmptyObjectStrictFacts = All & ~(EQUndefined | EQNull | EQUndefinedOrNull | IsUndefinedOrNull), 139 EmptyObjectFacts = All & ~IsUndefinedOrNull, 140 UnknownFacts = All & ~IsUndefinedOrNull, 141 AllTypeofNE = TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | NEUndefined, 142 // Masks 143 OrFactsMask = TypeofEQFunction | TypeofNEObject, 144 AndFactsMask = All & ~OrFactsMask, 145 } 146 147 const typeofNEFacts: ReadonlyESMap<string, TypeFacts> = new Map(getEntries({ 148 string: TypeFacts.TypeofNEString, 149 number: TypeFacts.TypeofNENumber, 150 bigint: TypeFacts.TypeofNEBigInt, 151 boolean: TypeFacts.TypeofNEBoolean, 152 symbol: TypeFacts.TypeofNESymbol, 153 undefined: TypeFacts.NEUndefined, 154 object: TypeFacts.TypeofNEObject, 155 function: TypeFacts.TypeofNEFunction 156 })); 157 158 type TypeSystemEntity = Node | Symbol | Type | Signature; 159 160 const enum TypeSystemPropertyName { 161 Type, 162 ResolvedBaseConstructorType, 163 DeclaredType, 164 ResolvedReturnType, 165 ImmediateBaseConstraint, 166 EnumTagType, 167 ResolvedTypeArguments, 168 ResolvedBaseTypes, 169 WriteType, 170 } 171 172 type AnnotationConstantExpressionType = number | string | boolean | AnnotationConstantExpressionType[]; 173 174 export const enum CheckMode { 175 Normal = 0, // Normal type checking 176 Contextual = 1 << 0, // Explicitly assigned contextual type, therefore not cacheable 177 Inferential = 1 << 1, // Inferential typing 178 SkipContextSensitive = 1 << 2, // Skip context sensitive function expressions 179 SkipGenericFunctions = 1 << 3, // Skip single signature generic functions 180 IsForSignatureHelp = 1 << 4, // Call resolution for purposes of signature help 181 IsForStringLiteralArgumentCompletions = 1 << 5, // Do not infer from the argument currently being typed 182 RestBindingElement = 1 << 6, // Checking a type that is going to be used to determine the type of a rest binding element 183 // e.g. in `const { a, ...rest } = foo`, when checking the type of `foo` to determine the type of `rest`, 184 // we need to preserve generic types instead of substituting them for constraints 185 SkipEtsComponentBody = 1 << 7, // Not check body for Completion 186 } 187 188 export const enum SignatureCheckMode { 189 BivariantCallback = 1 << 0, 190 StrictCallback = 1 << 1, 191 IgnoreReturnTypes = 1 << 2, 192 StrictArity = 1 << 3, 193 Callback = BivariantCallback | StrictCallback, 194 } 195 196 const enum IntersectionState { 197 None = 0, 198 Source = 1 << 0, 199 Target = 1 << 1, 200 } 201 202 const enum RecursionFlags { 203 None = 0, 204 Source = 1 << 0, 205 Target = 1 << 1, 206 Both = Source | Target, 207 } 208 209 const enum MappedTypeModifiers { 210 IncludeReadonly = 1 << 0, 211 ExcludeReadonly = 1 << 1, 212 IncludeOptional = 1 << 2, 213 ExcludeOptional = 1 << 3, 214 } 215 216 const enum ExpandingFlags { 217 None = 0, 218 Source = 1, 219 Target = 1 << 1, 220 Both = Source | Target, 221 } 222 223 const enum MembersOrExportsResolutionKind { 224 resolvedExports = "resolvedExports", 225 resolvedMembers = "resolvedMembers" 226 } 227 228 const enum UnusedKind { 229 Local, 230 Parameter, 231 } 232 233 /** @param containingNode Node to check for parse error */ 234 type AddUnusedDiagnostic = (containingNode: Node, type: UnusedKind, diagnostic: DiagnosticWithLocation) => void; 235 236 const isNotOverloadAndNotAccessor = and(isNotOverload, isNotAccessor); 237 238 const enum DeclarationMeaning { 239 GetAccessor = 1, 240 SetAccessor = 2, 241 PropertyAssignment = 4, 242 Method = 8, 243 PrivateStatic = 16, 244 GetOrSetAccessor = GetAccessor | SetAccessor, 245 PropertyAssignmentOrMethod = PropertyAssignment | Method, 246 } 247 248 const enum DeclarationSpaces { 249 None = 0, 250 ExportValue = 1 << 0, 251 ExportType = 1 << 1, 252 ExportNamespace = 1 << 2, 253 } 254 255 const enum MinArgumentCountFlags { 256 None = 0, 257 StrongArityForUntypedJS = 1 << 0, 258 VoidIsNonOptional = 1 << 1, 259 } 260 261 const enum IntrinsicTypeKind { 262 Uppercase, 263 Lowercase, 264 Capitalize, 265 Uncapitalize 266 } 267 268 const intrinsicTypeKinds: ReadonlyESMap<string, IntrinsicTypeKind> = new Map(getEntries({ 269 Uppercase: IntrinsicTypeKind.Uppercase, 270 Lowercase: IntrinsicTypeKind.Lowercase, 271 Capitalize: IntrinsicTypeKind.Capitalize, 272 Uncapitalize: IntrinsicTypeKind.Uncapitalize 273 })); 274 275 function SymbolLinks(this: SymbolLinks) { 276 } 277 278 function NodeLinks(this: NodeLinks) { 279 this.flags = 0; 280 } 281 282 export function getNodeId(node: Node): number { 283 if (!node.id) { 284 node.id = nextNodeId; 285 nextNodeId++; 286 } 287 return node.id; 288 } 289 290 export function getSymbolId(symbol: Symbol): SymbolId { 291 if (!symbol.id) { 292 symbol.id = nextSymbolId; 293 nextSymbolId++; 294 } 295 296 return symbol.id; 297 } 298 299 export function isInstantiatedModule(node: ModuleDeclaration, preserveConstEnums: boolean) { 300 const moduleState = getModuleInstanceState(node); 301 return moduleState === ModuleInstanceState.Instantiated || 302 (preserveConstEnums && moduleState === ModuleInstanceState.ConstEnumOnly); 303 } 304 305 export function createTypeChecker(host: TypeCheckerHost, isTypeCheckerForLinter: boolean = false): TypeChecker { 306 const getPackagesMap = memoize(() => { 307 // A package name maps to true when we detect it has .d.ts files. 308 // This is useful as an approximation of whether a package bundles its own types. 309 // Note: we only look at files already found by module resolution, 310 // so there may be files we did not consider. 311 const map = new Map<string, boolean>(); 312 host.getSourceFiles().forEach(sf => { 313 if (!sf.resolvedModules) return; 314 315 sf.resolvedModules.forEach(r => { 316 if (r && r.packageId) map.set(r.packageId.name, r.extension === Extension.Dts || !!map.get(r.packageId.name)); 317 }); 318 }); 319 return map; 320 }); 321 322 let deferredDiagnosticsCallbacks: (() => void)[] = []; 323 324 let addLazyDiagnostic = (arg: () => void) => { 325 deferredDiagnosticsCallbacks.push(arg); 326 }; 327 328 // Cancellation that controls whether or not we can cancel in the middle of type checking. 329 // In general cancelling is *not* safe for the type checker. We might be in the middle of 330 // computing something, and we will leave our internals in an inconsistent state. Callers 331 // who set the cancellation token should catch if a cancellation exception occurs, and 332 // should throw away and create a new TypeChecker. 333 // 334 // Currently we only support setting the cancellation token when getting diagnostics. This 335 // is because diagnostics can be quite expensive, and we want to allow hosts to bail out if 336 // they no longer need the information (for example, if the user started editing again). 337 let cancellationToken: CancellationToken | undefined; 338 let requestedExternalEmitHelpers: ExternalEmitHelpers; 339 let externalHelpersModule: Symbol; 340 341 const Symbol = objectAllocator.getSymbolConstructor(); 342 const Type = objectAllocator.getTypeConstructor(); 343 const Signature = objectAllocator.getSignatureConstructor(); 344 345 let typeCount = 0; 346 let symbolCount = 0; 347 let enumCount = 0; 348 let totalInstantiationCount = 0; 349 let instantiationCount = 0; 350 let instantiationDepth = 0; 351 let inlineLevel = 0; 352 let currentNode: Node | undefined; 353 let varianceTypeParameter: TypeParameter | undefined; 354 355 const emptySymbols = createSymbolTable(); 356 const arrayVariances = [VarianceFlags.Covariant]; 357 358 let getJsDocNodeCheckedConfig = host.getJsDocNodeCheckedConfig; 359 let compilerOptions: CompilerOptions = {...host.getCompilerOptions()}; 360 361 if (!!compilerOptions.needDoArkTsLinter) { 362 compilerOptions.skipLibCheck = false; 363 } 364 365 if (isTypeCheckerForLinter) { 366 // make the configuration as arkts linter required 367 compilerOptions.strictNullChecks = true; 368 compilerOptions.strictFunctionTypes = true; 369 compilerOptions.strictPropertyInitialization = true; 370 compilerOptions.noImplicitReturns = true; 371 372 getJsDocNodeCheckedConfig = undefined; 373 } 374 375 const languageVersion = getEmitScriptTarget(compilerOptions); 376 const moduleKind = getEmitModuleKind(compilerOptions); 377 const useDefineForClassFields = getUseDefineForClassFields(compilerOptions); 378 const allowSyntheticDefaultImports = getAllowSyntheticDefaultImports(compilerOptions); 379 const strictNullChecks = getStrictOptionValue(compilerOptions, "strictNullChecks"); 380 const strictFunctionTypes = getStrictOptionValue(compilerOptions, "strictFunctionTypes"); 381 const strictBindCallApply = getStrictOptionValue(compilerOptions, "strictBindCallApply"); 382 const strictPropertyInitialization = getStrictOptionValue(compilerOptions, "strictPropertyInitialization"); 383 const noImplicitAny = getStrictOptionValue(compilerOptions, "noImplicitAny"); 384 const noImplicitThis = getStrictOptionValue(compilerOptions, "noImplicitThis"); 385 const useUnknownInCatchVariables = getStrictOptionValue(compilerOptions, "useUnknownInCatchVariables"); 386 const keyofStringsOnly = !!compilerOptions.keyofStringsOnly; 387 const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : ObjectFlags.FreshLiteral; 388 const exactOptionalPropertyTypes = compilerOptions.exactOptionalPropertyTypes; 389 390 const checkBinaryExpression = createCheckBinaryExpression(); 391 const emitResolver = createResolver(); 392 const nodeBuilder = createNodeBuilder(); 393 394 const globals = createSymbolTable(); 395 const undefinedSymbol = createSymbol(SymbolFlags.Property, "undefined" as __String); 396 undefinedSymbol.declarations = []; 397 398 const globalThisSymbol = createSymbol(SymbolFlags.Module, "globalThis" as __String, CheckFlags.Readonly); 399 globalThisSymbol.exports = globals; 400 globalThisSymbol.declarations = []; 401 globals.set(globalThisSymbol.escapedName, globalThisSymbol); 402 403 const argumentsSymbol = createSymbol(SymbolFlags.Property, "arguments" as __String); 404 const requireSymbol = createSymbol(SymbolFlags.Property, "require" as __String); 405 406 /** This will be set during calls to `getResolvedSignature` where services determines an apparent number of arguments greater than what is actually provided. */ 407 let apparentArgumentCount: number | undefined; 408 409 let constEnumRelate: ESMap<string, ESMap<string, string>> = new Map(); 410 411 // for public members that accept a Node or one of its subtypes, we must guard against 412 // synthetic nodes created during transformations by calling `getParseTreeNode`. 413 // for most of these, we perform the guard only on `checker` to avoid any possible 414 // extra cost of calling `getParseTreeNode` when calling these functions from inside the 415 // checker. 416 const checker: TypeChecker = { 417 getNodeCount: () => sum(host.getSourceFiles(), "nodeCount"), 418 getIdentifierCount: () => sum(host.getSourceFiles(), "identifierCount"), 419 getSymbolCount: () => sum(host.getSourceFiles(), "symbolCount") + symbolCount, 420 getTypeCount: () => typeCount, 421 getInstantiationCount: () => totalInstantiationCount, 422 getRelationCacheSizes: () => ({ 423 assignable: assignableRelation.size, 424 identity: identityRelation.size, 425 subtype: subtypeRelation.size, 426 strictSubtype: strictSubtypeRelation.size, 427 }), 428 isUndefinedSymbol: symbol => symbol === undefinedSymbol, 429 isArgumentsSymbol: symbol => symbol === argumentsSymbol, 430 isUnknownSymbol: symbol => symbol === unknownSymbol, 431 getMergedSymbol, 432 getDiagnostics, 433 getGlobalDiagnostics, 434 getRecursionIdentity, 435 getUnmatchedProperties, 436 getTypeOfSymbolAtLocation: (symbol, locationIn) => { 437 const location = getParseTreeNode(locationIn); 438 return location ? getTypeOfSymbolAtLocation(symbol, location) : errorType; 439 }, 440 getTypeOfSymbol, 441 getSymbolsOfParameterPropertyDeclaration: (parameterIn, parameterName) => { 442 const parameter = getParseTreeNode(parameterIn, isParameter); 443 if (parameter === undefined) return Debug.fail("Cannot get symbols of a synthetic parameter that cannot be resolved to a parse-tree node."); 444 return getSymbolsOfParameterPropertyDeclaration(parameter, escapeLeadingUnderscores(parameterName)); 445 }, 446 getDeclaredTypeOfSymbol, 447 getPropertiesOfType, 448 getPropertyOfType: (type, name) => getPropertyOfType(type, escapeLeadingUnderscores(name)), 449 getPrivateIdentifierPropertyOfType: (leftType: Type, name: string, location: Node) => { 450 const node = getParseTreeNode(location); 451 if (!node) { 452 return undefined; 453 } 454 const propName = escapeLeadingUnderscores(name); 455 const lexicallyScopedIdentifier = lookupSymbolForPrivateIdentifierDeclaration(propName, node); 456 return lexicallyScopedIdentifier ? getPrivateIdentifierPropertyOfType(leftType, lexicallyScopedIdentifier) : undefined; 457 }, 458 getTypeOfPropertyOfType: (type, name) => getTypeOfPropertyOfType(type, escapeLeadingUnderscores(name)), 459 getIndexInfoOfType: (type, kind) => getIndexInfoOfType(type, kind === IndexKind.String ? stringType : numberType), 460 getIndexInfosOfType, 461 getIndexInfosOfIndexSymbol, 462 getSignaturesOfType, 463 getIndexTypeOfType: (type, kind) => getIndexTypeOfType(type, kind === IndexKind.String ? stringType : numberType), 464 getIndexType: type => getIndexType(type), 465 getBaseTypes, 466 getBaseTypeOfLiteralType, 467 getWidenedType, 468 getTypeFromTypeNode: nodeIn => { 469 const node = getParseTreeNode(nodeIn, isTypeNode); 470 return node ? getTypeFromTypeNode(node) : errorType; 471 }, 472 getParameterType: getTypeAtPosition, 473 getParameterIdentifierNameAtPosition, 474 getPromisedTypeOfPromise, 475 getAwaitedType: type => getAwaitedType(type), 476 getReturnTypeOfSignature, 477 isNullableType, 478 getNullableType, 479 getNonNullableType, 480 getNonOptionalType: removeOptionalTypeMarker, 481 getTypeArguments, 482 typeToTypeNode: nodeBuilder.typeToTypeNode, 483 indexInfoToIndexSignatureDeclaration: nodeBuilder.indexInfoToIndexSignatureDeclaration, 484 signatureToSignatureDeclaration: nodeBuilder.signatureToSignatureDeclaration, 485 symbolToEntityName: nodeBuilder.symbolToEntityName, 486 symbolToExpression: nodeBuilder.symbolToExpression, 487 symbolToNode: nodeBuilder.symbolToNode, 488 symbolToTypeParameterDeclarations: nodeBuilder.symbolToTypeParameterDeclarations, 489 symbolToParameterDeclaration: nodeBuilder.symbolToParameterDeclaration, 490 typeParameterToDeclaration: nodeBuilder.typeParameterToDeclaration, 491 getSymbolsInScope: (locationIn, meaning) => { 492 const location = getParseTreeNode(locationIn); 493 return location ? getSymbolsInScope(location, meaning) : []; 494 }, 495 getSymbolAtLocation: nodeIn => { 496 const node = getParseTreeNode(nodeIn); 497 // set ignoreErrors: true because any lookups invoked by the API shouldn't cause any new errors 498 return node ? getSymbolAtLocation(node, /*ignoreErrors*/ true) : undefined; 499 }, 500 getIndexInfosAtLocation: nodeIn => { 501 const node = getParseTreeNode(nodeIn); 502 return node ? getIndexInfosAtLocation(node) : undefined; 503 }, 504 getShorthandAssignmentValueSymbol: nodeIn => { 505 const node = getParseTreeNode(nodeIn); 506 return node ? getShorthandAssignmentValueSymbol(node) : undefined; 507 }, 508 getExportSpecifierLocalTargetSymbol: nodeIn => { 509 const node = getParseTreeNode(nodeIn, isExportSpecifier); 510 return node ? getExportSpecifierLocalTargetSymbol(node) : undefined; 511 }, 512 getExportSymbolOfSymbol(symbol) { 513 return getMergedSymbol(symbol.exportSymbol || symbol); 514 }, 515 getTypeAtLocation: nodeIn => { 516 const node = getParseTreeNode(nodeIn); 517 return node ? getTypeOfNode(node) : errorType; 518 }, 519 tryGetTypeAtLocationWithoutCheck: nodeIn => { 520 const node = getParseTreeNode(nodeIn); 521 return node ? tryGetTypeOfNodeWithoutCheck(node) : errorType; 522 }, 523 getTypeOfAssignmentPattern: nodeIn => { 524 const node = getParseTreeNode(nodeIn, isAssignmentPattern); 525 return node && getTypeOfAssignmentPattern(node) || errorType; 526 }, 527 getPropertySymbolOfDestructuringAssignment: locationIn => { 528 const location = getParseTreeNode(locationIn, isIdentifier); 529 return location ? getPropertySymbolOfDestructuringAssignment(location) : undefined; 530 }, 531 signatureToString: (signature, enclosingDeclaration, flags, kind) => { 532 return signatureToString(signature, getParseTreeNode(enclosingDeclaration), flags, kind); 533 }, 534 typeToString: (type, enclosingDeclaration, flags) => { 535 return typeToString(type, getParseTreeNode(enclosingDeclaration), flags); 536 }, 537 symbolToString: (symbol, enclosingDeclaration, meaning, flags) => { 538 return symbolToString(symbol, getParseTreeNode(enclosingDeclaration), meaning, flags); 539 }, 540 typePredicateToString: (predicate, enclosingDeclaration, flags) => { 541 return typePredicateToString(predicate, getParseTreeNode(enclosingDeclaration), flags); 542 }, 543 writeSignature: (signature, enclosingDeclaration, flags, kind, writer) => { 544 return signatureToString(signature, getParseTreeNode(enclosingDeclaration), flags, kind, writer); 545 }, 546 writeType: (type, enclosingDeclaration, flags, writer) => { 547 return typeToString(type, getParseTreeNode(enclosingDeclaration), flags, writer); 548 }, 549 writeSymbol: (symbol, enclosingDeclaration, meaning, flags, writer) => { 550 return symbolToString(symbol, getParseTreeNode(enclosingDeclaration), meaning, flags, writer); 551 }, 552 writeTypePredicate: (predicate, enclosingDeclaration, flags, writer) => { 553 return typePredicateToString(predicate, getParseTreeNode(enclosingDeclaration), flags, writer); 554 }, 555 getAugmentedPropertiesOfType, 556 getRootSymbols, 557 getSymbolOfExpando, 558 getContextualType: (nodeIn: Expression, contextFlags?: ContextFlags) => { 559 const node = getParseTreeNode(nodeIn, isExpression); 560 if (!node) { 561 return undefined; 562 } 563 if (contextFlags! & ContextFlags.Completions) { 564 return runWithInferenceBlockedFromSourceNode(node, () => getContextualType(node, contextFlags)); 565 } 566 return getContextualType(node, contextFlags); 567 }, 568 getContextualTypeForObjectLiteralElement: nodeIn => { 569 const node = getParseTreeNode(nodeIn, isObjectLiteralElementLike); 570 return node ? getContextualTypeForObjectLiteralElement(node, /*contextFlags*/ undefined) : undefined; 571 }, 572 getContextualTypeForArgumentAtIndex: (nodeIn, argIndex) => { 573 const node = getParseTreeNode(nodeIn, isCallLikeExpression); 574 return node && getContextualTypeForArgumentAtIndex(node, argIndex); 575 }, 576 getContextualTypeForJsxAttribute: (nodeIn) => { 577 const node = getParseTreeNode(nodeIn, isJsxAttributeLike); 578 return node && getContextualTypeForJsxAttribute(node, /*contextFlags*/ undefined); 579 }, 580 isContextSensitive, 581 getTypeOfPropertyOfContextualType, 582 getFullyQualifiedName, 583 tryGetResolvedSignatureWithoutCheck: (node, candidatesOutArray, argumentCount) => 584 getResolvedSignatureWorker(node, candidatesOutArray, argumentCount, CheckMode.SkipEtsComponentBody), 585 getResolvedSignature: (node, candidatesOutArray, argumentCount) => 586 getResolvedSignatureWorker(node, candidatesOutArray, argumentCount, CheckMode.Normal), 587 getResolvedSignatureForStringLiteralCompletions: (call, editingArgument, candidatesOutArray) => 588 getResolvedSignatureWorker(call, candidatesOutArray, /*argumentCount*/ undefined, CheckMode.IsForStringLiteralArgumentCompletions, editingArgument), 589 getResolvedSignatureForSignatureHelp: (node, candidatesOutArray, argumentCount) => 590 getResolvedSignatureWorker(node, candidatesOutArray, argumentCount, CheckMode.IsForSignatureHelp), 591 getExpandedParameters, 592 hasEffectiveRestParameter, 593 containsArgumentsReference, 594 getConstantValue: nodeIn => { 595 const node = getParseTreeNode(nodeIn, canHaveConstantValue); 596 return node ? getConstantValue(node) : undefined; 597 }, 598 isValidPropertyAccess: (nodeIn, propertyName) => { 599 const node = getParseTreeNode(nodeIn, isPropertyAccessOrQualifiedNameOrImportTypeNode); 600 return !!node && isValidPropertyAccess(node, escapeLeadingUnderscores(propertyName)); 601 }, 602 isValidPropertyAccessForCompletions: (nodeIn, type, property) => { 603 const node = getParseTreeNode(nodeIn, isPropertyAccessExpression); 604 return !!node && isValidPropertyAccessForCompletions(node, type, property); 605 }, 606 getSignatureFromDeclaration: declarationIn => { 607 const declaration = getParseTreeNode(declarationIn, isFunctionLike); 608 return declaration ? getSignatureFromDeclaration(declaration) : undefined; 609 }, 610 isImplementationOfOverload: nodeIn => { 611 const node = getParseTreeNode(nodeIn, isFunctionLike); 612 return node ? isImplementationOfOverload(node) : undefined; 613 }, 614 getImmediateAliasedSymbol, 615 getAliasedSymbol: resolveAlias, 616 getEmitResolver, 617 getExportsOfModule: getExportsOfModuleAsArray, 618 getExportsAndPropertiesOfModule, 619 forEachExportAndPropertyOfModule, 620 getSymbolWalker: createGetSymbolWalker( 621 getRestTypeOfSignature, 622 getTypePredicateOfSignature, 623 getReturnTypeOfSignature, 624 getBaseTypes, 625 resolveStructuredTypeMembers, 626 getTypeOfSymbol, 627 getResolvedSymbol, 628 getConstraintOfTypeParameter, 629 getFirstIdentifier, 630 getTypeArguments, 631 ), 632 getAmbientModules, 633 getJsxIntrinsicTagNamesAt, 634 isOptionalParameter: nodeIn => { 635 const node = getParseTreeNode(nodeIn, isParameter); 636 return node ? isOptionalParameter(node) : false; 637 }, 638 tryGetMemberInModuleExports: (name, symbol) => tryGetMemberInModuleExports(escapeLeadingUnderscores(name), symbol), 639 tryGetMemberInModuleExportsAndProperties: (name, symbol) => tryGetMemberInModuleExportsAndProperties(escapeLeadingUnderscores(name), symbol), 640 tryFindAmbientModule: moduleName => tryFindAmbientModule(moduleName, /*withAugmentations*/ true), 641 tryFindAmbientModuleWithoutAugmentations: moduleName => { 642 // we deliberately exclude augmentations 643 // since we are only interested in declarations of the module itself 644 return tryFindAmbientModule(moduleName, /*withAugmentations*/ false); 645 }, 646 getApparentType, 647 getUnionType, 648 isTypeAssignableTo, 649 createAnonymousType, 650 createSignature, 651 createSymbol, 652 createIndexInfo, 653 getAnyType: () => anyType, 654 getStringType: () => stringType, 655 getNumberType: () => numberType, 656 createPromiseType, 657 createArrayType, 658 getElementTypeOfArrayType, 659 getBooleanType: () => booleanType, 660 getFalseType: (fresh?) => fresh ? falseType : regularFalseType, 661 getTrueType: (fresh?) => fresh ? trueType : regularTrueType, 662 getVoidType: () => voidType, 663 getUndefinedType: () => undefinedType, 664 getNullType: () => nullType, 665 getESSymbolType: () => esSymbolType, 666 getNeverType: () => neverType, 667 getOptionalType: () => optionalType, 668 getPromiseType: () => getGlobalPromiseType(/*reportErrors*/ false), 669 getPromiseLikeType: () => getGlobalPromiseLikeType(/*reportErrors*/ false), 670 getAsyncIterableType: () => { 671 const type = getGlobalAsyncIterableType(/*reportErrors*/ false); 672 if (type === emptyGenericType) return undefined; 673 return type; 674 }, 675 isSymbolAccessible, 676 isArrayType, 677 isTupleType, 678 isArrayLikeType, 679 isTypeInvalidDueToUnionDiscriminant, 680 getExactOptionalProperties, 681 getAllPossiblePropertiesOfTypes, 682 getSuggestedSymbolForNonexistentProperty, 683 getSuggestionForNonexistentProperty, 684 getSuggestedSymbolForNonexistentJSXAttribute, 685 getSuggestedSymbolForNonexistentSymbol: (location, name, meaning) => getSuggestedSymbolForNonexistentSymbol(location, escapeLeadingUnderscores(name), meaning), 686 getSuggestionForNonexistentSymbol: (location, name, meaning) => getSuggestionForNonexistentSymbol(location, escapeLeadingUnderscores(name), meaning), 687 getSuggestedSymbolForNonexistentModule, 688 getSuggestionForNonexistentExport, 689 getSuggestedSymbolForNonexistentClassMember, 690 getBaseConstraintOfType, 691 getDefaultFromTypeParameter: type => type && type.flags & TypeFlags.TypeParameter ? getDefaultFromTypeParameter(type as TypeParameter) : undefined, 692 resolveName(name, location, meaning, excludeGlobals) { 693 return resolveName(location, escapeLeadingUnderscores(name), meaning, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false, excludeGlobals); 694 }, 695 getJsxNamespace: n => unescapeLeadingUnderscores(getJsxNamespace(n)), 696 getJsxFragmentFactory: n => { 697 const jsxFragmentFactory = getJsxFragmentFactoryEntity(n); 698 return jsxFragmentFactory && unescapeLeadingUnderscores(getFirstIdentifier(jsxFragmentFactory).escapedText); 699 }, 700 getAccessibleSymbolChain, 701 getTypePredicateOfSignature, 702 resolveExternalModuleName: moduleSpecifierIn => { 703 const moduleSpecifier = getParseTreeNode(moduleSpecifierIn, isExpression); 704 return moduleSpecifier && resolveExternalModuleName(moduleSpecifier, moduleSpecifier, /*ignoreErrors*/ true); 705 }, 706 resolveExternalModuleSymbol, 707 tryGetThisTypeAt: (nodeIn, includeGlobalThis, container) => { 708 const node = getParseTreeNode(nodeIn); 709 return node && tryGetThisTypeAt(node, includeGlobalThis, container); 710 }, 711 getTypeArgumentConstraint: nodeIn => { 712 const node = getParseTreeNode(nodeIn, isTypeNode); 713 return node && getTypeArgumentConstraint(node); 714 }, 715 getSuggestionDiagnostics: (fileIn, ct) => { 716 const file = getParseTreeNode(fileIn, isSourceFile) || Debug.fail("Could not determine parsed source file."); 717 if (skipTypeChecking(file, compilerOptions, host) || (file.isDeclarationFile && !!compilerOptions.needDoArkTsLinter)) { 718 return emptyArray; 719 } 720 721 let diagnostics: DiagnosticWithLocation[] | undefined; 722 try { 723 // Record the cancellation token so it can be checked later on during checkSourceElement. 724 // Do this in a finally block so we can ensure that it gets reset back to nothing after 725 // this call is done. 726 cancellationToken = ct; 727 728 // Ensure file is type checked, with _eager_ diagnostic production, so identifiers are registered as potentially unused 729 checkSourceFileWithEagerDiagnostics(file); 730 Debug.assert(!!(getNodeLinks(file).flags & NodeCheckFlags.TypeChecked)); 731 732 diagnostics = addRange(diagnostics, suggestionDiagnostics.getDiagnostics(file.fileName)); 733 checkUnusedIdentifiers(getPotentiallyUnusedIdentifiers(file), (containingNode, kind, diag) => { 734 if (!containsParseError(containingNode) && !unusedIsError(kind, !!(containingNode.flags & NodeFlags.Ambient))) { 735 (diagnostics || (diagnostics = [])).push({ ...diag, category: DiagnosticCategory.Suggestion }); 736 } 737 }); 738 739 return diagnostics || emptyArray; 740 } 741 finally { 742 cancellationToken = undefined; 743 } 744 }, 745 746 runWithCancellationToken: (token, callback) => { 747 try { 748 cancellationToken = token; 749 return callback(checker); 750 } 751 finally { 752 cancellationToken = undefined; 753 } 754 }, 755 756 getLocalTypeParametersOfClassOrInterfaceOrTypeAlias, 757 isDeclarationVisible, 758 isPropertyAccessible, 759 getTypeOnlyAliasDeclaration, 760 getMemberOverrideModifierStatus, 761 isTypeParameterPossiblyReferenced, 762 getConstEnumRelate: () => constEnumRelate, 763 clearConstEnumRelate: () => {constEnumRelate && constEnumRelate.clear()}, 764 deleteConstEnumRelate: (path: string) => {constEnumRelate && constEnumRelate.delete(path)}, 765 }; 766 767 function runWithInferenceBlockedFromSourceNode<T>(node: Node | undefined, fn: () => T): T { 768 const containingCall = findAncestor(node, isCallLikeExpression); 769 const containingCallResolvedSignature = containingCall && getNodeLinks(containingCall).resolvedSignature; 770 if (containingCall) { 771 let toMarkSkip = node!; 772 do { 773 getNodeLinks(toMarkSkip).skipDirectInference = true; 774 toMarkSkip = toMarkSkip.parent; 775 } while (toMarkSkip && toMarkSkip !== containingCall); 776 getNodeLinks(containingCall).resolvedSignature = undefined; 777 } 778 const result = fn(); 779 if (containingCall) { 780 let toMarkSkip = node!; 781 do { 782 getNodeLinks(toMarkSkip).skipDirectInference = undefined; 783 toMarkSkip = toMarkSkip.parent; 784 } while (toMarkSkip && toMarkSkip !== containingCall); 785 getNodeLinks(containingCall).resolvedSignature = containingCallResolvedSignature; 786 } 787 return result; 788 } 789 790 function getResolvedSignatureWorker(nodeIn: CallLikeExpression, candidatesOutArray: Signature[] | undefined, argumentCount: number | undefined, checkMode: CheckMode, editingArgument?: Node): Signature | undefined { 791 const node = getParseTreeNode(nodeIn, isCallLikeExpression); 792 apparentArgumentCount = argumentCount; 793 const res = 794 !node ? undefined : 795 editingArgument ? runWithInferenceBlockedFromSourceNode(editingArgument, () => getResolvedSignature(node, candidatesOutArray, checkMode)) : 796 getResolvedSignature(node, candidatesOutArray, checkMode); 797 apparentArgumentCount = undefined; 798 return res; 799 } 800 801 const tupleTypes = new Map<string, GenericType>(); 802 const unionTypes = new Map<string, UnionType>(); 803 const intersectionTypes = new Map<string, Type>(); 804 const stringLiteralTypes = new Map<string, StringLiteralType>(); 805 const numberLiteralTypes = new Map<number, NumberLiteralType>(); 806 const bigIntLiteralTypes = new Map<string, BigIntLiteralType>(); 807 const enumLiteralTypes = new Map<string, LiteralType>(); 808 const indexedAccessTypes = new Map<string, IndexedAccessType>(); 809 const templateLiteralTypes = new Map<string, TemplateLiteralType>(); 810 const stringMappingTypes = new Map<string, StringMappingType>(); 811 const substitutionTypes = new Map<string, SubstitutionType>(); 812 const subtypeReductionCache = new Map<string, Type[]>(); 813 const cachedTypes = new Map<string, Type>(); 814 const evolvingArrayTypes: EvolvingArrayType[] = []; 815 const undefinedProperties: SymbolTable = new Map(); 816 const markerTypes = new Set<number>(); 817 818 const unknownSymbol = createSymbol(SymbolFlags.Property, "unknown" as __String); 819 const resolvingSymbol = createSymbol(0, InternalSymbolName.Resolving); 820 const unresolvedSymbols = new Map<string, TransientSymbol>(); 821 const errorTypes = new Map<string, Type>(); 822 823 const anyType = createIntrinsicType(TypeFlags.Any, "any"); 824 const autoType = createIntrinsicType(TypeFlags.Any, "any", ObjectFlags.NonInferrableType); 825 const wildcardType = createIntrinsicType(TypeFlags.Any, "any"); 826 const errorType = createIntrinsicType(TypeFlags.Any, "error"); 827 const unresolvedType = createIntrinsicType(TypeFlags.Any, "unresolved"); 828 const nonInferrableAnyType = createIntrinsicType(TypeFlags.Any, "any", ObjectFlags.ContainsWideningType); 829 const intrinsicMarkerType = createIntrinsicType(TypeFlags.Any, "intrinsic"); 830 const unknownType = createIntrinsicType(TypeFlags.Unknown, "unknown"); 831 const nonNullUnknownType = createIntrinsicType(TypeFlags.Unknown, "unknown"); 832 const undefinedType = createIntrinsicType(TypeFlags.Undefined, "undefined"); 833 const undefinedWideningType = strictNullChecks ? undefinedType : createIntrinsicType(TypeFlags.Undefined, "undefined", ObjectFlags.ContainsWideningType); 834 const optionalType = createIntrinsicType(TypeFlags.Undefined, "undefined"); 835 const missingType = exactOptionalPropertyTypes ? createIntrinsicType(TypeFlags.Undefined, "undefined") : undefinedType; 836 const nullType = createIntrinsicType(TypeFlags.Null, "null"); 837 const nullWideningType = strictNullChecks ? nullType : createIntrinsicType(TypeFlags.Null, "null", ObjectFlags.ContainsWideningType); 838 const stringType = createIntrinsicType(TypeFlags.String, "string"); 839 const numberType = createIntrinsicType(TypeFlags.Number, "number"); 840 const bigintType = createIntrinsicType(TypeFlags.BigInt, "bigint"); 841 const falseType = createIntrinsicType(TypeFlags.BooleanLiteral, "false") as FreshableIntrinsicType; 842 const regularFalseType = createIntrinsicType(TypeFlags.BooleanLiteral, "false") as FreshableIntrinsicType; 843 const trueType = createIntrinsicType(TypeFlags.BooleanLiteral, "true") as FreshableIntrinsicType; 844 const regularTrueType = createIntrinsicType(TypeFlags.BooleanLiteral, "true") as FreshableIntrinsicType; 845 trueType.regularType = regularTrueType; 846 trueType.freshType = trueType; 847 regularTrueType.regularType = regularTrueType; 848 regularTrueType.freshType = trueType; 849 falseType.regularType = regularFalseType; 850 falseType.freshType = falseType; 851 regularFalseType.regularType = regularFalseType; 852 regularFalseType.freshType = falseType; 853 const booleanType = getUnionType([regularFalseType, regularTrueType]); 854 const esSymbolType = createIntrinsicType(TypeFlags.ESSymbol, "symbol"); 855 const voidType = createIntrinsicType(TypeFlags.Void, "void"); 856 const neverType = createIntrinsicType(TypeFlags.Never, "never"); 857 const silentNeverType = createIntrinsicType(TypeFlags.Never, "never", ObjectFlags.NonInferrableType); 858 const implicitNeverType = createIntrinsicType(TypeFlags.Never, "never"); 859 const unreachableNeverType = createIntrinsicType(TypeFlags.Never, "never"); 860 const nonPrimitiveType = createIntrinsicType(TypeFlags.NonPrimitive, "object"); 861 const stringOrNumberType = getUnionType([stringType, numberType]); 862 const stringNumberSymbolType = getUnionType([stringType, numberType, esSymbolType]); 863 const keyofConstraintType = keyofStringsOnly ? stringType : stringNumberSymbolType; 864 const numberOrBigIntType = getUnionType([numberType, bigintType]); 865 const templateConstraintType = getUnionType([stringType, numberType, booleanType, bigintType, nullType, undefinedType]) as UnionType; 866 const numericStringType = getTemplateLiteralType(["", ""], [numberType]); // The `${number}` type 867 868 const restrictiveMapper: TypeMapper = makeFunctionTypeMapper(t => t.flags & TypeFlags.TypeParameter ? getRestrictiveTypeParameter(t as TypeParameter) : t, () => "(restrictive mapper)"); 869 const permissiveMapper: TypeMapper = makeFunctionTypeMapper(t => t.flags & TypeFlags.TypeParameter ? wildcardType : t, () => "(permissive mapper)"); 870 const uniqueLiteralType = createIntrinsicType(TypeFlags.Never, "never"); // `uniqueLiteralType` is a special `never` flagged by union reduction to behave as a literal 871 const uniqueLiteralMapper: TypeMapper = makeFunctionTypeMapper(t => t.flags & TypeFlags.TypeParameter ? uniqueLiteralType : t, () => "(unique literal mapper)"); // replace all type parameters with the unique literal type (disregarding constraints) 872 let outofbandVarianceMarkerHandler: ((onlyUnreliable: boolean) => void) | undefined; 873 const reportUnreliableMapper = makeFunctionTypeMapper(t => { 874 if (outofbandVarianceMarkerHandler && (t === markerSuperType || t === markerSubType || t === markerOtherType)) { 875 outofbandVarianceMarkerHandler(/*onlyUnreliable*/ true); 876 } 877 return t; 878 }, () => "(unmeasurable reporter)"); 879 const reportUnmeasurableMapper = makeFunctionTypeMapper(t => { 880 if (outofbandVarianceMarkerHandler && (t === markerSuperType || t === markerSubType || t === markerOtherType)) { 881 outofbandVarianceMarkerHandler(/*onlyUnreliable*/ false); 882 } 883 return t; 884 }, () => "(unreliable reporter)"); 885 886 const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, emptyArray); 887 const emptyJsxObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, emptyArray); 888 emptyJsxObjectType.objectFlags |= ObjectFlags.JsxAttributes; 889 890 const emptyTypeLiteralSymbol = createSymbol(SymbolFlags.TypeLiteral, InternalSymbolName.Type); 891 emptyTypeLiteralSymbol.members = createSymbolTable(); 892 const emptyTypeLiteralType = createAnonymousType(emptyTypeLiteralSymbol, emptySymbols, emptyArray, emptyArray, emptyArray); 893 894 const unknownEmptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, emptyArray); 895 const unknownUnionType = strictNullChecks ? getUnionType([undefinedType, nullType, unknownEmptyObjectType]) : unknownType; 896 897 const emptyGenericType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, emptyArray) as ObjectType as GenericType; 898 emptyGenericType.instantiations = new Map<string, TypeReference>(); 899 900 const anyFunctionType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, emptyArray); 901 // The anyFunctionType contains the anyFunctionType by definition. The flag is further propagated 902 // in getPropagatingFlagsOfTypes, and it is checked in inferFromTypes. 903 anyFunctionType.objectFlags |= ObjectFlags.NonInferrableType; 904 905 const noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, emptyArray); 906 const circularConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, emptyArray); 907 const resolvingDefaultType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, emptyArray); 908 909 const markerSuperType = createTypeParameter(); 910 const markerSubType = createTypeParameter(); 911 markerSubType.constraint = markerSuperType; 912 const markerOtherType = createTypeParameter(); 913 914 const markerSuperTypeForCheck = createTypeParameter(); 915 const markerSubTypeForCheck = createTypeParameter(); 916 markerSubTypeForCheck.constraint = markerSuperTypeForCheck; 917 918 const noTypePredicate = createTypePredicate(TypePredicateKind.Identifier, "<<unresolved>>", 0, anyType); 919 920 const anySignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.None); 921 const unknownSignature = createSignature(undefined, undefined, undefined, emptyArray, errorType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.None); 922 const resolvingSignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.None); 923 const silentNeverSignature = createSignature(undefined, undefined, undefined, emptyArray, silentNeverType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.None); 924 const annotationDefaultSignature = createSignature(undefined, undefined, undefined, emptyArray, voidType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.None); 925 926 const enumNumberIndexInfo = createIndexInfo(numberType, stringType, /*isReadonly*/ true); 927 928 const iterationTypesCache = new Map<string, IterationTypes>(); // cache for common IterationTypes instances 929 const noIterationTypes: IterationTypes = { 930 get yieldType(): Type { return Debug.fail("Not supported"); }, 931 get returnType(): Type { return Debug.fail("Not supported"); }, 932 get nextType(): Type { return Debug.fail("Not supported"); }, 933 }; 934 935 const anyIterationTypes = createIterationTypes(anyType, anyType, anyType); 936 const anyIterationTypesExceptNext = createIterationTypes(anyType, anyType, unknownType); 937 const defaultIterationTypes = createIterationTypes(neverType, anyType, undefinedType); // default iteration types for `Iterator`. 938 939 const asyncIterationTypesResolver: IterationTypesResolver = { 940 iterableCacheKey: "iterationTypesOfAsyncIterable", 941 iteratorCacheKey: "iterationTypesOfAsyncIterator", 942 iteratorSymbolName: "asyncIterator", 943 getGlobalIteratorType: getGlobalAsyncIteratorType, 944 getGlobalIterableType: getGlobalAsyncIterableType, 945 getGlobalIterableIteratorType: getGlobalAsyncIterableIteratorType, 946 getGlobalGeneratorType: getGlobalAsyncGeneratorType, 947 resolveIterationType: getAwaitedType, 948 mustHaveANextMethodDiagnostic: Diagnostics.An_async_iterator_must_have_a_next_method, 949 mustBeAMethodDiagnostic: Diagnostics.The_0_property_of_an_async_iterator_must_be_a_method, 950 mustHaveAValueDiagnostic: Diagnostics.The_type_returned_by_the_0_method_of_an_async_iterator_must_be_a_promise_for_a_type_with_a_value_property, 951 }; 952 953 const syncIterationTypesResolver: IterationTypesResolver = { 954 iterableCacheKey: "iterationTypesOfIterable", 955 iteratorCacheKey: "iterationTypesOfIterator", 956 iteratorSymbolName: "iterator", 957 getGlobalIteratorType, 958 getGlobalIterableType, 959 getGlobalIterableIteratorType, 960 getGlobalGeneratorType, 961 resolveIterationType: (type, _errorNode) => type, 962 mustHaveANextMethodDiagnostic: Diagnostics.An_iterator_must_have_a_next_method, 963 mustBeAMethodDiagnostic: Diagnostics.The_0_property_of_an_iterator_must_be_a_method, 964 mustHaveAValueDiagnostic: Diagnostics.The_type_returned_by_the_0_method_of_an_iterator_must_have_a_value_property, 965 }; 966 967 interface DuplicateInfoForSymbol { 968 readonly firstFileLocations: Declaration[]; 969 readonly secondFileLocations: Declaration[]; 970 readonly isBlockScoped: boolean; 971 } 972 interface DuplicateInfoForFiles { 973 readonly firstFile: SourceFile; 974 readonly secondFile: SourceFile; 975 /** Key is symbol name. */ 976 readonly conflictingSymbols: ESMap<string, DuplicateInfoForSymbol>; 977 } 978 /** Key is "/path/to/a.ts|/path/to/b.ts". */ 979 let amalgamatedDuplicates: ESMap<string, DuplicateInfoForFiles> | undefined; 980 const reverseMappedCache = new Map<string, Type | undefined>(); 981 let inInferTypeForHomomorphicMappedType = false; 982 let ambientModulesCache: Symbol[] | undefined; 983 /** 984 * List of every ambient module with a "*" wildcard. 985 * Unlike other ambient modules, these can't be stored in `globals` because symbol tables only deal with exact matches. 986 * This is only used if there is no exact match. 987 */ 988 let patternAmbientModules: PatternAmbientModule[]; 989 let patternAmbientModuleAugmentations: ESMap<string, Symbol> | undefined; 990 991 let globalObjectType: ObjectType; 992 let globalFunctionType: ObjectType; 993 let globalCallableFunctionType: ObjectType; 994 let globalNewableFunctionType: ObjectType; 995 let globalArrayType: GenericType; 996 let globalReadonlyArrayType: GenericType; 997 let globalStringType: ObjectType; 998 let globalNumberType: ObjectType; 999 let globalBooleanType: ObjectType; 1000 let globalRegExpType: ObjectType; 1001 let globalThisType: GenericType; 1002 let anyArrayType: Type; 1003 let autoArrayType: Type; 1004 let anyReadonlyArrayType: Type; 1005 let deferredGlobalNonNullableTypeAlias: Symbol; 1006 1007 // The library files are only loaded when the feature is used. 1008 // This allows users to just specify library files they want to used through --lib 1009 // and they will not get an error from not having unrelated library files 1010 let deferredGlobalESSymbolConstructorSymbol: Symbol | undefined; 1011 let deferredGlobalESSymbolConstructorTypeSymbol: Symbol | undefined; 1012 let deferredGlobalESSymbolType: ObjectType | undefined; 1013 let deferredGlobalTypedPropertyDescriptorType: GenericType; 1014 let deferredGlobalPromiseType: GenericType | undefined; 1015 let deferredGlobalPromiseLikeType: GenericType | undefined; 1016 let deferredGlobalPromiseConstructorSymbol: Symbol | undefined; 1017 let deferredGlobalPromiseConstructorLikeType: ObjectType | undefined; 1018 let deferredGlobalIterableType: GenericType | undefined; 1019 let deferredGlobalIteratorType: GenericType | undefined; 1020 let deferredGlobalIterableIteratorType: GenericType | undefined; 1021 let deferredGlobalGeneratorType: GenericType | undefined; 1022 let deferredGlobalIteratorYieldResultType: GenericType | undefined; 1023 let deferredGlobalIteratorReturnResultType: GenericType | undefined; 1024 let deferredGlobalAsyncIterableType: GenericType | undefined; 1025 let deferredGlobalAsyncIteratorType: GenericType | undefined; 1026 let deferredGlobalAsyncIterableIteratorType: GenericType | undefined; 1027 let deferredGlobalAsyncGeneratorType: GenericType | undefined; 1028 let deferredGlobalTemplateStringsArrayType: ObjectType | undefined; 1029 let deferredGlobalImportMetaType: ObjectType; 1030 let deferredGlobalImportMetaExpressionType: ObjectType; 1031 let deferredGlobalImportCallOptionsType: ObjectType | undefined; 1032 let deferredGlobalExtractSymbol: Symbol | undefined; 1033 let deferredGlobalOmitSymbol: Symbol | undefined; 1034 let deferredGlobalAwaitedSymbol: Symbol | undefined; 1035 let deferredGlobalBigIntType: ObjectType | undefined; 1036 let deferredGlobalNaNSymbol: Symbol | undefined; 1037 let deferredGlobalRecordSymbol: Symbol | undefined; 1038 1039 const allPotentiallyUnusedIdentifiers = new Map<Path, PotentiallyUnusedIdentifier[]>(); // key is file name 1040 1041 let flowLoopStart = 0; 1042 let flowLoopCount = 0; 1043 let sharedFlowCount = 0; 1044 let flowAnalysisDisabled = false; 1045 let flowInvocationCount = 0; 1046 let lastFlowNode: FlowNode | undefined; 1047 let lastFlowNodeReachable: boolean; 1048 let flowTypeCache: Type[] | undefined; 1049 1050 const emptyStringType = getStringLiteralType(""); 1051 const zeroType = getNumberLiteralType(0); 1052 const zeroBigIntType = getBigIntLiteralType({ negative: false, base10Value: "0" }); 1053 1054 const resolutionTargets: TypeSystemEntity[] = []; 1055 const resolutionResults: boolean[] = []; 1056 const resolutionPropertyNames: TypeSystemPropertyName[] = []; 1057 1058 let suggestionCount = 0; 1059 const maximumSuggestionCount = 10; 1060 const mergedSymbols: Symbol[] = []; 1061 const symbolLinks: SymbolLinks[] = []; 1062 const nodeLinks: NodeLinks[] = []; 1063 const flowLoopCaches: ESMap<string, Type>[] = []; 1064 const flowLoopNodes: FlowNode[] = []; 1065 const flowLoopKeys: string[] = []; 1066 const flowLoopTypes: Type[][] = []; 1067 const sharedFlowNodes: FlowNode[] = []; 1068 const sharedFlowTypes: FlowType[] = []; 1069 const flowNodeReachable: (boolean | undefined)[] = []; 1070 const flowNodePostSuper: (boolean | undefined)[] = []; 1071 const potentialThisCollisions: Node[] = []; 1072 const potentialNewTargetCollisions: Node[] = []; 1073 const potentialWeakMapSetCollisions: Node[] = []; 1074 const potentialReflectCollisions: Node[] = []; 1075 const potentialUnusedRenamedBindingElementsInTypes: BindingElement[] = []; 1076 const awaitedTypeStack: number[] = []; 1077 1078 const diagnostics = createDiagnosticCollection(); 1079 const suggestionDiagnostics = createDiagnosticCollection(); 1080 1081 const typeofType = createTypeofType(); 1082 1083 let _jsxNamespace: __String; 1084 let _jsxFactoryEntity: EntityName | undefined; 1085 1086 const subtypeRelation = new Map<string, RelationComparisonResult>(); 1087 const strictSubtypeRelation = new Map<string, RelationComparisonResult>(); 1088 const assignableRelation = new Map<string, RelationComparisonResult>(); 1089 const comparableRelation = new Map<string, RelationComparisonResult>(); 1090 const identityRelation = new Map<string, RelationComparisonResult>(); 1091 const enumRelation = new Map<string, RelationComparisonResult>(); 1092 1093 const builtinGlobals = createSymbolTable(); 1094 builtinGlobals.set(undefinedSymbol.escapedName, undefinedSymbol); 1095 1096 // Extensions suggested for path imports when module resolution is node16 or higher. 1097 // The first element of each tuple is the extension a file has. 1098 // The second element of each tuple is the extension that should be used in a path import. 1099 // e.g. if we want to import file `foo.mts`, we should write `import {} from "./foo.mjs". 1100 const suggestedExtensions: [string, string][] = [ 1101 [".mts", ".mjs"], 1102 [".ts", ".js"], 1103 [".cts", ".cjs"], 1104 [".mjs", ".mjs"], 1105 [".js", ".js"], 1106 [".cjs", ".cjs"], 1107 [".tsx", compilerOptions.jsx === JsxEmit.Preserve ? ".jsx" : ".js"], 1108 [".jsx", ".jsx"], 1109 [".json", ".json"], 1110 ]; 1111 1112 let jsDocFileCheckInfo: FileCheckModuleInfo = { 1113 fileNeedCheck: false, 1114 checkPayload: undefined, 1115 currentFileName: "", 1116 } 1117 1118 initializeTypeChecker(); 1119 1120 return checker; 1121 1122 function getCachedType(key: string | undefined) { 1123 return key ? cachedTypes.get(key) : undefined; 1124 } 1125 1126 function setCachedType(key: string | undefined, type: Type) { 1127 if (key) cachedTypes.set(key, type); 1128 return type; 1129 } 1130 1131 function getJsxNamespace(location: Node | undefined): __String { 1132 if (location) { 1133 const file = getSourceFileOfNode(location); 1134 if (file) { 1135 if (isJsxOpeningFragment(location)) { 1136 if (file.localJsxFragmentNamespace) { 1137 return file.localJsxFragmentNamespace; 1138 } 1139 const jsxFragmentPragma = file.pragmas.get("jsxfrag"); 1140 if (jsxFragmentPragma) { 1141 const chosenPragma = isArray(jsxFragmentPragma) ? jsxFragmentPragma[0] : jsxFragmentPragma; 1142 file.localJsxFragmentFactory = parseIsolatedEntityName(chosenPragma.arguments.factory, languageVersion); 1143 visitNode(file.localJsxFragmentFactory, markAsSynthetic); 1144 if (file.localJsxFragmentFactory) { 1145 return file.localJsxFragmentNamespace = getFirstIdentifier(file.localJsxFragmentFactory).escapedText; 1146 } 1147 } 1148 const entity = getJsxFragmentFactoryEntity(location); 1149 if (entity) { 1150 file.localJsxFragmentFactory = entity; 1151 return file.localJsxFragmentNamespace = getFirstIdentifier(entity).escapedText; 1152 } 1153 } 1154 else { 1155 const localJsxNamespace = getLocalJsxNamespace(file); 1156 if (localJsxNamespace) { 1157 return file.localJsxNamespace = localJsxNamespace; 1158 } 1159 } 1160 } 1161 } 1162 if (!_jsxNamespace) { 1163 _jsxNamespace = "React" as __String; 1164 if (compilerOptions.jsxFactory) { 1165 _jsxFactoryEntity = parseIsolatedEntityName(compilerOptions.jsxFactory, languageVersion); 1166 visitNode(_jsxFactoryEntity, markAsSynthetic); 1167 if (_jsxFactoryEntity) { 1168 _jsxNamespace = getFirstIdentifier(_jsxFactoryEntity).escapedText; 1169 } 1170 } 1171 else if (compilerOptions.reactNamespace) { 1172 _jsxNamespace = escapeLeadingUnderscores(compilerOptions.reactNamespace); 1173 } 1174 } 1175 if (!_jsxFactoryEntity) { 1176 _jsxFactoryEntity = factory.createQualifiedName(factory.createIdentifier(unescapeLeadingUnderscores(_jsxNamespace)), "createElement"); 1177 } 1178 return _jsxNamespace; 1179 } 1180 1181 function getLocalJsxNamespace(file: SourceFile): __String | undefined { 1182 if (file.localJsxNamespace) { 1183 return file.localJsxNamespace; 1184 } 1185 const jsxPragma = file.pragmas.get("jsx"); 1186 if (jsxPragma) { 1187 const chosenPragma = isArray(jsxPragma) ? jsxPragma[0] : jsxPragma; 1188 file.localJsxFactory = parseIsolatedEntityName(chosenPragma.arguments.factory, languageVersion); 1189 visitNode(file.localJsxFactory, markAsSynthetic); 1190 if (file.localJsxFactory) { 1191 return file.localJsxNamespace = getFirstIdentifier(file.localJsxFactory).escapedText; 1192 } 1193 } 1194 } 1195 1196 function markAsSynthetic(node: Node): VisitResult<Node> { 1197 setTextRangePosEnd(node, -1, -1); 1198 return visitEachChild(node, markAsSynthetic, nullTransformationContext); 1199 } 1200 1201 function getEmitResolver(sourceFile: SourceFile, cancellationToken: CancellationToken) { 1202 // Ensure we have all the type information in place for this file so that all the 1203 // emitter questions of this resolver will return the right information. 1204 getDiagnostics(sourceFile, cancellationToken); 1205 return emitResolver; 1206 } 1207 1208 function lookupOrIssueError(location: Node | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): Diagnostic { 1209 const diagnostic = location 1210 ? createDiagnosticForNode(location, message, arg0, arg1, arg2, arg3) 1211 : createCompilerDiagnostic(message, arg0, arg1, arg2, arg3); 1212 const existing = diagnostics.lookup(diagnostic); 1213 if (existing) { 1214 return existing; 1215 } 1216 else { 1217 diagnostics.add(diagnostic); 1218 return diagnostic; 1219 } 1220 } 1221 1222 function errorSkippedOn(key: keyof CompilerOptions, location: Node | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): Diagnostic { 1223 const diagnostic = error(location, message, arg0, arg1, arg2, arg3); 1224 diagnostic.skippedOn = key; 1225 return diagnostic; 1226 } 1227 1228 function createError(location: Node | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): Diagnostic { 1229 return location 1230 ? createDiagnosticForNode(location, message, arg0, arg1, arg2, arg3) 1231 : createCompilerDiagnostic(message, arg0, arg1, arg2, arg3); 1232 } 1233 1234 function error(location: Node | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): Diagnostic { 1235 const diagnostic = createError(location, message, arg0, arg1, arg2, arg3); 1236 diagnostics.add(diagnostic); 1237 return diagnostic; 1238 } 1239 1240 function addErrorOrSuggestion(isError: boolean, diagnostic: Diagnostic) { 1241 if (isError) { 1242 diagnostics.add(diagnostic); 1243 } 1244 else { 1245 suggestionDiagnostics.add({ ...diagnostic, category: DiagnosticCategory.Suggestion }); 1246 } 1247 } 1248 function errorOrSuggestion(isError: boolean, location: Node, message: DiagnosticMessage | DiagnosticMessageChain, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): void { 1249 // Pseudo-synthesized input node 1250 if (location.pos < 0 || location.end < 0) { 1251 if (!isError) { 1252 return; // Drop suggestions (we have no span to suggest on) 1253 } 1254 // Issue errors globally 1255 const file = getSourceFileOfNode(location); 1256 addErrorOrSuggestion(isError, "message" in message ? createFileDiagnostic(file, 0, 0, message, arg0, arg1, arg2, arg3) : createDiagnosticForFileFromMessageChain(file, message)); // eslint-disable-line local/no-in-operator 1257 return; 1258 } 1259 addErrorOrSuggestion(isError, "message" in message ? createDiagnosticForNode(location, message, arg0, arg1, arg2, arg3) : createDiagnosticForNodeFromMessageChain(location, message)); // eslint-disable-line local/no-in-operator 1260 } 1261 1262 function errorAndMaybeSuggestAwait( 1263 location: Node, 1264 maybeMissingAwait: boolean, 1265 message: DiagnosticMessage, 1266 arg0?: string | number | undefined, arg1?: string | number | undefined, arg2?: string | number | undefined, arg3?: string | number | undefined): Diagnostic { 1267 const diagnostic = error(location, message, arg0, arg1, arg2, arg3); 1268 if (maybeMissingAwait) { 1269 const related = createDiagnosticForNode(location, Diagnostics.Did_you_forget_to_use_await); 1270 addRelatedInfo(diagnostic, related); 1271 } 1272 return diagnostic; 1273 } 1274 1275 function addDeprecatedSuggestionWorker(declarations: Node | Node[], diagnostic: DiagnosticWithLocation) { 1276 const deprecatedTag = Array.isArray(declarations) ? forEach(declarations, getJSDocDeprecatedTag) : getJSDocDeprecatedTag(declarations); 1277 if (deprecatedTag) { 1278 addRelatedInfo( 1279 diagnostic, 1280 createDiagnosticForNode(deprecatedTag, Diagnostics.The_declaration_was_marked_as_deprecated_here) 1281 ); 1282 } 1283 // We call `addRelatedInfo()` before adding the diagnostic to prevent duplicates. 1284 suggestionDiagnostics.add(diagnostic); 1285 return diagnostic; 1286 } 1287 1288 function isDeprecatedSymbol(symbol: Symbol) { 1289 return !!(getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Deprecated); 1290 } 1291 1292 function addDeprecatedSuggestion(location: Node, declarations: Node[], deprecatedEntity: string) { 1293 const diagnostic = createDiagnosticForNode(location, Diagnostics._0_is_deprecated, deprecatedEntity); 1294 return addDeprecatedSuggestionWorker(declarations, diagnostic); 1295 } 1296 1297 function addDeprecatedSuggestionWithSignature(location: Node, declaration: Node, deprecatedEntity: string | undefined, signatureString: string) { 1298 const diagnostic = deprecatedEntity 1299 ? createDiagnosticForNode(location, Diagnostics.The_signature_0_of_1_is_deprecated, signatureString, deprecatedEntity) 1300 : createDiagnosticForNode(location, Diagnostics._0_is_deprecated, signatureString); 1301 return addDeprecatedSuggestionWorker(declaration, diagnostic); 1302 } 1303 1304 function createSymbol(flags: SymbolFlags, name: __String, checkFlags?: CheckFlags) { 1305 symbolCount++; 1306 const symbol = (new Symbol(flags | SymbolFlags.Transient, name) as TransientSymbol); 1307 symbol.checkFlags = checkFlags || 0; 1308 return symbol; 1309 } 1310 1311 function getExcludedSymbolFlags(flags: SymbolFlags): SymbolFlags { 1312 let result: SymbolFlags = 0; 1313 if (flags & SymbolFlags.BlockScopedVariable) result |= SymbolFlags.BlockScopedVariableExcludes; 1314 if (flags & SymbolFlags.FunctionScopedVariable) result |= SymbolFlags.FunctionScopedVariableExcludes; 1315 if (flags & SymbolFlags.Property) result |= SymbolFlags.PropertyExcludes; 1316 if (flags & SymbolFlags.EnumMember) result |= SymbolFlags.EnumMemberExcludes; 1317 if (flags & SymbolFlags.Function) result |= SymbolFlags.FunctionExcludes; 1318 if (flags & SymbolFlags.Class) result |= SymbolFlags.ClassExcludes; 1319 if (flags & SymbolFlags.Interface) result |= SymbolFlags.InterfaceExcludes; 1320 if (flags & SymbolFlags.RegularEnum) result |= SymbolFlags.RegularEnumExcludes; 1321 if (flags & SymbolFlags.ConstEnum) result |= SymbolFlags.ConstEnumExcludes; 1322 if (flags & SymbolFlags.ValueModule) result |= SymbolFlags.ValueModuleExcludes; 1323 if (flags & SymbolFlags.Method) result |= SymbolFlags.MethodExcludes; 1324 if (flags & SymbolFlags.GetAccessor) result |= SymbolFlags.GetAccessorExcludes; 1325 if (flags & SymbolFlags.SetAccessor) result |= SymbolFlags.SetAccessorExcludes; 1326 if (flags & SymbolFlags.TypeParameter) result |= SymbolFlags.TypeParameterExcludes; 1327 if (flags & SymbolFlags.TypeAlias) result |= SymbolFlags.TypeAliasExcludes; 1328 if (flags & SymbolFlags.Alias) result |= SymbolFlags.AliasExcludes; 1329 return result; 1330 } 1331 1332 function recordMergedSymbol(target: Symbol, source: Symbol) { 1333 if (!source.mergeId) { 1334 source.mergeId = nextMergeId; 1335 nextMergeId++; 1336 } 1337 mergedSymbols[source.mergeId] = target; 1338 } 1339 1340 function cloneSymbol(symbol: Symbol): Symbol { 1341 const result = createSymbol(symbol.flags, symbol.escapedName); 1342 result.declarations = symbol.declarations ? symbol.declarations.slice() : []; 1343 result.parent = symbol.parent; 1344 if (symbol.valueDeclaration) result.valueDeclaration = symbol.valueDeclaration; 1345 if (symbol.constEnumOnlyModule) result.constEnumOnlyModule = true; 1346 if (symbol.members) result.members = new Map(symbol.members); 1347 if (symbol.exports) result.exports = new Map(symbol.exports); 1348 recordMergedSymbol(result, symbol); 1349 return result; 1350 } 1351 1352 /** 1353 * Note: if target is transient, then it is mutable, and mergeSymbol with both mutate and return it. 1354 * If target is not transient, mergeSymbol will produce a transient clone, mutate that and return it. 1355 */ 1356 function mergeSymbol(target: Symbol, source: Symbol, unidirectional = false): Symbol { 1357 if (!(target.flags & getExcludedSymbolFlags(source.flags)) || 1358 (source.flags | target.flags) & SymbolFlags.Assignment) { 1359 if (source === target) { 1360 // This can happen when an export assigned namespace exports something also erroneously exported at the top level 1361 // See `declarationFileNoCrashOnExtraExportModifier` for an example 1362 return target; 1363 } 1364 if (!(target.flags & SymbolFlags.Transient)) { 1365 const resolvedTarget = resolveSymbol(target); 1366 if (resolvedTarget === unknownSymbol) { 1367 return source; 1368 } 1369 target = cloneSymbol(resolvedTarget); 1370 } 1371 // Javascript static-property-assignment declarations always merge, even though they are also values 1372 if (source.flags & SymbolFlags.ValueModule && target.flags & SymbolFlags.ValueModule && target.constEnumOnlyModule && !source.constEnumOnlyModule) { 1373 // reset flag when merging instantiated module into value module that has only const enums 1374 target.constEnumOnlyModule = false; 1375 } 1376 target.flags |= source.flags; 1377 if (source.valueDeclaration) { 1378 setValueDeclaration(target, source.valueDeclaration); 1379 } 1380 addRange(target.declarations, source.declarations); 1381 if (source.members) { 1382 if (!target.members) target.members = createSymbolTable(); 1383 mergeSymbolTable(target.members, source.members, unidirectional); 1384 } 1385 if (source.exports) { 1386 if (!target.exports) target.exports = createSymbolTable(); 1387 mergeSymbolTable(target.exports, source.exports, unidirectional); 1388 } 1389 if (!unidirectional) { 1390 recordMergedSymbol(target, source); 1391 } 1392 } 1393 else if (target.flags & SymbolFlags.NamespaceModule) { 1394 // Do not report an error when merging `var globalThis` with the built-in `globalThis`, 1395 // as we will already report a "Declaration name conflicts..." error, and this error 1396 // won't make much sense. 1397 if (target !== globalThisSymbol) { 1398 error( 1399 source.declarations && getNameOfDeclaration(source.declarations[0]), 1400 Diagnostics.Cannot_augment_module_0_with_value_exports_because_it_resolves_to_a_non_module_entity, 1401 symbolToString(target)); 1402 } 1403 } 1404 else { // error 1405 const isEitherEnum = !!(target.flags & SymbolFlags.Enum || source.flags & SymbolFlags.Enum); 1406 const isEitherBlockScoped = !!(target.flags & SymbolFlags.BlockScopedVariable || source.flags & SymbolFlags.BlockScopedVariable); 1407 const message = isEitherEnum ? Diagnostics.Enum_declarations_can_only_merge_with_namespace_or_other_enum_declarations 1408 : isEitherBlockScoped ? Diagnostics.Cannot_redeclare_block_scoped_variable_0 1409 : Diagnostics.Duplicate_identifier_0; 1410 const sourceSymbolFile = source.declarations && getSourceFileOfNode(source.declarations[0]); 1411 const targetSymbolFile = target.declarations && getSourceFileOfNode(target.declarations[0]); 1412 1413 const isSourcePlainJs = isPlainJsFile(sourceSymbolFile, compilerOptions.checkJs); 1414 const isTargetPlainJs = isPlainJsFile(targetSymbolFile, compilerOptions.checkJs); 1415 const symbolName = symbolToString(source); 1416 1417 // Collect top-level duplicate identifier errors into one mapping, so we can then merge their diagnostics if there are a bunch 1418 if (sourceSymbolFile && targetSymbolFile && amalgamatedDuplicates && !isEitherEnum && sourceSymbolFile !== targetSymbolFile) { 1419 const firstFile = comparePaths(sourceSymbolFile.path, targetSymbolFile.path) === Comparison.LessThan ? sourceSymbolFile : targetSymbolFile; 1420 const secondFile = firstFile === sourceSymbolFile ? targetSymbolFile : sourceSymbolFile; 1421 const filesDuplicates = getOrUpdate(amalgamatedDuplicates, `${firstFile.path}|${secondFile.path}`, () => 1422 ({ firstFile, secondFile, conflictingSymbols: new Map() } as DuplicateInfoForFiles)); 1423 const conflictingSymbolInfo = getOrUpdate(filesDuplicates.conflictingSymbols, symbolName, () => 1424 ({ isBlockScoped: isEitherBlockScoped, firstFileLocations: [], secondFileLocations: [] } as DuplicateInfoForSymbol)); 1425 if (!isSourcePlainJs) addDuplicateLocations(conflictingSymbolInfo.firstFileLocations, source); 1426 if (!isTargetPlainJs) addDuplicateLocations(conflictingSymbolInfo.secondFileLocations, target); 1427 } 1428 else { 1429 if (!isSourcePlainJs) addDuplicateDeclarationErrorsForSymbols(source, message, symbolName, target); 1430 if (!isTargetPlainJs) addDuplicateDeclarationErrorsForSymbols(target, message, symbolName, source); 1431 } 1432 } 1433 return target; 1434 1435 function addDuplicateLocations(locs: Declaration[], symbol: Symbol): void { 1436 if (symbol.declarations) { 1437 for (const decl of symbol.declarations) { 1438 pushIfUnique(locs, decl); 1439 } 1440 } 1441 } 1442 } 1443 1444 function addDuplicateDeclarationErrorsForSymbols(target: Symbol, message: DiagnosticMessage, symbolName: string, source: Symbol) { 1445 forEach(target.declarations, node => { 1446 addDuplicateDeclarationError(node, message, symbolName, source.declarations); 1447 }); 1448 } 1449 1450 function addDuplicateDeclarationError(node: Declaration, message: DiagnosticMessage, symbolName: string, relatedNodes: readonly Declaration[] | undefined) { 1451 const errorNode = (getExpandoInitializer(node, /*isPrototypeAssignment*/ false) ? getNameOfExpando(node) : getNameOfDeclaration(node)) || node; 1452 const err = lookupOrIssueError(errorNode, message, symbolName); 1453 for (const relatedNode of relatedNodes || emptyArray) { 1454 const adjustedNode = (getExpandoInitializer(relatedNode, /*isPrototypeAssignment*/ false) ? getNameOfExpando(relatedNode) : getNameOfDeclaration(relatedNode)) || relatedNode; 1455 if (adjustedNode === errorNode) continue; 1456 err.relatedInformation = err.relatedInformation || []; 1457 const leadingMessage = createDiagnosticForNode(adjustedNode, Diagnostics._0_was_also_declared_here, symbolName); 1458 const followOnMessage = createDiagnosticForNode(adjustedNode, Diagnostics.and_here); 1459 if (length(err.relatedInformation) >= 5 || some(err.relatedInformation, r => compareDiagnostics(r, followOnMessage) === Comparison.EqualTo || compareDiagnostics(r, leadingMessage) === Comparison.EqualTo)) continue; 1460 addRelatedInfo(err, !length(err.relatedInformation) ? leadingMessage : followOnMessage); 1461 } 1462 } 1463 1464 function combineSymbolTables(first: SymbolTable | undefined, second: SymbolTable | undefined): SymbolTable | undefined { 1465 if (!first?.size) return second; 1466 if (!second?.size) return first; 1467 const combined = createSymbolTable(); 1468 mergeSymbolTable(combined, first); 1469 mergeSymbolTable(combined, second); 1470 return combined; 1471 } 1472 1473 function mergeSymbolTable(target: SymbolTable, source: SymbolTable, unidirectional = false) { 1474 source.forEach((sourceSymbol, id) => { 1475 const targetSymbol = target.get(id); 1476 target.set(id, targetSymbol ? mergeSymbol(targetSymbol, sourceSymbol, unidirectional) : getMergedSymbol(sourceSymbol)); 1477 }); 1478 } 1479 1480 function mergeModuleAugmentation(moduleName: StringLiteral | Identifier): void { 1481 const moduleAugmentation = moduleName.parent as ModuleDeclaration; 1482 if (moduleAugmentation.symbol.declarations?.[0] !== moduleAugmentation) { 1483 // this is a combined symbol for multiple augmentations within the same file. 1484 // its symbol already has accumulated information for all declarations 1485 // so we need to add it just once - do the work only for first declaration 1486 Debug.assert(moduleAugmentation.symbol.declarations!.length > 1); 1487 return; 1488 } 1489 1490 if (isGlobalScopeAugmentation(moduleAugmentation)) { 1491 mergeSymbolTable(globals, moduleAugmentation.symbol.exports!); 1492 } 1493 else { 1494 // find a module that about to be augmented 1495 // do not validate names of augmentations that are defined in ambient context 1496 const moduleNotFoundError = !(moduleName.parent.parent.flags & NodeFlags.Ambient) 1497 ? Diagnostics.Invalid_module_name_in_augmentation_module_0_cannot_be_found 1498 : undefined; 1499 let mainModule = resolveExternalModuleNameWorker(moduleName, moduleName, moduleNotFoundError, /*isForAugmentation*/ true); 1500 if (!mainModule) { 1501 return; 1502 } 1503 // obtain item referenced by 'export=' 1504 mainModule = resolveExternalModuleSymbol(mainModule); 1505 if (mainModule.flags & SymbolFlags.Namespace) { 1506 // If we're merging an augmentation to a pattern ambient module, we want to 1507 // perform the merge unidirectionally from the augmentation ('a.foo') to 1508 // the pattern ('*.foo'), so that 'getMergedSymbol()' on a.foo gives you 1509 // all the exports both from the pattern and from the augmentation, but 1510 // 'getMergedSymbol()' on *.foo only gives you exports from *.foo. 1511 if (some(patternAmbientModules, module => mainModule === module.symbol)) { 1512 const merged = mergeSymbol(moduleAugmentation.symbol, mainModule, /*unidirectional*/ true); 1513 if (!patternAmbientModuleAugmentations) { 1514 patternAmbientModuleAugmentations = new Map(); 1515 } 1516 // moduleName will be a StringLiteral since this is not `declare global`. 1517 patternAmbientModuleAugmentations.set((moduleName as StringLiteral).text, merged); 1518 } 1519 else { 1520 if (mainModule.exports?.get(InternalSymbolName.ExportStar) && moduleAugmentation.symbol.exports?.size) { 1521 // We may need to merge the module augmentation's exports into the target symbols of the resolved exports 1522 const resolvedExports = getResolvedMembersOrExportsOfSymbol(mainModule, MembersOrExportsResolutionKind.resolvedExports); 1523 for (const [key, value] of arrayFrom(moduleAugmentation.symbol.exports.entries())) { 1524 if (resolvedExports.has(key) && !mainModule.exports.has(key)) { 1525 mergeSymbol(resolvedExports.get(key)!, value); 1526 } 1527 } 1528 } 1529 mergeSymbol(mainModule, moduleAugmentation.symbol); 1530 } 1531 } 1532 else { 1533 // moduleName will be a StringLiteral since this is not `declare global`. 1534 error(moduleName, Diagnostics.Cannot_augment_module_0_because_it_resolves_to_a_non_module_entity, (moduleName as StringLiteral).text); 1535 } 1536 } 1537 } 1538 1539 function addToSymbolTable(target: SymbolTable, source: SymbolTable, message: DiagnosticMessage) { 1540 source.forEach((sourceSymbol, id) => { 1541 const targetSymbol = target.get(id); 1542 if (targetSymbol) { 1543 // Error on redeclarations 1544 forEach(targetSymbol.declarations, addDeclarationDiagnostic(unescapeLeadingUnderscores(id), message)); 1545 } 1546 else { 1547 target.set(id, sourceSymbol); 1548 } 1549 }); 1550 1551 function addDeclarationDiagnostic(id: string, message: DiagnosticMessage) { 1552 return (declaration: Declaration) => diagnostics.add(createDiagnosticForNode(declaration, message, id)); 1553 } 1554 } 1555 1556 function getSymbolLinks(symbol: Symbol): SymbolLinks { 1557 if (symbol.flags & SymbolFlags.Transient) return symbol as TransientSymbol; 1558 const id = getSymbolId(symbol); 1559 return symbolLinks[id] || (symbolLinks[id] = new (SymbolLinks as any)()); 1560 } 1561 1562 function getNodeLinks(node: Node): NodeLinks { 1563 const nodeId = getNodeId(node); 1564 return nodeLinks[nodeId] || (nodeLinks[nodeId] = new (NodeLinks as any)()); 1565 } 1566 1567 function isGlobalSourceFile(node: Node) { 1568 return node.kind === SyntaxKind.SourceFile && !isExternalOrCommonJsModule(node as SourceFile); 1569 } 1570 1571 function isValidFromLibs(symbol: Symbol, node?: Node): boolean { 1572 if (!node || !symbol.declarations || !symbol.declarations.length) { 1573 return true; 1574 } 1575 1576 const etsLibFilesNames = getEtsLibs(host); 1577 const sourceFileName = getSourceFileOfNode(node).fileName.trim(); 1578 if (!sourceFileName) { 1579 return true; 1580 } 1581 1582 const fileName = sys?.resolvePath(sourceFileName); 1583 if (fileName?.endsWith(Extension.Ets) || etsLibFilesNames.includes(fileName)) { 1584 return true; 1585 } 1586 1587 const declaration = symbol.declarations.filter(declaration => { 1588 if (!getSourceFileOfNode(declaration).fileName) { 1589 return true; 1590 } 1591 const symbolFileName = sys?.resolvePath(getSourceFileOfNode(declaration).fileName); 1592 if (etsLibFilesNames.indexOf(symbolFileName) !== -1) { 1593 return false; 1594 } 1595 return true; 1596 }); 1597 1598 if (!declaration.length) { 1599 return false; 1600 } 1601 1602 return true; 1603 } 1604 1605 function getSymbol(symbols: SymbolTable, name: __String, meaning: SymbolFlags, node?: Node): Symbol | undefined { 1606 if (meaning) { 1607 const symbol = getMergedSymbol(symbols.get(name)); 1608 if (symbol) { 1609 Debug.assert((getCheckFlags(symbol) & CheckFlags.Instantiated) === 0, "Should never get an instantiated symbol here."); 1610 if (!isValidFromLibs(symbol, node)) { 1611 return undefined; 1612 } 1613 1614 if (symbol.flags & meaning) { 1615 return symbol; 1616 } 1617 if (symbol.flags & SymbolFlags.Alias) { 1618 const targetFlags = getAllSymbolFlags(symbol); 1619 // `targetFlags` will be `SymbolFlags.All` if an error occurred in alias resolution; this avoids cascading errors 1620 if (targetFlags & meaning) { 1621 return symbol; 1622 } 1623 } 1624 } 1625 } 1626 // return undefined if we can't find a symbol. 1627 } 1628 1629 /** 1630 * Get symbols that represent parameter-property-declaration as parameter and as property declaration 1631 * @param parameter a parameterDeclaration node 1632 * @param parameterName a name of the parameter to get the symbols for. 1633 * @return a tuple of two symbols 1634 */ 1635 function getSymbolsOfParameterPropertyDeclaration(parameter: ParameterDeclaration, parameterName: __String): [Symbol, Symbol] { 1636 const constructorDeclaration = parameter.parent; 1637 const classDeclaration = parameter.parent.parent; 1638 1639 const parameterSymbol = getSymbol(constructorDeclaration.locals!, parameterName, SymbolFlags.Value); 1640 const propertySymbol = getSymbol(getMembersOfSymbol(classDeclaration.symbol), parameterName, SymbolFlags.Value); 1641 1642 if (parameterSymbol && propertySymbol) { 1643 return [parameterSymbol, propertySymbol]; 1644 } 1645 1646 return Debug.fail("There should exist two symbols, one as property declaration and one as parameter declaration"); 1647 } 1648 1649 function isBlockScopedNameDeclaredBeforeUse(declaration: Declaration, usage: Node): boolean { 1650 const declarationFile = getSourceFileOfNode(declaration); 1651 const useFile = getSourceFileOfNode(usage); 1652 const declContainer = getEnclosingBlockScopeContainer(declaration); 1653 if (declarationFile !== useFile) { 1654 if ((moduleKind && (declarationFile.externalModuleIndicator || useFile.externalModuleIndicator)) || 1655 (!outFile(compilerOptions)) || 1656 isInTypeQuery(usage) || 1657 declaration.flags & NodeFlags.Ambient) { 1658 // nodes are in different files and order cannot be determined 1659 return true; 1660 } 1661 // declaration is after usage 1662 // can be legal if usage is deferred (i.e. inside function or in initializer of instance property) 1663 if (isUsedInFunctionOrInstanceProperty(usage, declaration)) { 1664 return true; 1665 } 1666 const sourceFiles = host.getSourceFiles(); 1667 return sourceFiles.indexOf(declarationFile) <= sourceFiles.indexOf(useFile); 1668 } 1669 1670 if (declaration.pos <= usage.pos && !(isPropertyDeclaration(declaration) && isThisProperty(usage.parent) && !declaration.initializer && !declaration.exclamationToken)) { 1671 // declaration is before usage 1672 if (declaration.kind === SyntaxKind.BindingElement) { 1673 // still might be illegal if declaration and usage are both binding elements (eg var [a = b, b = b] = [1, 2]) 1674 const errorBindingElement = getAncestor(usage, SyntaxKind.BindingElement) as BindingElement; 1675 if (errorBindingElement) { 1676 return findAncestor(errorBindingElement, isBindingElement) !== findAncestor(declaration, isBindingElement) || 1677 declaration.pos < errorBindingElement.pos; 1678 } 1679 // or it might be illegal if usage happens before parent variable is declared (eg var [a] = a) 1680 return isBlockScopedNameDeclaredBeforeUse(getAncestor(declaration, SyntaxKind.VariableDeclaration) as Declaration, usage); 1681 } 1682 else if (declaration.kind === SyntaxKind.VariableDeclaration) { 1683 // still might be illegal if usage is in the initializer of the variable declaration (eg var a = a) 1684 return !isImmediatelyUsedInInitializerOfBlockScopedVariable(declaration as VariableDeclaration, usage); 1685 } 1686 else if (isClassDeclaration(declaration)) { 1687 // still might be illegal if the usage is within a computed property name in the class (eg class A { static p = "a"; [A.p]() {} }) 1688 return !findAncestor(usage, n => isComputedPropertyName(n) && n.parent.parent === declaration); 1689 } 1690 else if (isPropertyDeclaration(declaration)) { 1691 // still might be illegal if a self-referencing property initializer (eg private x = this.x) 1692 return !isPropertyImmediatelyReferencedWithinDeclaration(declaration, usage, /*stopAtAnyPropertyDeclaration*/ false); 1693 } 1694 else if (isParameterPropertyDeclaration(declaration, declaration.parent)) { 1695 // foo = this.bar is illegal in esnext+useDefineForClassFields when bar is a parameter property 1696 return !(getEmitScriptTarget(compilerOptions) === ScriptTarget.ESNext && useDefineForClassFields 1697 && getContainingClass(declaration) === getContainingClass(usage) 1698 && isUsedInFunctionOrInstanceProperty(usage, declaration)); 1699 } 1700 return true; 1701 } 1702 1703 1704 // declaration is after usage, but it can still be legal if usage is deferred: 1705 // 1. inside an export specifier 1706 // 2. inside a function 1707 // 3. inside an instance property initializer, a reference to a non-instance property 1708 // (except when target: "esnext" and useDefineForClassFields: true and the reference is to a parameter property) 1709 // 4. inside a static property initializer, a reference to a static method in the same class 1710 // 5. inside a TS export= declaration (since we will move the export statement during emit to avoid TDZ) 1711 // or if usage is in a type context: 1712 // 1. inside a type query (typeof in type position) 1713 // 2. inside a jsdoc comment 1714 if (usage.parent.kind === SyntaxKind.ExportSpecifier || (usage.parent.kind === SyntaxKind.ExportAssignment && (usage.parent as ExportAssignment).isExportEquals)) { 1715 // export specifiers do not use the variable, they only make it available for use 1716 return true; 1717 } 1718 // When resolving symbols for exports, the `usage` location passed in can be the export site directly 1719 if (usage.kind === SyntaxKind.ExportAssignment && (usage as ExportAssignment).isExportEquals) { 1720 return true; 1721 } 1722 1723 if (!!(usage.flags & NodeFlags.JSDoc) || isInTypeQuery(usage) || usageInTypeDeclaration()) { 1724 return true; 1725 } 1726 if (isUsedInFunctionOrInstanceProperty(usage, declaration)) { 1727 if (getEmitScriptTarget(compilerOptions) === ScriptTarget.ESNext && useDefineForClassFields 1728 && getContainingClass(declaration) 1729 && (isPropertyDeclaration(declaration) || isParameterPropertyDeclaration(declaration, declaration.parent))) { 1730 return !isPropertyImmediatelyReferencedWithinDeclaration(declaration, usage, /*stopAtAnyPropertyDeclaration*/ true); 1731 } 1732 else { 1733 return true; 1734 } 1735 } 1736 return false; 1737 1738 function usageInTypeDeclaration() { 1739 return !!findAncestor(usage, node => isInterfaceDeclaration(node) || isTypeAliasDeclaration(node)); 1740 } 1741 1742 function isImmediatelyUsedInInitializerOfBlockScopedVariable(declaration: VariableDeclaration, usage: Node): boolean { 1743 switch (declaration.parent.parent.kind) { 1744 case SyntaxKind.VariableStatement: 1745 case SyntaxKind.ForStatement: 1746 case SyntaxKind.ForOfStatement: 1747 // variable statement/for/for-of statement case, 1748 // use site should not be inside variable declaration (initializer of declaration or binding element) 1749 if (isSameScopeDescendentOf(usage, declaration, declContainer)) { 1750 return true; 1751 } 1752 break; 1753 } 1754 1755 // ForIn/ForOf case - use site should not be used in expression part 1756 const grandparent = declaration.parent.parent; 1757 return isForInOrOfStatement(grandparent) && isSameScopeDescendentOf(usage, grandparent.expression, declContainer); 1758 } 1759 1760 function isUsedInFunctionOrInstanceProperty(usage: Node, declaration: Node): boolean { 1761 return !!findAncestor(usage, current => { 1762 if (current === declContainer) { 1763 return "quit"; 1764 } 1765 if (isFunctionLike(current)) { 1766 return true; 1767 } 1768 if (isClassStaticBlockDeclaration(current)) { 1769 return declaration.pos < usage.pos; 1770 } 1771 1772 const propertyDeclaration = tryCast(current.parent, isPropertyDeclaration); 1773 if (propertyDeclaration) { 1774 const initializerOfProperty = propertyDeclaration.initializer === current; 1775 if (initializerOfProperty) { 1776 if (isStatic(current.parent)) { 1777 if (declaration.kind === SyntaxKind.MethodDeclaration) { 1778 return true; 1779 } 1780 if (isPropertyDeclaration(declaration) && getContainingClass(usage) === getContainingClass(declaration)) { 1781 const propName = declaration.name; 1782 if (isIdentifier(propName) || isPrivateIdentifier(propName)) { 1783 const type = getTypeOfSymbol(getSymbolOfNode(declaration)); 1784 const staticBlocks = filter(declaration.parent.members, isClassStaticBlockDeclaration); 1785 if (isPropertyInitializedInStaticBlocks(propName, type, staticBlocks, declaration.parent.pos, current.pos)) { 1786 return true; 1787 } 1788 } 1789 } 1790 } 1791 else { 1792 const isDeclarationInstanceProperty = declaration.kind === SyntaxKind.PropertyDeclaration && !isStatic(declaration); 1793 if (!isDeclarationInstanceProperty || getContainingClass(usage) !== getContainingClass(declaration)) { 1794 return true; 1795 } 1796 } 1797 } 1798 } 1799 return false; 1800 }); 1801 } 1802 1803 /** stopAtAnyPropertyDeclaration is used for detecting ES-standard class field use-before-def errors */ 1804 function isPropertyImmediatelyReferencedWithinDeclaration(declaration: PropertyDeclaration | ParameterPropertyDeclaration, usage: Node, stopAtAnyPropertyDeclaration: boolean) { 1805 // always legal if usage is after declaration 1806 if (usage.end > declaration.end) { 1807 return false; 1808 } 1809 1810 // still might be legal if usage is deferred (e.g. x: any = () => this.x) 1811 // otherwise illegal if immediately referenced within the declaration (e.g. x: any = this.x) 1812 const ancestorChangingReferenceScope = findAncestor(usage, (node: Node) => { 1813 if (node === declaration) { 1814 return "quit"; 1815 } 1816 1817 switch (node.kind) { 1818 case SyntaxKind.ArrowFunction: 1819 return true; 1820 case SyntaxKind.PropertyDeclaration: 1821 // even when stopping at any property declaration, they need to come from the same class 1822 return stopAtAnyPropertyDeclaration && 1823 (isPropertyDeclaration(declaration) && node.parent === declaration.parent 1824 || isParameterPropertyDeclaration(declaration, declaration.parent) && node.parent === declaration.parent.parent) 1825 ? "quit": true; 1826 case SyntaxKind.Block: 1827 switch (node.parent.kind) { 1828 case SyntaxKind.GetAccessor: 1829 case SyntaxKind.MethodDeclaration: 1830 case SyntaxKind.SetAccessor: 1831 return true; 1832 default: 1833 return false; 1834 } 1835 default: 1836 return false; 1837 } 1838 }); 1839 1840 return ancestorChangingReferenceScope === undefined; 1841 } 1842 } 1843 1844 function useOuterVariableScopeInParameter(result: Symbol, location: Node, lastLocation: Node) { 1845 const target = getEmitScriptTarget(compilerOptions); 1846 const functionLocation = location as FunctionLikeDeclaration; 1847 if (isParameter(lastLocation) 1848 && functionLocation.body 1849 && result.valueDeclaration 1850 && result.valueDeclaration.pos >= functionLocation.body.pos 1851 && result.valueDeclaration.end <= functionLocation.body.end) { 1852 // check for several cases where we introduce temporaries that require moving the name/initializer of the parameter to the body 1853 // - static field in a class expression 1854 // - optional chaining pre-es2020 1855 // - nullish coalesce pre-es2020 1856 // - spread assignment in binding pattern pre-es2017 1857 if (target >= ScriptTarget.ES2015) { 1858 const links = getNodeLinks(functionLocation); 1859 if (links.declarationRequiresScopeChange === undefined) { 1860 links.declarationRequiresScopeChange = forEach(functionLocation.parameters, requiresScopeChange) || false; 1861 } 1862 return !links.declarationRequiresScopeChange; 1863 } 1864 } 1865 return false; 1866 1867 function requiresScopeChange(node: ParameterDeclaration): boolean { 1868 return requiresScopeChangeWorker(node.name) 1869 || !!node.initializer && requiresScopeChangeWorker(node.initializer); 1870 } 1871 1872 function requiresScopeChangeWorker(node: Node): boolean { 1873 switch (node.kind) { 1874 case SyntaxKind.ArrowFunction: 1875 case SyntaxKind.FunctionExpression: 1876 case SyntaxKind.FunctionDeclaration: 1877 case SyntaxKind.Constructor: 1878 // do not descend into these 1879 return false; 1880 case SyntaxKind.MethodDeclaration: 1881 case SyntaxKind.GetAccessor: 1882 case SyntaxKind.SetAccessor: 1883 case SyntaxKind.PropertyAssignment: 1884 return requiresScopeChangeWorker((node as MethodDeclaration | AccessorDeclaration | PropertyAssignment).name); 1885 case SyntaxKind.PropertyDeclaration: 1886 // static properties in classes introduce temporary variables 1887 if (hasStaticModifier(node)) { 1888 return target < ScriptTarget.ESNext || !useDefineForClassFields; 1889 } 1890 return requiresScopeChangeWorker((node as PropertyDeclaration).name); 1891 case SyntaxKind.AnnotationPropertyDeclaration: 1892 return requiresScopeChangeWorker((node as AnnotationPropertyDeclaration).name); 1893 default: 1894 // null coalesce and optional chain pre-es2020 produce temporary variables 1895 if (isNullishCoalesce(node) || isOptionalChain(node)) { 1896 return target < ScriptTarget.ES2020; 1897 } 1898 if (isBindingElement(node) && node.dotDotDotToken && isObjectBindingPattern(node.parent)) { 1899 return target < ScriptTarget.ES2017; 1900 } 1901 if (isTypeNode(node)) return false; 1902 return forEachChild(node, requiresScopeChangeWorker) || false; 1903 } 1904 } 1905 } 1906 1907 function isConstAssertion(location: Node) { 1908 return (isAssertionExpression(location) && isConstTypeReference(location.type)) 1909 || (isJSDocTypeTag(location) && isConstTypeReference(location.typeExpression)); 1910 } 1911 1912 /** 1913 * Resolve a given name for a given meaning at a given location. An error is reported if the name was not found and 1914 * the nameNotFoundMessage argument is not undefined. Returns the resolved symbol, or undefined if no symbol with 1915 * the given name can be found. 1916 * 1917 * @param nameNotFoundMessage If defined, we will report errors found during resolve. 1918 * @param isUse If true, this will count towards --noUnusedLocals / --noUnusedParameters. 1919 */ 1920 function resolveName( 1921 location: Node | undefined, 1922 name: __String, 1923 meaning: SymbolFlags, 1924 nameNotFoundMessage: DiagnosticMessage | undefined, 1925 nameArg: __String | Identifier | undefined, 1926 isUse: boolean, 1927 excludeGlobals = false, 1928 getSpellingSuggestions = true): Symbol | undefined { 1929 return resolveNameHelper(location, name, meaning, nameNotFoundMessage, nameArg, isUse, excludeGlobals, getSpellingSuggestions, getSymbol); 1930 } 1931 1932 function resolveNameHelper( 1933 location: Node | undefined, 1934 name: __String, 1935 meaning: SymbolFlags, 1936 nameNotFoundMessage: DiagnosticMessage | undefined, 1937 nameArg: __String | Identifier | undefined, 1938 isUse: boolean, 1939 excludeGlobals: boolean, 1940 getSpellingSuggestions: boolean, 1941 lookup: typeof getSymbol): Symbol | undefined { 1942 const originalLocation = location; // needed for did-you-mean error reporting, which gathers candidates starting from the original location 1943 let result: Symbol | undefined; 1944 let lastLocation: Node | undefined; 1945 let lastSelfReferenceLocation: Node | undefined; 1946 let propertyWithInvalidInitializer: PropertyDeclaration | undefined; 1947 let associatedDeclarationForContainingInitializerOrBindingName: ParameterDeclaration | BindingElement | undefined; 1948 let withinDeferredContext = false; 1949 const errorLocation = location; 1950 let grandparent: Node; 1951 let isInExternalModule = false; 1952 1953 loop: while (location) { 1954 if (name === "const" && isConstAssertion(location)) { 1955 // `const` in an `as const` has no symbol, but issues no error because there is no *actual* lookup of the type 1956 // (it refers to the constant type of the expression instead) 1957 return undefined; 1958 } 1959 // Locals of a source file are not in scope (because they get merged into the global symbol table) 1960 if (location.locals && !isGlobalSourceFile(location)) { 1961 if (result = lookup(location.locals, name, meaning)) { 1962 let useResult = true; 1963 if (isFunctionLike(location) && lastLocation && lastLocation !== (location as FunctionLikeDeclaration).body) { 1964 // symbol lookup restrictions for function-like declarations 1965 // - Type parameters of a function are in scope in the entire function declaration, including the parameter 1966 // list and return type. However, local types are only in scope in the function body. 1967 // - parameters are only in the scope of function body 1968 // This restriction does not apply to JSDoc comment types because they are parented 1969 // at a higher level than type parameters would normally be 1970 if (meaning & result.flags & SymbolFlags.Type && lastLocation.kind !== SyntaxKind.JSDoc) { 1971 useResult = result.flags & SymbolFlags.TypeParameter 1972 // type parameters are visible in parameter list, return type and type parameter list 1973 ? lastLocation === (location as FunctionLikeDeclaration).type || 1974 lastLocation.kind === SyntaxKind.Parameter || 1975 lastLocation.kind === SyntaxKind.JSDocParameterTag || 1976 lastLocation.kind === SyntaxKind.JSDocReturnTag || 1977 lastLocation.kind === SyntaxKind.TypeParameter 1978 // local types not visible outside the function body 1979 : false; 1980 } 1981 if (meaning & result.flags & SymbolFlags.Variable) { 1982 // expression inside parameter will lookup as normal variable scope when targeting es2015+ 1983 if (useOuterVariableScopeInParameter(result, location, lastLocation)) { 1984 useResult = false; 1985 } 1986 else if (result.flags & SymbolFlags.FunctionScopedVariable) { 1987 // parameters are visible only inside function body, parameter list and return type 1988 // technically for parameter list case here we might mix parameters and variables declared in function, 1989 // however it is detected separately when checking initializers of parameters 1990 // to make sure that they reference no variables declared after them. 1991 useResult = 1992 lastLocation.kind === SyntaxKind.Parameter || 1993 ( 1994 lastLocation === (location as FunctionLikeDeclaration).type && 1995 !!findAncestor(result.valueDeclaration, isParameter) 1996 ); 1997 } 1998 } 1999 } 2000 else if (location.kind === SyntaxKind.ConditionalType) { 2001 // A type parameter declared using 'infer T' in a conditional type is visible only in 2002 // the true branch of the conditional type. 2003 useResult = lastLocation === (location as ConditionalTypeNode).trueType; 2004 } 2005 2006 if (useResult) { 2007 break loop; 2008 } 2009 else { 2010 result = undefined; 2011 } 2012 } 2013 } 2014 withinDeferredContext = withinDeferredContext || getIsDeferredContext(location, lastLocation); 2015 switch (location.kind) { 2016 case SyntaxKind.SourceFile: 2017 if (!isExternalOrCommonJsModule(location as SourceFile)) break; 2018 isInExternalModule = true; 2019 // falls through 2020 case SyntaxKind.ModuleDeclaration: 2021 const moduleExports = getSymbolOfNode(location) ? (getSymbolOfNode(location as SourceFile | ModuleDeclaration)?.exports || emptySymbols) : emptySymbols; 2022 if (location.kind === SyntaxKind.SourceFile || (isModuleDeclaration(location) && location.flags & NodeFlags.Ambient && !isGlobalScopeAugmentation(location))) { 2023 2024 // It's an external module. First see if the module has an export default and if the local 2025 // name of that export default matches. 2026 if (result = moduleExports.get(InternalSymbolName.Default)) { 2027 const localSymbol = getLocalSymbolForExportDefault(result); 2028 if (localSymbol && (result.flags & meaning) && localSymbol.escapedName === name) { 2029 break loop; 2030 } 2031 result = undefined; 2032 } 2033 2034 // Because of module/namespace merging, a module's exports are in scope, 2035 // yet we never want to treat an export specifier as putting a member in scope. 2036 // Therefore, if the name we find is purely an export specifier, it is not actually considered in scope. 2037 // Two things to note about this: 2038 // 1. We have to check this without calling getSymbol. The problem with calling getSymbol 2039 // on an export specifier is that it might find the export specifier itself, and try to 2040 // resolve it as an alias. This will cause the checker to consider the export specifier 2041 // a circular alias reference when it might not be. 2042 // 2. We check === SymbolFlags.Alias in order to check that the symbol is *purely* 2043 // an alias. If we used &, we'd be throwing out symbols that have non alias aspects, 2044 // which is not the desired behavior. 2045 const moduleExport = moduleExports.get(name); 2046 if (moduleExport && 2047 moduleExport.flags === SymbolFlags.Alias && 2048 (getDeclarationOfKind(moduleExport, SyntaxKind.ExportSpecifier) || getDeclarationOfKind(moduleExport, SyntaxKind.NamespaceExport))) { 2049 break; 2050 } 2051 } 2052 2053 // ES6 exports are also visible locally (except for 'default'), but commonjs exports are not (except typedefs) 2054 if (name !== InternalSymbolName.Default && (result = lookup(moduleExports, name, meaning & SymbolFlags.ModuleMember))) { 2055 if (isSourceFile(location) && location.commonJsModuleIndicator && !result.declarations?.some(isJSDocTypeAlias)) { 2056 result = undefined; 2057 } 2058 else { 2059 break loop; 2060 } 2061 } 2062 break; 2063 case SyntaxKind.EnumDeclaration: 2064 if (result = lookup(getSymbolOfNode(location)?.exports || emptySymbols, name, meaning & SymbolFlags.EnumMember)) { 2065 break loop; 2066 } 2067 break; 2068 case SyntaxKind.PropertyDeclaration: 2069 // TypeScript 1.0 spec (April 2014): 8.4.1 2070 // Initializer expressions for instance member variables are evaluated in the scope 2071 // of the class constructor body but are not permitted to reference parameters or 2072 // local variables of the constructor. This effectively means that entities from outer scopes 2073 // by the same name as a constructor parameter or local variable are inaccessible 2074 // in initializer expressions for instance member variables. 2075 if (!isStatic(location)) { 2076 const ctor = findConstructorDeclaration(location.parent as ClassLikeDeclaration); 2077 if (ctor && ctor.locals) { 2078 if (lookup(ctor.locals, name, meaning & SymbolFlags.Value)) { 2079 // Remember the property node, it will be used later to report appropriate error 2080 Debug.assertNode(location, isPropertyDeclaration); 2081 propertyWithInvalidInitializer = location; 2082 } 2083 } 2084 } 2085 break; 2086 case SyntaxKind.ClassDeclaration: 2087 case SyntaxKind.ClassExpression: 2088 case SyntaxKind.InterfaceDeclaration: 2089 // The below is used to lookup type parameters within a class or interface, as they are added to the class/interface locals 2090 // These can never be latebound, so the symbol's raw members are sufficient. `getMembersOfNode` cannot be used, as it would 2091 // trigger resolving late-bound names, which we may already be in the process of doing while we're here! 2092 if (result = lookup(getSymbolOfNode(location as ClassLikeDeclaration | InterfaceDeclaration).members || emptySymbols, name, meaning & SymbolFlags.Type)) { 2093 if (!isTypeParameterSymbolDeclaredInContainer(result, location)) { 2094 // ignore type parameters not declared in this container 2095 result = undefined; 2096 break; 2097 } 2098 if (lastLocation && isStatic(lastLocation)) { 2099 // TypeScript 1.0 spec (April 2014): 3.4.1 2100 // The scope of a type parameter extends over the entire declaration with which the type 2101 // parameter list is associated, with the exception of static member declarations in classes. 2102 if (nameNotFoundMessage) { 2103 error(errorLocation, Diagnostics.Static_members_cannot_reference_class_type_parameters); 2104 } 2105 return undefined; 2106 } 2107 break loop; 2108 } 2109 if (location.kind === SyntaxKind.ClassExpression && meaning & SymbolFlags.Class) { 2110 const className = (location as ClassExpression).name; 2111 if (className && name === className.escapedText) { 2112 result = location.symbol; 2113 break loop; 2114 } 2115 } 2116 break; 2117 case SyntaxKind.ExpressionWithTypeArguments: 2118 // The type parameters of a class are not in scope in the base class expression. 2119 if (lastLocation === (location as ExpressionWithTypeArguments).expression && (location.parent as HeritageClause).token === SyntaxKind.ExtendsKeyword) { 2120 const container = location.parent.parent; 2121 if (isClassLike(container) && (result = lookup(getSymbolOfNode(container).members!, name, meaning & SymbolFlags.Type))) { 2122 if (nameNotFoundMessage) { 2123 error(errorLocation, Diagnostics.Base_class_expressions_cannot_reference_class_type_parameters); 2124 } 2125 return undefined; 2126 } 2127 } 2128 break; 2129 // It is not legal to reference a class's own type parameters from a computed property name that 2130 // belongs to the class. For example: 2131 // 2132 // function foo<T>() { return '' } 2133 // class C<T> { // <-- Class's own type parameter T 2134 // [foo<T>()]() { } // <-- Reference to T from class's own computed property 2135 // } 2136 // 2137 case SyntaxKind.ComputedPropertyName: 2138 grandparent = location.parent.parent; 2139 if (isClassLike(grandparent) || grandparent.kind === SyntaxKind.InterfaceDeclaration) { 2140 // A reference to this grandparent's type parameters would be an error 2141 if (result = lookup(getSymbolOfNode(grandparent as ClassLikeDeclaration | InterfaceDeclaration).members!, name, meaning & SymbolFlags.Type)) { 2142 if (nameNotFoundMessage) { 2143 error(errorLocation, Diagnostics.A_computed_property_name_cannot_reference_a_type_parameter_from_its_containing_type); 2144 } 2145 return undefined; 2146 } 2147 } 2148 break; 2149 case SyntaxKind.ArrowFunction: 2150 // when targeting ES6 or higher there is no 'arguments' in an arrow function 2151 // for lower compile targets the resolved symbol is used to emit an error 2152 if (getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2015) { 2153 break; 2154 } 2155 // falls through 2156 case SyntaxKind.MethodDeclaration: 2157 case SyntaxKind.Constructor: 2158 case SyntaxKind.GetAccessor: 2159 case SyntaxKind.SetAccessor: 2160 case SyntaxKind.FunctionDeclaration: 2161 if (meaning & SymbolFlags.Variable && name === "arguments") { 2162 result = argumentsSymbol; 2163 break loop; 2164 } 2165 break; 2166 case SyntaxKind.FunctionExpression: 2167 if (meaning & SymbolFlags.Variable && name === "arguments") { 2168 result = argumentsSymbol; 2169 break loop; 2170 } 2171 2172 if (meaning & SymbolFlags.Function) { 2173 const functionName = (location as FunctionExpression).name; 2174 if (functionName && name === functionName.escapedText) { 2175 result = location.symbol; 2176 break loop; 2177 } 2178 } 2179 break; 2180 case SyntaxKind.Decorator: 2181 // Decorators are resolved at the class declaration. Resolving at the parameter 2182 // or member would result in looking up locals in the method. 2183 // 2184 // function y() {} 2185 // class C { 2186 // method(@y x, y) {} // <-- decorator y should be resolved at the class declaration, not the parameter. 2187 // } 2188 // 2189 if (location.parent && location.parent.kind === SyntaxKind.Parameter) { 2190 location = location.parent; 2191 } 2192 // 2193 // function y() {} 2194 // class C { 2195 // @y method(x, y) {} // <-- decorator y should be resolved at the class declaration, not the method. 2196 // } 2197 // 2198 2199 // class Decorators are resolved outside of the class to avoid referencing type parameters of that class. 2200 // 2201 // type T = number; 2202 // declare function y(x: T): any; 2203 // @param(1 as T) // <-- T should resolve to the type alias outside of class C 2204 // class C<T> {} 2205 if (location.parent && (isClassElement(location.parent) || location.parent.kind === SyntaxKind.ClassDeclaration)) { 2206 location = location.parent; 2207 } 2208 break; 2209 case SyntaxKind.JSDocTypedefTag: 2210 case SyntaxKind.JSDocCallbackTag: 2211 case SyntaxKind.JSDocEnumTag: 2212 // js type aliases do not resolve names from their host, so skip past it 2213 const root = getJSDocRoot(location); 2214 if (root) { 2215 location = root.parent; 2216 } 2217 break; 2218 case SyntaxKind.Parameter: 2219 if (lastLocation && ( 2220 lastLocation === (location as ParameterDeclaration).initializer || 2221 lastLocation === (location as ParameterDeclaration).name && isBindingPattern(lastLocation))) { 2222 if (!associatedDeclarationForContainingInitializerOrBindingName) { 2223 associatedDeclarationForContainingInitializerOrBindingName = location as ParameterDeclaration; 2224 } 2225 } 2226 break; 2227 case SyntaxKind.BindingElement: 2228 if (lastLocation && ( 2229 lastLocation === (location as BindingElement).initializer || 2230 lastLocation === (location as BindingElement).name && isBindingPattern(lastLocation))) { 2231 if (isParameterDeclaration(location as BindingElement) && !associatedDeclarationForContainingInitializerOrBindingName) { 2232 associatedDeclarationForContainingInitializerOrBindingName = location as BindingElement; 2233 } 2234 } 2235 break; 2236 case SyntaxKind.InferType: 2237 if (meaning & SymbolFlags.TypeParameter) { 2238 const parameterName = (location as InferTypeNode).typeParameter.name; 2239 if (parameterName && name === parameterName.escapedText) { 2240 result = (location as InferTypeNode).typeParameter.symbol; 2241 break loop; 2242 } 2243 } 2244 break; 2245 } 2246 if (isSelfReferenceLocation(location)) { 2247 lastSelfReferenceLocation = location; 2248 } 2249 lastLocation = location; 2250 location = isJSDocTemplateTag(location) ? getEffectiveContainerForJSDocTemplateTag(location) || location.parent : 2251 isJSDocParameterTag(location) || isJSDocReturnTag(location) ? getHostSignatureFromJSDoc(location) || location.parent : 2252 location.parent; 2253 } 2254 2255 // We just climbed up parents looking for the name, meaning that we started in a descendant node of `lastLocation`. 2256 // If `result === lastSelfReferenceLocation.symbol`, that means that we are somewhere inside `lastSelfReferenceLocation` looking up a name, and resolving to `lastLocation` itself. 2257 // That means that this is a self-reference of `lastLocation`, and shouldn't count this when considering whether `lastLocation` is used. 2258 if (isUse && result && (!lastSelfReferenceLocation || result !== lastSelfReferenceLocation.symbol)) { 2259 result.isReferenced! |= meaning; 2260 } 2261 2262 if (!result) { 2263 if (lastLocation) { 2264 Debug.assert(lastLocation.kind === SyntaxKind.SourceFile); 2265 if ((lastLocation as SourceFile).commonJsModuleIndicator && name === "exports" && meaning & lastLocation.symbol.flags) { 2266 return lastLocation.symbol; 2267 } 2268 } 2269 2270 if (!excludeGlobals) { 2271 result = lookup(globals, name, meaning, originalLocation); 2272 } 2273 } 2274 if (!result) { 2275 if (originalLocation && isInJSFile(originalLocation) && originalLocation.parent) { 2276 if (isRequireCall(originalLocation.parent, /*checkArgumentIsStringLiteralLike*/ false)) { 2277 return requireSymbol; 2278 } 2279 } 2280 } 2281 2282 // The invalid initializer error is needed in two situation: 2283 // 1. When result is undefined, after checking for a missing "this." 2284 // 2. When result is defined 2285 function checkAndReportErrorForInvalidInitializer() { 2286 if (propertyWithInvalidInitializer && !(useDefineForClassFields && getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2022)) { 2287 // We have a match, but the reference occurred within a property initializer and the identifier also binds 2288 // to a local variable in the constructor where the code will be emitted. Note that this is actually allowed 2289 // with ESNext+useDefineForClassFields because the scope semantics are different. 2290 error(errorLocation, 2291 errorLocation && propertyWithInvalidInitializer.type && textRangeContainsPositionInclusive(propertyWithInvalidInitializer.type, errorLocation.pos) 2292 ? Diagnostics.Type_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor 2293 : Diagnostics.Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor, 2294 declarationNameToString(propertyWithInvalidInitializer.name), diagnosticName(nameArg!)); 2295 return true; 2296 } 2297 return false; 2298 } 2299 2300 if (!result) { 2301 if (nameNotFoundMessage) { 2302 addLazyDiagnostic(() => { 2303 if (!errorLocation || 2304 !checkAndReportErrorForMissingPrefix(errorLocation, name, nameArg!) && // TODO: GH#18217 2305 !checkAndReportErrorForInvalidInitializer() && 2306 !checkAndReportErrorForExtendingInterface(errorLocation) && 2307 !checkAndReportErrorForUsingTypeAsNamespace(errorLocation, name, meaning) && 2308 !checkAndReportErrorForExportingPrimitiveType(errorLocation, name) && 2309 !checkAndReportErrorForUsingNamespaceAsTypeOrValue(errorLocation, name, meaning) && 2310 !checkAndReportErrorForUsingTypeAsValue(errorLocation, name, meaning) && 2311 !checkAndReportErrorForUsingValueAsType(errorLocation, name, meaning)) { 2312 let suggestion: Symbol | undefined; 2313 let suggestedLib: string | undefined; 2314 // Report missing lib first 2315 if (nameArg) { 2316 suggestedLib = getSuggestedLibForNonExistentName(nameArg); 2317 if (suggestedLib) { 2318 error(errorLocation, nameNotFoundMessage, diagnosticName(nameArg), suggestedLib); 2319 } 2320 } 2321 // then spelling suggestions 2322 if (!suggestedLib && getSpellingSuggestions && suggestionCount < maximumSuggestionCount) { 2323 suggestion = getSuggestedSymbolForNonexistentSymbol(originalLocation, name, meaning); 2324 const isGlobalScopeAugmentationDeclaration = suggestion?.valueDeclaration && isAmbientModule(suggestion.valueDeclaration) && isGlobalScopeAugmentation(suggestion.valueDeclaration); 2325 if (isGlobalScopeAugmentationDeclaration) { 2326 suggestion = undefined; 2327 } 2328 if (suggestion) { 2329 const suggestionName = symbolToString(suggestion); 2330 const isUncheckedJS = isUncheckedJSSuggestion(originalLocation, suggestion, /*excludeClasses*/ false); 2331 const message = meaning === SymbolFlags.Namespace || nameArg && typeof nameArg !== "string" && nodeIsSynthesized(nameArg) ? Diagnostics.Cannot_find_namespace_0_Did_you_mean_1 2332 : isUncheckedJS ? Diagnostics.Could_not_find_name_0_Did_you_mean_1 2333 : Diagnostics.Cannot_find_name_0_Did_you_mean_1; 2334 const diagnostic = createError(errorLocation, message, diagnosticName(nameArg!), suggestionName); 2335 addErrorOrSuggestion(!isUncheckedJS, diagnostic); 2336 if (suggestion.valueDeclaration) { 2337 addRelatedInfo( 2338 diagnostic, 2339 createDiagnosticForNode(suggestion.valueDeclaration, Diagnostics._0_is_declared_here, suggestionName) 2340 ); 2341 } 2342 } 2343 } 2344 // And then fall back to unspecified "not found" 2345 if (!suggestion && !suggestedLib && nameArg) { 2346 error(errorLocation, nameNotFoundMessage, diagnosticName(nameArg)); 2347 } 2348 suggestionCount++; 2349 } 2350 }); 2351 } 2352 return undefined; 2353 } 2354 else if (nameNotFoundMessage && checkAndReportErrorForInvalidInitializer()) { 2355 return undefined; 2356 } 2357 2358 // Perform extra checks only if error reporting was requested 2359 if (nameNotFoundMessage) { 2360 addLazyDiagnostic(() => { 2361 // Only check for block-scoped variable if we have an error location and are looking for the 2362 // name with variable meaning 2363 // For example, 2364 // declare module foo { 2365 // interface bar {} 2366 // } 2367 // const foo/*1*/: foo/*2*/.bar; 2368 // The foo at /*1*/ and /*2*/ will share same symbol with two meanings: 2369 // block-scoped variable and namespace module. However, only when we 2370 // try to resolve name in /*1*/ which is used in variable position, 2371 // we want to check for block-scoped 2372 if (errorLocation && 2373 (meaning & SymbolFlags.BlockScopedVariable || 2374 ((meaning & SymbolFlags.Class || meaning & SymbolFlags.Enum) && (meaning & SymbolFlags.Value) === SymbolFlags.Value))) { 2375 const exportOrLocalSymbol = getExportSymbolOfValueSymbolIfExported(result!); 2376 if (exportOrLocalSymbol.flags & SymbolFlags.BlockScopedVariable || exportOrLocalSymbol.flags & SymbolFlags.Class || exportOrLocalSymbol.flags & SymbolFlags.Enum) { 2377 checkResolvedBlockScopedVariable(exportOrLocalSymbol, errorLocation); 2378 } 2379 } 2380 2381 // If we're in an external module, we can't reference value symbols created from UMD export declarations 2382 if (result && isInExternalModule && (meaning & SymbolFlags.Value) === SymbolFlags.Value && !(originalLocation!.flags & NodeFlags.JSDoc)) { 2383 const merged = getMergedSymbol(result); 2384 if (length(merged.declarations) && every(merged.declarations, d => isNamespaceExportDeclaration(d) || isSourceFile(d) && !!d.symbol.globalExports)) { 2385 errorOrSuggestion(!compilerOptions.allowUmdGlobalAccess, errorLocation!, Diagnostics._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead, unescapeLeadingUnderscores(name)); 2386 } 2387 } 2388 2389 // If we're in a parameter initializer or binding name, we can't reference the values of the parameter whose initializer we're within or parameters to the right 2390 if (result && associatedDeclarationForContainingInitializerOrBindingName && !withinDeferredContext && (meaning & SymbolFlags.Value) === SymbolFlags.Value) { 2391 const candidate = getMergedSymbol(getLateBoundSymbol(result)); 2392 const root = (getRootDeclaration(associatedDeclarationForContainingInitializerOrBindingName) as ParameterDeclaration); 2393 // A parameter initializer or binding pattern initializer within a parameter cannot refer to itself 2394 if (candidate === getSymbolOfNode(associatedDeclarationForContainingInitializerOrBindingName)) { 2395 error(errorLocation, Diagnostics.Parameter_0_cannot_reference_itself, declarationNameToString(associatedDeclarationForContainingInitializerOrBindingName.name)); 2396 } 2397 // And it cannot refer to any declarations which come after it 2398 else if (candidate.valueDeclaration && candidate.valueDeclaration.pos > associatedDeclarationForContainingInitializerOrBindingName.pos && root.parent.locals && lookup(root.parent.locals, candidate.escapedName, meaning) === candidate) { 2399 error(errorLocation, Diagnostics.Parameter_0_cannot_reference_identifier_1_declared_after_it, declarationNameToString(associatedDeclarationForContainingInitializerOrBindingName.name), declarationNameToString(errorLocation as Identifier)); 2400 } 2401 } 2402 if (result && errorLocation && meaning & SymbolFlags.Value && result.flags & SymbolFlags.Alias && !(result.flags & SymbolFlags.Value) && !isValidTypeOnlyAliasUseSite(errorLocation)) { 2403 const typeOnlyDeclaration = getTypeOnlyAliasDeclaration(result, SymbolFlags.Value); 2404 if (typeOnlyDeclaration) { 2405 const message = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier 2406 ? Diagnostics._0_cannot_be_used_as_a_value_because_it_was_exported_using_export_type 2407 : Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type; 2408 const unescapedName = unescapeLeadingUnderscores(name); 2409 addTypeOnlyDeclarationRelatedInfo( 2410 error(errorLocation, message, unescapedName), 2411 typeOnlyDeclaration, 2412 unescapedName); 2413 } 2414 } 2415 }); 2416 } 2417 return result; 2418 } 2419 2420 function addTypeOnlyDeclarationRelatedInfo(diagnostic: Diagnostic, typeOnlyDeclaration: TypeOnlyCompatibleAliasDeclaration | undefined, unescapedName: string) { 2421 if (!typeOnlyDeclaration) return diagnostic; 2422 return addRelatedInfo( 2423 diagnostic, 2424 createDiagnosticForNode( 2425 typeOnlyDeclaration, 2426 typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier ? Diagnostics._0_was_exported_here : Diagnostics._0_was_imported_here, 2427 unescapedName)); 2428 } 2429 2430 function getIsDeferredContext(location: Node, lastLocation: Node | undefined): boolean { 2431 if (location.kind !== SyntaxKind.ArrowFunction && location.kind !== SyntaxKind.FunctionExpression) { 2432 // initializers in instance property declaration of class like entities are executed in constructor and thus deferred 2433 return isTypeQueryNode(location) || (( 2434 isFunctionLikeDeclaration(location) || 2435 (location.kind === SyntaxKind.PropertyDeclaration && !isStatic(location)) 2436 ) && (!lastLocation || lastLocation !== (location as SignatureDeclaration | PropertyDeclaration).name)); // A name is evaluated within the enclosing scope - so it shouldn't count as deferred 2437 } 2438 if (lastLocation && lastLocation === (location as FunctionExpression | ArrowFunction).name) { 2439 return false; 2440 } 2441 // generator functions and async functions are not inlined in control flow when immediately invoked 2442 if ((location as FunctionExpression | ArrowFunction).asteriskToken || hasSyntacticModifier(location, ModifierFlags.Async)) { 2443 return true; 2444 } 2445 return !getImmediatelyInvokedFunctionExpression(location); 2446 } 2447 2448 function isSelfReferenceLocation(node: Node): boolean { 2449 switch (node.kind) { 2450 case SyntaxKind.FunctionDeclaration: 2451 case SyntaxKind.ClassDeclaration: 2452 case SyntaxKind.InterfaceDeclaration: 2453 case SyntaxKind.EnumDeclaration: 2454 case SyntaxKind.TypeAliasDeclaration: 2455 case SyntaxKind.ModuleDeclaration: // For `namespace N { N; }` 2456 return true; 2457 default: 2458 return false; 2459 } 2460 } 2461 2462 function diagnosticName(nameArg: __String | Identifier | PrivateIdentifier) { 2463 return isString(nameArg) ? unescapeLeadingUnderscores(nameArg as __String) : declarationNameToString(nameArg as Identifier); 2464 } 2465 2466 function isTypeParameterSymbolDeclaredInContainer(symbol: Symbol, container: Node) { 2467 if (symbol.declarations) { 2468 for (const decl of symbol.declarations) { 2469 if (decl.kind === SyntaxKind.TypeParameter) { 2470 const parent = isJSDocTemplateTag(decl.parent) ? getJSDocHost(decl.parent) : decl.parent; 2471 if (parent === container) { 2472 return !(isJSDocTemplateTag(decl.parent) && find((decl.parent.parent as JSDoc).tags, isJSDocTypeAlias)); 2473 } 2474 } 2475 } 2476 } 2477 2478 return false; 2479 } 2480 2481 function checkAndReportErrorForMissingPrefix(errorLocation: Node, name: __String, nameArg: __String | Identifier): boolean { 2482 if (!isIdentifier(errorLocation) || errorLocation.escapedText !== name || isTypeReferenceIdentifier(errorLocation) || isInTypeQuery(errorLocation)) { 2483 return false; 2484 } 2485 2486 const container = getThisContainer(errorLocation, /*includeArrowFunctions*/ false); 2487 let location = container; 2488 while (location) { 2489 if (isClassLike(location.parent)) { 2490 const classSymbol = getSymbolOfNode(location.parent); 2491 if (!classSymbol) { 2492 break; 2493 } 2494 2495 // Check to see if a static member exists. 2496 const constructorType = getTypeOfSymbol(classSymbol); 2497 if (getPropertyOfType(constructorType, name)) { 2498 error(errorLocation, Diagnostics.Cannot_find_name_0_Did_you_mean_the_static_member_1_0, diagnosticName(nameArg), symbolToString(classSymbol)); 2499 return true; 2500 } 2501 2502 // No static member is present. 2503 // Check if we're in an instance method and look for a relevant instance member. 2504 if (location === container && !isStatic(location)) { 2505 const instanceType = (getDeclaredTypeOfSymbol(classSymbol) as InterfaceType).thisType!; // TODO: GH#18217 2506 if (getPropertyOfType(instanceType, name)) { 2507 error(errorLocation, Diagnostics.Cannot_find_name_0_Did_you_mean_the_instance_member_this_0, diagnosticName(nameArg)); 2508 return true; 2509 } 2510 } 2511 } 2512 2513 location = location.parent; 2514 } 2515 return false; 2516 } 2517 2518 2519 function checkAndReportErrorForExtendingInterface(errorLocation: Node): boolean { 2520 const expression = getEntityNameForExtendingInterface(errorLocation); 2521 if (expression && resolveEntityName(expression, SymbolFlags.Interface, /*ignoreErrors*/ true)) { 2522 error(errorLocation, Diagnostics.Cannot_extend_an_interface_0_Did_you_mean_implements, getTextOfNode(expression)); 2523 return true; 2524 } 2525 return false; 2526 } 2527 /** 2528 * Climbs up parents to an ExpressionWithTypeArguments, and returns its expression, 2529 * but returns undefined if that expression is not an EntityNameExpression. 2530 */ 2531 function getEntityNameForExtendingInterface(node: Node): EntityNameExpression | undefined { 2532 switch (node.kind) { 2533 case SyntaxKind.Identifier: 2534 case SyntaxKind.PropertyAccessExpression: 2535 return node.parent ? getEntityNameForExtendingInterface(node.parent) : undefined; 2536 case SyntaxKind.ExpressionWithTypeArguments: 2537 if (isEntityNameExpression((node as ExpressionWithTypeArguments).expression)) { 2538 return (node as ExpressionWithTypeArguments).expression as EntityNameExpression; 2539 } 2540 // falls through 2541 default: 2542 return undefined; 2543 } 2544 } 2545 2546 function checkAndReportErrorForUsingTypeAsNamespace(errorLocation: Node, name: __String, meaning: SymbolFlags): boolean { 2547 const namespaceMeaning = SymbolFlags.Namespace | (isInJSFile(errorLocation) ? SymbolFlags.Value : 0); 2548 if (meaning === namespaceMeaning) { 2549 const symbol = resolveSymbol(resolveName(errorLocation, name, SymbolFlags.Type & ~namespaceMeaning, /*nameNotFoundMessage*/undefined, /*nameArg*/ undefined, /*isUse*/ false)); 2550 const parent = errorLocation.parent; 2551 if (symbol) { 2552 if (isQualifiedName(parent)) { 2553 Debug.assert(parent.left === errorLocation, "Should only be resolving left side of qualified name as a namespace"); 2554 const propName = parent.right.escapedText; 2555 const propType = getPropertyOfType(getDeclaredTypeOfSymbol(symbol), propName); 2556 if (propType) { 2557 error( 2558 parent, 2559 Diagnostics.Cannot_access_0_1_because_0_is_a_type_but_not_a_namespace_Did_you_mean_to_retrieve_the_type_of_the_property_1_in_0_with_0_1, 2560 unescapeLeadingUnderscores(name), 2561 unescapeLeadingUnderscores(propName), 2562 ); 2563 return true; 2564 } 2565 } 2566 error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_namespace_here, unescapeLeadingUnderscores(name)); 2567 return true; 2568 } 2569 } 2570 2571 return false; 2572 } 2573 2574 function checkAndReportErrorForUsingValueAsType(errorLocation: Node, name: __String, meaning: SymbolFlags): boolean { 2575 if (meaning & (SymbolFlags.Type & ~SymbolFlags.Namespace)) { 2576 const symbol = resolveSymbol(resolveName(errorLocation, name, ~SymbolFlags.Type & SymbolFlags.Value, /*nameNotFoundMessage*/undefined, /*nameArg*/ undefined, /*isUse*/ false)); 2577 if (symbol && !(symbol.flags & SymbolFlags.Namespace)) { 2578 error(errorLocation, Diagnostics._0_refers_to_a_value_but_is_being_used_as_a_type_here_Did_you_mean_typeof_0, unescapeLeadingUnderscores(name)); 2579 return true; 2580 } 2581 } 2582 return false; 2583 } 2584 2585 function isPrimitiveTypeName(name: __String) { 2586 return name === "any" || name === "string" || name === "number" || name === "boolean" || name === "never" || name === "unknown"; 2587 } 2588 2589 function checkAndReportErrorForExportingPrimitiveType(errorLocation: Node, name: __String): boolean { 2590 if (isPrimitiveTypeName(name) && errorLocation.parent.kind === SyntaxKind.ExportSpecifier) { 2591 error(errorLocation, Diagnostics.Cannot_export_0_Only_local_declarations_can_be_exported_from_a_module, name as string); 2592 return true; 2593 } 2594 return false; 2595 } 2596 2597 function checkAndReportErrorForUsingTypeAsValue(errorLocation: Node, name: __String, meaning: SymbolFlags): boolean { 2598 if (meaning & SymbolFlags.Value) { 2599 if (isPrimitiveTypeName(name)) { 2600 if (isExtendedByInterface(errorLocation)) { 2601 error(errorLocation, Diagnostics.An_interface_cannot_extend_a_primitive_type_like_0_an_interface_can_only_extend_named_types_and_classes, unescapeLeadingUnderscores(name)); 2602 } 2603 else { 2604 error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here, unescapeLeadingUnderscores(name)); 2605 } 2606 return true; 2607 } 2608 const symbol = resolveSymbol(resolveName(errorLocation, name, SymbolFlags.Type & ~SymbolFlags.Value, /*nameNotFoundMessage*/undefined, /*nameArg*/ undefined, /*isUse*/ false)); 2609 const allFlags = symbol && getAllSymbolFlags(symbol); 2610 if (symbol && allFlags !== undefined && !(allFlags & SymbolFlags.Value)) { 2611 const rawName = unescapeLeadingUnderscores(name); 2612 if (isES2015OrLaterConstructorName(name)) { 2613 error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_es2015_or_later, rawName); 2614 } 2615 else if (maybeMappedType(errorLocation, symbol)) { 2616 error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here_Did_you_mean_to_use_1_in_0, rawName, rawName === "K" ? "P" : "K"); 2617 } 2618 else { 2619 error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here, rawName); 2620 } 2621 return true; 2622 } 2623 } 2624 return false; 2625 } 2626 2627 function isExtendedByInterface(node: Node): boolean { 2628 const grandparent = node.parent.parent; 2629 const parentOfGrandparent = grandparent.parent; 2630 if(grandparent && parentOfGrandparent){ 2631 const isExtending = isHeritageClause(grandparent) && grandparent.token === SyntaxKind.ExtendsKeyword; 2632 const isInterface = isInterfaceDeclaration(parentOfGrandparent); 2633 return isExtending && isInterface; 2634 } 2635 return false; 2636 } 2637 2638 function maybeMappedType(node: Node, symbol: Symbol) { 2639 const container = findAncestor(node.parent, n => 2640 isComputedPropertyName(n) || isPropertySignature(n) ? false : isTypeLiteralNode(n) || "quit") as TypeLiteralNode | undefined; 2641 if (container && container.members.length === 1) { 2642 const type = getDeclaredTypeOfSymbol(symbol); 2643 return !!(type.flags & TypeFlags.Union) && allTypesAssignableToKind(type, TypeFlags.StringOrNumberLiteral, /*strict*/ true); 2644 } 2645 return false; 2646 } 2647 2648 function isES2015OrLaterConstructorName(n: __String) { 2649 switch (n) { 2650 case "Promise": 2651 case "Symbol": 2652 case "Map": 2653 case "WeakMap": 2654 case "Set": 2655 case "WeakSet": 2656 return true; 2657 } 2658 return false; 2659 } 2660 2661 function checkAndReportErrorForUsingNamespaceAsTypeOrValue(errorLocation: Node, name: __String, meaning: SymbolFlags): boolean { 2662 if (meaning & (SymbolFlags.Value & ~SymbolFlags.Type)) { 2663 const symbol = resolveSymbol(resolveName(errorLocation, name, SymbolFlags.NamespaceModule, /*nameNotFoundMessage*/undefined, /*nameArg*/ undefined, /*isUse*/ false)); 2664 if (symbol) { 2665 error( 2666 errorLocation, 2667 Diagnostics.Cannot_use_namespace_0_as_a_value, 2668 unescapeLeadingUnderscores(name)); 2669 return true; 2670 } 2671 } 2672 else if (meaning & (SymbolFlags.Type & ~SymbolFlags.Value)) { 2673 const symbol = resolveSymbol(resolveName(errorLocation, name, SymbolFlags.Module, /*nameNotFoundMessage*/undefined, /*nameArg*/ undefined, /*isUse*/ false)); 2674 if (symbol) { 2675 error(errorLocation, Diagnostics.Cannot_use_namespace_0_as_a_type, unescapeLeadingUnderscores(name)); 2676 return true; 2677 } 2678 } 2679 return false; 2680 } 2681 2682 function checkResolvedBlockScopedVariable(result: Symbol, errorLocation: Node): void { 2683 Debug.assert(!!(result.flags & SymbolFlags.BlockScopedVariable || result.flags & SymbolFlags.Class || result.flags & SymbolFlags.Enum)); 2684 if (result.flags & (SymbolFlags.Function | SymbolFlags.FunctionScopedVariable | SymbolFlags.Assignment) && result.flags & SymbolFlags.Class) { 2685 // constructor functions aren't block scoped 2686 return; 2687 } 2688 // Block-scoped variables cannot be used before their definition 2689 const declaration = result.declarations?.find( 2690 d => isBlockOrCatchScoped(d) || isClassLike(d) || isAnnotationDeclaration(d) || (d.kind === SyntaxKind.EnumDeclaration)); 2691 2692 if (declaration === undefined) return Debug.fail("checkResolvedBlockScopedVariable could not find block-scoped declaration"); 2693 2694 if (!(declaration.flags & NodeFlags.Ambient) && !isBlockScopedNameDeclaredBeforeUse(declaration, errorLocation)) { 2695 let diagnosticMessage; 2696 const declarationName = declarationNameToString(getNameOfDeclaration(declaration)); 2697 if (result.flags & SymbolFlags.BlockScopedVariable) { 2698 diagnosticMessage = error(errorLocation, Diagnostics.Block_scoped_variable_0_used_before_its_declaration, declarationName); 2699 } 2700 else if (result.flags & SymbolFlags.Annotation) { 2701 diagnosticMessage = error(errorLocation, Diagnostics.Annotation_0_used_before_its_declaration, declarationName); 2702 } 2703 else if (result.flags & SymbolFlags.Class) { 2704 diagnosticMessage = error(errorLocation, Diagnostics.Class_0_used_before_its_declaration, declarationName); 2705 } 2706 else if (result.flags & SymbolFlags.RegularEnum) { 2707 diagnosticMessage = error(errorLocation, Diagnostics.Enum_0_used_before_its_declaration, declarationName); 2708 } 2709 else { 2710 Debug.assert(!!(result.flags & SymbolFlags.ConstEnum)); 2711 if (shouldPreserveConstEnums(compilerOptions)) { 2712 diagnosticMessage = error(errorLocation, Diagnostics.Enum_0_used_before_its_declaration, declarationName); 2713 } 2714 } 2715 2716 if (diagnosticMessage) { 2717 addRelatedInfo(diagnosticMessage, 2718 createDiagnosticForNode(declaration, Diagnostics._0_is_declared_here, declarationName) 2719 ); 2720 } 2721 } 2722 } 2723 2724 /* Starting from 'initial' node walk up the parent chain until 'stopAt' node is reached. 2725 * If at any point current node is equal to 'parent' node - return true. 2726 * If current node is an IIFE, continue walking up. 2727 * Return false if 'stopAt' node is reached or isFunctionLike(current) === true. 2728 */ 2729 function isSameScopeDescendentOf(initial: Node, parent: Node | undefined, stopAt: Node): boolean { 2730 return !!parent && !!findAncestor(initial, n => n === parent 2731 || (n === stopAt || isFunctionLike(n) && !getImmediatelyInvokedFunctionExpression(n) ? "quit" : false)); 2732 } 2733 2734 function getAnyImportSyntax(node: Node): AnyImportSyntax | undefined { 2735 switch (node.kind) { 2736 case SyntaxKind.ImportEqualsDeclaration: 2737 return node as ImportEqualsDeclaration; 2738 case SyntaxKind.ImportClause: 2739 return (node as ImportClause).parent; 2740 case SyntaxKind.NamespaceImport: 2741 return (node as NamespaceImport).parent.parent; 2742 case SyntaxKind.ImportSpecifier: 2743 return (node as ImportSpecifier).parent.parent.parent; 2744 default: 2745 return undefined; 2746 } 2747 } 2748 2749 function getDeclarationOfAliasSymbol(symbol: Symbol): Declaration | undefined { 2750 return symbol.declarations && findLast<Declaration>(symbol.declarations, isAliasSymbolDeclaration); 2751 } 2752 2753 /** 2754 * An alias symbol is created by one of the following declarations: 2755 * import <symbol> = ... 2756 * import <symbol> from ... 2757 * import * as <symbol> from ... 2758 * import { x as <symbol> } from ... 2759 * export { x as <symbol> } from ... 2760 * export * as ns <symbol> from ... 2761 * export = <EntityNameExpression> 2762 * export default <EntityNameExpression> 2763 * module.exports = <EntityNameExpression> 2764 * {<Identifier>} 2765 * {name: <EntityNameExpression>} 2766 * const { x } = require ... 2767 */ 2768 function isAliasSymbolDeclaration(node: Node): boolean { 2769 return node.kind === SyntaxKind.ImportEqualsDeclaration 2770 || node.kind === SyntaxKind.NamespaceExportDeclaration 2771 || node.kind === SyntaxKind.ImportClause && !!(node as ImportClause).name 2772 || node.kind === SyntaxKind.NamespaceImport 2773 || node.kind === SyntaxKind.NamespaceExport 2774 || node.kind === SyntaxKind.ImportSpecifier 2775 || node.kind === SyntaxKind.ExportSpecifier 2776 || node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(node as ExportAssignment) 2777 || isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ModuleExports && exportAssignmentIsAlias(node) 2778 || isAccessExpression(node) 2779 && isBinaryExpression(node.parent) 2780 && node.parent.left === node 2781 && node.parent.operatorToken.kind === SyntaxKind.EqualsToken 2782 && isAliasableOrJsExpression(node.parent.right) 2783 || node.kind === SyntaxKind.ShorthandPropertyAssignment 2784 || node.kind === SyntaxKind.PropertyAssignment && isAliasableOrJsExpression((node as PropertyAssignment).initializer) 2785 || node.kind === SyntaxKind.VariableDeclaration && isVariableDeclarationInitializedToBareOrAccessedRequire(node) 2786 || node.kind === SyntaxKind.BindingElement && isVariableDeclarationInitializedToBareOrAccessedRequire(node.parent.parent); 2787 } 2788 2789 function isAliasableOrJsExpression(e: Expression) { 2790 return isAliasableExpression(e) || isFunctionExpression(e) && isJSConstructor(e); 2791 } 2792 2793 function getTargetOfImportEqualsDeclaration(node: ImportEqualsDeclaration | VariableDeclaration, dontResolveAlias: boolean): Symbol | undefined { 2794 const commonJSPropertyAccess = getCommonJSPropertyAccess(node); 2795 if (commonJSPropertyAccess) { 2796 const name = (getLeftmostAccessExpression(commonJSPropertyAccess.expression) as CallExpression).arguments[0] as StringLiteral; 2797 return isIdentifier(commonJSPropertyAccess.name) 2798 ? resolveSymbol(getPropertyOfType(resolveExternalModuleTypeByLiteral(name), commonJSPropertyAccess.name.escapedText)) 2799 : undefined; 2800 } 2801 if (isVariableDeclaration(node) || node.moduleReference.kind === SyntaxKind.ExternalModuleReference) { 2802 const immediate = resolveExternalModuleName( 2803 node, 2804 getExternalModuleRequireArgument(node) || getExternalModuleImportEqualsDeclarationExpression(node)); 2805 const resolved = resolveExternalModuleSymbol(immediate); 2806 markSymbolOfAliasDeclarationIfTypeOnly(node, immediate, resolved, /*overwriteEmpty*/ false); 2807 return resolved; 2808 } 2809 const resolved = getSymbolOfPartOfRightHandSideOfImportEquals(node.moduleReference, dontResolveAlias); 2810 checkAndReportErrorForResolvingImportAliasToTypeOnlySymbol(node, resolved); 2811 return resolved; 2812 } 2813 2814 function checkAndReportErrorForResolvingImportAliasToTypeOnlySymbol(node: ImportEqualsDeclaration, resolved: Symbol | undefined) { 2815 if (markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false) && !node.isTypeOnly) { 2816 const typeOnlyDeclaration = getTypeOnlyAliasDeclaration(getSymbolOfNode(node))!; 2817 const isExport = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier; 2818 const message = isExport 2819 ? Diagnostics.An_import_alias_cannot_reference_a_declaration_that_was_exported_using_export_type 2820 : Diagnostics.An_import_alias_cannot_reference_a_declaration_that_was_imported_using_import_type; 2821 const relatedMessage = isExport 2822 ? Diagnostics._0_was_exported_here 2823 : Diagnostics._0_was_imported_here; 2824 2825 const name = unescapeLeadingUnderscores(typeOnlyDeclaration.name.escapedText); 2826 addRelatedInfo(error(node.moduleReference, message), createDiagnosticForNode(typeOnlyDeclaration, relatedMessage, name)); 2827 } 2828 } 2829 2830 function resolveExportByName(moduleSymbol: Symbol, name: __String, sourceNode: TypeOnlyCompatibleAliasDeclaration | undefined, dontResolveAlias: boolean) { 2831 const exportValue = moduleSymbol.exports!.get(InternalSymbolName.ExportEquals); 2832 const exportSymbol = exportValue ? getPropertyOfType(getTypeOfSymbol(exportValue), name) : moduleSymbol.exports!.get(name); 2833 const resolved = resolveSymbol(exportSymbol, dontResolveAlias); 2834 markSymbolOfAliasDeclarationIfTypeOnly(sourceNode, exportSymbol, resolved, /*overwriteEmpty*/ false); 2835 return resolved; 2836 } 2837 2838 function isSyntacticDefault(node: Node) { 2839 return ((isExportAssignment(node) && !node.isExportEquals) || hasSyntacticModifier(node, ModifierFlags.Default) || isExportSpecifier(node)); 2840 } 2841 2842 function getUsageModeForExpression(usage: Expression) { 2843 return isStringLiteralLike(usage) ? getModeForUsageLocation(getSourceFileOfNode(usage), usage) : undefined; 2844 } 2845 2846 function isESMFormatImportImportingCommonjsFormatFile(usageMode: SourceFile["impliedNodeFormat"], targetMode: SourceFile["impliedNodeFormat"]) { 2847 return usageMode === ModuleKind.ESNext && targetMode === ModuleKind.CommonJS; 2848 } 2849 2850 function isOnlyImportedAsDefault(usage: Expression) { 2851 const usageMode = getUsageModeForExpression(usage); 2852 return usageMode === ModuleKind.ESNext && endsWith((usage as StringLiteralLike).text, Extension.Json); 2853 } 2854 2855 function canHaveSyntheticDefault(file: SourceFile | undefined, moduleSymbol: Symbol, dontResolveAlias: boolean, usage: Expression) { 2856 const usageMode = file && getUsageModeForExpression(usage); 2857 if (file && usageMode !== undefined) { 2858 const result = isESMFormatImportImportingCommonjsFormatFile(usageMode, file.impliedNodeFormat); 2859 if (usageMode === ModuleKind.ESNext || result) { 2860 return result; 2861 } 2862 // fallthrough on cjs usages so we imply defaults for interop'd imports, too 2863 } 2864 if (!allowSyntheticDefaultImports) { 2865 return false; 2866 } 2867 // Declaration files (and ambient modules) 2868 if (!file || file.isDeclarationFile) { 2869 // Definitely cannot have a synthetic default if they have a syntactic default member specified 2870 const defaultExportSymbol = resolveExportByName(moduleSymbol, InternalSymbolName.Default, /*sourceNode*/ undefined, /*dontResolveAlias*/ true); // Dont resolve alias because we want the immediately exported symbol's declaration 2871 if (defaultExportSymbol && some(defaultExportSymbol.declarations, isSyntacticDefault)) { 2872 return false; 2873 } 2874 // It _might_ still be incorrect to assume there is no __esModule marker on the import at runtime, even if there is no `default` member 2875 // So we check a bit more, 2876 if (resolveExportByName(moduleSymbol, escapeLeadingUnderscores("__esModule"), /*sourceNode*/ undefined, dontResolveAlias)) { 2877 // If there is an `__esModule` specified in the declaration (meaning someone explicitly added it or wrote it in their code), 2878 // it definitely is a module and does not have a synthetic default 2879 return false; 2880 } 2881 // There are _many_ declaration files not written with esmodules in mind that still get compiled into a format with __esModule set 2882 // Meaning there may be no default at runtime - however to be on the permissive side, we allow access to a synthetic default member 2883 // as there is no marker to indicate if the accompanying JS has `__esModule` or not, or is even native esm 2884 return true; 2885 } 2886 // TypeScript files never have a synthetic default (as they are always emitted with an __esModule marker) _unless_ they contain an export= statement 2887 if (!isSourceFileJS(file)) { 2888 return hasExportAssignmentSymbol(moduleSymbol); 2889 } 2890 // JS files have a synthetic default if they do not contain ES2015+ module syntax (export = is not valid in js) _and_ do not have an __esModule marker 2891 return typeof file.externalModuleIndicator !== "object" && !resolveExportByName(moduleSymbol, escapeLeadingUnderscores("__esModule"), /*sourceNode*/ undefined, dontResolveAlias); 2892 } 2893 2894 function getTargetOfImportClause(node: ImportClause, dontResolveAlias: boolean): Symbol | undefined { 2895 const moduleSymbol = resolveExternalModuleName(node, node.parent.moduleSpecifier); 2896 if (moduleSymbol) { 2897 return getTargetofModuleDefault(moduleSymbol, node, dontResolveAlias); 2898 } 2899 } 2900 2901 function getTargetofModuleDefault(moduleSymbol: Symbol, node: ImportClause | ImportOrExportSpecifier, dontResolveAlias: boolean) { 2902 let exportDefaultSymbol: Symbol | undefined; 2903 if (isShorthandAmbientModuleSymbol(moduleSymbol)) { 2904 exportDefaultSymbol = moduleSymbol; 2905 } 2906 else { 2907 exportDefaultSymbol = resolveExportByName(moduleSymbol, InternalSymbolName.Default, node, dontResolveAlias); 2908 } 2909 2910 const file = moduleSymbol.declarations?.find(isSourceFile); 2911 const specifier = getModuleSpecifierForImportOrExport(node); 2912 if (!specifier) { 2913 return exportDefaultSymbol; 2914 } 2915 const hasDefaultOnly = isOnlyImportedAsDefault(specifier); 2916 const hasSyntheticDefault = canHaveSyntheticDefault(file, moduleSymbol, dontResolveAlias, specifier); 2917 if (!exportDefaultSymbol && !hasSyntheticDefault && !hasDefaultOnly) { 2918 if (hasExportAssignmentSymbol(moduleSymbol)) { 2919 const compilerOptionName = moduleKind >= ModuleKind.ES2015 ? "allowSyntheticDefaultImports" : "esModuleInterop"; 2920 const exportEqualsSymbol = moduleSymbol.exports!.get(InternalSymbolName.ExportEquals); 2921 const exportAssignment = exportEqualsSymbol!.valueDeclaration; 2922 const err = error(node.name, Diagnostics.Module_0_can_only_be_default_imported_using_the_1_flag, symbolToString(moduleSymbol), compilerOptionName); 2923 2924 if (exportAssignment) { 2925 addRelatedInfo(err, createDiagnosticForNode( 2926 exportAssignment, 2927 Diagnostics.This_module_is_declared_with_export_and_can_only_be_used_with_a_default_import_when_using_the_0_flag, 2928 compilerOptionName 2929 )); 2930 } 2931 } 2932 else if (isImportClause(node)) { 2933 reportNonDefaultExport(moduleSymbol, node); 2934 } 2935 else { 2936 errorNoModuleMemberSymbol(moduleSymbol, moduleSymbol, node, isImportOrExportSpecifier(node) && node.propertyName || node.name); 2937 } 2938 } 2939 else if (hasSyntheticDefault || hasDefaultOnly) { 2940 // per emit behavior, a synthetic default overrides a "real" .default member if `__esModule` is not present 2941 const resolved = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) || resolveSymbol(moduleSymbol, dontResolveAlias); 2942 markSymbolOfAliasDeclarationIfTypeOnly(node, moduleSymbol, resolved, /*overwriteTypeOnly*/ false); 2943 return resolved; 2944 } 2945 markSymbolOfAliasDeclarationIfTypeOnly(node, exportDefaultSymbol, /*finalTarget*/ undefined, /*overwriteTypeOnly*/ false); 2946 return exportDefaultSymbol; 2947 } 2948 2949 function getModuleSpecifierForImportOrExport(node: ImportEqualsDeclaration | ImportClause | NamespaceImport | ImportOrExportSpecifier): Expression | undefined { 2950 switch (node.kind) { 2951 case SyntaxKind.ImportClause: return node.parent.moduleSpecifier; 2952 case SyntaxKind.ImportEqualsDeclaration: return isExternalModuleReference(node.moduleReference) ? node.moduleReference.expression : undefined; 2953 case SyntaxKind.NamespaceImport: return node.parent.parent.moduleSpecifier; 2954 case SyntaxKind.ImportSpecifier: return node.parent.parent.parent.moduleSpecifier; 2955 case SyntaxKind.ExportSpecifier: return node.parent.parent.moduleSpecifier; 2956 default: return Debug.assertNever(node); 2957 } 2958 } 2959 2960 function reportNonDefaultExport(moduleSymbol: Symbol, node: ImportClause) { 2961 if (moduleSymbol.exports?.has(node.symbol.escapedName)) { 2962 error( 2963 node.name, 2964 Diagnostics.Module_0_has_no_default_export_Did_you_mean_to_use_import_1_from_0_instead, 2965 symbolToString(moduleSymbol), 2966 symbolToString(node.symbol), 2967 ); 2968 } 2969 else { 2970 const diagnostic = error(node.name, Diagnostics.Module_0_has_no_default_export, symbolToString(moduleSymbol)); 2971 const exportStar = moduleSymbol.exports?.get(InternalSymbolName.ExportStar); 2972 if (exportStar) { 2973 const defaultExport = exportStar.declarations?.find(decl => !!( 2974 isExportDeclaration(decl) && decl.moduleSpecifier && 2975 resolveExternalModuleName(decl, decl.moduleSpecifier)?.exports?.has(InternalSymbolName.Default) 2976 )); 2977 if (defaultExport) { 2978 addRelatedInfo(diagnostic, createDiagnosticForNode(defaultExport, Diagnostics.export_Asterisk_does_not_re_export_a_default)); 2979 } 2980 } 2981 } 2982 } 2983 2984 function getTargetOfNamespaceImport(node: NamespaceImport, dontResolveAlias: boolean): Symbol | undefined { 2985 const moduleSpecifier = node.parent.parent.moduleSpecifier; 2986 const immediate = resolveExternalModuleName(node, moduleSpecifier); 2987 const resolved = resolveESModuleSymbol(immediate, moduleSpecifier, dontResolveAlias, /*suppressUsageError*/ false); 2988 markSymbolOfAliasDeclarationIfTypeOnly(node, immediate, resolved, /*overwriteEmpty*/ false); 2989 return resolved; 2990 } 2991 2992 function getTargetOfNamespaceExport(node: NamespaceExport, dontResolveAlias: boolean): Symbol | undefined { 2993 const moduleSpecifier = node.parent.moduleSpecifier; 2994 const immediate = moduleSpecifier && resolveExternalModuleName(node, moduleSpecifier); 2995 const resolved = moduleSpecifier && resolveESModuleSymbol(immediate, moduleSpecifier, dontResolveAlias, /*suppressUsageError*/ false); 2996 markSymbolOfAliasDeclarationIfTypeOnly(node, immediate, resolved, /*overwriteEmpty*/ false); 2997 return resolved; 2998 } 2999 3000 // This function creates a synthetic symbol that combines the value side of one symbol with the 3001 // type/namespace side of another symbol. Consider this example: 3002 // 3003 // declare module graphics { 3004 // interface Point { 3005 // x: number; 3006 // y: number; 3007 // } 3008 // } 3009 // declare var graphics: { 3010 // Point: new (x: number, y: number) => graphics.Point; 3011 // } 3012 // declare module "graphics" { 3013 // export = graphics; 3014 // } 3015 // 3016 // An 'import { Point } from "graphics"' needs to create a symbol that combines the value side 'Point' 3017 // property with the type/namespace side interface 'Point'. 3018 function combineValueAndTypeSymbols(valueSymbol: Symbol, typeSymbol: Symbol): Symbol { 3019 if (valueSymbol === unknownSymbol && typeSymbol === unknownSymbol) { 3020 return unknownSymbol; 3021 } 3022 if (valueSymbol.flags & (SymbolFlags.Type | SymbolFlags.Namespace)) { 3023 return valueSymbol; 3024 } 3025 const result = createSymbol(valueSymbol.flags | typeSymbol.flags, valueSymbol.escapedName); 3026 result.declarations = deduplicate(concatenate(valueSymbol.declarations, typeSymbol.declarations), equateValues); 3027 result.parent = valueSymbol.parent || typeSymbol.parent; 3028 if (valueSymbol.valueDeclaration) result.valueDeclaration = valueSymbol.valueDeclaration; 3029 if (typeSymbol.members) result.members = new Map(typeSymbol.members); 3030 if (valueSymbol.exports) result.exports = new Map(valueSymbol.exports); 3031 return result; 3032 } 3033 3034 function getExportOfModule(symbol: Symbol, name: Identifier, specifier: Declaration, dontResolveAlias: boolean): Symbol | undefined { 3035 if (symbol.flags & SymbolFlags.Module) { 3036 const exportSymbol = getExportsOfSymbol(symbol).get(name.escapedText); 3037 const resolved = resolveSymbol(exportSymbol, dontResolveAlias); 3038 markSymbolOfAliasDeclarationIfTypeOnly(specifier, exportSymbol, resolved, /*overwriteEmpty*/ false); 3039 return resolved; 3040 } 3041 } 3042 3043 function getPropertyOfVariable(symbol: Symbol, name: __String): Symbol | undefined { 3044 if (symbol.flags & SymbolFlags.Variable) { 3045 const typeAnnotation = (symbol.valueDeclaration as VariableDeclaration).type; 3046 if (typeAnnotation) { 3047 return resolveSymbol(getPropertyOfType(getTypeFromTypeNode(typeAnnotation), name)); 3048 } 3049 } 3050 } 3051 3052 function getExternalModuleMember(node: ImportDeclaration | ExportDeclaration | VariableDeclaration, specifier: ImportOrExportSpecifier | BindingElement | PropertyAccessExpression, dontResolveAlias = false): Symbol | undefined { 3053 const moduleSpecifier = getExternalModuleRequireArgument(node) || (node as ImportDeclaration | ExportDeclaration).moduleSpecifier!; 3054 const moduleSymbol = resolveExternalModuleName(node, moduleSpecifier)!; // TODO: GH#18217 3055 const name = !isPropertyAccessExpression(specifier) && specifier.propertyName || specifier.name; 3056 if (!isIdentifier(name)) { 3057 return undefined; 3058 } 3059 const suppressInteropError = name.escapedText === InternalSymbolName.Default && !!(compilerOptions.allowSyntheticDefaultImports || getESModuleInterop(compilerOptions)); 3060 const targetSymbol = resolveESModuleSymbol(moduleSymbol, moduleSpecifier, /*dontResolveAlias*/ false, suppressInteropError); 3061 if (targetSymbol) { 3062 if (name.escapedText) { 3063 if (isShorthandAmbientModuleSymbol(moduleSymbol)) { 3064 return moduleSymbol; 3065 } 3066 3067 let symbolFromVariable: Symbol | undefined; 3068 // First check if module was specified with "export=". If so, get the member from the resolved type 3069 if (moduleSymbol && moduleSymbol.exports && moduleSymbol.exports.get(InternalSymbolName.ExportEquals)) { 3070 symbolFromVariable = getPropertyOfType(getTypeOfSymbol(targetSymbol), name.escapedText, /*skipObjectFunctionPropertyAugment*/ true); 3071 } 3072 else { 3073 symbolFromVariable = getPropertyOfVariable(targetSymbol, name.escapedText); 3074 } 3075 // if symbolFromVariable is export - get its final target 3076 symbolFromVariable = resolveSymbol(symbolFromVariable, dontResolveAlias); 3077 3078 let symbolFromModule = getExportOfModule(targetSymbol, name, specifier, dontResolveAlias); 3079 if (symbolFromModule === undefined && name.escapedText === InternalSymbolName.Default) { 3080 const file = moduleSymbol.declarations?.find(isSourceFile); 3081 if (isOnlyImportedAsDefault(moduleSpecifier) || canHaveSyntheticDefault(file, moduleSymbol, dontResolveAlias, moduleSpecifier)) { 3082 symbolFromModule = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) || resolveSymbol(moduleSymbol, dontResolveAlias); 3083 } 3084 } 3085 3086 const symbol = symbolFromModule && symbolFromVariable && symbolFromModule !== symbolFromVariable ? 3087 combineValueAndTypeSymbols(symbolFromVariable, symbolFromModule) : 3088 symbolFromModule || symbolFromVariable; 3089 if (!symbol) { 3090 errorNoModuleMemberSymbol(moduleSymbol, targetSymbol, node, name); 3091 } 3092 return symbol; 3093 } 3094 } 3095 } 3096 3097 function errorNoModuleMemberSymbol(moduleSymbol: Symbol, targetSymbol: Symbol, node: Node, name: Identifier) { 3098 const moduleName = getFullyQualifiedName(moduleSymbol, node); 3099 const declarationName = declarationNameToString(name); 3100 const suggestion = getSuggestedSymbolForNonexistentModule(name, targetSymbol); 3101 if (suggestion !== undefined) { 3102 const suggestionName = symbolToString(suggestion); 3103 const diagnostic = error(name, Diagnostics._0_has_no_exported_member_named_1_Did_you_mean_2, moduleName, declarationName, suggestionName); 3104 if (suggestion.valueDeclaration) { 3105 addRelatedInfo(diagnostic, 3106 createDiagnosticForNode(suggestion.valueDeclaration, Diagnostics._0_is_declared_here, suggestionName) 3107 ); 3108 } 3109 } 3110 else { 3111 if (moduleSymbol.exports?.has(InternalSymbolName.Default)) { 3112 error( 3113 name, 3114 Diagnostics.Module_0_has_no_exported_member_1_Did_you_mean_to_use_import_1_from_0_instead, 3115 moduleName, 3116 declarationName 3117 ); 3118 } 3119 else { 3120 reportNonExportedMember(node, name, declarationName, moduleSymbol, moduleName); 3121 } 3122 } 3123 } 3124 3125 function reportNonExportedMember(node: Node, name: Identifier, declarationName: string, moduleSymbol: Symbol, moduleName: string): void { 3126 const localSymbol = moduleSymbol.valueDeclaration?.locals?.get(name.escapedText); 3127 const exports = moduleSymbol.exports; 3128 if (localSymbol) { 3129 const exportedEqualsSymbol = exports?.get(InternalSymbolName.ExportEquals); 3130 if (exportedEqualsSymbol) { 3131 getSymbolIfSameReference(exportedEqualsSymbol, localSymbol) ? reportInvalidImportEqualsExportMember(node, name, declarationName, moduleName) : 3132 error(name, Diagnostics.Module_0_has_no_exported_member_1, moduleName, declarationName); 3133 } 3134 else { 3135 const exportedSymbol = exports ? find(symbolsToArray(exports), symbol => !!getSymbolIfSameReference(symbol, localSymbol)) : undefined; 3136 const diagnostic = exportedSymbol ? error(name, Diagnostics.Module_0_declares_1_locally_but_it_is_exported_as_2, moduleName, declarationName, symbolToString(exportedSymbol)) : 3137 error(name, Diagnostics.Module_0_declares_1_locally_but_it_is_not_exported, moduleName, declarationName); 3138 if (localSymbol.declarations) { 3139 addRelatedInfo(diagnostic, 3140 ...map(localSymbol.declarations, (decl, index) => 3141 createDiagnosticForNode(decl, index === 0 ? Diagnostics._0_is_declared_here : Diagnostics.and_here, declarationName))); 3142 } 3143 } 3144 } 3145 else { 3146 error(name, Diagnostics.Module_0_has_no_exported_member_1, moduleName, declarationName); 3147 } 3148 } 3149 3150 function reportInvalidImportEqualsExportMember(node: Node, name: Identifier, declarationName: string, moduleName: string) { 3151 if (moduleKind >= ModuleKind.ES2015) { 3152 const message = getESModuleInterop(compilerOptions) ? Diagnostics._0_can_only_be_imported_by_using_a_default_import : 3153 Diagnostics._0_can_only_be_imported_by_turning_on_the_esModuleInterop_flag_and_using_a_default_import; 3154 error(name, message, declarationName); 3155 } 3156 else { 3157 if (isInJSFile(node)) { 3158 const message = getESModuleInterop(compilerOptions) ? Diagnostics._0_can_only_be_imported_by_using_a_require_call_or_by_using_a_default_import : 3159 Diagnostics._0_can_only_be_imported_by_using_a_require_call_or_by_turning_on_the_esModuleInterop_flag_and_using_a_default_import; 3160 error(name, message, declarationName); 3161 } 3162 else { 3163 const message = getESModuleInterop(compilerOptions) ? Diagnostics._0_can_only_be_imported_by_using_import_1_require_2_or_a_default_import : 3164 Diagnostics._0_can_only_be_imported_by_using_import_1_require_2_or_by_turning_on_the_esModuleInterop_flag_and_using_a_default_import; 3165 error(name, message, declarationName, declarationName, moduleName); 3166 } 3167 } 3168 } 3169 3170 function getTargetOfImportSpecifier(node: ImportSpecifier | BindingElement, dontResolveAlias: boolean): Symbol | undefined { 3171 if (isImportSpecifier(node) && idText(node.propertyName || node.name) === InternalSymbolName.Default) { 3172 const specifier = getModuleSpecifierForImportOrExport(node); 3173 const moduleSymbol = specifier && resolveExternalModuleName(node, specifier); 3174 if (moduleSymbol) { 3175 return getTargetofModuleDefault(moduleSymbol, node, dontResolveAlias); 3176 } 3177 } 3178 const root = isBindingElement(node) ? getRootDeclaration(node) as VariableDeclaration : node.parent.parent.parent; 3179 const commonJSPropertyAccess = getCommonJSPropertyAccess(root); 3180 const resolved = getExternalModuleMember(root, commonJSPropertyAccess || node, dontResolveAlias); 3181 const name = node.propertyName || node.name; 3182 if (commonJSPropertyAccess && resolved && isIdentifier(name)) { 3183 return resolveSymbol(getPropertyOfType(getTypeOfSymbol(resolved), name.escapedText), dontResolveAlias); 3184 } 3185 markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false); 3186 return resolved; 3187 } 3188 3189 function getCommonJSPropertyAccess(node: Node) { 3190 if (isVariableDeclaration(node) && node.initializer && isPropertyAccessExpression(node.initializer)) { 3191 return node.initializer; 3192 } 3193 } 3194 3195 function getTargetOfNamespaceExportDeclaration(node: NamespaceExportDeclaration, dontResolveAlias: boolean): Symbol { 3196 const resolved = resolveExternalModuleSymbol(node.parent.symbol, dontResolveAlias); 3197 markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false); 3198 return resolved; 3199 } 3200 3201 function getTargetOfExportSpecifier(node: ExportSpecifier, meaning: SymbolFlags, dontResolveAlias?: boolean) { 3202 if (idText(node.propertyName || node.name) === InternalSymbolName.Default) { 3203 const specifier = getModuleSpecifierForImportOrExport(node); 3204 const moduleSymbol = specifier && resolveExternalModuleName(node, specifier); 3205 if (moduleSymbol) { 3206 return getTargetofModuleDefault(moduleSymbol, node, !!dontResolveAlias); 3207 } 3208 } 3209 const resolved = node.parent.parent.moduleSpecifier ? 3210 getExternalModuleMember(node.parent.parent, node, dontResolveAlias) : 3211 resolveEntityName(node.propertyName || node.name, meaning, /*ignoreErrors*/ false, dontResolveAlias); 3212 markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false); 3213 return resolved; 3214 } 3215 3216 function getTargetOfExportAssignment(node: ExportAssignment | BinaryExpression, dontResolveAlias: boolean): Symbol | undefined { 3217 const expression = isExportAssignment(node) ? node.expression : node.right; 3218 const resolved = getTargetOfAliasLikeExpression(expression, dontResolveAlias); 3219 markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false); 3220 return resolved; 3221 } 3222 3223 function getTargetOfAliasLikeExpression(expression: Expression, dontResolveAlias: boolean) { 3224 if (isClassExpression(expression)) { 3225 return checkExpressionCached(expression).symbol; 3226 } 3227 if (!isEntityName(expression) && !isEntityNameExpression(expression)) { 3228 return undefined; 3229 } 3230 const aliasLike = resolveEntityName(expression, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, /*ignoreErrors*/ true, dontResolveAlias); 3231 if (aliasLike) { 3232 return aliasLike; 3233 } 3234 checkExpressionCached(expression); 3235 return getNodeLinks(expression).resolvedSymbol; 3236 } 3237 3238 function getTargetOfAccessExpression(node: AccessExpression, dontRecursivelyResolve: boolean): Symbol | undefined { 3239 if (!(isBinaryExpression(node.parent) && node.parent.left === node && node.parent.operatorToken.kind === SyntaxKind.EqualsToken)) { 3240 return undefined; 3241 } 3242 3243 return getTargetOfAliasLikeExpression(node.parent.right, dontRecursivelyResolve); 3244 } 3245 3246 function getTargetOfAliasDeclaration(node: Declaration, dontRecursivelyResolve = false): Symbol | undefined { 3247 switch (node.kind) { 3248 case SyntaxKind.ImportEqualsDeclaration: 3249 case SyntaxKind.VariableDeclaration: 3250 return getTargetOfImportEqualsDeclaration(node as ImportEqualsDeclaration | VariableDeclaration, dontRecursivelyResolve); 3251 case SyntaxKind.ImportClause: 3252 return getTargetOfImportClause(node as ImportClause, dontRecursivelyResolve); 3253 case SyntaxKind.NamespaceImport: 3254 return getTargetOfNamespaceImport(node as NamespaceImport, dontRecursivelyResolve); 3255 case SyntaxKind.NamespaceExport: 3256 return getTargetOfNamespaceExport(node as NamespaceExport, dontRecursivelyResolve); 3257 case SyntaxKind.ImportSpecifier: 3258 case SyntaxKind.BindingElement: 3259 return getTargetOfImportSpecifier(node as ImportSpecifier | BindingElement, dontRecursivelyResolve); 3260 case SyntaxKind.ExportSpecifier: 3261 return getTargetOfExportSpecifier(node as ExportSpecifier, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, dontRecursivelyResolve); 3262 case SyntaxKind.ExportAssignment: 3263 case SyntaxKind.BinaryExpression: 3264 return getTargetOfExportAssignment((node as ExportAssignment | BinaryExpression), dontRecursivelyResolve); 3265 case SyntaxKind.NamespaceExportDeclaration: 3266 return getTargetOfNamespaceExportDeclaration(node as NamespaceExportDeclaration, dontRecursivelyResolve); 3267 case SyntaxKind.ShorthandPropertyAssignment: 3268 return resolveEntityName((node as ShorthandPropertyAssignment).name, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, /*ignoreErrors*/ true, dontRecursivelyResolve); 3269 case SyntaxKind.PropertyAssignment: 3270 return getTargetOfAliasLikeExpression((node as PropertyAssignment).initializer, dontRecursivelyResolve); 3271 case SyntaxKind.ElementAccessExpression: 3272 case SyntaxKind.PropertyAccessExpression: 3273 return getTargetOfAccessExpression(node as AccessExpression, dontRecursivelyResolve); 3274 default: 3275 return Debug.fail(); 3276 } 3277 } 3278 3279 /** 3280 * Indicates that a symbol is an alias that does not merge with a local declaration. 3281 * OR Is a JSContainer which may merge an alias with a local declaration 3282 */ 3283 function isNonLocalAlias(symbol: Symbol | undefined, excludes = SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace): symbol is Symbol { 3284 if (!symbol) return false; 3285 return (symbol.flags & (SymbolFlags.Alias | excludes)) === SymbolFlags.Alias || !!(symbol.flags & SymbolFlags.Alias && symbol.flags & SymbolFlags.Assignment); 3286 } 3287 3288 function resolveSymbol(symbol: Symbol, dontResolveAlias?: boolean): Symbol; 3289 function resolveSymbol(symbol: Symbol | undefined, dontResolveAlias?: boolean): Symbol | undefined; 3290 function resolveSymbol(symbol: Symbol | undefined, dontResolveAlias?: boolean): Symbol | undefined { 3291 return !dontResolveAlias && isNonLocalAlias(symbol) ? resolveAlias(symbol) : symbol; 3292 } 3293 3294 function resolveAlias(symbol: Symbol): Symbol { 3295 Debug.assert((symbol.flags & SymbolFlags.Alias) !== 0, "Should only get Alias here."); 3296 const links = getSymbolLinks(symbol); 3297 if (!links.aliasTarget) { 3298 links.aliasTarget = resolvingSymbol; 3299 const node = getDeclarationOfAliasSymbol(symbol); 3300 if (!node) return Debug.fail(); 3301 const target = getTargetOfAliasDeclaration(node); 3302 if (links.aliasTarget === resolvingSymbol) { 3303 links.aliasTarget = target || unknownSymbol; 3304 } 3305 else { 3306 error(node, Diagnostics.Circular_definition_of_import_alias_0, symbolToString(symbol)); 3307 } 3308 } 3309 else if (links.aliasTarget === resolvingSymbol) { 3310 links.aliasTarget = unknownSymbol; 3311 } 3312 return links.aliasTarget; 3313 } 3314 3315 function tryResolveAlias(symbol: Symbol): Symbol | undefined { 3316 const links = getSymbolLinks(symbol); 3317 if (links.aliasTarget !== resolvingSymbol) { 3318 return resolveAlias(symbol); 3319 } 3320 3321 return undefined; 3322 } 3323 3324 /** 3325 * Gets combined flags of a `symbol` and all alias targets it resolves to. `resolveAlias` 3326 * is typically recursive over chains of aliases, but stops mid-chain if an alias is merged 3327 * with another exported symbol, e.g. 3328 * ```ts 3329 * // a.ts 3330 * export const a = 0; 3331 * // b.ts 3332 * export { a } from "./a"; 3333 * export type a = number; 3334 * // c.ts 3335 * import { a } from "./b"; 3336 * ``` 3337 * Calling `resolveAlias` on the `a` in c.ts would stop at the merged symbol exported 3338 * from b.ts, even though there is still more alias to resolve. Consequently, if we were 3339 * trying to determine if the `a` in c.ts has a value meaning, looking at the flags on 3340 * the local symbol and on the symbol returned by `resolveAlias` is not enough. 3341 * @returns SymbolFlags.All if `symbol` is an alias that ultimately resolves to `unknown`; 3342 * combined flags of all alias targets otherwise. 3343 */ 3344 function getAllSymbolFlags(symbol: Symbol): SymbolFlags { 3345 let flags = symbol.flags; 3346 let seenSymbols; 3347 while (symbol.flags & SymbolFlags.Alias) { 3348 const target = resolveAlias(symbol); 3349 if (target === unknownSymbol) { 3350 return SymbolFlags.All; 3351 } 3352 3353 // Optimizations - try to avoid creating or adding to 3354 // `seenSymbols` if possible 3355 if (target === symbol || seenSymbols?.has(target)) { 3356 break; 3357 } 3358 if (target.flags & SymbolFlags.Alias) { 3359 if (seenSymbols) { 3360 seenSymbols.add(target); 3361 } 3362 else { 3363 seenSymbols = new Set([symbol, target]); 3364 } 3365 } 3366 flags |= target.flags; 3367 symbol = target; 3368 } 3369 return flags; 3370 } 3371 3372 /** 3373 * Marks a symbol as type-only if its declaration is syntactically type-only. 3374 * If it is not itself marked type-only, but resolves to a type-only alias 3375 * somewhere in its resolution chain, save a reference to the type-only alias declaration 3376 * so the alias _not_ marked type-only can be identified as _transitively_ type-only. 3377 * 3378 * This function is called on each alias declaration that could be type-only or resolve to 3379 * another type-only alias during `resolveAlias`, so that later, when an alias is used in a 3380 * JS-emitting expression, we can quickly determine if that symbol is effectively type-only 3381 * and issue an error if so. 3382 * 3383 * @param aliasDeclaration The alias declaration not marked as type-only 3384 * @param immediateTarget The symbol to which the alias declaration immediately resolves 3385 * @param finalTarget The symbol to which the alias declaration ultimately resolves 3386 * @param overwriteEmpty Checks `resolvesToSymbol` for type-only declarations even if `aliasDeclaration` 3387 * has already been marked as not resolving to a type-only alias. Used when recursively resolving qualified 3388 * names of import aliases, e.g. `import C = a.b.C`. If namespace `a` is not found to be type-only, the 3389 * import declaration will initially be marked as not resolving to a type-only symbol. But, namespace `b` 3390 * must still be checked for a type-only marker, overwriting the previous negative result if found. 3391 */ 3392 function markSymbolOfAliasDeclarationIfTypeOnly( 3393 aliasDeclaration: Declaration | undefined, 3394 immediateTarget: Symbol | undefined, 3395 finalTarget: Symbol | undefined, 3396 overwriteEmpty: boolean, 3397 ): boolean { 3398 if (!aliasDeclaration || isPropertyAccessExpression(aliasDeclaration)) return false; 3399 3400 // If the declaration itself is type-only, mark it and return. 3401 // No need to check what it resolves to. 3402 const sourceSymbol = getSymbolOfNode(aliasDeclaration); 3403 if (isTypeOnlyImportOrExportDeclaration(aliasDeclaration)) { 3404 const links = getSymbolLinks(sourceSymbol); 3405 links.typeOnlyDeclaration = aliasDeclaration; 3406 return true; 3407 } 3408 3409 const links = getSymbolLinks(sourceSymbol); 3410 return markSymbolOfAliasDeclarationIfTypeOnlyWorker(links, immediateTarget, overwriteEmpty) 3411 || markSymbolOfAliasDeclarationIfTypeOnlyWorker(links, finalTarget, overwriteEmpty); 3412 } 3413 3414 function markSymbolOfAliasDeclarationIfTypeOnlyWorker(aliasDeclarationLinks: SymbolLinks, target: Symbol | undefined, overwriteEmpty: boolean): boolean { 3415 if (target && (aliasDeclarationLinks.typeOnlyDeclaration === undefined || overwriteEmpty && aliasDeclarationLinks.typeOnlyDeclaration === false)) { 3416 const exportSymbol = target.exports?.get(InternalSymbolName.ExportEquals) ?? target; 3417 const typeOnly = exportSymbol.declarations && find(exportSymbol.declarations, isTypeOnlyImportOrExportDeclaration); 3418 aliasDeclarationLinks.typeOnlyDeclaration = typeOnly ?? getSymbolLinks(exportSymbol).typeOnlyDeclaration ?? false; 3419 } 3420 return !!aliasDeclarationLinks.typeOnlyDeclaration; 3421 } 3422 3423 /** Indicates that a symbol directly or indirectly resolves to a type-only import or export. */ 3424 function getTypeOnlyAliasDeclaration(symbol: Symbol, include?: SymbolFlags): TypeOnlyAliasDeclaration | undefined { 3425 if (!(symbol.flags & SymbolFlags.Alias)) { 3426 return undefined; 3427 } 3428 const links = getSymbolLinks(symbol); 3429 if (include === undefined) { 3430 return links.typeOnlyDeclaration || undefined; 3431 } 3432 if (links.typeOnlyDeclaration) { 3433 return getAllSymbolFlags(resolveAlias(links.typeOnlyDeclaration.symbol)) & include ? links.typeOnlyDeclaration : undefined; 3434 } 3435 return undefined; 3436 } 3437 3438 function markExportAsReferenced(node: ImportEqualsDeclaration | ExportSpecifier) { 3439 const symbol = getSymbolOfNode(node); 3440 const target = resolveAlias(symbol); 3441 if (target) { 3442 const markAlias = target === unknownSymbol || 3443 ((getAllSymbolFlags(target) & SymbolFlags.Value) && !isConstEnumOrConstEnumOnlyModule(target) && !getTypeOnlyAliasDeclaration(symbol, SymbolFlags.Value)); 3444 3445 if (markAlias) { 3446 markAliasSymbolAsReferenced(symbol); 3447 } 3448 } 3449 } 3450 3451 // When an alias symbol is referenced, we need to mark the entity it references as referenced and in turn repeat that until 3452 // we reach a non-alias or an exported entity (which is always considered referenced). We do this by checking the target of 3453 // the alias as an expression (which recursively takes us back here if the target references another alias). 3454 function markAliasSymbolAsReferenced(symbol: Symbol) { 3455 const links = getSymbolLinks(symbol); 3456 if (!links.referenced) { 3457 links.referenced = true; 3458 const node = getDeclarationOfAliasSymbol(symbol); 3459 if (!node) return Debug.fail(); 3460 // We defer checking of the reference of an `import =` until the import itself is referenced, 3461 // This way a chain of imports can be elided if ultimately the final input is only used in a type 3462 // position. 3463 if (isInternalModuleImportEqualsDeclaration(node)) { 3464 if (getAllSymbolFlags(resolveSymbol(symbol)) & SymbolFlags.Value) { 3465 // import foo = <symbol> 3466 checkExpressionCached(node.moduleReference as Expression); 3467 } 3468 } 3469 } 3470 } 3471 3472 // Aliases that resolve to const enums are not marked as referenced because they are not emitted, 3473 // but their usage in value positions must be tracked to determine if the import can be type-only. 3474 function markConstEnumAliasAsReferenced(symbol: Symbol) { 3475 const links = getSymbolLinks(symbol); 3476 if (!links.constEnumReferenced) { 3477 links.constEnumReferenced = true; 3478 } 3479 } 3480 3481 // This function is only for imports with entity names 3482 function getSymbolOfPartOfRightHandSideOfImportEquals(entityName: EntityName, dontResolveAlias?: boolean): Symbol | undefined { 3483 // There are three things we might try to look for. In the following examples, 3484 // the search term is enclosed in |...|: 3485 // 3486 // import a = |b|; // Namespace 3487 // import a = |b.c|; // Value, type, namespace 3488 // import a = |b.c|.d; // Namespace 3489 if (entityName.kind === SyntaxKind.Identifier && isRightSideOfQualifiedNameOrPropertyAccess(entityName)) { 3490 entityName = entityName.parent as QualifiedName; 3491 } 3492 // Check for case 1 and 3 in the above example 3493 if (entityName.kind === SyntaxKind.Identifier || entityName.parent.kind === SyntaxKind.QualifiedName) { 3494 return resolveEntityName(entityName, SymbolFlags.Namespace, /*ignoreErrors*/ false, dontResolveAlias); 3495 } 3496 else { 3497 // Case 2 in above example 3498 // entityName.kind could be a QualifiedName or a Missing identifier 3499 Debug.assert(entityName.parent.kind === SyntaxKind.ImportEqualsDeclaration); 3500 return resolveEntityName(entityName, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, /*ignoreErrors*/ false, dontResolveAlias); 3501 } 3502 } 3503 3504 function getFullyQualifiedName(symbol: Symbol, containingLocation?: Node): string { 3505 return symbol.parent ? getFullyQualifiedName(symbol.parent, containingLocation) + "." + symbolToString(symbol) : symbolToString(symbol, containingLocation, /*meaning*/ undefined, SymbolFormatFlags.DoNotIncludeSymbolChain | SymbolFormatFlags.AllowAnyNodeKind); 3506 } 3507 3508 function getContainingQualifiedNameNode(node: QualifiedName) { 3509 while (isQualifiedName(node.parent)) { 3510 node = node.parent; 3511 } 3512 return node; 3513 } 3514 3515 function tryGetQualifiedNameAsValue(node: QualifiedName) { 3516 let left: Identifier | QualifiedName = getFirstIdentifier(node); 3517 let symbol = resolveName(left, left.escapedText, SymbolFlags.Value, undefined, left, /*isUse*/ true); 3518 if (!symbol) { 3519 return undefined; 3520 } 3521 while (isQualifiedName(left.parent)) { 3522 const type = getTypeOfSymbol(symbol); 3523 symbol = getPropertyOfType(type, left.parent.right.escapedText); 3524 if (!symbol) { 3525 return undefined; 3526 } 3527 left = left.parent; 3528 } 3529 return symbol; 3530 } 3531 3532 /** 3533 * Resolves a qualified name and any involved aliases. 3534 */ 3535 function resolveEntityName(name: EntityNameOrEntityNameExpression, meaning: SymbolFlags, ignoreErrors?: boolean, dontResolveAlias?: boolean, location?: Node): Symbol | undefined { 3536 if (nodeIsMissing(name)) { 3537 return undefined; 3538 } 3539 3540 const namespaceMeaning = SymbolFlags.Namespace | (isInJSFile(name) ? meaning & SymbolFlags.Value : 0); 3541 let symbol: Symbol | undefined; 3542 if (name.kind === SyntaxKind.Identifier) { 3543 const message = meaning === namespaceMeaning || nodeIsSynthesized(name) ? Diagnostics.Cannot_find_namespace_0 : getCannotFindNameDiagnosticForName(getFirstIdentifier(name)); 3544 const symbolFromJSPrototype = isInJSFile(name) && !nodeIsSynthesized(name) ? resolveEntityNameFromAssignmentDeclaration(name, meaning) : undefined; 3545 symbol = getMergedSymbol(resolveName(location || name, name.escapedText, meaning, ignoreErrors || symbolFromJSPrototype ? undefined : message, name, /*isUse*/ true, false)); 3546 if (!symbol) { 3547 return getMergedSymbol(symbolFromJSPrototype); 3548 } 3549 } 3550 else if (name.kind === SyntaxKind.QualifiedName || name.kind === SyntaxKind.PropertyAccessExpression) { 3551 const left = name.kind === SyntaxKind.QualifiedName ? name.left : name.expression; 3552 const right = name.kind === SyntaxKind.QualifiedName ? name.right : name.name; 3553 let namespace = resolveEntityName(left, namespaceMeaning, ignoreErrors, /*dontResolveAlias*/ false, location); 3554 if (!namespace || nodeIsMissing(right)) { 3555 return undefined; 3556 } 3557 else if (namespace === unknownSymbol) { 3558 return namespace; 3559 } 3560 if ( 3561 namespace.valueDeclaration && 3562 isInJSFile(namespace.valueDeclaration) && 3563 isVariableDeclaration(namespace.valueDeclaration) && 3564 namespace.valueDeclaration.initializer && 3565 isCommonJsRequire(namespace.valueDeclaration.initializer) 3566 ) { 3567 const moduleName = (namespace.valueDeclaration.initializer as CallExpression).arguments[0] as StringLiteral; 3568 const moduleSym = resolveExternalModuleName(moduleName, moduleName); 3569 if (moduleSym) { 3570 const resolvedModuleSymbol = resolveExternalModuleSymbol(moduleSym); 3571 if (resolvedModuleSymbol) { 3572 namespace = resolvedModuleSymbol; 3573 } 3574 } 3575 } 3576 symbol = getMergedSymbol(getSymbol(getExportsOfSymbol(namespace), right.escapedText, meaning)); 3577 if (!symbol) { 3578 if (!ignoreErrors) { 3579 const namespaceName = getFullyQualifiedName(namespace); 3580 const declarationName = declarationNameToString(right); 3581 const suggestionForNonexistentModule = getSuggestedSymbolForNonexistentModule(right, namespace); 3582 if (suggestionForNonexistentModule) { 3583 error(right, Diagnostics._0_has_no_exported_member_named_1_Did_you_mean_2, namespaceName, declarationName, symbolToString(suggestionForNonexistentModule)); 3584 return undefined; 3585 } 3586 3587 const containingQualifiedName = isQualifiedName(name) && getContainingQualifiedNameNode(name); 3588 const canSuggestTypeof = globalObjectType // <-- can't pull on types if global types aren't initialized yet 3589 && (meaning & SymbolFlags.Type) 3590 && containingQualifiedName 3591 && !isTypeOfExpression(containingQualifiedName.parent) 3592 && tryGetQualifiedNameAsValue(containingQualifiedName); 3593 if (canSuggestTypeof) { 3594 error( 3595 containingQualifiedName, 3596 Diagnostics._0_refers_to_a_value_but_is_being_used_as_a_type_here_Did_you_mean_typeof_0, 3597 entityNameToString(containingQualifiedName) 3598 ); 3599 return undefined; 3600 } 3601 3602 if (meaning & SymbolFlags.Namespace && isQualifiedName(name.parent)) { 3603 const exportedTypeSymbol = getMergedSymbol(getSymbol(getExportsOfSymbol(namespace), right.escapedText, SymbolFlags.Type)); 3604 if (exportedTypeSymbol) { 3605 error( 3606 name.parent.right, 3607 Diagnostics.Cannot_access_0_1_because_0_is_a_type_but_not_a_namespace_Did_you_mean_to_retrieve_the_type_of_the_property_1_in_0_with_0_1, 3608 symbolToString(exportedTypeSymbol), 3609 unescapeLeadingUnderscores(name.parent.right.escapedText) 3610 ); 3611 return undefined; 3612 } 3613 } 3614 3615 error(right, Diagnostics.Namespace_0_has_no_exported_member_1, namespaceName, declarationName); 3616 } 3617 return undefined; 3618 } 3619 } 3620 else { 3621 throw Debug.assertNever(name, "Unknown entity name kind."); 3622 } 3623 Debug.assert((getCheckFlags(symbol) & CheckFlags.Instantiated) === 0, "Should never get an instantiated symbol here."); 3624 if (!nodeIsSynthesized(name) && isEntityName(name) && (symbol.flags & SymbolFlags.Alias || name.parent.kind === SyntaxKind.ExportAssignment)) { 3625 markSymbolOfAliasDeclarationIfTypeOnly(getAliasDeclarationFromName(name), symbol, /*finalTarget*/ undefined, /*overwriteEmpty*/ true); 3626 } 3627 return (symbol.flags & meaning) || dontResolveAlias ? symbol : resolveAlias(symbol); 3628 } 3629 3630 /** 3631 * 1. For prototype-property methods like `A.prototype.m = function () ...`, try to resolve names in the scope of `A` too. 3632 * Note that prototype-property assignment to locations outside the current file (eg globals) doesn't work, so 3633 * name resolution won't work either. 3634 * 2. For property assignments like `{ x: function f () { } }`, try to resolve names in the scope of `f` too. 3635 */ 3636 function resolveEntityNameFromAssignmentDeclaration(name: Identifier, meaning: SymbolFlags) { 3637 if (isJSDocTypeReference(name.parent)) { 3638 const secondaryLocation = getAssignmentDeclarationLocation(name.parent); 3639 if (secondaryLocation) { 3640 return resolveName(secondaryLocation, name.escapedText, meaning, /*nameNotFoundMessage*/ undefined, name, /*isUse*/ true); 3641 } 3642 } 3643 } 3644 3645 function getAssignmentDeclarationLocation(node: TypeReferenceNode): Node | undefined { 3646 const typeAlias = findAncestor(node, node => !(isJSDocNode(node) || node.flags & NodeFlags.JSDoc) ? "quit" : isJSDocTypeAlias(node)); 3647 if (typeAlias) { 3648 return; 3649 } 3650 const host = getJSDocHost(node); 3651 if (host && isExpressionStatement(host) && isPrototypePropertyAssignment(host.expression)) { 3652 // /** @param {K} p */ X.prototype.m = function () { } <-- look for K on X's declaration 3653 const symbol = getSymbolOfNode(host.expression.left); 3654 if (symbol) { 3655 return getDeclarationOfJSPrototypeContainer(symbol); 3656 } 3657 } 3658 if (host && isFunctionExpression(host) && isPrototypePropertyAssignment(host.parent) && isExpressionStatement(host.parent.parent)) { 3659 // X.prototype.m = /** @param {K} p */ function () { } <-- look for K on X's declaration 3660 const symbol = getSymbolOfNode(host.parent.left); 3661 if (symbol) { 3662 return getDeclarationOfJSPrototypeContainer(symbol); 3663 } 3664 } 3665 if (host && (isObjectLiteralMethod(host) || isPropertyAssignment(host)) && 3666 isBinaryExpression(host.parent.parent) && 3667 getAssignmentDeclarationKind(host.parent.parent) === AssignmentDeclarationKind.Prototype) { 3668 // X.prototype = { /** @param {K} p */m() { } } <-- look for K on X's declaration 3669 const symbol = getSymbolOfNode(host.parent.parent.left); 3670 if (symbol) { 3671 return getDeclarationOfJSPrototypeContainer(symbol); 3672 } 3673 } 3674 const sig = getEffectiveJSDocHost(node); 3675 if (sig && isFunctionLike(sig)) { 3676 const symbol = getSymbolOfNode(sig); 3677 return symbol && symbol.valueDeclaration; 3678 } 3679 } 3680 3681 function getDeclarationOfJSPrototypeContainer(symbol: Symbol) { 3682 const decl = symbol.parent!.valueDeclaration; 3683 if (!decl) { 3684 return undefined; 3685 } 3686 const initializer = isAssignmentDeclaration(decl) ? getAssignedExpandoInitializer(decl) : 3687 hasOnlyExpressionInitializer(decl) ? getDeclaredExpandoInitializer(decl) : 3688 undefined; 3689 return initializer || decl; 3690 } 3691 3692 /** 3693 * Get the real symbol of a declaration with an expando initializer. 3694 * 3695 * Normally, declarations have an associated symbol, but when a declaration has an expando 3696 * initializer, the expando's symbol is the one that has all the members merged into it. 3697 */ 3698 function getExpandoSymbol(symbol: Symbol): Symbol | undefined { 3699 const decl = symbol.valueDeclaration; 3700 if (!decl || !isInJSFile(decl) || symbol.flags & SymbolFlags.TypeAlias || getExpandoInitializer(decl, /*isPrototypeAssignment*/ false)) { 3701 return undefined; 3702 } 3703 const init = isVariableDeclaration(decl) ? getDeclaredExpandoInitializer(decl) : getAssignedExpandoInitializer(decl); 3704 if (init) { 3705 const initSymbol = getSymbolOfNode(init); 3706 if (initSymbol) { 3707 return mergeJSSymbols(initSymbol, symbol); 3708 } 3709 } 3710 } 3711 3712 function resolveExternalModuleName(location: Node, moduleReferenceExpression: Expression, ignoreErrors?: boolean): Symbol | undefined { 3713 const isClassic = getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Classic; 3714 const errorMessage = isClassic? 3715 Diagnostics.Cannot_find_module_0_Did_you_mean_to_set_the_moduleResolution_option_to_node_or_to_add_aliases_to_the_paths_option 3716 : Diagnostics.Cannot_find_module_0_or_its_corresponding_type_declarations; 3717 return resolveExternalModuleNameWorker(location, moduleReferenceExpression, ignoreErrors ? undefined : errorMessage); 3718 } 3719 3720 function resolveExternalModuleNameWorker(location: Node, moduleReferenceExpression: Expression, moduleNotFoundError: DiagnosticMessage | undefined, isForAugmentation = false): Symbol | undefined { 3721 return isStringLiteralLike(moduleReferenceExpression) 3722 ? resolveExternalModule(location, moduleReferenceExpression.text, moduleNotFoundError, moduleReferenceExpression, isForAugmentation) 3723 : undefined; 3724 } 3725 3726 function resolveExternalModule(location: Node, moduleReference: string, moduleNotFoundError: DiagnosticMessage | undefined, errorNode: Node, isForAugmentation = false): Symbol | undefined { 3727 if (startsWith(moduleReference, "@types/")) { 3728 const diag = Diagnostics.Cannot_import_type_declaration_files_Consider_importing_0_instead_of_1; 3729 const withoutAtTypePrefix = removePrefix(moduleReference, "@types/"); 3730 error(errorNode, diag, withoutAtTypePrefix, moduleReference); 3731 } 3732 3733 const isSoFile = (moduleReference.lastIndexOf(".so") !== -1); 3734 3735 if (isSoFile && !(isInETSFile(location) && compilerOptions.needDoArkTsLinter && !compilerOptions.isCompatibleVersion)) { 3736 const diagnostic = createDiagnosticForNode(errorNode, Diagnostics.Currently_module_for_0_is_not_verified_If_you_re_importing_napi_its_verification_will_be_enabled_in_later_SDK_version_Please_make_sure_the_corresponding_d_ts_file_is_provided_and_the_napis_are_correctly_declared, moduleReference); 3737 diagnostics.add(diagnostic); 3738 return undefined; 3739 } 3740 3741 const ambientModule = tryFindAmbientModule(moduleReference, /*withAugmentations*/ true); 3742 if (ambientModule) { 3743 return ambientModule; 3744 } 3745 const currentSourceFile = getSourceFileOfNode(location); 3746 const contextSpecifier = isStringLiteralLike(location) 3747 ? location 3748 : findAncestor(location, isImportCall)?.arguments[0] || 3749 findAncestor(location, isImportDeclaration)?.moduleSpecifier || 3750 findAncestor(location, isExternalModuleImportEqualsDeclaration)?.moduleReference.expression || 3751 findAncestor(location, isExportDeclaration)?.moduleSpecifier || 3752 (isModuleDeclaration(location) ? location : location.parent && isModuleDeclaration(location.parent) && location.parent.name === location ? location.parent : undefined)?.name || 3753 (isLiteralImportTypeNode(location) ? location : undefined)?.argument.literal; 3754 const mode = contextSpecifier && isStringLiteralLike(contextSpecifier) ? getModeForUsageLocation(currentSourceFile, contextSpecifier) : currentSourceFile.impliedNodeFormat; 3755 const resolvedModule = getResolvedModule(currentSourceFile, moduleReference, mode); 3756 // the relative path of sdk 3757 const sdkPath = compilerOptions.etsLoaderPath ? resolvePath(compilerOptions.etsLoaderPath, '../..') : undefined; 3758 if (compilerOptions.needDoArkTsLinter && 3759 currentSourceFile && currentSourceFile.scriptKind === ScriptKind.TS && 3760 resolvedModule && (resolvedModule.extension === ".ets" || resolvedModule.extension === ".d.ets")) { 3761 const diagnosticType = compilerOptions.isCompatibleVersion ? 3762 Diagnostics.Importing_ArkTS_files_in_JS_and_TS_files_is_about_to_be_forbidden : 3763 Diagnostics.Importing_ArkTS_files_in_JS_and_TS_files_is_forbidden; 3764 if (contextSpecifier && 3765 !isImportDeclaration(contextSpecifier.parent) && 3766 !isExportDeclaration(contextSpecifier.parent) || 3767 !allowImportSendable(sdkPath, currentSourceFile)) { 3768 // If the node is ImportCall throw error 3769 // If currentSourceFile is not allowImportSendable (.d.ts inside sdk or .ts file when tsImportSendable is true) 3770 error(errorNode, diagnosticType, moduleReference); 3771 } 3772 } 3773 3774 const resolutionDiagnostic = resolvedModule && getResolutionDiagnostic(compilerOptions, resolvedModule); 3775 const sourceFile = resolvedModule 3776 && (!resolutionDiagnostic || resolutionDiagnostic === Diagnostics.Module_0_was_resolved_to_1_but_jsx_is_not_set) 3777 // For ets/ts files, in non linter check, skip resolving symbols from js files 3778 && (!compilerOptions.needDoArkTsLinter || isTypeCheckerForLinter || !hasJSFileExtension(resolvedModule.resolvedFileName)) 3779 && host.getSourceFile(resolvedModule.resolvedFileName); 3780 if (sourceFile) { 3781 // If there's a resolutionDiagnostic we need to report it even if a sourceFile is found. 3782 if (resolutionDiagnostic) { 3783 error(errorNode, resolutionDiagnostic, moduleReference, resolvedModule.resolvedFileName); 3784 } 3785 if (sourceFile.symbol) { 3786 if (resolvedModule.isExternalLibraryImport && !resolutionExtensionIsTSOrJson(resolvedModule.extension)) { 3787 errorOnImplicitAnyModule(/*isError*/ false, errorNode, resolvedModule, moduleReference); 3788 } 3789 if (getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Node16 || getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeNext) { 3790 const isSyncImport = (currentSourceFile.impliedNodeFormat === ModuleKind.CommonJS && !findAncestor(location, isImportCall)) || !!findAncestor(location, isImportEqualsDeclaration); 3791 const overrideClauseHost = findAncestor(location, l => isImportTypeNode(l) || isExportDeclaration(l) || isImportDeclaration(l)) as ImportTypeNode | ImportDeclaration | ExportDeclaration | undefined; 3792 const overrideClause = overrideClauseHost && isImportTypeNode(overrideClauseHost) ? overrideClauseHost.assertions?.assertClause : overrideClauseHost?.assertClause; 3793 // An override clause will take effect for type-only imports and import types, and allows importing the types across formats, regardless of 3794 // normal mode restrictions 3795 if (isSyncImport && sourceFile.impliedNodeFormat === ModuleKind.ESNext && !getResolutionModeOverrideForClause(overrideClause)) { 3796 if (findAncestor(location, isImportEqualsDeclaration)) { 3797 // ImportEquals in a ESM file resolving to another ESM file 3798 error(errorNode, Diagnostics.Module_0_cannot_be_imported_using_this_construct_The_specifier_only_resolves_to_an_ES_module_which_cannot_be_imported_with_require_Use_an_ECMAScript_import_instead, moduleReference); 3799 } 3800 else { 3801 // CJS file resolving to an ESM file 3802 let diagnosticDetails; 3803 const ext = tryGetExtensionFromPath(currentSourceFile.fileName); 3804 if (ext === Extension.Ts || ext === Extension.Js || ext === Extension.Tsx || ext === Extension.Jsx) { 3805 const scope = currentSourceFile.packageJsonScope; 3806 const targetExt = ext === Extension.Ts ? Extension.Mts : ext === Extension.Js ? Extension.Mjs : undefined; 3807 if (scope && !scope.contents.packageJsonContent.type) { 3808 if (targetExt) { 3809 diagnosticDetails = chainDiagnosticMessages( 3810 /*details*/ undefined, 3811 Diagnostics.To_convert_this_file_to_an_ECMAScript_module_change_its_file_extension_to_0_or_add_the_field_type_Colon_module_to_1, 3812 targetExt, 3813 combinePaths(scope.packageDirectory, getPackageJsonByPMType(compilerOptions.packageManagerType))); 3814 } 3815 else { 3816 diagnosticDetails = chainDiagnosticMessages( 3817 /*details*/ undefined, 3818 Diagnostics.To_convert_this_file_to_an_ECMAScript_module_add_the_field_type_Colon_module_to_0, 3819 combinePaths(scope.packageDirectory, getPackageJsonByPMType(compilerOptions.packageManagerType))); 3820 } 3821 } 3822 else { 3823 if (targetExt) { 3824 diagnosticDetails = chainDiagnosticMessages( 3825 /*details*/ undefined, 3826 Diagnostics.To_convert_this_file_to_an_ECMAScript_module_change_its_file_extension_to_0_or_create_a_local_package_json_file_with_type_Colon_module, 3827 targetExt); 3828 } 3829 else { 3830 diagnosticDetails = chainDiagnosticMessages( 3831 /*details*/ undefined, 3832 Diagnostics.To_convert_this_file_to_an_ECMAScript_module_create_a_local_package_json_file_with_type_Colon_module); 3833 } 3834 } 3835 } 3836 diagnostics.add(createDiagnosticForNodeFromMessageChain(errorNode, chainDiagnosticMessages( 3837 diagnosticDetails, 3838 Diagnostics.The_current_file_is_a_CommonJS_module_whose_imports_will_produce_require_calls_however_the_referenced_file_is_an_ECMAScript_module_and_cannot_be_imported_with_require_Consider_writing_a_dynamic_import_0_call_instead, 3839 moduleReference))); 3840 } 3841 } 3842 } 3843 // merged symbol is module declaration symbol combined with all augmentations 3844 return getMergedSymbol(sourceFile.symbol); 3845 } 3846 if (moduleNotFoundError) { 3847 // report errors only if it was requested 3848 error(errorNode, Diagnostics.File_0_is_not_a_module, sourceFile.fileName); 3849 } 3850 return undefined; 3851 } 3852 3853 if (patternAmbientModules) { 3854 const pattern = findBestPatternMatch(patternAmbientModules, _ => _.pattern, moduleReference); 3855 if (pattern) { 3856 // If the module reference matched a pattern ambient module ('*.foo') but there's also a 3857 // module augmentation by the specific name requested ('a.foo'), we store the merged symbol 3858 // by the augmentation name ('a.foo'), because asking for *.foo should not give you exports 3859 // from a.foo. 3860 const augmentation = patternAmbientModuleAugmentations && patternAmbientModuleAugmentations.get(moduleReference); 3861 if (augmentation) { 3862 return getMergedSymbol(augmentation); 3863 } 3864 return getMergedSymbol(pattern.symbol); 3865 } 3866 } 3867 3868 // May be an untyped module. If so, ignore resolutionDiagnostic. 3869 if (resolvedModule && !resolutionExtensionIsTSOrJson(resolvedModule.extension) && resolutionDiagnostic === undefined || resolutionDiagnostic === Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type) { 3870 if (isForAugmentation) { 3871 const diag = Diagnostics.Invalid_module_name_in_augmentation_Module_0_resolves_to_an_untyped_module_at_1_which_cannot_be_augmented; 3872 error(errorNode, diag, moduleReference, resolvedModule!.resolvedFileName); 3873 } 3874 else { 3875 errorOnImplicitAnyModule(/*isError*/ noImplicitAny && !!moduleNotFoundError, errorNode, resolvedModule!, moduleReference); 3876 } 3877 // Failed imports and untyped modules are both treated in an untyped manner; only difference is whether we give a diagnostic first. 3878 return undefined; 3879 } 3880 3881 if (moduleNotFoundError) { 3882 // See if this was possibly a projectReference redirect 3883 if (resolvedModule) { 3884 const redirect = host.getProjectReferenceRedirect(resolvedModule.resolvedFileName); 3885 if (redirect) { 3886 error(errorNode, Diagnostics.Output_file_0_has_not_been_built_from_source_file_1, redirect, resolvedModule.resolvedFileName); 3887 return undefined; 3888 } 3889 } 3890 3891 if (resolutionDiagnostic) { 3892 error(errorNode, resolutionDiagnostic, moduleReference, resolvedModule.resolvedFileName); 3893 } 3894 else { 3895 const tsExtension = tryExtractTSExtension(moduleReference); 3896 const isExtensionlessRelativePathImport = pathIsRelative(moduleReference) && !hasExtension(moduleReference); 3897 const moduleResolutionKind = getEmitModuleResolutionKind(compilerOptions); 3898 const resolutionIsNode16OrNext = moduleResolutionKind === ModuleResolutionKind.Node16 || 3899 moduleResolutionKind === ModuleResolutionKind.NodeNext; 3900 if (tsExtension) { 3901 const diag = Diagnostics.An_import_path_cannot_end_with_a_0_extension_Consider_importing_1_instead; 3902 const importSourceWithoutExtension = removeExtension(moduleReference, tsExtension); 3903 let replacedImportSource = importSourceWithoutExtension; 3904 /** 3905 * Direct users to import source with .js extension if outputting an ES module. 3906 * @see https://github.com/microsoft/TypeScript/issues/42151 3907 */ 3908 if (moduleKind >= ModuleKind.ES2015) { 3909 replacedImportSource += tsExtension === Extension.Mts ? ".mjs" : tsExtension === Extension.Cts ? ".cjs" : ".js"; 3910 } 3911 error(errorNode, diag, tsExtension, replacedImportSource); 3912 } 3913 else if (!compilerOptions.resolveJsonModule && 3914 fileExtensionIs(moduleReference, Extension.Json) && 3915 getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Classic && 3916 hasJsonModuleEmitEnabled(compilerOptions)) { 3917 error(errorNode, Diagnostics.Cannot_find_module_0_Consider_using_resolveJsonModule_to_import_module_with_json_extension, moduleReference); 3918 } 3919 else if (mode === ModuleKind.ESNext && resolutionIsNode16OrNext && isExtensionlessRelativePathImport) { 3920 const absoluteRef = getNormalizedAbsolutePath(moduleReference, getDirectoryPath(currentSourceFile.path)); 3921 const suggestedExt = suggestedExtensions.find(([actualExt, _importExt]) => host.fileExists(absoluteRef + actualExt))?.[1]; 3922 if (suggestedExt) { 3923 error(errorNode, 3924 Diagnostics.Relative_import_paths_need_explicit_file_extensions_in_EcmaScript_imports_when_moduleResolution_is_node16_or_nodenext_Did_you_mean_0, 3925 moduleReference + suggestedExt); 3926 } 3927 else { 3928 error(errorNode, Diagnostics.Relative_import_paths_need_explicit_file_extensions_in_EcmaScript_imports_when_moduleResolution_is_node16_or_nodenext_Consider_adding_an_extension_to_the_import_path); 3929 } 3930 } 3931 else { 3932 if (isSoFile) { 3933 const diagnostic = createDiagnosticForNode(errorNode, Diagnostics.Currently_module_for_0_is_not_verified_If_you_re_importing_napi_its_verification_will_be_enabled_in_later_SDK_version_Please_make_sure_the_corresponding_d_ts_file_is_provided_and_the_napis_are_correctly_declared, moduleReference); 3934 diagnostics.add(diagnostic); 3935 } else { 3936 error(errorNode, moduleNotFoundError, moduleReference); 3937 } 3938 } 3939 } 3940 } 3941 return undefined; 3942 } 3943 3944 function allowImportSendable(sdkPath: string | undefined, currentSourceFile: SourceFile): boolean { 3945 const isInSdkPath = !!(sdkPath && ts.normalizePath(currentSourceFile.fileName).startsWith(sdkPath)); 3946 // Check the file is a TypeScript file outside of the method 3947 // currentSourceFile must be a ts file 3948 return ( 3949 (isInSdkPath && currentSourceFile.isDeclarationFile) || 3950 (!!compilerOptions.tsImportSendableEnable && !currentSourceFile.isDeclarationFile) 3951 ); 3952 } 3953 3954 function errorOnImplicitAnyModule(isError: boolean, errorNode: Node, { packageId, resolvedFileName }: ResolvedModuleFull, moduleReference: string): void { 3955 const errorInfo = !isExternalModuleNameRelative(moduleReference) && packageId 3956 ? typesPackageExists(packageId.name) 3957 ? chainDiagnosticMessages( 3958 /*details*/ undefined, 3959 Diagnostics.If_the_0_package_actually_exposes_this_module_consider_sending_a_pull_request_to_amend_https_Colon_Slash_Slashgithub_com_SlashDefinitelyTyped_SlashDefinitelyTyped_Slashtree_Slashmaster_Slashtypes_Slash_1, 3960 packageId.name, mangleScopedPackageName(packageId.name)) 3961 : packageBundlesTypes(packageId.name) 3962 ? chainDiagnosticMessages( 3963 /*details*/ undefined, 3964 Diagnostics.If_the_0_package_actually_exposes_this_module_try_adding_a_new_declaration_d_ts_file_containing_declare_module_1, 3965 packageId.name, 3966 moduleReference) 3967 : chainDiagnosticMessages( 3968 /*details*/ undefined, 3969 Diagnostics.Try_npm_i_save_dev_types_Slash_1_if_it_exists_or_add_a_new_declaration_d_ts_file_containing_declare_module_0, 3970 moduleReference, 3971 mangleScopedPackageName(packageId.name)) 3972 : undefined; 3973 errorOrSuggestion(isError, errorNode, chainDiagnosticMessages( 3974 errorInfo, 3975 Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type, 3976 moduleReference, 3977 resolvedFileName)); 3978 } 3979 function typesPackageExists(packageName: string): boolean { 3980 return getPackagesMap().has(getTypesPackageName(packageName)); 3981 } 3982 function packageBundlesTypes(packageName: string): boolean { 3983 return !!getPackagesMap().get(packageName); 3984 } 3985 3986 function resolveExternalModuleSymbol(moduleSymbol: Symbol, dontResolveAlias?: boolean): Symbol; 3987 function resolveExternalModuleSymbol(moduleSymbol: Symbol | undefined, dontResolveAlias?: boolean): Symbol | undefined; 3988 function resolveExternalModuleSymbol(moduleSymbol: Symbol, dontResolveAlias?: boolean): Symbol | undefined { 3989 if (moduleSymbol?.exports) { 3990 const exportEquals = resolveSymbol(moduleSymbol.exports.get(InternalSymbolName.ExportEquals), dontResolveAlias); 3991 const exported = getCommonJsExportEquals(getMergedSymbol(exportEquals), getMergedSymbol(moduleSymbol)); 3992 return getMergedSymbol(exported) || moduleSymbol; 3993 } 3994 return undefined; 3995 } 3996 3997 function getCommonJsExportEquals(exported: Symbol | undefined, moduleSymbol: Symbol): Symbol | undefined { 3998 if (!exported || exported === unknownSymbol || exported === moduleSymbol || moduleSymbol.exports!.size === 1 || exported.flags & SymbolFlags.Alias) { 3999 return exported; 4000 } 4001 const links = getSymbolLinks(exported); 4002 if (links.cjsExportMerged) { 4003 return links.cjsExportMerged; 4004 } 4005 const merged = exported.flags & SymbolFlags.Transient ? exported : cloneSymbol(exported); 4006 merged.flags = merged.flags | SymbolFlags.ValueModule; 4007 if (merged.exports === undefined) { 4008 merged.exports = createSymbolTable(); 4009 } 4010 moduleSymbol.exports!.forEach((s, name) => { 4011 if (name === InternalSymbolName.ExportEquals) return; 4012 merged.exports!.set(name, merged.exports!.has(name) ? mergeSymbol(merged.exports!.get(name)!, s) : s); 4013 }); 4014 getSymbolLinks(merged).cjsExportMerged = merged; 4015 return links.cjsExportMerged = merged; 4016 } 4017 4018 // An external module with an 'export =' declaration may be referenced as an ES6 module provided the 'export =' 4019 // references a symbol that is at least declared as a module or a variable. The target of the 'export =' may 4020 // combine other declarations with the module or variable (e.g. a class/module, function/module, interface/variable). 4021 function resolveESModuleSymbol(moduleSymbol: Symbol | undefined, referencingLocation: Node, dontResolveAlias: boolean, suppressInteropError: boolean): Symbol | undefined { 4022 const symbol = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias); 4023 4024 if (!dontResolveAlias && symbol) { 4025 if (!suppressInteropError && !(symbol.flags & (SymbolFlags.Module | SymbolFlags.Variable)) && !getDeclarationOfKind(symbol, SyntaxKind.SourceFile)) { 4026 const compilerOptionName = moduleKind >= ModuleKind.ES2015 4027 ? "allowSyntheticDefaultImports" 4028 : "esModuleInterop"; 4029 4030 error(referencingLocation, Diagnostics.This_module_can_only_be_referenced_with_ECMAScript_imports_Slashexports_by_turning_on_the_0_flag_and_referencing_its_default_export, compilerOptionName); 4031 4032 return symbol; 4033 } 4034 4035 const referenceParent = referencingLocation.parent; 4036 if ( 4037 (isImportDeclaration(referenceParent) && getNamespaceDeclarationNode(referenceParent)) || 4038 isImportCall(referenceParent) 4039 ) { 4040 const reference = isImportCall(referenceParent) ? referenceParent.arguments[0] : referenceParent.moduleSpecifier; 4041 const type = getTypeOfSymbol(symbol); 4042 const defaultOnlyType = getTypeWithSyntheticDefaultOnly(type, symbol, moduleSymbol!, reference); 4043 if (defaultOnlyType) { 4044 return cloneTypeAsModuleType(symbol, defaultOnlyType, referenceParent); 4045 } 4046 4047 const targetFile = moduleSymbol?.declarations?.find(isSourceFile); 4048 const isEsmCjsRef = targetFile && isESMFormatImportImportingCommonjsFormatFile(getUsageModeForExpression(reference), targetFile.impliedNodeFormat); 4049 if (getESModuleInterop(compilerOptions) || isEsmCjsRef) { 4050 let sigs = getSignaturesOfStructuredType(type, SignatureKind.Call); 4051 if (!sigs || !sigs.length) { 4052 sigs = getSignaturesOfStructuredType(type, SignatureKind.Construct); 4053 } 4054 if ( 4055 (sigs && sigs.length) || 4056 getPropertyOfType(type, InternalSymbolName.Default, /*skipObjectFunctionPropertyAugment*/ true) || 4057 isEsmCjsRef 4058 ) { 4059 const moduleType = getTypeWithSyntheticDefaultImportType(type, symbol, moduleSymbol!, reference); 4060 return cloneTypeAsModuleType(symbol, moduleType, referenceParent); 4061 } 4062 } 4063 } 4064 } 4065 return symbol; 4066 } 4067 4068 /** 4069 * Create a new symbol which has the module's type less the call and construct signatures 4070 */ 4071 function cloneTypeAsModuleType(symbol: Symbol, moduleType: Type, referenceParent: ImportDeclaration | ImportCall) { 4072 const result = createSymbol(symbol.flags, symbol.escapedName); 4073 result.declarations = symbol.declarations ? symbol.declarations.slice() : []; 4074 result.parent = symbol.parent; 4075 result.target = symbol; 4076 result.originatingImport = referenceParent; 4077 if (symbol.valueDeclaration) result.valueDeclaration = symbol.valueDeclaration; 4078 if (symbol.constEnumOnlyModule) result.constEnumOnlyModule = true; 4079 if (symbol.members) result.members = new Map(symbol.members); 4080 if (symbol.exports) result.exports = new Map(symbol.exports); 4081 const resolvedModuleType = resolveStructuredTypeMembers(moduleType as StructuredType); // Should already be resolved from the signature checks above 4082 result.type = createAnonymousType(result, resolvedModuleType.members, emptyArray, emptyArray, resolvedModuleType.indexInfos); 4083 return result; 4084 } 4085 4086 function hasExportAssignmentSymbol(moduleSymbol: Symbol): boolean { 4087 return moduleSymbol.exports!.get(InternalSymbolName.ExportEquals) !== undefined; 4088 } 4089 4090 function getExportsOfModuleAsArray(moduleSymbol: Symbol): Symbol[] { 4091 return symbolsToArray(getExportsOfModule(moduleSymbol)); 4092 } 4093 4094 function getExportsAndPropertiesOfModule(moduleSymbol: Symbol): Symbol[] { 4095 const exports = getExportsOfModuleAsArray(moduleSymbol); 4096 const exportEquals = resolveExternalModuleSymbol(moduleSymbol); 4097 if (exportEquals !== moduleSymbol) { 4098 const type = getTypeOfSymbol(exportEquals); 4099 if (shouldTreatPropertiesOfExternalModuleAsExports(type)) { 4100 addRange(exports, getPropertiesOfType(type)); 4101 } 4102 } 4103 return exports; 4104 } 4105 4106 function forEachExportAndPropertyOfModule(moduleSymbol: Symbol, cb: (symbol: Symbol, key: __String) => void): void { 4107 const exports = getExportsOfModule(moduleSymbol); 4108 exports.forEach((symbol, key) => { 4109 if (!isReservedMemberName(key)) { 4110 cb(symbol, key); 4111 } 4112 }); 4113 const exportEquals = resolveExternalModuleSymbol(moduleSymbol); 4114 if (exportEquals !== moduleSymbol) { 4115 const type = getTypeOfSymbol(exportEquals); 4116 if (shouldTreatPropertiesOfExternalModuleAsExports(type)) { 4117 forEachPropertyOfType(type, (symbol, escapedName) => { 4118 cb(symbol, escapedName); 4119 }); 4120 } 4121 } 4122 } 4123 4124 function tryGetMemberInModuleExports(memberName: __String, moduleSymbol: Symbol): Symbol | undefined { 4125 const symbolTable = getExportsOfModule(moduleSymbol); 4126 if (symbolTable) { 4127 return symbolTable.get(memberName); 4128 } 4129 } 4130 4131 function tryGetMemberInModuleExportsAndProperties(memberName: __String, moduleSymbol: Symbol): Symbol | undefined { 4132 const symbol = tryGetMemberInModuleExports(memberName, moduleSymbol); 4133 if (symbol) { 4134 return symbol; 4135 } 4136 4137 const exportEquals = resolveExternalModuleSymbol(moduleSymbol); 4138 if (exportEquals === moduleSymbol) { 4139 return undefined; 4140 } 4141 4142 const type = getTypeOfSymbol(exportEquals); 4143 return shouldTreatPropertiesOfExternalModuleAsExports(type) ? getPropertyOfType(type, memberName) : undefined; 4144 } 4145 4146 function shouldTreatPropertiesOfExternalModuleAsExports(resolvedExternalModuleType: Type) { 4147 return !(resolvedExternalModuleType.flags & TypeFlags.Primitive || 4148 getObjectFlags(resolvedExternalModuleType) & ObjectFlags.Class || 4149 // `isArrayOrTupleLikeType` is too expensive to use in this auto-imports hot path 4150 isArrayType(resolvedExternalModuleType) || 4151 isTupleType(resolvedExternalModuleType)); 4152 } 4153 4154 function getExportsOfSymbol(symbol: Symbol): SymbolTable { 4155 return symbol.flags & SymbolFlags.LateBindingContainer ? getResolvedMembersOrExportsOfSymbol(symbol, MembersOrExportsResolutionKind.resolvedExports) : 4156 symbol.flags & SymbolFlags.Module ? getExportsOfModule(symbol) : 4157 symbol.exports || emptySymbols; 4158 } 4159 4160 function getExportsOfModule(moduleSymbol: Symbol): SymbolTable { 4161 const links = getSymbolLinks(moduleSymbol); 4162 return links.resolvedExports || (links.resolvedExports = getExportsOfModuleWorker(moduleSymbol)); 4163 } 4164 4165 interface ExportCollisionTracker { 4166 specifierText: string; 4167 exportsWithDuplicate: ExportDeclaration[]; 4168 } 4169 4170 type ExportCollisionTrackerTable = UnderscoreEscapedMap<ExportCollisionTracker>; 4171 4172 /** 4173 * Extends one symbol table with another while collecting information on name collisions for error message generation into the `lookupTable` argument 4174 * Not passing `lookupTable` and `exportNode` disables this collection, and just extends the tables 4175 */ 4176 function extendExportSymbols(target: SymbolTable, source: SymbolTable | undefined, lookupTable?: ExportCollisionTrackerTable, exportNode?: ExportDeclaration) { 4177 if (!source) return; 4178 source.forEach((sourceSymbol, id) => { 4179 if (id === InternalSymbolName.Default) return; 4180 4181 const targetSymbol = target.get(id); 4182 if (!targetSymbol) { 4183 target.set(id, sourceSymbol); 4184 if (lookupTable && exportNode) { 4185 lookupTable.set(id, { 4186 specifierText: getTextOfNode(exportNode.moduleSpecifier!) 4187 } as ExportCollisionTracker); 4188 } 4189 } 4190 else if (lookupTable && exportNode && targetSymbol && resolveSymbol(targetSymbol) !== resolveSymbol(sourceSymbol)) { 4191 const collisionTracker = lookupTable.get(id)!; 4192 if (!collisionTracker.exportsWithDuplicate) { 4193 collisionTracker.exportsWithDuplicate = [exportNode]; 4194 } 4195 else { 4196 collisionTracker.exportsWithDuplicate.push(exportNode); 4197 } 4198 } 4199 }); 4200 } 4201 4202 function getExportsOfModuleWorker(moduleSymbol: Symbol): SymbolTable { 4203 const visitedSymbols: Symbol[] = []; 4204 4205 // A module defined by an 'export=' consists of one export that needs to be resolved 4206 moduleSymbol = resolveExternalModuleSymbol(moduleSymbol); 4207 4208 return visit(moduleSymbol) || emptySymbols; 4209 4210 // The ES6 spec permits export * declarations in a module to circularly reference the module itself. For example, 4211 // module 'a' can 'export * from "b"' and 'b' can 'export * from "a"' without error. 4212 function visit(symbol: Symbol | undefined): SymbolTable | undefined { 4213 if (!(symbol && symbol.exports && pushIfUnique(visitedSymbols, symbol))) { 4214 return; 4215 } 4216 const symbols = new Map(symbol.exports); 4217 // All export * declarations are collected in an __export symbol by the binder 4218 const exportStars = symbol.exports.get(InternalSymbolName.ExportStar); 4219 if (exportStars) { 4220 const nestedSymbols = createSymbolTable(); 4221 const lookupTable: ExportCollisionTrackerTable = new Map(); 4222 if (exportStars.declarations) { 4223 for (const node of exportStars.declarations) { 4224 const resolvedModule = resolveExternalModuleName(node, (node as ExportDeclaration).moduleSpecifier!); 4225 const exportedSymbols = visit(resolvedModule); 4226 extendExportSymbols( 4227 nestedSymbols, 4228 exportedSymbols, 4229 lookupTable, 4230 node as ExportDeclaration 4231 ); 4232 } 4233 } 4234 lookupTable.forEach(({ exportsWithDuplicate }, id) => { 4235 // It's not an error if the file with multiple `export *`s with duplicate names exports a member with that name itself 4236 if (id === "export=" || !(exportsWithDuplicate && exportsWithDuplicate.length) || symbols.has(id)) { 4237 return; 4238 } 4239 for (const node of exportsWithDuplicate) { 4240 diagnostics.add(createDiagnosticForNode( 4241 node, 4242 Diagnostics.Module_0_has_already_exported_a_member_named_1_Consider_explicitly_re_exporting_to_resolve_the_ambiguity, 4243 lookupTable.get(id)!.specifierText, 4244 unescapeLeadingUnderscores(id) 4245 )); 4246 } 4247 }); 4248 extendExportSymbols(symbols, nestedSymbols); 4249 } 4250 return symbols; 4251 } 4252 } 4253 4254 function getMergedSymbol(symbol: Symbol): Symbol; 4255 function getMergedSymbol(symbol: Symbol | undefined): Symbol | undefined; 4256 function getMergedSymbol(symbol: Symbol | undefined): Symbol | undefined { 4257 let merged: Symbol; 4258 return symbol && symbol.mergeId && (merged = mergedSymbols[symbol.mergeId]) ? merged : symbol; 4259 } 4260 4261 function getSymbolOfNode(node: Declaration): Symbol; 4262 function getSymbolOfNode(node: Node): Symbol | undefined; 4263 function getSymbolOfNode(node: Node): Symbol | undefined { 4264 return getMergedSymbol(node.symbol && getLateBoundSymbol(node.symbol)); 4265 } 4266 4267 function getParentOfSymbol(symbol: Symbol): Symbol | undefined { 4268 return getMergedSymbol(symbol.parent && getLateBoundSymbol(symbol.parent)); 4269 } 4270 4271 function getAlternativeContainingModules(symbol: Symbol, enclosingDeclaration: Node): Symbol[] { 4272 const containingFile = getSourceFileOfNode(enclosingDeclaration); 4273 const id = getNodeId(containingFile); 4274 const links = getSymbolLinks(symbol); 4275 let results: Symbol[] | undefined; 4276 if (links.extendedContainersByFile && (results = links.extendedContainersByFile.get(id))) { 4277 return results; 4278 } 4279 if (containingFile && containingFile.imports) { 4280 // Try to make an import using an import already in the enclosing file, if possible 4281 for (const importRef of containingFile.imports) { 4282 if (nodeIsSynthesized(importRef)) continue; // Synthetic names can't be resolved by `resolveExternalModuleName` - they'll cause a debug assert if they error 4283 const resolvedModule = resolveExternalModuleName(enclosingDeclaration, importRef, /*ignoreErrors*/ true); 4284 if (!resolvedModule) continue; 4285 const ref = getAliasForSymbolInContainer(resolvedModule, symbol); 4286 if (!ref) continue; 4287 results = append(results, resolvedModule); 4288 } 4289 if (length(results)) { 4290 (links.extendedContainersByFile || (links.extendedContainersByFile = new Map())).set(id, results!); 4291 return results!; 4292 } 4293 } 4294 if (links.extendedContainers) { 4295 return links.extendedContainers; 4296 } 4297 // No results from files already being imported by this file - expand search (expensive, but not location-specific, so cached) 4298 const otherFiles = host.getSourceFiles(); 4299 for (const file of otherFiles) { 4300 if (!isExternalModule(file)) continue; 4301 const sym = getSymbolOfNode(file); 4302 const ref = getAliasForSymbolInContainer(sym, symbol); 4303 if (!ref) continue; 4304 results = append(results, sym); 4305 } 4306 return links.extendedContainers = results || emptyArray; 4307 } 4308 4309 /** 4310 * Attempts to find the symbol corresponding to the container a symbol is in - usually this 4311 * is just its' `.parent`, but for locals, this value is `undefined` 4312 */ 4313 function getContainersOfSymbol(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags): Symbol[] | undefined { 4314 const container = getParentOfSymbol(symbol); 4315 // Type parameters end up in the `members` lists but are not externally visible 4316 if (container && !(symbol.flags & SymbolFlags.TypeParameter)) { 4317 const additionalContainers = mapDefined(container.declarations, fileSymbolIfFileSymbolExportEqualsContainer); 4318 const reexportContainers = enclosingDeclaration && getAlternativeContainingModules(symbol, enclosingDeclaration); 4319 const objectLiteralContainer = getVariableDeclarationOfObjectLiteral(container, meaning); 4320 if ( 4321 enclosingDeclaration && 4322 container.flags & getQualifiedLeftMeaning(meaning) && 4323 getAccessibleSymbolChain(container, enclosingDeclaration, SymbolFlags.Namespace, /*externalOnly*/ false) 4324 ) { 4325 return append(concatenate(concatenate([container], additionalContainers), reexportContainers), objectLiteralContainer); // This order expresses a preference for the real container if it is in scope 4326 } 4327 // we potentially have a symbol which is a member of the instance side of something - look for a variable in scope with the container's type 4328 // which may be acting like a namespace (eg, `Symbol` acts like a namespace when looking up `Symbol.toStringTag`) 4329 const firstVariableMatch = !(container.flags & getQualifiedLeftMeaning(meaning)) 4330 && container.flags & SymbolFlags.Type 4331 && getDeclaredTypeOfSymbol(container).flags & TypeFlags.Object 4332 && meaning === SymbolFlags.Value 4333 ? forEachSymbolTableInScope(enclosingDeclaration, t => { 4334 return forEachEntry(t, s => { 4335 if (s.flags & getQualifiedLeftMeaning(meaning) && getTypeOfSymbol(s) === getDeclaredTypeOfSymbol(container)) { 4336 return s; 4337 } 4338 }); 4339 }) : undefined; 4340 let res = firstVariableMatch ? [firstVariableMatch, ...additionalContainers, container] : [...additionalContainers, container]; 4341 res = append(res, objectLiteralContainer); 4342 res = addRange(res, reexportContainers); 4343 return res; 4344 } 4345 const candidates = mapDefined(symbol.declarations, d => { 4346 if (!isAmbientModule(d) && d.parent){ 4347 // direct children of a module 4348 if (hasNonGlobalAugmentationExternalModuleSymbol(d.parent)) { 4349 return getSymbolOfNode(d.parent); 4350 } 4351 // export ='d member of an ambient module 4352 if (isModuleBlock(d.parent) && d.parent.parent && resolveExternalModuleSymbol(getSymbolOfNode(d.parent.parent)) === symbol) { 4353 return getSymbolOfNode(d.parent.parent); 4354 } 4355 } 4356 if (isClassExpression(d) && isBinaryExpression(d.parent) && d.parent.operatorToken.kind === SyntaxKind.EqualsToken && isAccessExpression(d.parent.left) && isEntityNameExpression(d.parent.left.expression)) { 4357 if (isModuleExportsAccessExpression(d.parent.left) || isExportsIdentifier(d.parent.left.expression)) { 4358 return getSymbolOfNode(getSourceFileOfNode(d)); 4359 } 4360 checkExpressionCached(d.parent.left.expression); 4361 return getNodeLinks(d.parent.left.expression).resolvedSymbol; 4362 } 4363 }); 4364 if (!length(candidates)) { 4365 return undefined; 4366 } 4367 return mapDefined(candidates, candidate => getAliasForSymbolInContainer(candidate, symbol) ? candidate : undefined); 4368 4369 function fileSymbolIfFileSymbolExportEqualsContainer(d: Declaration) { 4370 return container && getFileSymbolIfFileSymbolExportEqualsContainer(d, container); 4371 } 4372 } 4373 4374 function getVariableDeclarationOfObjectLiteral(symbol: Symbol, meaning: SymbolFlags) { 4375 // If we're trying to reference some object literal in, eg `var a = { x: 1 }`, the symbol for the literal, `__object`, is distinct 4376 // from the symbol of the declaration it is being assigned to. Since we can use the declaration to refer to the literal, however, 4377 // we'd like to make that connection here - potentially causing us to paint the declaration's visibility, and therefore the literal. 4378 const firstDecl: Node | false = !!length(symbol.declarations) && first(symbol.declarations!); 4379 if (meaning & SymbolFlags.Value && firstDecl && firstDecl.parent && isVariableDeclaration(firstDecl.parent)) { 4380 if (isObjectLiteralExpression(firstDecl) && firstDecl === firstDecl.parent.initializer || isTypeLiteralNode(firstDecl) && firstDecl === firstDecl.parent.type) { 4381 return getSymbolOfNode(firstDecl.parent); 4382 } 4383 } 4384 } 4385 4386 function getFileSymbolIfFileSymbolExportEqualsContainer(d: Declaration, container: Symbol) { 4387 const fileSymbol = getExternalModuleContainer(d); 4388 const exported = fileSymbol && fileSymbol.exports && fileSymbol.exports.get(InternalSymbolName.ExportEquals); 4389 return exported && getSymbolIfSameReference(exported, container) ? fileSymbol : undefined; 4390 } 4391 4392 function getAliasForSymbolInContainer(container: Symbol, symbol: Symbol) { 4393 if (container === getParentOfSymbol(symbol)) { 4394 // fast path, `symbol` is either already the alias or isn't aliased 4395 return symbol; 4396 } 4397 // Check if container is a thing with an `export=` which points directly at `symbol`, and if so, return 4398 // the container itself as the alias for the symbol 4399 const exportEquals = container.exports && container.exports.get(InternalSymbolName.ExportEquals); 4400 if (exportEquals && getSymbolIfSameReference(exportEquals, symbol)) { 4401 return container; 4402 } 4403 const exports = getExportsOfSymbol(container); 4404 const quick = exports.get(symbol.escapedName); 4405 if (quick && getSymbolIfSameReference(quick, symbol)) { 4406 return quick; 4407 } 4408 return forEachEntry(exports, exported => { 4409 if (getSymbolIfSameReference(exported, symbol)) { 4410 return exported; 4411 } 4412 }); 4413 } 4414 4415 /** 4416 * Checks if two symbols, through aliasing and/or merging, refer to the same thing 4417 */ 4418 function getSymbolIfSameReference(s1: Symbol, s2: Symbol) { 4419 if (getMergedSymbol(resolveSymbol(getMergedSymbol(s1))) === getMergedSymbol(resolveSymbol(getMergedSymbol(s2)))) { 4420 return s1; 4421 } 4422 } 4423 4424 function getExportSymbolOfValueSymbolIfExported(symbol: Symbol): Symbol; 4425 function getExportSymbolOfValueSymbolIfExported(symbol: Symbol | undefined): Symbol | undefined; 4426 function getExportSymbolOfValueSymbolIfExported(symbol: Symbol | undefined): Symbol | undefined { 4427 return getMergedSymbol(symbol && (symbol.flags & SymbolFlags.ExportValue) !== 0 && symbol.exportSymbol || symbol); 4428 } 4429 4430 function symbolIsValue(symbol: Symbol, includeTypeOnlyMembers?: boolean): boolean { 4431 return !!( 4432 symbol.flags & SymbolFlags.Value || 4433 symbol.flags & SymbolFlags.Alias && getAllSymbolFlags(symbol) & SymbolFlags.Value && (includeTypeOnlyMembers || !getTypeOnlyAliasDeclaration(symbol))); 4434 } 4435 4436 function findConstructorDeclaration(node: ClassLikeDeclaration): ConstructorDeclaration | undefined { 4437 const members = node.members; 4438 for (const member of members) { 4439 if (member.kind === SyntaxKind.Constructor && nodeIsPresent((member as ConstructorDeclaration).body)) { 4440 return member as ConstructorDeclaration; 4441 } 4442 } 4443 } 4444 4445 function createType(flags: TypeFlags): Type { 4446 const result = new Type(checker, flags); 4447 typeCount++; 4448 result.id = typeCount; 4449 tracing?.recordType(result); 4450 return result; 4451 } 4452 4453 function createOriginType(flags: TypeFlags): Type { 4454 return new Type(checker, flags); 4455 } 4456 4457 function createIntrinsicType(kind: TypeFlags, intrinsicName: string, objectFlags: ObjectFlags = 0): IntrinsicType { 4458 const type = createType(kind) as IntrinsicType; 4459 type.intrinsicName = intrinsicName; 4460 type.objectFlags = objectFlags; 4461 return type; 4462 } 4463 4464 function createObjectType(objectFlags: ObjectFlags, symbol?: Symbol): ObjectType { 4465 const type = createType(TypeFlags.Object) as ObjectType; 4466 type.objectFlags = objectFlags; 4467 type.symbol = symbol!; 4468 type.members = undefined; 4469 type.properties = undefined; 4470 type.callSignatures = undefined; 4471 type.constructSignatures = undefined; 4472 type.indexInfos = undefined; 4473 return type; 4474 } 4475 4476 function createTypeofType() { 4477 return getUnionType(arrayFrom(typeofNEFacts.keys(), getStringLiteralType)); 4478 } 4479 4480 function createTypeParameter(symbol?: Symbol) { 4481 const type = createType(TypeFlags.TypeParameter) as TypeParameter; 4482 if (symbol) type.symbol = symbol; 4483 return type; 4484 } 4485 4486 // A reserved member name starts with two underscores, but the third character cannot be an underscore, 4487 // @, or #. A third underscore indicates an escaped form of an identifier that started 4488 // with at least two underscores. The @ character indicates that the name is denoted by a well known ES 4489 // Symbol instance and the # character indicates that the name is a PrivateIdentifier. 4490 function isReservedMemberName(name: __String) { 4491 return (name as string).charCodeAt(0) === CharacterCodes._ && 4492 (name as string).charCodeAt(1) === CharacterCodes._ && 4493 (name as string).charCodeAt(2) !== CharacterCodes._ && 4494 (name as string).charCodeAt(2) !== CharacterCodes.at && 4495 (name as string).charCodeAt(2) !== CharacterCodes.hash; 4496 } 4497 4498 function getNamedMembers(members: SymbolTable): Symbol[] { 4499 let result: Symbol[] | undefined; 4500 members.forEach((symbol, id) => { 4501 if (isNamedMember(symbol, id)) { 4502 (result || (result = [])).push(symbol); 4503 } 4504 }); 4505 return result || emptyArray; 4506 } 4507 4508 function isNamedMember(member: Symbol, escapedName: __String) { 4509 return !isReservedMemberName(escapedName) && symbolIsValue(member); 4510 } 4511 4512 function getNamedOrIndexSignatureMembers(members: SymbolTable): Symbol[] { 4513 const result = getNamedMembers(members); 4514 const index = getIndexSymbolFromSymbolTable(members); 4515 return index ? concatenate(result, [index]) : result; 4516 } 4517 4518 function setStructuredTypeMembers(type: StructuredType, members: SymbolTable, callSignatures: readonly Signature[], constructSignatures: readonly Signature[], indexInfos: readonly IndexInfo[]): ResolvedType { 4519 const resolved = type as ResolvedType; 4520 resolved.members = members; 4521 resolved.properties = emptyArray; 4522 resolved.callSignatures = callSignatures; 4523 resolved.constructSignatures = constructSignatures; 4524 resolved.indexInfos = indexInfos; 4525 // This can loop back to getPropertyOfType() which would crash if `callSignatures` & `constructSignatures` are not initialized. 4526 if (members !== emptySymbols) resolved.properties = getNamedMembers(members); 4527 return resolved; 4528 } 4529 4530 function createAnonymousType(symbol: Symbol | undefined, members: SymbolTable, callSignatures: readonly Signature[], constructSignatures: readonly Signature[], indexInfos: readonly IndexInfo[]): ResolvedType { 4531 return setStructuredTypeMembers(createObjectType(ObjectFlags.Anonymous, symbol), 4532 members, callSignatures, constructSignatures, indexInfos); 4533 } 4534 4535 function getResolvedTypeWithoutAbstractConstructSignatures(type: ResolvedType) { 4536 if (type.constructSignatures.length === 0) return type; 4537 if (type.objectTypeWithoutAbstractConstructSignatures) return type.objectTypeWithoutAbstractConstructSignatures; 4538 const constructSignatures = filter(type.constructSignatures, signature => !(signature.flags & SignatureFlags.Abstract)); 4539 if (type.constructSignatures === constructSignatures) return type; 4540 const typeCopy = createAnonymousType( 4541 type.symbol, 4542 type.members, 4543 type.callSignatures, 4544 some(constructSignatures) ? constructSignatures : emptyArray, 4545 type.indexInfos); 4546 type.objectTypeWithoutAbstractConstructSignatures = typeCopy; 4547 typeCopy.objectTypeWithoutAbstractConstructSignatures = typeCopy; 4548 return typeCopy; 4549 } 4550 4551 function forEachSymbolTableInScope<T>(enclosingDeclaration: Node | undefined, callback: (symbolTable: SymbolTable, ignoreQualification?: boolean, isLocalNameLookup?: boolean, scopeNode?: Node) => T): T { 4552 let result: T; 4553 for (let location = enclosingDeclaration; location; location = location.parent) { 4554 // Locals of a source file are not in scope (because they get merged into the global symbol table) 4555 if (location.locals && !isGlobalSourceFile(location)) { 4556 if (result = callback(location.locals, /*ignoreQualification*/ undefined, /*isLocalNameLookup*/ true, location)) { 4557 return result; 4558 } 4559 } 4560 switch (location.kind) { 4561 case SyntaxKind.SourceFile: 4562 if (!isExternalOrCommonJsModule(location as SourceFile)) { 4563 break; 4564 } 4565 // falls through 4566 case SyntaxKind.ModuleDeclaration: 4567 const sym = getSymbolOfNode(location as ModuleDeclaration); 4568 // `sym` may not have exports if this module declaration is backed by the symbol for a `const` that's being rewritten 4569 // into a namespace - in such cases, it's best to just let the namespace appear empty (the const members couldn't have referred 4570 // to one another anyway) 4571 if (result = callback(sym?.exports || emptySymbols, /*ignoreQualification*/ undefined, /*isLocalNameLookup*/ true, location)) { 4572 return result; 4573 } 4574 break; 4575 case SyntaxKind.ClassDeclaration: 4576 case SyntaxKind.ClassExpression: 4577 case SyntaxKind.InterfaceDeclaration: 4578 // Type parameters are bound into `members` lists so they can merge across declarations 4579 // This is troublesome, since in all other respects, they behave like locals :cries: 4580 // TODO: the below is shared with similar code in `resolveName` - in fact, rephrasing all this symbol 4581 // lookup logic in terms of `resolveName` would be nice 4582 // The below is used to lookup type parameters within a class or interface, as they are added to the class/interface locals 4583 // These can never be latebound, so the symbol's raw members are sufficient. `getMembersOfNode` cannot be used, as it would 4584 // trigger resolving late-bound names, which we may already be in the process of doing while we're here! 4585 let table: UnderscoreEscapedMap<Symbol> | undefined; 4586 // TODO: Should this filtered table be cached in some way? 4587 (getSymbolOfNode(location as ClassLikeDeclaration | InterfaceDeclaration).members || emptySymbols).forEach((memberSymbol, key) => { 4588 if (memberSymbol.flags & (SymbolFlags.Type & ~SymbolFlags.Assignment)) { 4589 (table || (table = createSymbolTable())).set(key, memberSymbol); 4590 } 4591 }); 4592 if (table && (result = callback(table, /*ignoreQualification*/ undefined, /*isLocalNameLookup*/ false, location))) { 4593 return result; 4594 } 4595 break; 4596 } 4597 } 4598 4599 return callback(globals, /*ignoreQualification*/ undefined, /*isLocalNameLookup*/ true); 4600 } 4601 4602 function getQualifiedLeftMeaning(rightMeaning: SymbolFlags) { 4603 // If we are looking in value space, the parent meaning is value, other wise it is namespace 4604 return rightMeaning === SymbolFlags.Value ? SymbolFlags.Value : SymbolFlags.Namespace; 4605 } 4606 4607 function getAccessibleSymbolChain(symbol: Symbol | undefined, enclosingDeclaration: Node | undefined, meaning: SymbolFlags, useOnlyExternalAliasing: boolean, visitedSymbolTablesMap: ESMap<SymbolId, SymbolTable[]> = new Map()): Symbol[] | undefined { 4608 if (!(symbol && !isPropertyOrMethodDeclarationSymbol(symbol))) { 4609 return undefined; 4610 } 4611 const links = getSymbolLinks(symbol); 4612 const cache = (links.accessibleChainCache ||= new Map()); 4613 // Go from enclosingDeclaration to the first scope we check, so the cache is keyed off the scope and thus shared more 4614 const firstRelevantLocation = forEachSymbolTableInScope(enclosingDeclaration, (_, __, ___, node) => node); 4615 const key = `${useOnlyExternalAliasing ? 0 : 1}|${firstRelevantLocation && getNodeId(firstRelevantLocation)}|${meaning}`; 4616 if (cache.has(key)) { 4617 return cache.get(key); 4618 } 4619 4620 const id = getSymbolId(symbol); 4621 let visitedSymbolTables = visitedSymbolTablesMap.get(id); 4622 if (!visitedSymbolTables) { 4623 visitedSymbolTablesMap.set(id, visitedSymbolTables = []); 4624 } 4625 const result = forEachSymbolTableInScope(enclosingDeclaration, getAccessibleSymbolChainFromSymbolTable); 4626 cache.set(key, result); 4627 return result; 4628 4629 /** 4630 * @param {ignoreQualification} boolean Set when a symbol is being looked for through the exports of another symbol (meaning we have a route to qualify it already) 4631 */ 4632 function getAccessibleSymbolChainFromSymbolTable(symbols: SymbolTable, ignoreQualification?: boolean, isLocalNameLookup?: boolean): Symbol[] | undefined { 4633 if (!pushIfUnique(visitedSymbolTables!, symbols)) { 4634 return undefined; 4635 } 4636 4637 const result = trySymbolTable(symbols, ignoreQualification, isLocalNameLookup); 4638 visitedSymbolTables!.pop(); 4639 return result; 4640 } 4641 4642 function canQualifySymbol(symbolFromSymbolTable: Symbol, meaning: SymbolFlags) { 4643 // If the symbol is equivalent and doesn't need further qualification, this symbol is accessible 4644 return !needsQualification(symbolFromSymbolTable, enclosingDeclaration, meaning) || 4645 // If symbol needs qualification, make sure that parent is accessible, if it is then this symbol is accessible too 4646 !!getAccessibleSymbolChain(symbolFromSymbolTable.parent, enclosingDeclaration, getQualifiedLeftMeaning(meaning), useOnlyExternalAliasing, visitedSymbolTablesMap); 4647 } 4648 4649 function isAccessible(symbolFromSymbolTable: Symbol, resolvedAliasSymbol?: Symbol, ignoreQualification?: boolean) { 4650 return (symbol === (resolvedAliasSymbol || symbolFromSymbolTable) || getMergedSymbol(symbol) === getMergedSymbol(resolvedAliasSymbol || symbolFromSymbolTable)) && 4651 // if the symbolFromSymbolTable is not external module (it could be if it was determined as ambient external module and would be in globals table) 4652 // and if symbolFromSymbolTable or alias resolution matches the symbol, 4653 // check the symbol can be qualified, it is only then this symbol is accessible 4654 !some(symbolFromSymbolTable.declarations, hasNonGlobalAugmentationExternalModuleSymbol) && 4655 (ignoreQualification || canQualifySymbol(getMergedSymbol(symbolFromSymbolTable), meaning)); 4656 } 4657 4658 function trySymbolTable(symbols: SymbolTable, ignoreQualification: boolean | undefined, isLocalNameLookup: boolean | undefined): Symbol[] | undefined { 4659 // If symbol is directly available by its name in the symbol table 4660 if (isAccessible(symbols.get(symbol!.escapedName)!, /*resolvedAliasSymbol*/ undefined, ignoreQualification)) { 4661 return [symbol!]; 4662 } 4663 4664 // Check if symbol is any of the aliases in scope 4665 const result = forEachEntry(symbols, symbolFromSymbolTable => { 4666 if (symbolFromSymbolTable.flags & SymbolFlags.Alias 4667 && symbolFromSymbolTable.escapedName !== InternalSymbolName.ExportEquals 4668 && symbolFromSymbolTable.escapedName !== InternalSymbolName.Default 4669 && !(isUMDExportSymbol(symbolFromSymbolTable) && enclosingDeclaration && isExternalModule(getSourceFileOfNode(enclosingDeclaration))) 4670 // If `!useOnlyExternalAliasing`, we can use any type of alias to get the name 4671 && (!useOnlyExternalAliasing || some(symbolFromSymbolTable.declarations, isExternalModuleImportEqualsDeclaration)) 4672 // If we're looking up a local name to reference directly, omit namespace reexports, otherwise when we're trawling through an export list to make a dotted name, we can keep it 4673 && (isLocalNameLookup ? !some(symbolFromSymbolTable.declarations, isNamespaceReexportDeclaration) : true) 4674 // While exports are generally considered to be in scope, export-specifier declared symbols are _not_ 4675 // See similar comment in `resolveName` for details 4676 && (ignoreQualification || !getDeclarationOfKind(symbolFromSymbolTable, SyntaxKind.ExportSpecifier)) 4677 ) { 4678 4679 const resolvedImportedSymbol = resolveAlias(symbolFromSymbolTable); 4680 const candidate = getCandidateListForSymbol(symbolFromSymbolTable, resolvedImportedSymbol, ignoreQualification); 4681 if (candidate) { 4682 return candidate; 4683 } 4684 } 4685 if (symbolFromSymbolTable.escapedName === symbol!.escapedName && symbolFromSymbolTable.exportSymbol) { 4686 if (isAccessible(getMergedSymbol(symbolFromSymbolTable.exportSymbol), /*aliasSymbol*/ undefined, ignoreQualification)) { 4687 return [symbol!]; 4688 } 4689 } 4690 }); 4691 4692 // If there's no result and we're looking at the global symbol table, treat `globalThis` like an alias and try to lookup thru that 4693 return result || (symbols === globals ? getCandidateListForSymbol(globalThisSymbol, globalThisSymbol, ignoreQualification) : undefined); 4694 } 4695 4696 function getCandidateListForSymbol(symbolFromSymbolTable: Symbol, resolvedImportedSymbol: Symbol, ignoreQualification: boolean | undefined) { 4697 if (isAccessible(symbolFromSymbolTable, resolvedImportedSymbol, ignoreQualification)) { 4698 return [symbolFromSymbolTable]; 4699 } 4700 4701 // Look in the exported members, if we can find accessibleSymbolChain, symbol is accessible using this chain 4702 // but only if the symbolFromSymbolTable can be qualified 4703 const candidateTable = getExportsOfSymbol(resolvedImportedSymbol); 4704 const accessibleSymbolsFromExports = candidateTable && getAccessibleSymbolChainFromSymbolTable(candidateTable, /*ignoreQualification*/ true); 4705 if (accessibleSymbolsFromExports && canQualifySymbol(symbolFromSymbolTable, getQualifiedLeftMeaning(meaning))) { 4706 return [symbolFromSymbolTable].concat(accessibleSymbolsFromExports); 4707 } 4708 } 4709 } 4710 4711 function needsQualification(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags) { 4712 let qualify = false; 4713 forEachSymbolTableInScope(enclosingDeclaration, symbolTable => { 4714 // If symbol of this name is not available in the symbol table we are ok 4715 let symbolFromSymbolTable = getMergedSymbol(symbolTable.get(symbol.escapedName)); 4716 if (!symbolFromSymbolTable) { 4717 // Continue to the next symbol table 4718 return false; 4719 } 4720 // If the symbol with this name is present it should refer to the symbol 4721 if (symbolFromSymbolTable === symbol) { 4722 // No need to qualify 4723 return true; 4724 } 4725 4726 // Qualify if the symbol from symbol table has same meaning as expected 4727 const shouldResolveAlias = (symbolFromSymbolTable.flags & SymbolFlags.Alias && !getDeclarationOfKind(symbolFromSymbolTable, SyntaxKind.ExportSpecifier)); 4728 symbolFromSymbolTable = shouldResolveAlias ? resolveAlias(symbolFromSymbolTable) : symbolFromSymbolTable; 4729 const flags = shouldResolveAlias ? getAllSymbolFlags(symbolFromSymbolTable) : symbolFromSymbolTable.flags; 4730 if (flags & meaning) { 4731 qualify = true; 4732 return true; 4733 } 4734 4735 // Continue to the next symbol table 4736 return false; 4737 }); 4738 4739 return qualify; 4740 } 4741 4742 function isPropertyOrMethodDeclarationSymbol(symbol: Symbol) { 4743 if (symbol.declarations && symbol.declarations.length) { 4744 for (const declaration of symbol.declarations) { 4745 switch (declaration.kind) { 4746 case SyntaxKind.PropertyDeclaration: 4747 case SyntaxKind.MethodDeclaration: 4748 case SyntaxKind.GetAccessor: 4749 case SyntaxKind.SetAccessor: 4750 continue; 4751 default: 4752 return false; 4753 } 4754 } 4755 return true; 4756 } 4757 return false; 4758 } 4759 4760 function isTypeSymbolAccessible(typeSymbol: Symbol, enclosingDeclaration: Node | undefined): boolean { 4761 const access = isSymbolAccessibleWorker(typeSymbol, enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false, /*allowModules*/ true); 4762 return access.accessibility === SymbolAccessibility.Accessible; 4763 } 4764 4765 function isValueSymbolAccessible(typeSymbol: Symbol, enclosingDeclaration: Node | undefined): boolean { 4766 const access = isSymbolAccessibleWorker(typeSymbol, enclosingDeclaration, SymbolFlags.Value, /*shouldComputeAliasesToMakeVisible*/ false, /*allowModules*/ true); 4767 return access.accessibility === SymbolAccessibility.Accessible; 4768 } 4769 4770 function isSymbolAccessibleByFlags(typeSymbol: Symbol, enclosingDeclaration: Node | undefined, flags: SymbolFlags): boolean { 4771 const access = isSymbolAccessibleWorker(typeSymbol, enclosingDeclaration, flags, /*shouldComputeAliasesToMakeVisible*/ false, /*allowModules*/ false); 4772 return access.accessibility === SymbolAccessibility.Accessible; 4773 } 4774 4775 function isAnySymbolAccessible(symbols: Symbol[] | undefined, enclosingDeclaration: Node | undefined, initialSymbol: Symbol, meaning: SymbolFlags, shouldComputeAliasesToMakeVisible: boolean, allowModules: boolean): SymbolAccessibilityResult | undefined { 4776 if (!length(symbols)) return; 4777 4778 let hadAccessibleChain: Symbol | undefined; 4779 let earlyModuleBail = false; 4780 for (const symbol of symbols!) { 4781 // Symbol is accessible if it by itself is accessible 4782 const accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaning, /*useOnlyExternalAliasing*/ false); 4783 if (accessibleSymbolChain) { 4784 hadAccessibleChain = symbol; 4785 const hasAccessibleDeclarations = hasVisibleDeclarations(accessibleSymbolChain[0], shouldComputeAliasesToMakeVisible); 4786 if (hasAccessibleDeclarations) { 4787 return hasAccessibleDeclarations; 4788 } 4789 } 4790 if (allowModules) { 4791 if (some(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol)) { 4792 if (shouldComputeAliasesToMakeVisible) { 4793 earlyModuleBail = true; 4794 // Generally speaking, we want to use the aliases that already exist to refer to a module, if present 4795 // In order to do so, we need to find those aliases in order to retain them in declaration emit; so 4796 // if we are in declaration emit, we cannot use the fast path for module visibility until we've exhausted 4797 // all other visibility options (in order to capture the possible aliases used to reference the module) 4798 continue; 4799 } 4800 // Any meaning of a module symbol is always accessible via an `import` type 4801 return { 4802 accessibility: SymbolAccessibility.Accessible 4803 }; 4804 } 4805 } 4806 4807 // If we haven't got the accessible symbol, it doesn't mean the symbol is actually inaccessible. 4808 // It could be a qualified symbol and hence verify the path 4809 // e.g.: 4810 // module m { 4811 // export class c { 4812 // } 4813 // } 4814 // const x: typeof m.c 4815 // In the above example when we start with checking if typeof m.c symbol is accessible, 4816 // we are going to see if c can be accessed in scope directly. 4817 // But it can't, hence the accessible is going to be undefined, but that doesn't mean m.c is inaccessible 4818 // It is accessible if the parent m is accessible because then m.c can be accessed through qualification 4819 4820 const containers = getContainersOfSymbol(symbol, enclosingDeclaration, meaning); 4821 const parentResult = isAnySymbolAccessible(containers, enclosingDeclaration, initialSymbol, initialSymbol === symbol ? getQualifiedLeftMeaning(meaning) : meaning, shouldComputeAliasesToMakeVisible, allowModules); 4822 if (parentResult) { 4823 return parentResult; 4824 } 4825 } 4826 4827 if (earlyModuleBail) { 4828 return { 4829 accessibility: SymbolAccessibility.Accessible 4830 }; 4831 } 4832 4833 if (hadAccessibleChain) { 4834 return { 4835 accessibility: SymbolAccessibility.NotAccessible, 4836 errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning), 4837 errorModuleName: hadAccessibleChain !== initialSymbol ? symbolToString(hadAccessibleChain, enclosingDeclaration, SymbolFlags.Namespace) : undefined, 4838 }; 4839 } 4840 } 4841 4842 /** 4843 * Check if the given symbol in given enclosing declaration is accessible and mark all associated alias to be visible if requested 4844 * 4845 * @param symbol a Symbol to check if accessible 4846 * @param enclosingDeclaration a Node containing reference to the symbol 4847 * @param meaning a SymbolFlags to check if such meaning of the symbol is accessible 4848 * @param shouldComputeAliasToMakeVisible a boolean value to indicate whether to return aliases to be mark visible in case the symbol is accessible 4849 */ 4850 function isSymbolAccessible(symbol: Symbol | undefined, enclosingDeclaration: Node | undefined, meaning: SymbolFlags, shouldComputeAliasesToMakeVisible: boolean): SymbolAccessibilityResult { 4851 return isSymbolAccessibleWorker(symbol, enclosingDeclaration, meaning, shouldComputeAliasesToMakeVisible, /*allowModules*/ true); 4852 } 4853 4854 function isSymbolAccessibleWorker(symbol: Symbol | undefined, enclosingDeclaration: Node | undefined, meaning: SymbolFlags, shouldComputeAliasesToMakeVisible: boolean, allowModules: boolean): SymbolAccessibilityResult { 4855 if (symbol && enclosingDeclaration) { 4856 const result = isAnySymbolAccessible([symbol], enclosingDeclaration, symbol, meaning, shouldComputeAliasesToMakeVisible, allowModules); 4857 if (result) { 4858 return result; 4859 } 4860 4861 // This could be a symbol that is not exported in the external module 4862 // or it could be a symbol from different external module that is not aliased and hence cannot be named 4863 const symbolExternalModule = forEach(symbol.declarations, getExternalModuleContainer); 4864 if (symbolExternalModule) { 4865 const enclosingExternalModule = getExternalModuleContainer(enclosingDeclaration); 4866 if (symbolExternalModule !== enclosingExternalModule) { 4867 // name from different external module that is not visible 4868 return { 4869 accessibility: SymbolAccessibility.CannotBeNamed, 4870 errorSymbolName: symbolToString(symbol, enclosingDeclaration, meaning), 4871 errorModuleName: symbolToString(symbolExternalModule), 4872 errorNode: isInJSFile(enclosingDeclaration) ? enclosingDeclaration : undefined, 4873 }; 4874 } 4875 } 4876 4877 // Just a local name that is not accessible 4878 return { 4879 accessibility: SymbolAccessibility.NotAccessible, 4880 errorSymbolName: symbolToString(symbol, enclosingDeclaration, meaning), 4881 }; 4882 } 4883 4884 return { accessibility: SymbolAccessibility.Accessible }; 4885 } 4886 4887 function getExternalModuleContainer(declaration: Node) { 4888 const node = findAncestor(declaration, hasExternalModuleSymbol); 4889 return node && getSymbolOfNode(node); 4890 } 4891 4892 function hasExternalModuleSymbol(declaration: Node) { 4893 return isAmbientModule(declaration) || (declaration.kind === SyntaxKind.SourceFile && isExternalOrCommonJsModule(declaration as SourceFile)); 4894 } 4895 4896 function hasNonGlobalAugmentationExternalModuleSymbol(declaration: Node) { 4897 return isModuleWithStringLiteralName(declaration) || (declaration.kind === SyntaxKind.SourceFile && isExternalOrCommonJsModule(declaration as SourceFile)); 4898 } 4899 4900 function hasVisibleDeclarations(symbol: Symbol, shouldComputeAliasToMakeVisible: boolean): SymbolVisibilityResult | undefined { 4901 let aliasesToMakeVisible: LateVisibilityPaintedStatement[] | undefined; 4902 if (!every(filter(symbol.declarations, d => d.kind !== SyntaxKind.Identifier), getIsDeclarationVisible)) { 4903 return undefined; 4904 } 4905 return { accessibility: SymbolAccessibility.Accessible, aliasesToMakeVisible }; 4906 4907 function getIsDeclarationVisible(declaration: Declaration) { 4908 if (!isDeclarationVisible(declaration)) { 4909 // Mark the unexported alias as visible if its parent is visible 4910 // because these kind of aliases can be used to name types in declaration file 4911 4912 const anyImportSyntax = getAnyImportSyntax(declaration); 4913 if (anyImportSyntax && 4914 !hasSyntacticModifier(anyImportSyntax, ModifierFlags.Export) && // import clause without export 4915 isDeclarationVisible(anyImportSyntax.parent)) { 4916 return addVisibleAlias(declaration, anyImportSyntax); 4917 } 4918 else if (isVariableDeclaration(declaration) && isVariableStatement(declaration.parent.parent) && 4919 !hasSyntacticModifier(declaration.parent.parent, ModifierFlags.Export) && // unexported variable statement 4920 isDeclarationVisible(declaration.parent.parent.parent)) { 4921 return addVisibleAlias(declaration, declaration.parent.parent); 4922 } 4923 else if (isLateVisibilityPaintedStatement(declaration) // unexported top-level statement 4924 && !hasSyntacticModifier(declaration, ModifierFlags.Export) 4925 && isDeclarationVisible(declaration.parent)) { 4926 return addVisibleAlias(declaration, declaration); 4927 } 4928 else if (isBindingElement(declaration)) { 4929 if (symbol.flags & SymbolFlags.Alias && isInJSFile(declaration) && declaration.parent?.parent // exported import-like top-level JS require statement 4930 && isVariableDeclaration(declaration.parent.parent) 4931 && declaration.parent.parent.parent?.parent && isVariableStatement(declaration.parent.parent.parent.parent) 4932 && !hasSyntacticModifier(declaration.parent.parent.parent.parent, ModifierFlags.Export) 4933 && declaration.parent.parent.parent.parent.parent // check if the thing containing the variable statement is visible (ie, the file) 4934 && isDeclarationVisible(declaration.parent.parent.parent.parent.parent)) { 4935 return addVisibleAlias(declaration, declaration.parent.parent.parent.parent); 4936 } 4937 else if (symbol.flags & SymbolFlags.BlockScopedVariable) { 4938 const variableStatement = findAncestor(declaration, isVariableStatement)!; 4939 if (hasSyntacticModifier(variableStatement, ModifierFlags.Export)) { 4940 return true; 4941 } 4942 if (!isDeclarationVisible(variableStatement.parent)) { 4943 return false; 4944 } 4945 return addVisibleAlias(declaration, variableStatement); 4946 } 4947 } 4948 4949 // Declaration is not visible 4950 return false; 4951 } 4952 4953 return true; 4954 } 4955 4956 function addVisibleAlias(declaration: Declaration, aliasingStatement: LateVisibilityPaintedStatement) { 4957 // In function "buildTypeDisplay" where we decide whether to write type-alias or serialize types, 4958 // we want to just check if type- alias is accessible or not but we don't care about emitting those alias at that time 4959 // since we will do the emitting later in trackSymbol. 4960 if (shouldComputeAliasToMakeVisible) { 4961 getNodeLinks(declaration).isVisible = true; 4962 aliasesToMakeVisible = appendIfUnique(aliasesToMakeVisible, aliasingStatement); 4963 } 4964 return true; 4965 } 4966 } 4967 4968 function isEntityNameVisible(entityName: EntityNameOrEntityNameExpression, enclosingDeclaration: Node): SymbolVisibilityResult { 4969 // get symbol of the first identifier of the entityName 4970 let meaning: SymbolFlags; 4971 if (entityName.parent.kind === SyntaxKind.TypeQuery || 4972 entityName.parent.kind === SyntaxKind.ExpressionWithTypeArguments && !isPartOfTypeNode(entityName.parent) || 4973 entityName.parent.kind === SyntaxKind.ComputedPropertyName) { 4974 // Typeof value 4975 meaning = SymbolFlags.Value | SymbolFlags.ExportValue; 4976 } 4977 else if (entityName.kind === SyntaxKind.QualifiedName || entityName.kind === SyntaxKind.PropertyAccessExpression || 4978 entityName.parent.kind === SyntaxKind.ImportEqualsDeclaration) { 4979 // Left identifier from type reference or TypeAlias 4980 // Entity name of the import declaration 4981 meaning = SymbolFlags.Namespace; 4982 } 4983 else { 4984 // Type Reference or TypeAlias entity = Identifier 4985 meaning = SymbolFlags.Type; 4986 } 4987 4988 const firstIdentifier = getFirstIdentifier(entityName); 4989 const symbol = resolveName(enclosingDeclaration, firstIdentifier.escapedText, meaning, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false); 4990 if (symbol && symbol.flags & SymbolFlags.TypeParameter && meaning & SymbolFlags.Type) { 4991 return { accessibility: SymbolAccessibility.Accessible }; 4992 } 4993 if (!symbol && isThisIdentifier(firstIdentifier) && isSymbolAccessible(getSymbolOfNode(getThisContainer(firstIdentifier, /*includeArrowFunctions*/ false)), firstIdentifier, meaning, /*computeAliases*/ false).accessibility === SymbolAccessibility.Accessible) { 4994 return { accessibility: SymbolAccessibility.Accessible }; 4995 } 4996 4997 // Verify if the symbol is accessible 4998 return (symbol && hasVisibleDeclarations(symbol, /*shouldComputeAliasToMakeVisible*/ true)) || { 4999 accessibility: SymbolAccessibility.NotAccessible, 5000 errorSymbolName: getTextOfNode(firstIdentifier), 5001 errorNode: firstIdentifier 5002 }; 5003 } 5004 5005 function symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags: SymbolFormatFlags = SymbolFormatFlags.AllowAnyNodeKind, writer?: EmitTextWriter): string { 5006 let nodeFlags = NodeBuilderFlags.IgnoreErrors; 5007 if (flags & SymbolFormatFlags.UseOnlyExternalAliasing) { 5008 nodeFlags |= NodeBuilderFlags.UseOnlyExternalAliasing; 5009 } 5010 if (flags & SymbolFormatFlags.WriteTypeParametersOrArguments) { 5011 nodeFlags |= NodeBuilderFlags.WriteTypeParametersInQualifiedName; 5012 } 5013 if (flags & SymbolFormatFlags.UseAliasDefinedOutsideCurrentScope) { 5014 nodeFlags |= NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope; 5015 } 5016 if (flags & SymbolFormatFlags.DoNotIncludeSymbolChain) { 5017 nodeFlags |= NodeBuilderFlags.DoNotIncludeSymbolChain; 5018 } 5019 if (flags & SymbolFormatFlags.WriteComputedProps) { 5020 nodeFlags |= NodeBuilderFlags.WriteComputedProps; 5021 } 5022 const builder = flags & SymbolFormatFlags.AllowAnyNodeKind ? nodeBuilder.symbolToNode : nodeBuilder.symbolToEntityName; 5023 return writer ? symbolToStringWorker(writer).getText() : usingSingleLineStringWriter(symbolToStringWorker); 5024 5025 function symbolToStringWorker(writer: EmitTextWriter) { 5026 const entity = builder(symbol, meaning!, enclosingDeclaration, nodeFlags)!; // TODO: GH#18217 5027 // add neverAsciiEscape for GH#39027 5028 const printer = enclosingDeclaration?.kind === SyntaxKind.SourceFile ? createPrinter({ removeComments: true, neverAsciiEscape: true }) : createPrinter({ removeComments: true }); 5029 const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); 5030 printer.writeNode(EmitHint.Unspecified, entity, /*sourceFile*/ sourceFile, writer); 5031 return writer; 5032 } 5033 } 5034 5035 function signatureToString(signature: Signature, enclosingDeclaration?: Node, flags = TypeFormatFlags.None, kind?: SignatureKind, writer?: EmitTextWriter): string { 5036 return writer ? signatureToStringWorker(writer).getText() : usingSingleLineStringWriter(signatureToStringWorker); 5037 5038 function signatureToStringWorker(writer: EmitTextWriter) { 5039 let sigOutput: SyntaxKind; 5040 if (flags & TypeFormatFlags.WriteArrowStyleSignature) { 5041 sigOutput = kind === SignatureKind.Construct ? SyntaxKind.ConstructorType : SyntaxKind.FunctionType; 5042 } 5043 else { 5044 sigOutput = kind === SignatureKind.Construct ? SyntaxKind.ConstructSignature : SyntaxKind.CallSignature; 5045 } 5046 const sig = nodeBuilder.signatureToSignatureDeclaration(signature, sigOutput, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName); 5047 const printer = createPrinter({ removeComments: true, omitTrailingSemicolon: true }); 5048 const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); 5049 printer.writeNode(EmitHint.Unspecified, sig!, /*sourceFile*/ sourceFile, getTrailingSemicolonDeferringWriter(writer)); // TODO: GH#18217 5050 return writer; 5051 } 5052 } 5053 5054 function typeToString(type: Type, enclosingDeclaration?: Node, flags: TypeFormatFlags = TypeFormatFlags.AllowUniqueESSymbolType | TypeFormatFlags.UseAliasDefinedOutsideCurrentScope, writer: EmitTextWriter = createTextWriter("")): string { 5055 const noTruncation = compilerOptions.noErrorTruncation || flags & TypeFormatFlags.NoTruncation; 5056 const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | (noTruncation ? NodeBuilderFlags.NoTruncation : 0), writer); 5057 if (typeNode === undefined) return Debug.fail("should always get typenode"); 5058 // The unresolved type gets a synthesized comment on `any` to hint to users that it's not a plain `any`. 5059 // Otherwise, we always strip comments out. 5060 const options = { removeComments: type !== unresolvedType }; 5061 const printer = createPrinter(options); 5062 const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); 5063 printer.writeNode(EmitHint.Unspecified, typeNode, /*sourceFile*/ sourceFile, writer); 5064 const result = writer.getText(); 5065 5066 const maxLength = noTruncation ? noTruncationMaximumTruncationLength * 2 : defaultMaximumTruncationLength * 2; 5067 if (maxLength && result && result.length >= maxLength) { 5068 return result.substr(0, maxLength - "...".length) + "..."; 5069 } 5070 return result; 5071 } 5072 5073 function getTypeNamesForErrorDisplay(left: Type, right: Type): [string, string] { 5074 let leftStr = symbolValueDeclarationIsContextSensitive(left.symbol) ? typeToString(left, left.symbol.valueDeclaration) : typeToString(left); 5075 let rightStr = symbolValueDeclarationIsContextSensitive(right.symbol) ? typeToString(right, right.symbol.valueDeclaration) : typeToString(right); 5076 if (leftStr === rightStr) { 5077 leftStr = getTypeNameForErrorDisplay(left); 5078 rightStr = getTypeNameForErrorDisplay(right); 5079 } 5080 return [leftStr, rightStr]; 5081 } 5082 5083 function getTypeNameForErrorDisplay(type: Type) { 5084 return typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType); 5085 } 5086 5087 function symbolValueDeclarationIsContextSensitive(symbol: Symbol): boolean { 5088 return symbol && !!symbol.valueDeclaration && isExpression(symbol.valueDeclaration) && !isContextSensitive(symbol.valueDeclaration); 5089 } 5090 5091 function toNodeBuilderFlags(flags = TypeFormatFlags.None): NodeBuilderFlags { 5092 return flags & TypeFormatFlags.NodeBuilderFlagsMask; 5093 } 5094 5095 function isClassInstanceSide(type: Type) { 5096 return !!type.symbol && !!(type.symbol.flags & SymbolFlags.Class) && (type === getDeclaredTypeOfClassOrInterface(type.symbol) || (!!(type.flags & TypeFlags.Object) && !!(getObjectFlags(type) & ObjectFlags.IsClassInstanceClone))); 5097 } 5098 5099 function createNodeBuilder() { 5100 return { 5101 typeToTypeNode: (type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => 5102 withContext(enclosingDeclaration, flags, tracker, context => typeToTypeNodeHelper(type, context)), 5103 indexInfoToIndexSignatureDeclaration: (indexInfo: IndexInfo, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => 5104 withContext(enclosingDeclaration, flags, tracker, context => indexInfoToIndexSignatureDeclarationHelper(indexInfo, context, /*typeNode*/ undefined)), 5105 signatureToSignatureDeclaration: (signature: Signature, kind: SignatureDeclaration["kind"], enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => 5106 withContext(enclosingDeclaration, flags, tracker, context => signatureToSignatureDeclarationHelper(signature, kind, context)), 5107 symbolToEntityName: (symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => 5108 withContext(enclosingDeclaration, flags, tracker, context => symbolToName(symbol, context, meaning, /*expectsIdentifier*/ false)), 5109 symbolToExpression: (symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => 5110 withContext(enclosingDeclaration, flags, tracker, context => symbolToExpression(symbol, context, meaning)), 5111 symbolToTypeParameterDeclarations: (symbol: Symbol, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => 5112 withContext(enclosingDeclaration, flags, tracker, context => typeParametersToTypeParameterDeclarations(symbol, context)), 5113 symbolToParameterDeclaration: (symbol: Symbol, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => 5114 withContext(enclosingDeclaration, flags, tracker, context => symbolToParameterDeclaration(symbol, context)), 5115 typeParameterToDeclaration: (parameter: TypeParameter, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => 5116 withContext(enclosingDeclaration, flags, tracker, context => typeParameterToDeclaration(parameter, context)), 5117 symbolTableToDeclarationStatements: (symbolTable: SymbolTable, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker, bundled?: boolean) => 5118 withContext(enclosingDeclaration, flags, tracker, context => symbolTableToDeclarationStatements(symbolTable, context, bundled)), 5119 symbolToNode: (symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => 5120 withContext(enclosingDeclaration, flags, tracker, context => symbolToNode(symbol, context, meaning)), 5121 }; 5122 5123 function symbolToNode(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags) { 5124 if (context.flags & NodeBuilderFlags.WriteComputedProps) { 5125 if (symbol.valueDeclaration) { 5126 const name = getNameOfDeclaration(symbol.valueDeclaration); 5127 if (name && isComputedPropertyName(name)) return name; 5128 } 5129 const nameType = getSymbolLinks(symbol).nameType; 5130 if (nameType && nameType.flags & (TypeFlags.EnumLiteral | TypeFlags.UniqueESSymbol)) { 5131 context.enclosingDeclaration = nameType.symbol.valueDeclaration; 5132 return factory.createComputedPropertyName(symbolToExpression(nameType.symbol, context, meaning)); 5133 } 5134 } 5135 return symbolToExpression(symbol, context, meaning); 5136 } 5137 5138 function withContext<T>(enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined, tracker: SymbolTracker | undefined, cb: (context: NodeBuilderContext) => T): T | undefined { 5139 Debug.assert(enclosingDeclaration === undefined || (enclosingDeclaration.flags & NodeFlags.Synthesized) === 0); 5140 const context: NodeBuilderContext = { 5141 enclosingDeclaration, 5142 flags: flags || NodeBuilderFlags.None, 5143 // If no full tracker is provided, fake up a dummy one with a basic limited-functionality moduleResolverHost 5144 tracker: tracker && tracker.trackSymbol ? tracker : { trackSymbol: () => false, moduleResolverHost: flags! & NodeBuilderFlags.DoNotIncludeSymbolChain ? { 5145 getCommonSourceDirectory: !!(host as Program).getCommonSourceDirectory ? () => (host as Program).getCommonSourceDirectory() : () => "", 5146 getCurrentDirectory: () => host.getCurrentDirectory(), 5147 getSymlinkCache: maybeBind(host, host.getSymlinkCache), 5148 getPackageJsonInfoCache: () => host.getPackageJsonInfoCache?.(), 5149 useCaseSensitiveFileNames: maybeBind(host, host.useCaseSensitiveFileNames), 5150 redirectTargetsMap: host.redirectTargetsMap, 5151 getProjectReferenceRedirect: fileName => host.getProjectReferenceRedirect(fileName), 5152 isSourceOfProjectReferenceRedirect: fileName => host.isSourceOfProjectReferenceRedirect(fileName), 5153 fileExists: fileName => host.fileExists(fileName), 5154 getFileIncludeReasons: () => host.getFileIncludeReasons(), 5155 readFile: host.readFile ? (fileName => host.readFile!(fileName)) : undefined, 5156 } : undefined }, 5157 encounteredError: false, 5158 reportedDiagnostic: false, 5159 visitedTypes: undefined, 5160 symbolDepth: undefined, 5161 inferTypeParameters: undefined, 5162 approximateLength: 0 5163 }; 5164 context.tracker = wrapSymbolTrackerToReportForContext(context, context.tracker); 5165 const resultingNode = cb(context); 5166 if (context.truncating && context.flags & NodeBuilderFlags.NoTruncation) { 5167 context.tracker?.reportTruncationError?.(); 5168 } 5169 return context.encounteredError ? undefined : resultingNode; 5170 } 5171 5172 function wrapSymbolTrackerToReportForContext(context: NodeBuilderContext, tracker: SymbolTracker): SymbolTracker { 5173 const oldTrackSymbol = tracker.trackSymbol; 5174 return { 5175 ...tracker, 5176 reportCyclicStructureError: wrapReportedDiagnostic(tracker.reportCyclicStructureError), 5177 reportInaccessibleThisError: wrapReportedDiagnostic(tracker.reportInaccessibleThisError), 5178 reportInaccessibleUniqueSymbolError: wrapReportedDiagnostic(tracker.reportInaccessibleUniqueSymbolError), 5179 reportLikelyUnsafeImportRequiredError: wrapReportedDiagnostic(tracker.reportLikelyUnsafeImportRequiredError), 5180 reportNonlocalAugmentation: wrapReportedDiagnostic(tracker.reportNonlocalAugmentation), 5181 reportPrivateInBaseOfClassExpression: wrapReportedDiagnostic(tracker.reportPrivateInBaseOfClassExpression), 5182 reportNonSerializableProperty: wrapReportedDiagnostic(tracker.reportNonSerializableProperty), 5183 trackSymbol: oldTrackSymbol && ((...args) => { 5184 const result = oldTrackSymbol(...args); 5185 if (result) { 5186 context.reportedDiagnostic = true; 5187 } 5188 return result; 5189 }), 5190 }; 5191 5192 function wrapReportedDiagnostic<T extends (...args: any[]) => any>(method: T | undefined): T | undefined { 5193 if (!method) { 5194 return method; 5195 } 5196 return (((...args) => { 5197 context.reportedDiagnostic = true; 5198 return method(...args); 5199 }) as T); 5200 } 5201 } 5202 5203 function checkTruncationLength(context: NodeBuilderContext): boolean { 5204 if (context.truncating) return context.truncating; 5205 return context.truncating = context.approximateLength > ((context.flags & NodeBuilderFlags.NoTruncation) ? noTruncationMaximumTruncationLength : defaultMaximumTruncationLength); 5206 } 5207 5208 function typeToTypeNodeHelper(type: Type, context: NodeBuilderContext): TypeNode { 5209 const savedFlags = context.flags; 5210 const typeNode = typeToTypeNodeWorker(type, context); 5211 context.flags = savedFlags; 5212 return typeNode; 5213 } 5214 5215 function typeToTypeNodeWorker(type: Type, context: NodeBuilderContext): TypeNode { 5216 if (cancellationToken && cancellationToken.throwIfCancellationRequested) { 5217 cancellationToken.throwIfCancellationRequested(); 5218 } 5219 const inTypeAlias = context.flags & NodeBuilderFlags.InTypeAlias; 5220 context.flags &= ~NodeBuilderFlags.InTypeAlias; 5221 5222 if (!type) { 5223 if (!(context.flags & NodeBuilderFlags.AllowEmptyUnionOrIntersection)) { 5224 context.encounteredError = true; 5225 return undefined!; // TODO: GH#18217 5226 } 5227 context.approximateLength += 3; 5228 return factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); 5229 } 5230 5231 if (!(context.flags & NodeBuilderFlags.NoTypeReduction)) { 5232 type = getReducedType(type); 5233 } 5234 5235 if (type.flags & TypeFlags.Any) { 5236 if (type.aliasSymbol) { 5237 return factory.createTypeReferenceNode(symbolToEntityNameNode(type.aliasSymbol), mapToTypeNodes(type.aliasTypeArguments, context)); 5238 } 5239 if (type === unresolvedType) { 5240 return addSyntheticLeadingComment(factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), SyntaxKind.MultiLineCommentTrivia, "unresolved"); 5241 } 5242 context.approximateLength += 3; 5243 return factory.createKeywordTypeNode(type === intrinsicMarkerType ? SyntaxKind.IntrinsicKeyword : SyntaxKind.AnyKeyword); 5244 } 5245 if (type.flags & TypeFlags.Unknown) { 5246 return factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword); 5247 } 5248 if (type.flags & TypeFlags.String) { 5249 context.approximateLength += 6; 5250 return factory.createKeywordTypeNode(SyntaxKind.StringKeyword); 5251 } 5252 if (type.flags & TypeFlags.Number) { 5253 context.approximateLength += 6; 5254 return factory.createKeywordTypeNode(SyntaxKind.NumberKeyword); 5255 } 5256 if (type.flags & TypeFlags.BigInt) { 5257 context.approximateLength += 6; 5258 return factory.createKeywordTypeNode(SyntaxKind.BigIntKeyword); 5259 } 5260 if (type.flags & TypeFlags.Boolean && !type.aliasSymbol) { 5261 context.approximateLength += 7; 5262 return factory.createKeywordTypeNode(SyntaxKind.BooleanKeyword); 5263 } 5264 if (type.flags & TypeFlags.EnumLiteral && !(type.flags & TypeFlags.Union)) { 5265 const parentSymbol = getParentOfSymbol(type.symbol)!; 5266 const parentName = symbolToTypeNode(parentSymbol, context, SymbolFlags.Type); 5267 if (getDeclaredTypeOfSymbol(parentSymbol) === type) { 5268 return parentName; 5269 } 5270 const memberName = symbolName(type.symbol); 5271 if (isIdentifierText(memberName, ScriptTarget.ES3)) { 5272 return appendReferenceToType( 5273 parentName as TypeReferenceNode | ImportTypeNode, 5274 factory.createTypeReferenceNode(memberName, /*typeArguments*/ undefined) 5275 ); 5276 } 5277 if (isImportTypeNode(parentName)) { 5278 (parentName as any).isTypeOf = true; // mutably update, node is freshly manufactured anyhow 5279 return factory.createIndexedAccessTypeNode(parentName, factory.createLiteralTypeNode(factory.createStringLiteral(memberName))); 5280 } 5281 else if (isTypeReferenceNode(parentName)) { 5282 return factory.createIndexedAccessTypeNode(factory.createTypeQueryNode(parentName.typeName), factory.createLiteralTypeNode(factory.createStringLiteral(memberName))); 5283 } 5284 else { 5285 return Debug.fail("Unhandled type node kind returned from `symbolToTypeNode`."); 5286 } 5287 } 5288 if (type.flags & TypeFlags.EnumLike) { 5289 return symbolToTypeNode(type.symbol, context, SymbolFlags.Type); 5290 } 5291 if (type.flags & TypeFlags.StringLiteral) { 5292 context.approximateLength += ((type as StringLiteralType).value.length + 2); 5293 return factory.createLiteralTypeNode(setEmitFlags(factory.createStringLiteral((type as StringLiteralType).value, !!(context.flags & NodeBuilderFlags.UseSingleQuotesForStringLiteralType)), EmitFlags.NoAsciiEscaping)); 5294 } 5295 if (type.flags & TypeFlags.NumberLiteral) { 5296 const value = (type as NumberLiteralType).value; 5297 context.approximateLength += ("" + value).length; 5298 return factory.createLiteralTypeNode(value < 0 ? factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, factory.createNumericLiteral(-value)) : factory.createNumericLiteral(value)); 5299 } 5300 if (type.flags & TypeFlags.BigIntLiteral) { 5301 context.approximateLength += (pseudoBigIntToString((type as BigIntLiteralType).value).length) + 1; 5302 return factory.createLiteralTypeNode((factory.createBigIntLiteral((type as BigIntLiteralType).value))); 5303 } 5304 if (type.flags & TypeFlags.BooleanLiteral) { 5305 context.approximateLength += (type as IntrinsicType).intrinsicName.length; 5306 return factory.createLiteralTypeNode((type as IntrinsicType).intrinsicName === "true" ? factory.createTrue() : factory.createFalse()); 5307 } 5308 if (type.flags & TypeFlags.UniqueESSymbol) { 5309 if (!(context.flags & NodeBuilderFlags.AllowUniqueESSymbolType)) { 5310 if (isValueSymbolAccessible(type.symbol, context.enclosingDeclaration)) { 5311 context.approximateLength += 6; 5312 return symbolToTypeNode(type.symbol, context, SymbolFlags.Value); 5313 } 5314 if (context.tracker.reportInaccessibleUniqueSymbolError) { 5315 context.tracker.reportInaccessibleUniqueSymbolError(); 5316 } 5317 } 5318 context.approximateLength += 13; 5319 return factory.createTypeOperatorNode(SyntaxKind.UniqueKeyword, factory.createKeywordTypeNode(SyntaxKind.SymbolKeyword)); 5320 } 5321 if (type.flags & TypeFlags.Void) { 5322 context.approximateLength += 4; 5323 return factory.createKeywordTypeNode(SyntaxKind.VoidKeyword); 5324 } 5325 if (type.flags & TypeFlags.Undefined) { 5326 context.approximateLength += 9; 5327 return factory.createKeywordTypeNode(SyntaxKind.UndefinedKeyword); 5328 } 5329 if (type.flags & TypeFlags.Null) { 5330 context.approximateLength += 4; 5331 return factory.createLiteralTypeNode(factory.createNull()); 5332 } 5333 if (type.flags & TypeFlags.Never) { 5334 context.approximateLength += 5; 5335 return factory.createKeywordTypeNode(SyntaxKind.NeverKeyword); 5336 } 5337 if (type.flags & TypeFlags.ESSymbol) { 5338 context.approximateLength += 6; 5339 return factory.createKeywordTypeNode(SyntaxKind.SymbolKeyword); 5340 } 5341 if (type.flags & TypeFlags.NonPrimitive) { 5342 context.approximateLength += 6; 5343 return factory.createKeywordTypeNode(SyntaxKind.ObjectKeyword); 5344 } 5345 if (isThisTypeParameter(type)) { 5346 if (context.flags & NodeBuilderFlags.InObjectTypeLiteral) { 5347 if (!context.encounteredError && !(context.flags & NodeBuilderFlags.AllowThisInObjectLiteral)) { 5348 context.encounteredError = true; 5349 } 5350 if (context.tracker.reportInaccessibleThisError) { 5351 context.tracker.reportInaccessibleThisError(); 5352 } 5353 } 5354 context.approximateLength += 4; 5355 return factory.createThisTypeNode(); 5356 } 5357 5358 if (!inTypeAlias && type.aliasSymbol && (context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope || isTypeSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration))) { 5359 const typeArgumentNodes = mapToTypeNodes(type.aliasTypeArguments, context); 5360 if (isReservedMemberName(type.aliasSymbol.escapedName) && !(type.aliasSymbol.flags & SymbolFlags.Class)) return factory.createTypeReferenceNode(factory.createIdentifier(""), typeArgumentNodes); 5361 if (length(typeArgumentNodes) === 1 && type.aliasSymbol === globalArrayType.symbol) { 5362 return factory.createArrayTypeNode(typeArgumentNodes![0]); 5363 } 5364 return symbolToTypeNode(type.aliasSymbol, context, SymbolFlags.Type, typeArgumentNodes); 5365 } 5366 5367 const objectFlags = getObjectFlags(type); 5368 5369 if (objectFlags & ObjectFlags.Reference) { 5370 Debug.assert(!!(type.flags & TypeFlags.Object)); 5371 return (type as TypeReference).node ? visitAndTransformType(type, typeReferenceToTypeNode) : typeReferenceToTypeNode(type as TypeReference); 5372 } 5373 if (type.flags & TypeFlags.TypeParameter || objectFlags & ObjectFlags.ClassOrInterface) { 5374 if (type.flags & TypeFlags.TypeParameter && contains(context.inferTypeParameters, type)) { 5375 context.approximateLength += (symbolName(type.symbol).length + 6); 5376 let constraintNode: TypeNode | undefined; 5377 const constraint = getConstraintOfTypeParameter(type as TypeParameter); 5378 if (constraint) { 5379 // If the infer type has a constraint that is not the same as the constraint 5380 // we would have normally inferred based on context, we emit the constraint 5381 // using `infer T extends ?`. We omit inferred constraints from type references 5382 // as they may be elided. 5383 const inferredConstraint = getInferredTypeParameterConstraint(type as TypeParameter, /*omitTypeReferences*/ true); 5384 if (!(inferredConstraint && isTypeIdenticalTo(constraint, inferredConstraint))) { 5385 context.approximateLength += 9; 5386 constraintNode = constraint && typeToTypeNodeHelper(constraint, context); 5387 } 5388 } 5389 return factory.createInferTypeNode(typeParameterToDeclarationWithConstraint(type as TypeParameter, context, constraintNode)); 5390 } 5391 if (context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams && 5392 type.flags & TypeFlags.TypeParameter && 5393 !isTypeSymbolAccessible(type.symbol, context.enclosingDeclaration)) { 5394 const name = typeParameterToName(type, context); 5395 context.approximateLength += idText(name).length; 5396 return factory.createTypeReferenceNode(factory.createIdentifier(idText(name)), /*typeArguments*/ undefined); 5397 } 5398 // Ignore constraint/default when creating a usage (as opposed to declaration) of a type parameter. 5399 if (type.symbol) { 5400 return symbolToTypeNode(type.symbol, context, SymbolFlags.Type); 5401 } 5402 const name = (type === markerSuperTypeForCheck || type === markerSubTypeForCheck) && varianceTypeParameter && varianceTypeParameter.symbol ? 5403 (type === markerSubTypeForCheck ? "sub-" : "super-") + symbolName(varianceTypeParameter.symbol) : "?"; 5404 return factory.createTypeReferenceNode(factory.createIdentifier(name), /*typeArguments*/ undefined); 5405 } 5406 if (type.flags & TypeFlags.Union && (type as UnionType).origin) { 5407 type = (type as UnionType).origin!; 5408 } 5409 if (type.flags & (TypeFlags.Union | TypeFlags.Intersection)) { 5410 const types = type.flags & TypeFlags.Union ? formatUnionTypes((type as UnionType).types) : (type as IntersectionType).types; 5411 if (length(types) === 1) { 5412 return typeToTypeNodeHelper(types[0], context); 5413 } 5414 const typeNodes = mapToTypeNodes(types, context, /*isBareList*/ true); 5415 if (typeNodes && typeNodes.length > 0) { 5416 return type.flags & TypeFlags.Union ? factory.createUnionTypeNode(typeNodes) : factory.createIntersectionTypeNode(typeNodes); 5417 } 5418 else { 5419 if (!context.encounteredError && !(context.flags & NodeBuilderFlags.AllowEmptyUnionOrIntersection)) { 5420 context.encounteredError = true; 5421 } 5422 return undefined!; // TODO: GH#18217 5423 } 5424 } 5425 if (objectFlags & (ObjectFlags.Anonymous | ObjectFlags.Mapped)) { 5426 Debug.assert(!!(type.flags & TypeFlags.Object)); 5427 // The type is an object literal type. 5428 return createAnonymousTypeNode(type as ObjectType); 5429 } 5430 if (type.flags & TypeFlags.Index) { 5431 const indexedType = (type as IndexType).type; 5432 context.approximateLength += 6; 5433 const indexTypeNode = typeToTypeNodeHelper(indexedType, context); 5434 return factory.createTypeOperatorNode(SyntaxKind.KeyOfKeyword, indexTypeNode); 5435 } 5436 if (type.flags & TypeFlags.TemplateLiteral) { 5437 const texts = (type as TemplateLiteralType).texts; 5438 const types = (type as TemplateLiteralType).types; 5439 const templateHead = factory.createTemplateHead(texts[0]); 5440 const templateSpans = factory.createNodeArray( 5441 map(types, (t, i) => factory.createTemplateLiteralTypeSpan( 5442 typeToTypeNodeHelper(t, context), 5443 (i < types.length - 1 ? factory.createTemplateMiddle : factory.createTemplateTail)(texts[i + 1])))); 5444 context.approximateLength += 2; 5445 return factory.createTemplateLiteralType(templateHead, templateSpans); 5446 } 5447 if (type.flags & TypeFlags.StringMapping) { 5448 const typeNode = typeToTypeNodeHelper((type as StringMappingType).type, context); 5449 return symbolToTypeNode((type as StringMappingType).symbol, context, SymbolFlags.Type, [typeNode]); 5450 } 5451 if (type.flags & TypeFlags.IndexedAccess) { 5452 const objectTypeNode = typeToTypeNodeHelper((type as IndexedAccessType).objectType, context); 5453 const indexTypeNode = typeToTypeNodeHelper((type as IndexedAccessType).indexType, context); 5454 context.approximateLength += 2; 5455 return factory.createIndexedAccessTypeNode(objectTypeNode, indexTypeNode); 5456 } 5457 if (type.flags & TypeFlags.Conditional) { 5458 return visitAndTransformType(type, type => conditionalTypeToTypeNode(type as ConditionalType)); 5459 } 5460 if (type.flags & TypeFlags.Substitution) { 5461 return typeToTypeNodeHelper((type as SubstitutionType).baseType, context); 5462 } 5463 5464 return Debug.fail("Should be unreachable."); 5465 5466 5467 function conditionalTypeToTypeNode(type: ConditionalType) { 5468 const checkTypeNode = typeToTypeNodeHelper(type.checkType, context); 5469 context.approximateLength += 15; 5470 if (context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams && type.root.isDistributive && !(type.checkType.flags & TypeFlags.TypeParameter)) { 5471 const newParam = createTypeParameter(createSymbol(SymbolFlags.TypeParameter, "T" as __String)); 5472 const name = typeParameterToName(newParam, context); 5473 const newTypeVariable = factory.createTypeReferenceNode(name); 5474 context.approximateLength += 37; // 15 each for two added conditionals, 7 for an added infer type 5475 const newMapper = prependTypeMapping(type.root.checkType, newParam, type.mapper); 5476 const saveInferTypeParameters = context.inferTypeParameters; 5477 context.inferTypeParameters = type.root.inferTypeParameters; 5478 const extendsTypeNode = typeToTypeNodeHelper(instantiateType(type.root.extendsType, newMapper), context); 5479 context.inferTypeParameters = saveInferTypeParameters; 5480 const trueTypeNode = typeToTypeNodeOrCircularityElision(instantiateType(getTypeFromTypeNode(type.root.node.trueType), newMapper)); 5481 const falseTypeNode = typeToTypeNodeOrCircularityElision(instantiateType(getTypeFromTypeNode(type.root.node.falseType), newMapper)); 5482 5483 5484 // outermost conditional makes `T` a type parameter, allowing the inner conditionals to be distributive 5485 // second conditional makes `T` have `T & checkType` substitution, so it is correctly usable as the checkType 5486 // inner conditional runs the check the user provided on the check type (distributively) and returns the result 5487 // checkType extends infer T ? T extends checkType ? T extends extendsType<T> ? trueType<T> : falseType<T> : never : never; 5488 // this is potentially simplifiable to 5489 // checkType extends infer T ? T extends checkType & extendsType<T> ? trueType<T> : falseType<T> : never; 5490 // but that may confuse users who read the output more. 5491 // On the other hand, 5492 // checkType extends infer T extends checkType ? T extends extendsType<T> ? trueType<T> : falseType<T> : never; 5493 // may also work with `infer ... extends ...` in, but would produce declarations only compatible with the latest TS. 5494 return factory.createConditionalTypeNode( 5495 checkTypeNode, 5496 factory.createInferTypeNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, factory.cloneNode(newTypeVariable.typeName) as Identifier)), 5497 factory.createConditionalTypeNode( 5498 factory.createTypeReferenceNode(factory.cloneNode(name)), 5499 typeToTypeNodeHelper(type.checkType, context), 5500 factory.createConditionalTypeNode(newTypeVariable, extendsTypeNode, trueTypeNode, falseTypeNode), 5501 factory.createKeywordTypeNode(SyntaxKind.NeverKeyword) 5502 ), 5503 factory.createKeywordTypeNode(SyntaxKind.NeverKeyword) 5504 ); 5505 } 5506 const saveInferTypeParameters = context.inferTypeParameters; 5507 context.inferTypeParameters = type.root.inferTypeParameters; 5508 const extendsTypeNode = typeToTypeNodeHelper(type.extendsType, context); 5509 context.inferTypeParameters = saveInferTypeParameters; 5510 const trueTypeNode = typeToTypeNodeOrCircularityElision(getTrueTypeFromConditionalType(type)); 5511 const falseTypeNode = typeToTypeNodeOrCircularityElision(getFalseTypeFromConditionalType(type)); 5512 return factory.createConditionalTypeNode(checkTypeNode, extendsTypeNode, trueTypeNode, falseTypeNode); 5513 } 5514 5515 function typeToTypeNodeOrCircularityElision(type: Type) { 5516 if (type.flags & TypeFlags.Union) { 5517 if (context.visitedTypes?.has(getTypeId(type))) { 5518 if (!(context.flags & NodeBuilderFlags.AllowAnonymousIdentifier)) { 5519 context.encounteredError = true; 5520 context.tracker?.reportCyclicStructureError?.(); 5521 } 5522 return createElidedInformationPlaceholder(context); 5523 } 5524 return visitAndTransformType(type, type => typeToTypeNodeHelper(type, context)); 5525 } 5526 return typeToTypeNodeHelper(type, context); 5527 } 5528 5529 function isHomomorphicMappedTypeWithNonHomomorphicInstantiation(type: MappedType) { 5530 return isMappedTypeWithKeyofConstraintDeclaration(type) 5531 && !(getModifiersTypeFromMappedType(type).flags & TypeFlags.TypeParameter); 5532 } 5533 5534 function createMappedTypeNodeFromType(type: MappedType) { 5535 Debug.assert(!!(type.flags & TypeFlags.Object)); 5536 const readonlyToken = type.declaration.readonlyToken ? factory.createToken(type.declaration.readonlyToken.kind) as ReadonlyKeyword | PlusToken | MinusToken : undefined; 5537 const questionToken = type.declaration.questionToken ? factory.createToken(type.declaration.questionToken.kind) as QuestionToken | PlusToken | MinusToken : undefined; 5538 let appropriateConstraintTypeNode: TypeNode; 5539 let newTypeVariable: TypeReferenceNode | undefined; 5540 if (isMappedTypeWithKeyofConstraintDeclaration(type)) { 5541 // We have a { [P in keyof T]: X } 5542 // We do this to ensure we retain the toplevel keyof-ness of the type which may be lost due to keyof distribution during `getConstraintTypeFromMappedType` 5543 if (isHomomorphicMappedTypeWithNonHomomorphicInstantiation(type) && context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams) { 5544 const newParam = createTypeParameter(createSymbol(SymbolFlags.TypeParameter, "T" as __String)); 5545 const name = typeParameterToName(newParam, context); 5546 newTypeVariable = factory.createTypeReferenceNode(name); 5547 } 5548 appropriateConstraintTypeNode = factory.createTypeOperatorNode(SyntaxKind.KeyOfKeyword, newTypeVariable || typeToTypeNodeHelper(getModifiersTypeFromMappedType(type), context)); 5549 } 5550 else { 5551 appropriateConstraintTypeNode = typeToTypeNodeHelper(getConstraintTypeFromMappedType(type), context); 5552 } 5553 const typeParameterNode = typeParameterToDeclarationWithConstraint(getTypeParameterFromMappedType(type), context, appropriateConstraintTypeNode); 5554 const nameTypeNode = type.declaration.nameType ? typeToTypeNodeHelper(getNameTypeFromMappedType(type)!, context) : undefined; 5555 const templateTypeNode = typeToTypeNodeHelper(removeMissingType(getTemplateTypeFromMappedType(type), !!(getMappedTypeModifiers(type) & MappedTypeModifiers.IncludeOptional)), context); 5556 const mappedTypeNode = factory.createMappedTypeNode(readonlyToken, typeParameterNode, nameTypeNode, questionToken, templateTypeNode, /*members*/ undefined); 5557 context.approximateLength += 10; 5558 const result = setEmitFlags(mappedTypeNode, EmitFlags.SingleLine); 5559 if (isHomomorphicMappedTypeWithNonHomomorphicInstantiation(type) && context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams) { 5560 // homomorphic mapped type with a non-homomorphic naive inlining 5561 // wrap it with a conditional like `SomeModifiersType extends infer U ? {..the mapped type...} : never` to ensure the resulting 5562 // type stays homomorphic 5563 const originalConstraint = instantiateType(getConstraintOfTypeParameter(getTypeFromTypeNode((type.declaration.typeParameter.constraint! as TypeOperatorNode).type) as TypeParameter) || unknownType, type.mapper); 5564 return factory.createConditionalTypeNode( 5565 typeToTypeNodeHelper(getModifiersTypeFromMappedType(type), context), 5566 factory.createInferTypeNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, factory.cloneNode(newTypeVariable!.typeName) as Identifier, originalConstraint.flags & TypeFlags.Unknown ? undefined : typeToTypeNodeHelper(originalConstraint, context))), 5567 result, 5568 factory.createKeywordTypeNode(SyntaxKind.NeverKeyword) 5569 ); 5570 } 5571 return result; 5572 } 5573 5574 function createAnonymousTypeNode(type: ObjectType): TypeNode { 5575 const typeId = type.id; 5576 const symbol = type.symbol; 5577 if (symbol) { 5578 const isInstanceType = isClassInstanceSide(type) ? SymbolFlags.Type : SymbolFlags.Value; 5579 if (isJSConstructor(symbol.valueDeclaration)) { 5580 // Instance and static types share the same symbol; only add 'typeof' for the static side. 5581 return symbolToTypeNode(symbol, context, isInstanceType); 5582 } 5583 // Always use 'typeof T' for type of class, enum, and module objects 5584 else if (symbol.flags & SymbolFlags.Class 5585 && !getBaseTypeVariableOfClass(symbol) 5586 && !(symbol.valueDeclaration && isClassLike(symbol.valueDeclaration) && context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral && (!isClassDeclaration(symbol.valueDeclaration) || isSymbolAccessible(symbol, context.enclosingDeclaration, isInstanceType, /*computeAliases*/ false).accessibility !== SymbolAccessibility.Accessible)) || 5587 symbol.flags & (SymbolFlags.Enum | SymbolFlags.ValueModule) || 5588 shouldWriteTypeOfFunctionSymbol()) { 5589 return symbolToTypeNode(symbol, context, isInstanceType); 5590 } 5591 else if (context.visitedTypes?.has(typeId)) { 5592 // If type is an anonymous type literal in a type alias declaration, use type alias name 5593 const typeAlias = getTypeAliasForTypeLiteral(type); 5594 if (typeAlias) { 5595 // The specified symbol flags need to be reinterpreted as type flags 5596 return symbolToTypeNode(typeAlias, context, SymbolFlags.Type); 5597 } 5598 else { 5599 return createElidedInformationPlaceholder(context); 5600 } 5601 } 5602 else { 5603 return visitAndTransformType(type, createTypeNodeFromObjectType); 5604 } 5605 } 5606 else { 5607 // Anonymous types without a symbol are never circular. 5608 return createTypeNodeFromObjectType(type); 5609 } 5610 function shouldWriteTypeOfFunctionSymbol() { 5611 const isStaticMethodSymbol = !!(symbol.flags & SymbolFlags.Method) && // typeof static method 5612 some(symbol.declarations, declaration => isStatic(declaration)); 5613 const isNonLocalFunctionSymbol = !!(symbol.flags & SymbolFlags.Function) && 5614 (symbol.parent || // is exported function symbol 5615 forEach(symbol.declarations, declaration => 5616 declaration.parent.kind === SyntaxKind.SourceFile || declaration.parent.kind === SyntaxKind.ModuleBlock)); 5617 if (isStaticMethodSymbol || isNonLocalFunctionSymbol) { 5618 // typeof is allowed only for static/non local functions 5619 return (!!(context.flags & NodeBuilderFlags.UseTypeOfFunction) || (context.visitedTypes?.has(typeId))) && // it is type of the symbol uses itself recursively 5620 (!(context.flags & NodeBuilderFlags.UseStructuralFallback) || isValueSymbolAccessible(symbol, context.enclosingDeclaration)); // And the build is going to succeed without visibility error or there is no structural fallback allowed 5621 } 5622 } 5623 } 5624 5625 function visitAndTransformType<T extends TypeNode>(type: Type, transform: (type: Type) => T) { 5626 const typeId = type.id; 5627 const isConstructorObject = getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & SymbolFlags.Class; 5628 const id = getObjectFlags(type) & ObjectFlags.Reference && (type as TypeReference).node ? "N" + getNodeId((type as TypeReference).node!) : 5629 type.flags & TypeFlags.Conditional ? "N" + getNodeId((type as ConditionalType).root.node) : 5630 type.symbol ? (isConstructorObject ? "+" : "") + getSymbolId(type.symbol) : 5631 undefined; 5632 // Since instantiations of the same anonymous type have the same symbol, tracking symbols instead 5633 // of types allows us to catch circular references to instantiations of the same anonymous type 5634 if (!context.visitedTypes) { 5635 context.visitedTypes = new Set(); 5636 } 5637 if (id && !context.symbolDepth) { 5638 context.symbolDepth = new Map(); 5639 } 5640 5641 const links = context.enclosingDeclaration && getNodeLinks(context.enclosingDeclaration); 5642 const key = `${getTypeId(type)}|${context.flags}`; 5643 if (links) { 5644 links.serializedTypes ||= new Map(); 5645 } 5646 const cachedResult = links?.serializedTypes?.get(key); 5647 if (cachedResult) { 5648 if (cachedResult.truncating) { 5649 context.truncating = true; 5650 } 5651 context.approximateLength += cachedResult.addedLength; 5652 return deepCloneOrReuseNode(cachedResult) as TypeNode as T; 5653 } 5654 5655 let depth: number | undefined; 5656 if (id) { 5657 depth = context.symbolDepth!.get(id) || 0; 5658 if (depth > 10) { 5659 return createElidedInformationPlaceholder(context); 5660 } 5661 context.symbolDepth!.set(id, depth + 1); 5662 } 5663 context.visitedTypes.add(typeId); 5664 const startLength = context.approximateLength; 5665 const result = transform(type); 5666 const addedLength = context.approximateLength - startLength; 5667 if (!context.reportedDiagnostic && !context.encounteredError) { 5668 if (context.truncating) { 5669 (result as any).truncating = true; 5670 } 5671 (result as any).addedLength = addedLength; 5672 links?.serializedTypes?.set(key, result as TypeNode as TypeNode & {truncating?: boolean, addedLength: number}); 5673 } 5674 context.visitedTypes.delete(typeId); 5675 if (id) { 5676 context.symbolDepth!.set(id, depth!); 5677 } 5678 return result; 5679 5680 function deepCloneOrReuseNode(node: Node): Node { 5681 if (!nodeIsSynthesized(node) && getParseTreeNode(node) === node) { 5682 return node; 5683 } 5684 return setTextRange(factory.cloneNode(visitEachChild(node, deepCloneOrReuseNode, nullTransformationContext, deepCloneOrReuseNodes)), node); 5685 } 5686 5687 function deepCloneOrReuseNodes<T extends Node>(nodes: NodeArray<T>, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray<T>; 5688 function deepCloneOrReuseNodes<T extends Node>(nodes: NodeArray<T> | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray<T> | undefined; 5689 function deepCloneOrReuseNodes<T extends Node>(nodes: NodeArray<T> | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray<T> | undefined { 5690 if (nodes && nodes.length === 0) { 5691 // Ensure we explicitly make a copy of an empty array; visitNodes will not do this unless the array has elements, 5692 // which can lead to us reusing the same empty NodeArray more than once within the same AST during type noding. 5693 return setTextRange(factory.createNodeArray<T>(/*nodes*/ undefined, nodes.hasTrailingComma), nodes); 5694 } 5695 return visitNodes(nodes, visitor, test, start, count); 5696 } 5697 } 5698 5699 function createTypeNodeFromObjectType(type: ObjectType): TypeNode { 5700 if (isGenericMappedType(type) || (type as MappedType).containsError) { 5701 return createMappedTypeNodeFromType(type as MappedType); 5702 } 5703 5704 const resolved = resolveStructuredTypeMembers(type); 5705 if (!resolved.properties.length && !resolved.indexInfos.length) { 5706 if (!resolved.callSignatures.length && !resolved.constructSignatures.length) { 5707 context.approximateLength += 2; 5708 return setEmitFlags(factory.createTypeLiteralNode(/*members*/ undefined), EmitFlags.SingleLine); 5709 } 5710 5711 if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) { 5712 const signature = resolved.callSignatures[0]; 5713 const signatureNode = signatureToSignatureDeclarationHelper(signature, SyntaxKind.FunctionType, context) as FunctionTypeNode; 5714 return signatureNode; 5715 5716 } 5717 5718 if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) { 5719 const signature = resolved.constructSignatures[0]; 5720 const signatureNode = signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructorType, context) as ConstructorTypeNode; 5721 return signatureNode; 5722 } 5723 } 5724 5725 const abstractSignatures = filter(resolved.constructSignatures, signature => !!(signature.flags & SignatureFlags.Abstract)); 5726 if (some(abstractSignatures)) { 5727 const types = map(abstractSignatures, getOrCreateTypeFromSignature); 5728 // count the number of type elements excluding abstract constructors 5729 const typeElementCount = 5730 resolved.callSignatures.length + 5731 (resolved.constructSignatures.length - abstractSignatures.length) + 5732 resolved.indexInfos.length + 5733 // exclude `prototype` when writing a class expression as a type literal, as per 5734 // the logic in `createTypeNodesFromResolvedType`. 5735 (context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral ? 5736 countWhere(resolved.properties, p => !(p.flags & SymbolFlags.Prototype)) : 5737 length(resolved.properties)); 5738 // don't include an empty object literal if there were no other static-side 5739 // properties to write, i.e. `abstract class C { }` becomes `abstract new () => {}` 5740 // and not `(abstract new () => {}) & {}` 5741 if (typeElementCount) { 5742 // create a copy of the object type without any abstract construct signatures. 5743 types.push(getResolvedTypeWithoutAbstractConstructSignatures(resolved)); 5744 } 5745 return typeToTypeNodeHelper(getIntersectionType(types), context); 5746 } 5747 5748 const savedFlags = context.flags; 5749 context.flags |= NodeBuilderFlags.InObjectTypeLiteral; 5750 const members = createTypeNodesFromResolvedType(resolved); 5751 context.flags = savedFlags; 5752 const typeLiteralNode = factory.createTypeLiteralNode(members); 5753 context.approximateLength += 2; 5754 setEmitFlags(typeLiteralNode, (context.flags & NodeBuilderFlags.MultilineObjectLiterals) ? 0 : EmitFlags.SingleLine); 5755 return typeLiteralNode; 5756 } 5757 5758 function typeReferenceToTypeNode(type: TypeReference) { 5759 let typeArguments: readonly Type[] = getTypeArguments(type); 5760 if (type.target === globalArrayType || type.target === globalReadonlyArrayType) { 5761 if (context.flags & NodeBuilderFlags.WriteArrayAsGenericType) { 5762 const typeArgumentNode = typeToTypeNodeHelper(typeArguments[0], context); 5763 return factory.createTypeReferenceNode(type.target === globalArrayType ? "Array" : "ReadonlyArray", [typeArgumentNode]); 5764 } 5765 const elementType = typeToTypeNodeHelper(typeArguments[0], context); 5766 const arrayType = factory.createArrayTypeNode(elementType); 5767 return type.target === globalArrayType ? arrayType : factory.createTypeOperatorNode(SyntaxKind.ReadonlyKeyword, arrayType); 5768 } 5769 else if (type.target.objectFlags & ObjectFlags.Tuple) { 5770 typeArguments = sameMap(typeArguments, (t, i) => removeMissingType(t, !!((type.target as TupleType).elementFlags[i] & ElementFlags.Optional))); 5771 if (typeArguments.length > 0) { 5772 const arity = getTypeReferenceArity(type); 5773 const tupleConstituentNodes = mapToTypeNodes(typeArguments.slice(0, arity), context); 5774 if (tupleConstituentNodes) { 5775 if ((type.target as TupleType).labeledElementDeclarations) { 5776 for (let i = 0; i < tupleConstituentNodes.length; i++) { 5777 const flags = (type.target as TupleType).elementFlags[i]; 5778 tupleConstituentNodes[i] = factory.createNamedTupleMember( 5779 flags & ElementFlags.Variable ? factory.createToken(SyntaxKind.DotDotDotToken) : undefined, 5780 factory.createIdentifier(unescapeLeadingUnderscores(getTupleElementLabel((type.target as TupleType).labeledElementDeclarations![i]))), 5781 flags & ElementFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined, 5782 flags & ElementFlags.Rest ? factory.createArrayTypeNode(tupleConstituentNodes[i]) : 5783 tupleConstituentNodes[i] 5784 ); 5785 } 5786 } 5787 else { 5788 for (let i = 0; i < Math.min(arity, tupleConstituentNodes.length); i++) { 5789 const flags = (type.target as TupleType).elementFlags[i]; 5790 tupleConstituentNodes[i] = 5791 flags & ElementFlags.Variable ? factory.createRestTypeNode(flags & ElementFlags.Rest ? factory.createArrayTypeNode(tupleConstituentNodes[i]) : tupleConstituentNodes[i]) : 5792 flags & ElementFlags.Optional ? factory.createOptionalTypeNode(tupleConstituentNodes[i]) : 5793 tupleConstituentNodes[i]; 5794 } 5795 } 5796 const tupleTypeNode = setEmitFlags(factory.createTupleTypeNode(tupleConstituentNodes), EmitFlags.SingleLine); 5797 return (type.target as TupleType).readonly ? factory.createTypeOperatorNode(SyntaxKind.ReadonlyKeyword, tupleTypeNode) : tupleTypeNode; 5798 } 5799 } 5800 if (context.encounteredError || (context.flags & NodeBuilderFlags.AllowEmptyTuple)) { 5801 const tupleTypeNode = setEmitFlags(factory.createTupleTypeNode([]), EmitFlags.SingleLine); 5802 return (type.target as TupleType).readonly ? factory.createTypeOperatorNode(SyntaxKind.ReadonlyKeyword, tupleTypeNode) : tupleTypeNode; 5803 } 5804 context.encounteredError = true; 5805 return undefined!; // TODO: GH#18217 5806 } 5807 else if (context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral && 5808 type.symbol.valueDeclaration && 5809 isClassLike(type.symbol.valueDeclaration) && 5810 !isValueSymbolAccessible(type.symbol, context.enclosingDeclaration) 5811 ) { 5812 return createAnonymousTypeNode(type); 5813 } 5814 else { 5815 const outerTypeParameters = type.target.outerTypeParameters; 5816 let i = 0; 5817 let resultType: TypeReferenceNode | ImportTypeNode | undefined; 5818 if (outerTypeParameters) { 5819 const length = outerTypeParameters.length; 5820 while (i < length) { 5821 // Find group of type arguments for type parameters with the same declaring container. 5822 const start = i; 5823 const parent = getParentSymbolOfTypeParameter(outerTypeParameters[i])!; 5824 do { 5825 i++; 5826 } while (i < length && getParentSymbolOfTypeParameter(outerTypeParameters[i]) === parent); 5827 // When type parameters are their own type arguments for the whole group (i.e. we have 5828 // the default outer type arguments), we don't show the group. 5829 if (!rangeEquals(outerTypeParameters, typeArguments, start, i)) { 5830 const typeArgumentSlice = mapToTypeNodes(typeArguments.slice(start, i), context); 5831 const flags = context.flags; 5832 context.flags |= NodeBuilderFlags.ForbidIndexedAccessSymbolReferences; 5833 const ref = symbolToTypeNode(parent, context, SymbolFlags.Type, typeArgumentSlice) as TypeReferenceNode | ImportTypeNode; 5834 context.flags = flags; 5835 resultType = !resultType ? ref : appendReferenceToType(resultType, ref as TypeReferenceNode); 5836 } 5837 } 5838 } 5839 let typeArgumentNodes: readonly TypeNode[] | undefined; 5840 if (typeArguments.length > 0) { 5841 const typeParameterCount = (type.target.typeParameters || emptyArray).length; 5842 typeArgumentNodes = mapToTypeNodes(typeArguments.slice(i, typeParameterCount), context); 5843 } 5844 const flags = context.flags; 5845 context.flags |= NodeBuilderFlags.ForbidIndexedAccessSymbolReferences; 5846 const finalRef = symbolToTypeNode(type.symbol, context, SymbolFlags.Type, typeArgumentNodes); 5847 context.flags = flags; 5848 return !resultType ? finalRef : appendReferenceToType(resultType, finalRef as TypeReferenceNode); 5849 } 5850 } 5851 5852 5853 function appendReferenceToType(root: TypeReferenceNode | ImportTypeNode, ref: TypeReferenceNode): TypeReferenceNode | ImportTypeNode { 5854 if (isImportTypeNode(root)) { 5855 // first shift type arguments 5856 let typeArguments = root.typeArguments; 5857 let qualifier = root.qualifier; 5858 if (qualifier) { 5859 if (isIdentifier(qualifier)) { 5860 qualifier = factory.updateIdentifier(qualifier, typeArguments); 5861 } 5862 else { 5863 qualifier = factory.updateQualifiedName(qualifier, 5864 qualifier.left, 5865 factory.updateIdentifier(qualifier.right, typeArguments)); 5866 } 5867 } 5868 typeArguments = ref.typeArguments; 5869 // then move qualifiers 5870 const ids = getAccessStack(ref); 5871 for (const id of ids) { 5872 qualifier = qualifier ? factory.createQualifiedName(qualifier, id) : id; 5873 } 5874 return factory.updateImportTypeNode( 5875 root, 5876 root.argument, 5877 root.assertions, 5878 qualifier, 5879 typeArguments, 5880 root.isTypeOf); 5881 } 5882 else { 5883 // first shift type arguments 5884 let typeArguments = root.typeArguments; 5885 let typeName = root.typeName; 5886 if (isIdentifier(typeName)) { 5887 typeName = factory.updateIdentifier(typeName, typeArguments); 5888 } 5889 else { 5890 typeName = factory.updateQualifiedName(typeName, 5891 typeName.left, 5892 factory.updateIdentifier(typeName.right, typeArguments)); 5893 } 5894 typeArguments = ref.typeArguments; 5895 // then move qualifiers 5896 const ids = getAccessStack(ref); 5897 for (const id of ids) { 5898 typeName = factory.createQualifiedName(typeName, id); 5899 } 5900 return factory.updateTypeReferenceNode( 5901 root, 5902 typeName, 5903 typeArguments); 5904 } 5905 } 5906 5907 function getAccessStack(ref: TypeReferenceNode): Identifier[] { 5908 let state = ref.typeName; 5909 const ids = []; 5910 while (!isIdentifier(state)) { 5911 ids.unshift(state.right); 5912 state = state.left; 5913 } 5914 ids.unshift(state); 5915 return ids; 5916 } 5917 5918 function createTypeNodesFromResolvedType(resolvedType: ResolvedType): TypeElement[] | undefined { 5919 if (checkTruncationLength(context)) { 5920 return [factory.createPropertySignature(/*modifiers*/ undefined, "...", /*questionToken*/ undefined, /*type*/ undefined)]; 5921 } 5922 const typeElements: TypeElement[] = []; 5923 for (const signature of resolvedType.callSignatures) { 5924 typeElements.push(signatureToSignatureDeclarationHelper(signature, SyntaxKind.CallSignature, context) as CallSignatureDeclaration); 5925 } 5926 for (const signature of resolvedType.constructSignatures) { 5927 if (signature.flags & SignatureFlags.Abstract) continue; 5928 typeElements.push(signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructSignature, context) as ConstructSignatureDeclaration); 5929 } 5930 for (const info of resolvedType.indexInfos) { 5931 typeElements.push(indexInfoToIndexSignatureDeclarationHelper(info, context, resolvedType.objectFlags & ObjectFlags.ReverseMapped ? createElidedInformationPlaceholder(context) : undefined)); 5932 } 5933 5934 const properties = resolvedType.properties; 5935 if (!properties) { 5936 return typeElements; 5937 } 5938 5939 let i = 0; 5940 for (const propertySymbol of properties) { 5941 i++; 5942 if (context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral) { 5943 if (propertySymbol.flags & SymbolFlags.Prototype) { 5944 continue; 5945 } 5946 if (getDeclarationModifierFlagsFromSymbol(propertySymbol) & (ModifierFlags.Private | ModifierFlags.Protected) && context.tracker.reportPrivateInBaseOfClassExpression) { 5947 context.tracker.reportPrivateInBaseOfClassExpression(unescapeLeadingUnderscores(propertySymbol.escapedName)); 5948 } 5949 } 5950 if (checkTruncationLength(context) && (i + 2 < properties.length - 1)) { 5951 typeElements.push(factory.createPropertySignature(/*modifiers*/ undefined, `... ${properties.length - i} more ...`, /*questionToken*/ undefined, /*type*/ undefined)); 5952 addPropertyToElementList(properties[properties.length - 1], context, typeElements); 5953 break; 5954 } 5955 addPropertyToElementList(propertySymbol, context, typeElements); 5956 5957 } 5958 return typeElements.length ? typeElements : undefined; 5959 } 5960 } 5961 5962 function createElidedInformationPlaceholder(context: NodeBuilderContext) { 5963 context.approximateLength += 3; 5964 if (!(context.flags & NodeBuilderFlags.NoTruncation)) { 5965 return factory.createTypeReferenceNode(factory.createIdentifier("..."), /*typeArguments*/ undefined); 5966 } 5967 return factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); 5968 } 5969 5970 function shouldUsePlaceholderForProperty(propertySymbol: Symbol, context: NodeBuilderContext) { 5971 // Use placeholders for reverse mapped types we've either already descended into, or which 5972 // are nested reverse mappings within a mapping over a non-anonymous type. The later is a restriction mostly just to 5973 // reduce the blowup in printback size from doing, eg, a deep reverse mapping over `Window`. 5974 // Since anonymous types usually come from expressions, this allows us to preserve the output 5975 // for deep mappings which likely come from expressions, while truncating those parts which 5976 // come from mappings over library functions. 5977 return !!(getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped) 5978 && ( 5979 contains(context.reverseMappedStack, propertySymbol as ReverseMappedSymbol) 5980 || ( 5981 context.reverseMappedStack?.[0] 5982 && !(getObjectFlags(last(context.reverseMappedStack).propertyType) & ObjectFlags.Anonymous) 5983 ) 5984 ); 5985 } 5986 5987 function addPropertyToElementList(propertySymbol: Symbol, context: NodeBuilderContext, typeElements: TypeElement[]) { 5988 const propertyIsReverseMapped = !!(getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped); 5989 const propertyType = shouldUsePlaceholderForProperty(propertySymbol, context) ? 5990 anyType : getNonMissingTypeOfSymbol(propertySymbol); 5991 const saveEnclosingDeclaration = context.enclosingDeclaration; 5992 context.enclosingDeclaration = undefined; 5993 if (context.tracker.trackSymbol && isLateBoundName(propertySymbol.escapedName)) { 5994 if (propertySymbol.declarations) { 5995 const decl = first(propertySymbol.declarations); 5996 if (hasLateBindableName(decl)) { 5997 if (isBinaryExpression(decl)) { 5998 const name = getNameOfDeclaration(decl); 5999 if (name && isElementAccessExpression(name) && isPropertyAccessEntityNameExpression(name.argumentExpression)) { 6000 trackComputedName(name.argumentExpression, saveEnclosingDeclaration, context); 6001 } 6002 } 6003 else { 6004 trackComputedName(decl.name.expression, saveEnclosingDeclaration, context); 6005 } 6006 } 6007 } 6008 else if (context.tracker?.reportNonSerializableProperty) { 6009 context.tracker.reportNonSerializableProperty(symbolToString(propertySymbol)); 6010 } 6011 } 6012 context.enclosingDeclaration = propertySymbol.valueDeclaration || propertySymbol.declarations?.[0] || saveEnclosingDeclaration; 6013 const propertyName = getPropertyNameNodeForSymbol(propertySymbol, context); 6014 context.enclosingDeclaration = saveEnclosingDeclaration; 6015 context.approximateLength += (symbolName(propertySymbol).length + 1); 6016 const optionalToken = propertySymbol.flags & SymbolFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined; 6017 if (propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(propertyType).length && !isReadonlySymbol(propertySymbol)) { 6018 const signatures = getSignaturesOfType(filterType(propertyType, t => !(t.flags & TypeFlags.Undefined)), SignatureKind.Call); 6019 for (const signature of signatures) { 6020 const methodDeclaration = signatureToSignatureDeclarationHelper(signature, SyntaxKind.MethodSignature, context, { name: propertyName, questionToken: optionalToken }) as MethodSignature; 6021 typeElements.push(preserveCommentsOn(methodDeclaration)); 6022 } 6023 } 6024 else { 6025 let propertyTypeNode: TypeNode; 6026 if (shouldUsePlaceholderForProperty(propertySymbol, context)) { 6027 propertyTypeNode = createElidedInformationPlaceholder(context); 6028 } 6029 else { 6030 if (propertyIsReverseMapped) { 6031 context.reverseMappedStack ||= []; 6032 context.reverseMappedStack.push(propertySymbol as ReverseMappedSymbol); 6033 } 6034 propertyTypeNode = propertyType ? serializeTypeForDeclaration(context, propertyType, propertySymbol, saveEnclosingDeclaration) : factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); 6035 if (propertyIsReverseMapped) { 6036 context.reverseMappedStack!.pop(); 6037 } 6038 } 6039 6040 const modifiers = isReadonlySymbol(propertySymbol) ? [factory.createToken(SyntaxKind.ReadonlyKeyword)] : undefined; 6041 if (modifiers) { 6042 context.approximateLength += 9; 6043 } 6044 const propertySignature = factory.createPropertySignature( 6045 modifiers, 6046 propertyName, 6047 optionalToken, 6048 propertyTypeNode); 6049 6050 typeElements.push(preserveCommentsOn(propertySignature)); 6051 } 6052 6053 function preserveCommentsOn<T extends Node>(node: T) { 6054 if (some(propertySymbol.declarations, d => d.kind === SyntaxKind.JSDocPropertyTag)) { 6055 const d = propertySymbol.declarations?.find(d => d.kind === SyntaxKind.JSDocPropertyTag)! as JSDocPropertyTag; 6056 const commentText = getTextOfJSDocComment(d.comment); 6057 if (commentText) { 6058 setSyntheticLeadingComments(node, [{ kind: SyntaxKind.MultiLineCommentTrivia, text: "*\n * " + commentText.replace(/\n/g, "\n * ") + "\n ", pos: -1, end: -1, hasTrailingNewLine: true }]); 6059 } 6060 } 6061 else if (propertySymbol.valueDeclaration) { 6062 // Copy comments to node for declaration emit 6063 setCommentRange(node, propertySymbol.valueDeclaration); 6064 } 6065 return node; 6066 } 6067 } 6068 6069 function mapToTypeNodes(types: readonly Type[] | undefined, context: NodeBuilderContext, isBareList?: boolean): TypeNode[] | undefined { 6070 if (some(types)) { 6071 if (checkTruncationLength(context)) { 6072 if (!isBareList) { 6073 return [factory.createTypeReferenceNode("...", /*typeArguments*/ undefined)]; 6074 } 6075 else if (types.length > 2) { 6076 return [ 6077 typeToTypeNodeHelper(types[0], context), 6078 factory.createTypeReferenceNode(`... ${types.length - 2} more ...`, /*typeArguments*/ undefined), 6079 typeToTypeNodeHelper(types[types.length - 1], context) 6080 ]; 6081 } 6082 } 6083 const mayHaveNameCollisions = !(context.flags & NodeBuilderFlags.UseFullyQualifiedType); 6084 /** Map from type reference identifier text to [type, index in `result` where the type node is] */ 6085 const seenNames = mayHaveNameCollisions ? createUnderscoreEscapedMultiMap<[Type, number]>() : undefined; 6086 const result: TypeNode[] = []; 6087 let i = 0; 6088 for (const type of types) { 6089 i++; 6090 if (checkTruncationLength(context) && (i + 2 < types.length - 1)) { 6091 result.push(factory.createTypeReferenceNode(`... ${types.length - i} more ...`, /*typeArguments*/ undefined)); 6092 const typeNode = typeToTypeNodeHelper(types[types.length - 1], context); 6093 if (typeNode) { 6094 result.push(typeNode); 6095 } 6096 break; 6097 } 6098 context.approximateLength += 2; // Account for whitespace + separator 6099 const typeNode = typeToTypeNodeHelper(type, context); 6100 if (typeNode) { 6101 result.push(typeNode); 6102 if (seenNames && isIdentifierTypeReference(typeNode)) { 6103 seenNames.add(typeNode.typeName.escapedText, [type, result.length - 1]); 6104 } 6105 } 6106 } 6107 6108 if (seenNames) { 6109 // To avoid printing types like `[Foo, Foo]` or `Bar & Bar` where 6110 // occurrences of the same name actually come from different 6111 // namespaces, go through the single-identifier type reference nodes 6112 // we just generated, and see if any names were generated more than 6113 // once while referring to different types. If so, regenerate the 6114 // type node for each entry by that name with the 6115 // `UseFullyQualifiedType` flag enabled. 6116 const saveContextFlags = context.flags; 6117 context.flags |= NodeBuilderFlags.UseFullyQualifiedType; 6118 seenNames.forEach(types => { 6119 if (!arrayIsHomogeneous(types, ([a], [b]) => typesAreSameReference(a, b))) { 6120 for (const [type, resultIndex] of types) { 6121 result[resultIndex] = typeToTypeNodeHelper(type, context); 6122 } 6123 } 6124 }); 6125 context.flags = saveContextFlags; 6126 } 6127 6128 return result; 6129 } 6130 } 6131 6132 function typesAreSameReference(a: Type, b: Type): boolean { 6133 return a === b 6134 || !!a.symbol && a.symbol === b.symbol 6135 || !!a.aliasSymbol && a.aliasSymbol === b.aliasSymbol; 6136 } 6137 6138 function indexInfoToIndexSignatureDeclarationHelper(indexInfo: IndexInfo, context: NodeBuilderContext, typeNode: TypeNode | undefined): IndexSignatureDeclaration { 6139 const name = getNameFromIndexInfo(indexInfo) || "x"; 6140 const indexerTypeNode = typeToTypeNodeHelper(indexInfo.keyType, context); 6141 6142 const indexingParameter = factory.createParameterDeclaration( 6143 /*modifiers*/ undefined, 6144 /*dotDotDotToken*/ undefined, 6145 name, 6146 /*questionToken*/ undefined, 6147 indexerTypeNode, 6148 /*initializer*/ undefined); 6149 if (!typeNode) { 6150 typeNode = typeToTypeNodeHelper(indexInfo.type || anyType, context); 6151 } 6152 if (!indexInfo.type && !(context.flags & NodeBuilderFlags.AllowEmptyIndexInfoType)) { 6153 context.encounteredError = true; 6154 } 6155 context.approximateLength += (name.length + 4); 6156 return factory.createIndexSignature( 6157 indexInfo.isReadonly ? [factory.createToken(SyntaxKind.ReadonlyKeyword)] : undefined, 6158 [indexingParameter], 6159 typeNode); 6160 } 6161 6162 interface SignatureToSignatureDeclarationOptions { 6163 modifiers?: readonly Modifier[]; 6164 name?: PropertyName; 6165 questionToken?: QuestionToken; 6166 privateSymbolVisitor?: (s: Symbol) => void; 6167 bundledImports?: boolean; 6168 } 6169 6170 function signatureToSignatureDeclarationHelper(signature: Signature, kind: SignatureDeclaration["kind"], context: NodeBuilderContext, options?: SignatureToSignatureDeclarationOptions): SignatureDeclaration { 6171 const suppressAny = context.flags & NodeBuilderFlags.SuppressAnyReturnType; 6172 if (suppressAny) context.flags &= ~NodeBuilderFlags.SuppressAnyReturnType; // suppress only toplevel `any`s 6173 context.approximateLength += 3; // Usually a signature contributes a few more characters than this, but 3 is the minimum 6174 let typeParameters: TypeParameterDeclaration[] | undefined; 6175 let typeArguments: TypeNode[] | undefined; 6176 if (context.flags & NodeBuilderFlags.WriteTypeArgumentsOfSignature && signature.target && signature.mapper && signature.target.typeParameters) { 6177 typeArguments = signature.target.typeParameters.map(parameter => typeToTypeNodeHelper(instantiateType(parameter, signature.mapper), context)); 6178 } 6179 else { 6180 typeParameters = signature.typeParameters && signature.typeParameters.map(parameter => typeParameterToDeclaration(parameter, context)); 6181 } 6182 6183 const expandedParams = getExpandedParameters(signature, /*skipUnionExpanding*/ true)[0]; 6184 // If the expanded parameter list had a variadic in a non-trailing position, don't expand it 6185 const parameters = (some(expandedParams, p => p !== expandedParams[expandedParams.length - 1] && !!(getCheckFlags(p) & CheckFlags.RestParameter)) ? signature.parameters : expandedParams).map(parameter => symbolToParameterDeclaration(parameter, context, kind === SyntaxKind.Constructor, options?.privateSymbolVisitor, options?.bundledImports)); 6186 const thisParameter = context.flags & NodeBuilderFlags.OmitThisParameter ? undefined : tryGetThisParameterDeclaration(signature, context); 6187 if (thisParameter) { 6188 parameters.unshift(thisParameter); 6189 } 6190 6191 let returnTypeNode: TypeNode | undefined; 6192 const typePredicate = getTypePredicateOfSignature(signature); 6193 if (typePredicate) { 6194 const assertsModifier = typePredicate.kind === TypePredicateKind.AssertsThis || typePredicate.kind === TypePredicateKind.AssertsIdentifier ? 6195 factory.createToken(SyntaxKind.AssertsKeyword) : 6196 undefined; 6197 const parameterName = typePredicate.kind === TypePredicateKind.Identifier || typePredicate.kind === TypePredicateKind.AssertsIdentifier ? 6198 setEmitFlags(factory.createIdentifier(typePredicate.parameterName), EmitFlags.NoAsciiEscaping) : 6199 factory.createThisTypeNode(); 6200 const typeNode = typePredicate.type && typeToTypeNodeHelper(typePredicate.type, context); 6201 returnTypeNode = factory.createTypePredicateNode(assertsModifier, parameterName, typeNode); 6202 } 6203 else { 6204 const returnType = getReturnTypeOfSignature(signature); 6205 if (returnType && !(suppressAny && isTypeAny(returnType))) { 6206 returnTypeNode = serializeReturnTypeForSignature(context, returnType, signature, options?.privateSymbolVisitor, options?.bundledImports); 6207 } 6208 else if (!suppressAny) { 6209 returnTypeNode = factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); 6210 } 6211 } 6212 let modifiers = options?.modifiers; 6213 if ((kind === SyntaxKind.ConstructorType) && signature.flags & SignatureFlags.Abstract) { 6214 const flags = modifiersToFlags(modifiers); 6215 modifiers = factory.createModifiersFromModifierFlags(flags | ModifierFlags.Abstract); 6216 } 6217 6218 const node = 6219 kind === SyntaxKind.CallSignature ? factory.createCallSignature(typeParameters, parameters, returnTypeNode) : 6220 kind === SyntaxKind.ConstructSignature ? factory.createConstructSignature(typeParameters, parameters, returnTypeNode) : 6221 kind === SyntaxKind.MethodSignature ? factory.createMethodSignature(modifiers, options?.name ?? factory.createIdentifier(""), options?.questionToken, typeParameters, parameters, returnTypeNode) : 6222 kind === SyntaxKind.MethodDeclaration ? factory.createMethodDeclaration(modifiers, /*asteriskToken*/ undefined, options?.name ?? factory.createIdentifier(""), /*questionToken*/ undefined, typeParameters, parameters, returnTypeNode, /*body*/ undefined) : 6223 kind === SyntaxKind.Constructor ? factory.createConstructorDeclaration(modifiers, parameters, /*body*/ undefined) : 6224 kind === SyntaxKind.GetAccessor ? factory.createGetAccessorDeclaration(modifiers, options?.name ?? factory.createIdentifier(""), parameters, returnTypeNode, /*body*/ undefined) : 6225 kind === SyntaxKind.SetAccessor ? factory.createSetAccessorDeclaration(modifiers, options?.name ?? factory.createIdentifier(""), parameters, /*body*/ undefined) : 6226 kind === SyntaxKind.IndexSignature ? factory.createIndexSignature(modifiers, parameters, returnTypeNode) : 6227 kind === SyntaxKind.JSDocFunctionType ? factory.createJSDocFunctionType(parameters, returnTypeNode) : 6228 kind === SyntaxKind.FunctionType ? factory.createFunctionTypeNode(typeParameters, parameters, returnTypeNode ?? factory.createTypeReferenceNode(factory.createIdentifier(""))) : 6229 kind === SyntaxKind.ConstructorType ? factory.createConstructorTypeNode(modifiers, typeParameters, parameters, returnTypeNode ?? factory.createTypeReferenceNode(factory.createIdentifier(""))) : 6230 kind === SyntaxKind.FunctionDeclaration ? factory.createFunctionDeclaration(modifiers, /*asteriskToken*/ undefined, options?.name ? cast(options.name, isIdentifier) : factory.createIdentifier(""), typeParameters, parameters, returnTypeNode, /*body*/ undefined) : 6231 kind === SyntaxKind.FunctionExpression ? factory.createFunctionExpression(modifiers, /*asteriskToken*/ undefined, options?.name ? cast(options.name, isIdentifier) : factory.createIdentifier(""), typeParameters, parameters, returnTypeNode, factory.createBlock([])) : 6232 kind === SyntaxKind.ArrowFunction ? factory.createArrowFunction(modifiers, typeParameters, parameters, returnTypeNode, /*equalsGreaterThanToken*/ undefined, factory.createBlock([])) : 6233 Debug.assertNever(kind); 6234 6235 if (typeArguments) { 6236 node.typeArguments = factory.createNodeArray(typeArguments); 6237 } 6238 6239 return node; 6240 } 6241 6242 function tryGetThisParameterDeclaration(signature: Signature, context: NodeBuilderContext) { 6243 if (signature.thisParameter) { 6244 return symbolToParameterDeclaration(signature.thisParameter, context); 6245 } 6246 if (signature.declaration) { 6247 const thisTag = getJSDocThisTag(signature.declaration); 6248 if (thisTag && thisTag.typeExpression) { 6249 return factory.createParameterDeclaration( 6250 /* modifiers */ undefined, 6251 /* dotDotDotToken */ undefined, 6252 "this", 6253 /* questionToken */ undefined, 6254 typeToTypeNodeHelper(getTypeFromTypeNode(thisTag.typeExpression), context) 6255 ); 6256 } 6257 } 6258 } 6259 6260 function typeParameterToDeclarationWithConstraint(type: TypeParameter, context: NodeBuilderContext, constraintNode: TypeNode | undefined): TypeParameterDeclaration { 6261 const savedContextFlags = context.flags; 6262 context.flags &= ~NodeBuilderFlags.WriteTypeParametersInQualifiedName; // Avoids potential infinite loop when building for a claimspace with a generic 6263 const modifiers = factory.createModifiersFromModifierFlags(getVarianceModifiers(type)); 6264 const name = typeParameterToName(type, context); 6265 const defaultParameter = getDefaultFromTypeParameter(type); 6266 const defaultParameterNode = defaultParameter && typeToTypeNodeHelper(defaultParameter, context); 6267 context.flags = savedContextFlags; 6268 return factory.createTypeParameterDeclaration(modifiers, name, constraintNode, defaultParameterNode); 6269 } 6270 6271 function typeParameterToDeclaration(type: TypeParameter, context: NodeBuilderContext, constraint = getConstraintOfTypeParameter(type)): TypeParameterDeclaration { 6272 const constraintNode = constraint && typeToTypeNodeHelper(constraint, context); 6273 return typeParameterToDeclarationWithConstraint(type, context, constraintNode); 6274 } 6275 6276 function symbolToParameterDeclaration(parameterSymbol: Symbol, context: NodeBuilderContext, preserveModifierFlags?: boolean, privateSymbolVisitor?: (s: Symbol) => void, bundledImports?: boolean): ParameterDeclaration { 6277 let parameterDeclaration: ParameterDeclaration | JSDocParameterTag | undefined = getDeclarationOfKind<ParameterDeclaration>(parameterSymbol, SyntaxKind.Parameter); 6278 if (!parameterDeclaration && !isTransientSymbol(parameterSymbol)) { 6279 parameterDeclaration = getDeclarationOfKind<JSDocParameterTag>(parameterSymbol, SyntaxKind.JSDocParameterTag); 6280 } 6281 6282 let parameterType = getTypeOfSymbol(parameterSymbol); 6283 if (parameterDeclaration && isRequiredInitializedParameter(parameterDeclaration)) { 6284 parameterType = getOptionalType(parameterType); 6285 } 6286 const parameterTypeNode = serializeTypeForDeclaration(context, parameterType, parameterSymbol, context.enclosingDeclaration, privateSymbolVisitor, bundledImports); 6287 6288 const modifiers = !(context.flags & NodeBuilderFlags.OmitParameterModifiers) && preserveModifierFlags && parameterDeclaration && canHaveModifiers(parameterDeclaration) ? map(getModifiers(parameterDeclaration), factory.cloneNode) : undefined; 6289 const isRest = parameterDeclaration && isRestParameter(parameterDeclaration) || getCheckFlags(parameterSymbol) & CheckFlags.RestParameter; 6290 const dotDotDotToken = isRest ? factory.createToken(SyntaxKind.DotDotDotToken) : undefined; 6291 const name = parameterDeclaration ? parameterDeclaration.name ? 6292 parameterDeclaration.name.kind === SyntaxKind.Identifier ? setEmitFlags(factory.cloneNode(parameterDeclaration.name), EmitFlags.NoAsciiEscaping) : 6293 parameterDeclaration.name.kind === SyntaxKind.QualifiedName ? setEmitFlags(factory.cloneNode(parameterDeclaration.name.right), EmitFlags.NoAsciiEscaping) : 6294 cloneBindingName(parameterDeclaration.name) : 6295 symbolName(parameterSymbol) : 6296 symbolName(parameterSymbol); 6297 const isOptional = parameterDeclaration && isOptionalParameter(parameterDeclaration) || getCheckFlags(parameterSymbol) & CheckFlags.OptionalParameter; 6298 const questionToken = isOptional ? factory.createToken(SyntaxKind.QuestionToken) : undefined; 6299 const parameterNode = factory.createParameterDeclaration( 6300 modifiers, 6301 dotDotDotToken, 6302 name, 6303 questionToken, 6304 parameterTypeNode, 6305 /*initializer*/ undefined); 6306 context.approximateLength += symbolName(parameterSymbol).length + 3; 6307 return parameterNode; 6308 6309 function cloneBindingName(node: BindingName): BindingName { 6310 return elideInitializerAndSetEmitFlags(node) as BindingName; 6311 function elideInitializerAndSetEmitFlags(node: Node): Node { 6312 if (context.tracker.trackSymbol && isComputedPropertyName(node) && isLateBindableName(node)) { 6313 trackComputedName(node.expression, context.enclosingDeclaration, context); 6314 } 6315 let visited = visitEachChild(node, elideInitializerAndSetEmitFlags, nullTransformationContext, /*nodesVisitor*/ undefined, elideInitializerAndSetEmitFlags)!; 6316 if (isBindingElement(visited)) { 6317 visited = factory.updateBindingElement( 6318 visited, 6319 visited.dotDotDotToken, 6320 visited.propertyName, 6321 visited.name, 6322 /*initializer*/ undefined); 6323 } 6324 if (!nodeIsSynthesized(visited)) { 6325 visited = factory.cloneNode(visited); 6326 } 6327 return setEmitFlags(visited, EmitFlags.SingleLine | EmitFlags.NoAsciiEscaping); 6328 } 6329 } 6330 } 6331 6332 function trackComputedName(accessExpression: EntityNameOrEntityNameExpression, enclosingDeclaration: Node | undefined, context: NodeBuilderContext) { 6333 if (!context.tracker.trackSymbol) return; 6334 // get symbol of the first identifier of the entityName 6335 const firstIdentifier = getFirstIdentifier(accessExpression); 6336 const name = resolveName(firstIdentifier, firstIdentifier.escapedText, SymbolFlags.Value | SymbolFlags.ExportValue, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ true); 6337 if (name) { 6338 context.tracker.trackSymbol(name, enclosingDeclaration, SymbolFlags.Value); 6339 } 6340 } 6341 6342 function lookupSymbolChain(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, yieldModuleSymbol?: boolean) { 6343 context.tracker.trackSymbol!(symbol, context.enclosingDeclaration, meaning); // TODO: GH#18217 6344 return lookupSymbolChainWorker(symbol, context, meaning, yieldModuleSymbol); 6345 } 6346 6347 function lookupSymbolChainWorker(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, yieldModuleSymbol?: boolean) { 6348 // Try to get qualified name if the symbol is not a type parameter and there is an enclosing declaration. 6349 let chain: Symbol[]; 6350 const isTypeParameter = symbol.flags & SymbolFlags.TypeParameter; 6351 if (!isTypeParameter && (context.enclosingDeclaration || context.flags & NodeBuilderFlags.UseFullyQualifiedType) && !(context.flags & NodeBuilderFlags.DoNotIncludeSymbolChain)) { 6352 chain = Debug.checkDefined(getSymbolChain(symbol, meaning, /*endOfChain*/ true)); 6353 Debug.assert(chain && chain.length > 0); 6354 } 6355 else { 6356 chain = [symbol]; 6357 } 6358 return chain; 6359 6360 /** @param endOfChain Set to false for recursive calls; non-recursive calls should always output something. */ 6361 function getSymbolChain(symbol: Symbol, meaning: SymbolFlags, endOfChain: boolean): Symbol[] | undefined { 6362 let accessibleSymbolChain = getAccessibleSymbolChain(symbol, context.enclosingDeclaration, meaning, !!(context.flags & NodeBuilderFlags.UseOnlyExternalAliasing)); 6363 let parentSpecifiers: (string | undefined)[]; 6364 if (!accessibleSymbolChain || 6365 needsQualification(accessibleSymbolChain[0], context.enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning))) { 6366 6367 // Go up and add our parent. 6368 const parents = getContainersOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol, context.enclosingDeclaration, meaning); 6369 if (length(parents)) { 6370 parentSpecifiers = parents!.map(symbol => 6371 some(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol) 6372 ? getSpecifierForModuleSymbol(symbol, context) 6373 : undefined); 6374 const indices = parents!.map((_, i) => i); 6375 indices.sort(sortByBestName); 6376 const sortedParents = indices.map(i => parents![i]); 6377 for (const parent of sortedParents) { 6378 const parentChain = getSymbolChain(parent, getQualifiedLeftMeaning(meaning), /*endOfChain*/ false); 6379 if (parentChain) { 6380 if (parent.exports && parent.exports.get(InternalSymbolName.ExportEquals) && 6381 getSymbolIfSameReference(parent.exports.get(InternalSymbolName.ExportEquals)!, symbol)) { 6382 // parentChain root _is_ symbol - symbol is a module export=, so it kinda looks like it's own parent 6383 // No need to lookup an alias for the symbol in itself 6384 accessibleSymbolChain = parentChain; 6385 break; 6386 } 6387 accessibleSymbolChain = parentChain.concat(accessibleSymbolChain || [getAliasForSymbolInContainer(parent, symbol) || symbol]); 6388 break; 6389 } 6390 } 6391 } 6392 } 6393 6394 if (accessibleSymbolChain) { 6395 return accessibleSymbolChain; 6396 } 6397 if ( 6398 // If this is the last part of outputting the symbol, always output. The cases apply only to parent symbols. 6399 endOfChain || 6400 // If a parent symbol is an anonymous type, don't write it. 6401 !(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral))) { 6402 // If a parent symbol is an external module, don't write it. (We prefer just `x` vs `"foo/bar".x`.) 6403 if (!endOfChain && !yieldModuleSymbol && !!forEach(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol)) { 6404 return; 6405 } 6406 return [symbol]; 6407 } 6408 6409 function sortByBestName(a: number, b: number) { 6410 const specifierA = parentSpecifiers[a]; 6411 const specifierB = parentSpecifiers[b]; 6412 if (specifierA && specifierB) { 6413 const isBRelative = pathIsRelative(specifierB); 6414 if (pathIsRelative(specifierA) === isBRelative) { 6415 // Both relative or both non-relative, sort by number of parts 6416 return moduleSpecifiers.countPathComponents(specifierA) - moduleSpecifiers.countPathComponents(specifierB); 6417 } 6418 if (isBRelative) { 6419 // A is non-relative, B is relative: prefer A 6420 return -1; 6421 } 6422 // A is relative, B is non-relative: prefer B 6423 return 1; 6424 } 6425 return 0; 6426 } 6427 } 6428 } 6429 6430 function typeParametersToTypeParameterDeclarations(symbol: Symbol, context: NodeBuilderContext) { 6431 let typeParameterNodes: NodeArray<TypeParameterDeclaration> | undefined; 6432 const targetSymbol = getTargetSymbol(symbol); 6433 if (targetSymbol.flags & (SymbolFlags.Class | SymbolFlags.Interface | SymbolFlags.TypeAlias)) { 6434 typeParameterNodes = factory.createNodeArray(map(getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol), tp => typeParameterToDeclaration(tp, context))); 6435 } 6436 return typeParameterNodes; 6437 } 6438 6439 function lookupTypeParameterNodes(chain: Symbol[], index: number, context: NodeBuilderContext) { 6440 Debug.assert(chain && 0 <= index && index < chain.length); 6441 const symbol = chain[index]; 6442 const symbolId = getSymbolId(symbol); 6443 if (context.typeParameterSymbolList?.has(symbolId)) { 6444 return undefined; 6445 } 6446 (context.typeParameterSymbolList || (context.typeParameterSymbolList = new Set())).add(symbolId); 6447 let typeParameterNodes: readonly TypeNode[] | readonly TypeParameterDeclaration[] | undefined; 6448 if (context.flags & NodeBuilderFlags.WriteTypeParametersInQualifiedName && index < (chain.length - 1)) { 6449 const parentSymbol = symbol; 6450 const nextSymbol = chain[index + 1]; 6451 if (getCheckFlags(nextSymbol) & CheckFlags.Instantiated) { 6452 const params = getTypeParametersOfClassOrInterface( 6453 parentSymbol.flags & SymbolFlags.Alias ? resolveAlias(parentSymbol) : parentSymbol 6454 ); 6455 typeParameterNodes = mapToTypeNodes(map(params, t => getMappedType(t, (nextSymbol as TransientSymbol).mapper!)), context); 6456 } 6457 else { 6458 typeParameterNodes = typeParametersToTypeParameterDeclarations(symbol, context); 6459 } 6460 } 6461 return typeParameterNodes; 6462 } 6463 6464 /** 6465 * Given A[B][C][D], finds A[B] 6466 */ 6467 function getTopmostIndexedAccessType(top: IndexedAccessTypeNode): IndexedAccessTypeNode { 6468 if (isIndexedAccessTypeNode(top.objectType)) { 6469 return getTopmostIndexedAccessType(top.objectType); 6470 } 6471 return top; 6472 } 6473 6474 function getSpecifierForModuleSymbol(symbol: Symbol, context: NodeBuilderContext, overrideImportMode?: SourceFile["impliedNodeFormat"]) { 6475 let file = getDeclarationOfKind<SourceFile>(symbol, SyntaxKind.SourceFile); 6476 if (!file) { 6477 const equivalentFileSymbol = firstDefined(symbol.declarations, d => getFileSymbolIfFileSymbolExportEqualsContainer(d, symbol)); 6478 if (equivalentFileSymbol) { 6479 file = getDeclarationOfKind<SourceFile>(equivalentFileSymbol, SyntaxKind.SourceFile); 6480 } 6481 } 6482 if (file && file.moduleName !== undefined) { 6483 // Use the amd name if it is available 6484 return file.moduleName; 6485 } 6486 if (!file) { 6487 if (context.tracker.trackReferencedAmbientModule) { 6488 const ambientDecls = filter(symbol.declarations, isAmbientModule); 6489 if (length(ambientDecls)) { 6490 for (const decl of ambientDecls!) { 6491 context.tracker.trackReferencedAmbientModule(decl, symbol); 6492 } 6493 } 6494 } 6495 if (ambientModuleSymbolRegex.test(symbol.escapedName as string)) { 6496 return (symbol.escapedName as string).substring(1, (symbol.escapedName as string).length - 1); 6497 } 6498 } 6499 if (!context.enclosingDeclaration || !context.tracker.moduleResolverHost) { 6500 // If there's no context declaration, we can't lookup a non-ambient specifier, so we just use the symbol name 6501 if (ambientModuleSymbolRegex.test(symbol.escapedName as string)) { 6502 return (symbol.escapedName as string).substring(1, (symbol.escapedName as string).length - 1); 6503 } 6504 return getSourceFileOfNode(getNonAugmentationDeclaration(symbol)!).fileName; // A resolver may not be provided for baselines and errors - in those cases we use the fileName in full 6505 } 6506 const contextFile = getSourceFileOfNode(getOriginalNode(context.enclosingDeclaration)); 6507 const resolutionMode = overrideImportMode || contextFile?.impliedNodeFormat; 6508 const cacheKey = getSpecifierCacheKey(contextFile.path, resolutionMode); 6509 const links = getSymbolLinks(symbol); 6510 let specifier = links.specifierCache && links.specifierCache.get(cacheKey); 6511 if (!specifier) { 6512 const isBundle = !!outFile(compilerOptions); 6513 // For declaration bundles, we need to generate absolute paths relative to the common source dir for imports, 6514 // just like how the declaration emitter does for the ambient module declarations - we can easily accomplish this 6515 // using the `baseUrl` compiler option (which we would otherwise never use in declaration emit) and a non-relative 6516 // specifier preference 6517 const { moduleResolverHost } = context.tracker; 6518 const specifierCompilerOptions = isBundle ? { ...compilerOptions, baseUrl: moduleResolverHost.getCommonSourceDirectory() } : compilerOptions; 6519 specifier = first(moduleSpecifiers.getModuleSpecifiers( 6520 symbol, 6521 checker, 6522 specifierCompilerOptions, 6523 contextFile, 6524 moduleResolverHost, 6525 { 6526 importModuleSpecifierPreference: isBundle ? "non-relative" : "project-relative", 6527 importModuleSpecifierEnding: isBundle ? "minimal" 6528 : resolutionMode === ModuleKind.ESNext ? "js" 6529 : undefined, 6530 }, 6531 { overrideImportMode } 6532 )); 6533 links.specifierCache ??= new Map(); 6534 links.specifierCache.set(cacheKey, specifier); 6535 } 6536 return specifier; 6537 6538 function getSpecifierCacheKey(path: string, mode: SourceFile["impliedNodeFormat"] | undefined) { 6539 return mode === undefined ? path : `${mode}|${path}`; 6540 } 6541 } 6542 6543 function symbolToEntityNameNode(symbol: Symbol): EntityName { 6544 const identifier = factory.createIdentifier(unescapeLeadingUnderscores(symbol.escapedName)); 6545 return symbol.parent ? factory.createQualifiedName(symbolToEntityNameNode(symbol.parent), identifier) : identifier; 6546 } 6547 6548 function symbolToTypeNode(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, overrideTypeArguments?: readonly TypeNode[]): TypeNode { 6549 const chain = lookupSymbolChain(symbol, context, meaning, !(context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope)); // If we're using aliases outside the current scope, dont bother with the module 6550 6551 const isTypeOf = meaning === SymbolFlags.Value; 6552 if (some(chain[0].declarations, hasNonGlobalAugmentationExternalModuleSymbol)) { 6553 // module is root, must use `ImportTypeNode` 6554 const nonRootParts = chain.length > 1 ? createAccessFromSymbolChain(chain, chain.length - 1, 1) : undefined; 6555 const typeParameterNodes = overrideTypeArguments || lookupTypeParameterNodes(chain, 0, context); 6556 const contextFile = getSourceFileOfNode(getOriginalNode(context.enclosingDeclaration)); 6557 const targetFile = getSourceFileOfModule(chain[0]); 6558 let specifier: string | undefined; 6559 let assertion: ImportTypeAssertionContainer | undefined; 6560 if (getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Node16 || getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeNext) { 6561 // An `import` type directed at an esm format file is only going to resolve in esm mode - set the esm mode assertion 6562 if (targetFile?.impliedNodeFormat === ModuleKind.ESNext && targetFile.impliedNodeFormat !== contextFile?.impliedNodeFormat) { 6563 specifier = getSpecifierForModuleSymbol(chain[0], context, ModuleKind.ESNext); 6564 assertion = factory.createImportTypeAssertionContainer(factory.createAssertClause(factory.createNodeArray([ 6565 factory.createAssertEntry( 6566 factory.createStringLiteral("resolution-mode"), 6567 factory.createStringLiteral("import") 6568 ) 6569 ]))); 6570 context.tracker.reportImportTypeNodeResolutionModeOverride?.(); 6571 } 6572 } 6573 if (!specifier) { 6574 specifier = getSpecifierForModuleSymbol(chain[0], context); 6575 } 6576 if (!(context.flags & NodeBuilderFlags.AllowNodeModulesRelativePaths) && getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Classic && 6577 (specifier.indexOf("/node_modules/") >= 0 || isOhpmAndOhModules(compilerOptions.packageManagerType, specifier))) { 6578 const oldSpecifier = specifier; 6579 if (getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Node16 || getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeNext) { 6580 // We might be able to write a portable import type using a mode override; try specifier generation again, but with a different mode set 6581 const swappedMode = contextFile?.impliedNodeFormat === ModuleKind.ESNext ? ModuleKind.CommonJS : ModuleKind.ESNext; 6582 specifier = getSpecifierForModuleSymbol(chain[0], context, swappedMode); 6583 6584 if (specifier.indexOf("/node_modules/") >= 0 || isOHModules(specifier)) { 6585 // Still unreachable :( 6586 specifier = oldSpecifier; 6587 } 6588 else { 6589 assertion = factory.createImportTypeAssertionContainer(factory.createAssertClause(factory.createNodeArray([ 6590 factory.createAssertEntry( 6591 factory.createStringLiteral("resolution-mode"), 6592 factory.createStringLiteral(swappedMode === ModuleKind.ESNext ? "import" : "require") 6593 ) 6594 ]))); 6595 context.tracker.reportImportTypeNodeResolutionModeOverride?.(); 6596 } 6597 } 6598 6599 if (!assertion) { 6600 // If ultimately we can only name the symbol with a reference that dives into a `node_modules` folder, we should error 6601 // since declaration files with these kinds of references are liable to fail when published :( 6602 context.encounteredError = true; 6603 if (context.tracker.reportLikelyUnsafeImportRequiredError) { 6604 context.tracker.reportLikelyUnsafeImportRequiredError(oldSpecifier); 6605 } 6606 } 6607 } 6608 // Only for Resource type in openharmony SDK 6609 if (specifier.endsWith('/openharmony/ets/api/global/resource')) { 6610 const lastSymbol = chain[chain.length - 1]; 6611 // Create typeReferenceNode if is Resource type 6612 if (lastSymbol.escapedName === 'Resource') { 6613 const entityName = createAccessFromSymbolChain([lastSymbol], 0, 0); 6614 if (isIndexedAccessTypeNode(entityName)) { 6615 return entityName; // Indexed accesses can never be `typeof` 6616 } 6617 return factory.createTypeReferenceNode(entityName); 6618 } 6619 } 6620 const lit = factory.createLiteralTypeNode(factory.createStringLiteral(specifier)); 6621 if (context.tracker.trackExternalModuleSymbolOfImportTypeNode) context.tracker.trackExternalModuleSymbolOfImportTypeNode(chain[0]); 6622 context.approximateLength += specifier.length + 10; // specifier + import("") 6623 if (!nonRootParts || isEntityName(nonRootParts)) { 6624 if (nonRootParts) { 6625 const lastId = isIdentifier(nonRootParts) ? nonRootParts : nonRootParts.right; 6626 lastId.typeArguments = undefined; 6627 } 6628 return factory.createImportTypeNode(lit, assertion, nonRootParts as EntityName, typeParameterNodes as readonly TypeNode[], isTypeOf); 6629 } 6630 else { 6631 const splitNode = getTopmostIndexedAccessType(nonRootParts); 6632 const qualifier = (splitNode.objectType as TypeReferenceNode).typeName; 6633 return factory.createIndexedAccessTypeNode(factory.createImportTypeNode(lit, assertion, qualifier, typeParameterNodes as readonly TypeNode[], isTypeOf), splitNode.indexType); 6634 } 6635 } 6636 6637 const entityName = createAccessFromSymbolChain(chain, chain.length - 1, 0); 6638 if (isIndexedAccessTypeNode(entityName)) { 6639 return entityName; // Indexed accesses can never be `typeof` 6640 } 6641 if (isTypeOf) { 6642 return factory.createTypeQueryNode(entityName); 6643 } 6644 else { 6645 const lastId = isIdentifier(entityName) ? entityName : entityName.right; 6646 const lastTypeArgs = lastId.typeArguments; 6647 lastId.typeArguments = undefined; 6648 return factory.createTypeReferenceNode(entityName, lastTypeArgs as NodeArray<TypeNode>); 6649 } 6650 6651 function createAccessFromSymbolChain(chain: Symbol[], index: number, stopper: number): EntityName | IndexedAccessTypeNode { 6652 const typeParameterNodes = index === (chain.length - 1) ? overrideTypeArguments : lookupTypeParameterNodes(chain, index, context); 6653 const symbol = chain[index]; 6654 const parent = chain[index - 1]; 6655 6656 let symbolName: string | undefined; 6657 if (index === 0) { 6658 context.flags |= NodeBuilderFlags.InInitialEntityName; 6659 symbolName = getNameOfSymbolAsWritten(symbol, context); 6660 context.approximateLength += (symbolName ? symbolName.length : 0) + 1; 6661 context.flags ^= NodeBuilderFlags.InInitialEntityName; 6662 } 6663 else { 6664 if (parent && getExportsOfSymbol(parent)) { 6665 const exports = getExportsOfSymbol(parent); 6666 forEachEntry(exports, (ex, name) => { 6667 if (getSymbolIfSameReference(ex, symbol) && !isLateBoundName(name) && name !== InternalSymbolName.ExportEquals) { 6668 symbolName = unescapeLeadingUnderscores(name); 6669 return true; 6670 } 6671 }); 6672 } 6673 } 6674 6675 if (symbolName === undefined) { 6676 const name = firstDefined(symbol.declarations, getNameOfDeclaration); 6677 if (name && isComputedPropertyName(name) && isEntityName(name.expression)) { 6678 const LHS = createAccessFromSymbolChain(chain, index - 1, stopper); 6679 if (isEntityName(LHS)) { 6680 return factory.createIndexedAccessTypeNode(factory.createParenthesizedType(factory.createTypeQueryNode(LHS)), factory.createTypeQueryNode(name.expression)); 6681 } 6682 return LHS; 6683 } 6684 symbolName = getNameOfSymbolAsWritten(symbol, context); 6685 } 6686 context.approximateLength += symbolName.length + 1; 6687 6688 if (!(context.flags & NodeBuilderFlags.ForbidIndexedAccessSymbolReferences) && parent && 6689 getMembersOfSymbol(parent) && getMembersOfSymbol(parent).get(symbol.escapedName) && 6690 getSymbolIfSameReference(getMembersOfSymbol(parent).get(symbol.escapedName)!, symbol)) { 6691 // Should use an indexed access 6692 const LHS = createAccessFromSymbolChain(chain, index - 1, stopper); 6693 if (isIndexedAccessTypeNode(LHS)) { 6694 return factory.createIndexedAccessTypeNode(LHS, factory.createLiteralTypeNode(factory.createStringLiteral(symbolName))); 6695 } 6696 else { 6697 return factory.createIndexedAccessTypeNode(factory.createTypeReferenceNode(LHS, typeParameterNodes as readonly TypeNode[]), factory.createLiteralTypeNode(factory.createStringLiteral(symbolName))); 6698 } 6699 } 6700 6701 const identifier = setEmitFlags(factory.createIdentifier(symbolName, typeParameterNodes), EmitFlags.NoAsciiEscaping); 6702 identifier.symbol = symbol; 6703 6704 if (index > stopper) { 6705 const LHS = createAccessFromSymbolChain(chain, index - 1, stopper); 6706 if (!isEntityName(LHS)) { 6707 return Debug.fail("Impossible construct - an export of an indexed access cannot be reachable"); 6708 } 6709 return factory.createQualifiedName(LHS, identifier); 6710 } 6711 return identifier; 6712 } 6713 } 6714 6715 function typeParameterShadowsNameInScope(escapedName: __String, context: NodeBuilderContext, type: TypeParameter) { 6716 const result = resolveName(context.enclosingDeclaration, escapedName, SymbolFlags.Type, /*nameNotFoundArg*/ undefined, escapedName, /*isUse*/ false); 6717 if (result) { 6718 if (result.flags & SymbolFlags.TypeParameter && result === type.symbol) { 6719 return false; 6720 } 6721 return true; 6722 } 6723 return false; 6724 } 6725 6726 function typeParameterToName(type: TypeParameter, context: NodeBuilderContext) { 6727 if (context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams && context.typeParameterNames) { 6728 const cached = context.typeParameterNames.get(getTypeId(type)); 6729 if (cached) { 6730 return cached; 6731 } 6732 } 6733 let result = symbolToName(type.symbol, context, SymbolFlags.Type, /*expectsIdentifier*/ true); 6734 if (!(result.kind & SyntaxKind.Identifier)) { 6735 return factory.createIdentifier("(Missing type parameter)"); 6736 } 6737 if (context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams) { 6738 const rawtext = result.escapedText as string; 6739 let i = context.typeParameterNamesByTextNextNameCount?.get(rawtext) || 0; 6740 let text = rawtext; 6741 while (context.typeParameterNamesByText?.has(text) || typeParameterShadowsNameInScope(text as __String, context, type)) { 6742 i++; 6743 text = `${rawtext}_${i}`; 6744 } 6745 if (text !== rawtext) { 6746 result = factory.createIdentifier(text, result.typeArguments); 6747 } 6748 // avoiding iterations of the above loop turns out to be worth it when `i` starts to get large, so we cache the max 6749 // `i` we've used thus far, to save work later 6750 (context.typeParameterNamesByTextNextNameCount ||= new Map()).set(rawtext, i); 6751 (context.typeParameterNames ||= new Map()).set(getTypeId(type), result); 6752 (context.typeParameterNamesByText ||= new Set()).add(rawtext); 6753 } 6754 return result; 6755 } 6756 6757 function symbolToName(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, expectsIdentifier: true): Identifier; 6758 function symbolToName(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, expectsIdentifier: false): EntityName; 6759 function symbolToName(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, expectsIdentifier: boolean): EntityName { 6760 const chain = lookupSymbolChain(symbol, context, meaning); 6761 6762 if (expectsIdentifier && chain.length !== 1 6763 && !context.encounteredError 6764 && !(context.flags & NodeBuilderFlags.AllowQualifiedNameInPlaceOfIdentifier)) { 6765 context.encounteredError = true; 6766 } 6767 return createEntityNameFromSymbolChain(chain, chain.length - 1); 6768 6769 function createEntityNameFromSymbolChain(chain: Symbol[], index: number): EntityName { 6770 const typeParameterNodes = lookupTypeParameterNodes(chain, index, context); 6771 const symbol = chain[index]; 6772 6773 if (index === 0) { 6774 context.flags |= NodeBuilderFlags.InInitialEntityName; 6775 } 6776 const symbolName = getNameOfSymbolAsWritten(symbol, context); 6777 if (index === 0) { 6778 context.flags ^= NodeBuilderFlags.InInitialEntityName; 6779 } 6780 6781 const identifier = setEmitFlags(factory.createIdentifier(symbolName, typeParameterNodes), EmitFlags.NoAsciiEscaping); 6782 identifier.symbol = symbol; 6783 6784 return index > 0 ? factory.createQualifiedName(createEntityNameFromSymbolChain(chain, index - 1), identifier) : identifier; 6785 } 6786 } 6787 6788 function symbolToExpression(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags) { 6789 const chain = lookupSymbolChain(symbol, context, meaning); 6790 6791 return createExpressionFromSymbolChain(chain, chain.length - 1); 6792 6793 function createExpressionFromSymbolChain(chain: Symbol[], index: number): Expression { 6794 const typeParameterNodes = lookupTypeParameterNodes(chain, index, context); 6795 const symbol = chain[index]; 6796 6797 if (index === 0) { 6798 context.flags |= NodeBuilderFlags.InInitialEntityName; 6799 } 6800 let symbolName = getNameOfSymbolAsWritten(symbol, context); 6801 if (index === 0) { 6802 context.flags ^= NodeBuilderFlags.InInitialEntityName; 6803 } 6804 let firstChar = symbolName.charCodeAt(0); 6805 6806 if (isSingleOrDoubleQuote(firstChar) && some(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol)) { 6807 return factory.createStringLiteral(getSpecifierForModuleSymbol(symbol, context)); 6808 } 6809 const canUsePropertyAccess = firstChar === CharacterCodes.hash ? 6810 symbolName.length > 1 && isIdentifierStart(symbolName.charCodeAt(1), languageVersion) : 6811 isIdentifierStart(firstChar, languageVersion); 6812 if (index === 0 || canUsePropertyAccess) { 6813 const identifier = setEmitFlags(factory.createIdentifier(symbolName, typeParameterNodes), EmitFlags.NoAsciiEscaping); 6814 identifier.symbol = symbol; 6815 6816 return index > 0 ? factory.createPropertyAccessExpression(createExpressionFromSymbolChain(chain, index - 1), identifier) : identifier; 6817 } 6818 else { 6819 if (firstChar === CharacterCodes.openBracket) { 6820 symbolName = symbolName.substring(1, symbolName.length - 1); 6821 firstChar = symbolName.charCodeAt(0); 6822 } 6823 let expression: Expression | undefined; 6824 if (isSingleOrDoubleQuote(firstChar) && !(symbol.flags & SymbolFlags.EnumMember)) { 6825 expression = factory.createStringLiteral(stripQuotes(symbolName).replace(/\\./g, s => s.substring(1)), firstChar === CharacterCodes.singleQuote); 6826 } 6827 else if (("" + +symbolName) === symbolName) { 6828 expression = factory.createNumericLiteral(+symbolName); 6829 } 6830 if (!expression) { 6831 expression = setEmitFlags(factory.createIdentifier(symbolName, typeParameterNodes), EmitFlags.NoAsciiEscaping); 6832 expression.symbol = symbol; 6833 } 6834 return factory.createElementAccessExpression(createExpressionFromSymbolChain(chain, index - 1), expression); 6835 } 6836 } 6837 } 6838 6839 function isStringNamed(d: Declaration) { 6840 const name = getNameOfDeclaration(d); 6841 return !!name && isStringLiteral(name); 6842 } 6843 6844 function isSingleQuotedStringNamed(d: Declaration) { 6845 const name = getNameOfDeclaration(d); 6846 return !!(name && isStringLiteral(name) && (name.singleQuote || !nodeIsSynthesized(name) && startsWith(getTextOfNode(name, /*includeTrivia*/ false), "'"))); 6847 } 6848 6849 function getPropertyNameNodeForSymbol(symbol: Symbol, context: NodeBuilderContext) { 6850 const singleQuote = !!length(symbol.declarations) && every(symbol.declarations, isSingleQuotedStringNamed); 6851 const fromNameType = getPropertyNameNodeForSymbolFromNameType(symbol, context, singleQuote); 6852 if (fromNameType) { 6853 return fromNameType; 6854 } 6855 const rawName = unescapeLeadingUnderscores(symbol.escapedName); 6856 const stringNamed = !!length(symbol.declarations) && every(symbol.declarations, isStringNamed); 6857 return createPropertyNameNodeForIdentifierOrLiteral(rawName, getEmitScriptTarget(compilerOptions), singleQuote, stringNamed); 6858 } 6859 6860 // See getNameForSymbolFromNameType for a stringy equivalent 6861 function getPropertyNameNodeForSymbolFromNameType(symbol: Symbol, context: NodeBuilderContext, singleQuote?: boolean) { 6862 const nameType = getSymbolLinks(symbol).nameType; 6863 if (nameType) { 6864 if (nameType.flags & TypeFlags.StringOrNumberLiteral) { 6865 const name = "" + (nameType as StringLiteralType | NumberLiteralType).value; 6866 if (!isIdentifierText(name, getEmitScriptTarget(compilerOptions)) && !isNumericLiteralName(name)) { 6867 return factory.createStringLiteral(name, !!singleQuote); 6868 } 6869 if (isNumericLiteralName(name) && startsWith(name, "-")) { 6870 return factory.createComputedPropertyName(factory.createNumericLiteral(+name)); 6871 } 6872 return createPropertyNameNodeForIdentifierOrLiteral(name, getEmitScriptTarget(compilerOptions)); 6873 } 6874 if (nameType.flags & TypeFlags.UniqueESSymbol) { 6875 return factory.createComputedPropertyName(symbolToExpression((nameType as UniqueESSymbolType).symbol, context, SymbolFlags.Value)); 6876 } 6877 } 6878 } 6879 6880 function cloneNodeBuilderContext(context: NodeBuilderContext): NodeBuilderContext { 6881 const initial: NodeBuilderContext = { ...context }; 6882 // Make type parameters created within this context not consume the name outside this context 6883 // The symbol serializer ends up creating many sibling scopes that all need "separate" contexts when 6884 // it comes to naming things - within a normal `typeToTypeNode` call, the node builder only ever descends 6885 // through the type tree, so the only cases where we could have used distinct sibling scopes was when there 6886 // were multiple generic overloads with similar generated type parameter names 6887 // The effect: 6888 // When we write out 6889 // export const x: <T>(x: T) => T 6890 // export const y: <T>(x: T) => T 6891 // we write it out like that, rather than as 6892 // export const x: <T>(x: T) => T 6893 // export const y: <T_1>(x: T_1) => T_1 6894 if (initial.typeParameterNames) { 6895 initial.typeParameterNames = new Map(initial.typeParameterNames); 6896 } 6897 if (initial.typeParameterNamesByText) { 6898 initial.typeParameterNamesByText = new Set(initial.typeParameterNamesByText); 6899 } 6900 if (initial.typeParameterSymbolList) { 6901 initial.typeParameterSymbolList = new Set(initial.typeParameterSymbolList); 6902 } 6903 initial.tracker = wrapSymbolTrackerToReportForContext(initial, initial.tracker); 6904 return initial; 6905 } 6906 6907 6908 function getDeclarationWithTypeAnnotation(symbol: Symbol, enclosingDeclaration: Node | undefined) { 6909 return symbol.declarations && find(symbol.declarations, s => !!getEffectiveTypeAnnotationNode(s) && (!enclosingDeclaration || !!findAncestor(s, n => n === enclosingDeclaration))); 6910 } 6911 6912 function existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount(existing: TypeNode, type: Type) { 6913 return !(getObjectFlags(type) & ObjectFlags.Reference) || !isTypeReferenceNode(existing) || length(existing.typeArguments) >= getMinTypeArgumentCount((type as TypeReference).target.typeParameters); 6914 } 6915 6916 /** 6917 * Unlike `typeToTypeNodeHelper`, this handles setting up the `AllowUniqueESSymbolType` flag 6918 * so a `unique symbol` is returned when appropriate for the input symbol, rather than `typeof sym` 6919 */ 6920 function serializeTypeForDeclaration(context: NodeBuilderContext, type: Type, symbol: Symbol, enclosingDeclaration: Node | undefined, includePrivateSymbol?: (s: Symbol) => void, bundled?: boolean) { 6921 if (!isErrorType(type) && enclosingDeclaration) { 6922 const declWithExistingAnnotation = getDeclarationWithTypeAnnotation(symbol, enclosingDeclaration); 6923 if (declWithExistingAnnotation && !isFunctionLikeDeclaration(declWithExistingAnnotation) && !isGetAccessorDeclaration(declWithExistingAnnotation)) { 6924 // try to reuse the existing annotation 6925 const existing = getEffectiveTypeAnnotationNode(declWithExistingAnnotation)!; 6926 if (typeNodeIsEquivalentToType(existing, declWithExistingAnnotation, type) && existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount(existing, type)) { 6927 const result = serializeExistingTypeNode(context, existing, includePrivateSymbol, bundled); 6928 if (result) { 6929 return result; 6930 } 6931 } 6932 } 6933 } 6934 const oldFlags = context.flags; 6935 if (type.flags & TypeFlags.UniqueESSymbol && 6936 type.symbol === symbol && (!context.enclosingDeclaration || some(symbol.declarations, d => getSourceFileOfNode(d) === getSourceFileOfNode(context.enclosingDeclaration!)))) { 6937 context.flags |= NodeBuilderFlags.AllowUniqueESSymbolType; 6938 } 6939 const result = typeToTypeNodeHelper(type, context); 6940 context.flags = oldFlags; 6941 return result; 6942 } 6943 6944 function typeNodeIsEquivalentToType(typeNode: TypeNode, annotatedDeclaration: Declaration, type: Type) { 6945 const typeFromTypeNode = getTypeFromTypeNode(typeNode); 6946 if (typeFromTypeNode === type) { 6947 return true; 6948 } 6949 if (isParameter(annotatedDeclaration) && annotatedDeclaration.questionToken) { 6950 return getTypeWithFacts(type, TypeFacts.NEUndefined) === typeFromTypeNode; 6951 } 6952 return false; 6953 } 6954 6955 function serializeReturnTypeForSignature(context: NodeBuilderContext, type: Type, signature: Signature, includePrivateSymbol?: (s: Symbol) => void, bundled?: boolean) { 6956 if (!isErrorType(type) && context.enclosingDeclaration) { 6957 const annotation = signature.declaration && getEffectiveReturnTypeNode(signature.declaration); 6958 if (!!findAncestor(annotation, n => n === context.enclosingDeclaration) && annotation) { 6959 const annotated = getTypeFromTypeNode(annotation); 6960 const thisInstantiated = annotated.flags & TypeFlags.TypeParameter && (annotated as TypeParameter).isThisType ? instantiateType(annotated, signature.mapper) : annotated; 6961 if (thisInstantiated === type && existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount(annotation, type)) { 6962 const result = serializeExistingTypeNode(context, annotation, includePrivateSymbol, bundled); 6963 if (result) { 6964 return result; 6965 } 6966 } 6967 } 6968 } 6969 return typeToTypeNodeHelper(type, context); 6970 } 6971 6972 function trackExistingEntityName<T extends EntityNameOrEntityNameExpression>(node: T, context: NodeBuilderContext, includePrivateSymbol?: (s: Symbol) => void) { 6973 let introducesError = false; 6974 const leftmost = getFirstIdentifier(node); 6975 if (isInJSFile(node) && (isExportsIdentifier(leftmost) || isModuleExportsAccessExpression(leftmost.parent) || (isQualifiedName(leftmost.parent) && isModuleIdentifier(leftmost.parent.left) && isExportsIdentifier(leftmost.parent.right)))) { 6976 introducesError = true; 6977 return { introducesError, node }; 6978 } 6979 const sym = resolveEntityName(leftmost, SymbolFlags.All, /*ignoreErrors*/ true, /*dontResolveALias*/ true); 6980 if (sym) { 6981 if (isSymbolAccessible(sym, context.enclosingDeclaration, SymbolFlags.All, /*shouldComputeAliasesToMakeVisible*/ false).accessibility !== SymbolAccessibility.Accessible) { 6982 introducesError = true; 6983 } 6984 else { 6985 context.tracker?.trackSymbol?.(sym, context.enclosingDeclaration, SymbolFlags.All); 6986 includePrivateSymbol?.(sym); 6987 } 6988 if (isIdentifier(node)) { 6989 const type = getDeclaredTypeOfSymbol(sym); 6990 const name = sym.flags & SymbolFlags.TypeParameter && !isTypeSymbolAccessible(type.symbol, context.enclosingDeclaration) ? typeParameterToName(type, context) : factory.cloneNode(node); 6991 name.symbol = sym; // for quickinfo, which uses identifier symbol information 6992 return { introducesError, node: setEmitFlags(setOriginalNode(name, node), EmitFlags.NoAsciiEscaping) }; 6993 } 6994 } 6995 6996 return { introducesError, node }; 6997 } 6998 6999 function serializeExistingTypeNode(context: NodeBuilderContext, existing: TypeNode, includePrivateSymbol?: (s: Symbol) => void, bundled?: boolean) { 7000 if (cancellationToken && cancellationToken.throwIfCancellationRequested) { 7001 cancellationToken.throwIfCancellationRequested(); 7002 } 7003 let hadError = false; 7004 const file = getSourceFileOfNode(existing); 7005 const transformed = visitNode(existing, visitExistingNodeTreeSymbols); 7006 if (hadError) { 7007 return undefined; 7008 } 7009 return transformed === existing ? setTextRange(factory.cloneNode(existing), existing) : transformed; 7010 7011 function visitExistingNodeTreeSymbols<T extends Node>(node: T): Node { 7012 // We don't _actually_ support jsdoc namepath types, emit `any` instead 7013 if (isJSDocAllType(node) || node.kind === SyntaxKind.JSDocNamepathType) { 7014 return factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); 7015 } 7016 if (isJSDocUnknownType(node)) { 7017 return factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword); 7018 } 7019 if (isJSDocNullableType(node)) { 7020 return factory.createUnionTypeNode([visitNode(node.type, visitExistingNodeTreeSymbols), factory.createLiteralTypeNode(factory.createNull())]); 7021 } 7022 if (isJSDocOptionalType(node)) { 7023 return factory.createUnionTypeNode([visitNode(node.type, visitExistingNodeTreeSymbols), factory.createKeywordTypeNode(SyntaxKind.UndefinedKeyword)]); 7024 } 7025 if (isJSDocNonNullableType(node)) { 7026 return visitNode(node.type, visitExistingNodeTreeSymbols); 7027 } 7028 if (isJSDocVariadicType(node)) { 7029 return factory.createArrayTypeNode(visitNode((node as JSDocVariadicType).type, visitExistingNodeTreeSymbols)); 7030 } 7031 if (isJSDocTypeLiteral(node)) { 7032 return factory.createTypeLiteralNode(map(node.jsDocPropertyTags, t => { 7033 const name = isIdentifier(t.name) ? t.name : t.name.right; 7034 const typeViaParent = getTypeOfPropertyOfType(getTypeFromTypeNode(node), name.escapedText); 7035 const overrideTypeNode = typeViaParent && t.typeExpression && getTypeFromTypeNode(t.typeExpression.type) !== typeViaParent ? typeToTypeNodeHelper(typeViaParent, context) : undefined; 7036 7037 return factory.createPropertySignature( 7038 /*modifiers*/ undefined, 7039 name, 7040 t.isBracketed || t.typeExpression && isJSDocOptionalType(t.typeExpression.type) ? factory.createToken(SyntaxKind.QuestionToken) : undefined, 7041 overrideTypeNode || (t.typeExpression && visitNode(t.typeExpression.type, visitExistingNodeTreeSymbols)) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) 7042 ); 7043 })); 7044 } 7045 if (isTypeReferenceNode(node) && isIdentifier(node.typeName) && node.typeName.escapedText === "") { 7046 return setOriginalNode(factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), node); 7047 } 7048 if ((isExpressionWithTypeArguments(node) || isTypeReferenceNode(node)) && isJSDocIndexSignature(node)) { 7049 return factory.createTypeLiteralNode([factory.createIndexSignature( 7050 /*modifiers*/ undefined, 7051 [factory.createParameterDeclaration( 7052 /*modifiers*/ undefined, 7053 /*dotdotdotToken*/ undefined, 7054 "x", 7055 /*questionToken*/ undefined, 7056 visitNode(node.typeArguments![0], visitExistingNodeTreeSymbols) 7057 )], 7058 visitNode(node.typeArguments![1], visitExistingNodeTreeSymbols) 7059 )]); 7060 } 7061 if (isJSDocFunctionType(node)) { 7062 if (isJSDocConstructSignature(node)) { 7063 let newTypeNode: TypeNode | undefined; 7064 return factory.createConstructorTypeNode( 7065 /*modifiers*/ undefined, 7066 visitNodes(node.typeParameters, visitExistingNodeTreeSymbols), 7067 mapDefined(node.parameters, (p, i) => p.name && isIdentifier(p.name) && p.name.escapedText === "new" ? (newTypeNode = p.type, undefined) : factory.createParameterDeclaration( 7068 /*modifiers*/ undefined, 7069 getEffectiveDotDotDotForParameter(p), 7070 getNameForJSDocFunctionParameter(p, i), 7071 p.questionToken, 7072 visitNode(p.type, visitExistingNodeTreeSymbols), 7073 /*initializer*/ undefined 7074 )), 7075 visitNode(newTypeNode || node.type, visitExistingNodeTreeSymbols) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) 7076 ); 7077 } 7078 else { 7079 return factory.createFunctionTypeNode( 7080 visitNodes(node.typeParameters, visitExistingNodeTreeSymbols), 7081 map(node.parameters, (p, i) => factory.createParameterDeclaration( 7082 /*modifiers*/ undefined, 7083 getEffectiveDotDotDotForParameter(p), 7084 getNameForJSDocFunctionParameter(p, i), 7085 p.questionToken, 7086 visitNode(p.type, visitExistingNodeTreeSymbols), 7087 /*initializer*/ undefined 7088 )), 7089 visitNode(node.type, visitExistingNodeTreeSymbols) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) 7090 ); 7091 } 7092 } 7093 if (isTypeReferenceNode(node) && isInJSDoc(node) && (!existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount(node, getTypeFromTypeNode(node)) || getIntendedTypeFromJSDocTypeReference(node) || unknownSymbol === resolveTypeReferenceName(node, SymbolFlags.Type, /*ignoreErrors*/ true))) { 7094 return setOriginalNode(typeToTypeNodeHelper(getTypeFromTypeNode(node), context), node); 7095 } 7096 if (isLiteralImportTypeNode(node)) { 7097 const nodeSymbol = getNodeLinks(node).resolvedSymbol; 7098 if (isInJSDoc(node) && 7099 nodeSymbol && 7100 ( 7101 // The import type resolved using jsdoc fallback logic 7102 (!node.isTypeOf && !(nodeSymbol.flags & SymbolFlags.Type)) || 7103 // The import type had type arguments autofilled by js fallback logic 7104 !(length(node.typeArguments) >= getMinTypeArgumentCount(getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(nodeSymbol))) 7105 ) 7106 ) { 7107 return setOriginalNode(typeToTypeNodeHelper(getTypeFromTypeNode(node), context), node); 7108 } 7109 return factory.updateImportTypeNode( 7110 node, 7111 factory.updateLiteralTypeNode(node.argument, rewriteModuleSpecifier(node, node.argument.literal)), 7112 node.assertions, 7113 node.qualifier, 7114 visitNodes(node.typeArguments, visitExistingNodeTreeSymbols, isTypeNode), 7115 node.isTypeOf 7116 ); 7117 } 7118 7119 if (isEntityName(node) || isEntityNameExpression(node)) { 7120 const { introducesError, node: result } = trackExistingEntityName(node, context, includePrivateSymbol); 7121 hadError = hadError || introducesError; 7122 if (result !== node) { 7123 return result; 7124 } 7125 } 7126 7127 if (file && isTupleTypeNode(node) && (getLineAndCharacterOfPosition(file, node.pos).line === getLineAndCharacterOfPosition(file, node.end).line)) { 7128 setEmitFlags(node, EmitFlags.SingleLine); 7129 } 7130 7131 return visitEachChild(node, visitExistingNodeTreeSymbols, nullTransformationContext); 7132 7133 function getEffectiveDotDotDotForParameter(p: ParameterDeclaration) { 7134 return p.dotDotDotToken || (p.type && isJSDocVariadicType(p.type) ? factory.createToken(SyntaxKind.DotDotDotToken) : undefined); 7135 } 7136 7137 /** Note that `new:T` parameters are not handled, but should be before calling this function. */ 7138 function getNameForJSDocFunctionParameter(p: ParameterDeclaration, index: number) { 7139 return p.name && isIdentifier(p.name) && p.name.escapedText === "this" ? "this" 7140 : getEffectiveDotDotDotForParameter(p) ? `args` 7141 : `arg${index}`; 7142 } 7143 7144 function rewriteModuleSpecifier(parent: ImportTypeNode, lit: StringLiteral) { 7145 if (bundled) { 7146 if (context.tracker && context.tracker.moduleResolverHost) { 7147 const targetFile = getExternalModuleFileFromDeclaration(parent); 7148 if (targetFile) { 7149 const getCanonicalFileName = createGetCanonicalFileName(!!host.useCaseSensitiveFileNames); 7150 const resolverHost = { 7151 getCanonicalFileName, 7152 getCurrentDirectory: () => context.tracker.moduleResolverHost!.getCurrentDirectory(), 7153 getCommonSourceDirectory: () => context.tracker.moduleResolverHost!.getCommonSourceDirectory() 7154 }; 7155 const newName = getResolvedExternalModuleName(resolverHost, targetFile); 7156 return factory.createStringLiteral(newName); 7157 } 7158 } 7159 } 7160 else { 7161 if (context.tracker && context.tracker.trackExternalModuleSymbolOfImportTypeNode) { 7162 const moduleSym = resolveExternalModuleNameWorker(lit, lit, /*moduleNotFoundError*/ undefined); 7163 if (moduleSym) { 7164 context.tracker.trackExternalModuleSymbolOfImportTypeNode(moduleSym); 7165 } 7166 } 7167 } 7168 return lit; 7169 } 7170 } 7171 } 7172 7173 function symbolTableToDeclarationStatements(symbolTable: SymbolTable, context: NodeBuilderContext, bundled?: boolean): Statement[] { 7174 const serializePropertySymbolForClass = makeSerializePropertySymbol<ClassElement>(factory.createPropertyDeclaration, SyntaxKind.MethodDeclaration, /*useAcessors*/ true); 7175 const serializePropertySymbolForInterfaceWorker = makeSerializePropertySymbol<TypeElement>((mods, name, question, type) => factory.createPropertySignature(mods, name, question, type), SyntaxKind.MethodSignature, /*useAcessors*/ false); 7176 7177 // TODO: Use `setOriginalNode` on original declaration names where possible so these declarations see some kind of 7178 // declaration mapping 7179 7180 // We save the enclosing declaration off here so it's not adjusted by well-meaning declaration 7181 // emit codepaths which want to apply more specific contexts (so we can still refer to the root real declaration 7182 // we're trying to emit from later on) 7183 const enclosingDeclaration = context.enclosingDeclaration!; 7184 let results: Statement[] = []; 7185 const visitedSymbols = new Set<number>(); 7186 const deferredPrivatesStack: ESMap<SymbolId, Symbol>[] = []; 7187 const oldcontext = context; 7188 context = { 7189 ...oldcontext, 7190 usedSymbolNames: new Set(oldcontext.usedSymbolNames), 7191 remappedSymbolNames: new Map(), 7192 tracker: { 7193 ...oldcontext.tracker, 7194 trackSymbol: (sym, decl, meaning) => { 7195 const accessibleResult = isSymbolAccessible(sym, decl, meaning, /*computeAliases*/ false); 7196 if (accessibleResult.accessibility === SymbolAccessibility.Accessible) { 7197 // Lookup the root symbol of the chain of refs we'll use to access it and serialize it 7198 const chain = lookupSymbolChainWorker(sym, context, meaning); 7199 if (!(sym.flags & SymbolFlags.Property)) { 7200 includePrivateSymbol(chain[0]); 7201 } 7202 } 7203 else if (oldcontext.tracker && oldcontext.tracker.trackSymbol) { 7204 return oldcontext.tracker.trackSymbol(sym, decl, meaning); 7205 } 7206 return false; 7207 }, 7208 }, 7209 }; 7210 context.tracker = wrapSymbolTrackerToReportForContext(context, context.tracker); 7211 forEachEntry(symbolTable, (symbol, name) => { 7212 const baseName = unescapeLeadingUnderscores(name); 7213 void getInternalSymbolName(symbol, baseName); // Called to cache values into `usedSymbolNames` and `remappedSymbolNames` 7214 }); 7215 let addingDeclare = !bundled; 7216 const exportEquals = symbolTable.get(InternalSymbolName.ExportEquals); 7217 if (exportEquals && symbolTable.size > 1 && exportEquals.flags & SymbolFlags.Alias) { 7218 symbolTable = createSymbolTable(); 7219 // Remove extraneous elements from root symbol table (they'll be mixed back in when the target of the `export=` is looked up) 7220 symbolTable.set(InternalSymbolName.ExportEquals, exportEquals); 7221 } 7222 7223 visitSymbolTable(symbolTable); 7224 return mergeRedundantStatements(results); 7225 7226 function isIdentifierAndNotUndefined(node: Node | undefined): node is Identifier { 7227 return !!node && node.kind === SyntaxKind.Identifier; 7228 } 7229 7230 function getNamesOfDeclaration(statement: Statement): Identifier[] { 7231 if (isVariableStatement(statement)) { 7232 return filter(map(statement.declarationList.declarations, getNameOfDeclaration), isIdentifierAndNotUndefined); 7233 } 7234 return filter([getNameOfDeclaration(statement as DeclarationStatement)], isIdentifierAndNotUndefined); 7235 } 7236 7237 function flattenExportAssignedNamespace(statements: Statement[]) { 7238 const exportAssignment = find(statements, isExportAssignment); 7239 const nsIndex = findIndex(statements, isModuleDeclaration); 7240 let ns = nsIndex !== -1 ? statements[nsIndex] as ModuleDeclaration : undefined; 7241 if (ns && exportAssignment && exportAssignment.isExportEquals && 7242 isIdentifier(exportAssignment.expression) && isIdentifier(ns.name) && idText(ns.name) === idText(exportAssignment.expression) && 7243 ns.body && isModuleBlock(ns.body)) { 7244 // Pass 0: Correct situations where a module has both an `export = ns` and multiple top-level exports by stripping the export modifiers from 7245 // the top-level exports and exporting them in the targeted ns, as can occur when a js file has both typedefs and `module.export` assignments 7246 const excessExports = filter(statements, s => !!(getEffectiveModifierFlags(s) & ModifierFlags.Export)); 7247 const name = ns.name; 7248 let body = ns.body; 7249 if (length(excessExports)) { 7250 ns = factory.updateModuleDeclaration( 7251 ns, 7252 ns.modifiers, 7253 ns.name, 7254 body = factory.updateModuleBlock( 7255 body, 7256 factory.createNodeArray([...ns.body.statements, factory.createExportDeclaration( 7257 /*modifiers*/ undefined, 7258 /*isTypeOnly*/ false, 7259 factory.createNamedExports(map(flatMap(excessExports, e => getNamesOfDeclaration(e)), id => factory.createExportSpecifier(/*isTypeOnly*/ false, /*alias*/ undefined, id))), 7260 /*moduleSpecifier*/ undefined 7261 )]) 7262 ) 7263 ); 7264 statements = [...statements.slice(0, nsIndex), ns, ...statements.slice(nsIndex + 1)]; 7265 } 7266 7267 // Pass 1: Flatten `export namespace _exports {} export = _exports;` so long as the `export=` only points at a single namespace declaration 7268 if (!find(statements, s => s !== ns && nodeHasName(s, name))) { 7269 results = []; 7270 // If the namespace contains no export assignments or declarations, and no declarations flagged with `export`, then _everything_ is exported - 7271 // to respect this as the top level, we need to add an `export` modifier to everything 7272 const mixinExportFlag = !some(body.statements, s => hasSyntacticModifier(s, ModifierFlags.Export) || isExportAssignment(s) || isExportDeclaration(s)); 7273 forEach(body.statements, s => { 7274 addResult(s, mixinExportFlag ? ModifierFlags.Export : ModifierFlags.None); // Recalculates the ambient (and export, if applicable from above) flag 7275 }); 7276 statements = [...filter(statements, s => s !== ns && s !== exportAssignment), ...results]; 7277 } 7278 } 7279 return statements; 7280 } 7281 7282 function mergeExportDeclarations(statements: Statement[]) { 7283 // Pass 2: Combine all `export {}` declarations 7284 const exports = filter(statements, d => isExportDeclaration(d) && !d.moduleSpecifier && !!d.exportClause && isNamedExports(d.exportClause)) as ExportDeclaration[]; 7285 if (length(exports) > 1) { 7286 const nonExports = filter(statements, d => !isExportDeclaration(d) || !!d.moduleSpecifier || !d.exportClause); 7287 statements = [...nonExports, factory.createExportDeclaration( 7288 /*modifiers*/ undefined, 7289 /*isTypeOnly*/ false, 7290 factory.createNamedExports(flatMap(exports, e => cast(e.exportClause, isNamedExports).elements)), 7291 /*moduleSpecifier*/ undefined 7292 )]; 7293 } 7294 // Pass 2b: Also combine all `export {} from "..."` declarations as needed 7295 const reexports = filter(statements, d => isExportDeclaration(d) && !!d.moduleSpecifier && !!d.exportClause && isNamedExports(d.exportClause)) as ExportDeclaration[]; 7296 if (length(reexports) > 1) { 7297 const groups = group(reexports, decl => isStringLiteral(decl.moduleSpecifier!) ? ">" + decl.moduleSpecifier.text : ">"); 7298 if (groups.length !== reexports.length) { 7299 for (const group of groups) { 7300 if (group.length > 1) { 7301 // remove group members from statements and then merge group members and add back to statements 7302 statements = [ 7303 ...filter(statements, s => group.indexOf(s as ExportDeclaration) === -1), 7304 factory.createExportDeclaration( 7305 /*modifiers*/ undefined, 7306 /*isTypeOnly*/ false, 7307 factory.createNamedExports(flatMap(group, e => cast(e.exportClause, isNamedExports).elements)), 7308 group[0].moduleSpecifier 7309 ) 7310 ]; 7311 } 7312 } 7313 } 7314 } 7315 return statements; 7316 } 7317 7318 function inlineExportModifiers(statements: Statement[]) { 7319 // Pass 3: Move all `export {}`'s to `export` modifiers where possible 7320 const index = findIndex(statements, d => isExportDeclaration(d) && !d.moduleSpecifier && !d.assertClause && !!d.exportClause && isNamedExports(d.exportClause)); 7321 if (index >= 0) { 7322 const exportDecl = statements[index] as ExportDeclaration & { readonly exportClause: NamedExports }; 7323 const replacements = mapDefined(exportDecl.exportClause.elements, e => { 7324 if (!e.propertyName) { 7325 // export {name} - look thru `statements` for `name`, and if all results can take an `export` modifier, do so and filter it 7326 const indices = indicesOf(statements); 7327 const associatedIndices = filter(indices, i => nodeHasName(statements[i], e.name)); 7328 if (length(associatedIndices) && every(associatedIndices, i => canHaveExportModifier(statements[i]))) { 7329 for (const index of associatedIndices) { 7330 statements[index] = addExportModifier(statements[index] as Extract<HasModifiers, Statement>); 7331 } 7332 return undefined; 7333 } 7334 } 7335 return e; 7336 }); 7337 if (!length(replacements)) { 7338 // all clauses removed, remove the export declaration 7339 orderedRemoveItemAt(statements, index); 7340 } 7341 else { 7342 // some items filtered, others not - update the export declaration 7343 statements[index] = factory.updateExportDeclaration( 7344 exportDecl, 7345 exportDecl.modifiers, 7346 exportDecl.isTypeOnly, 7347 factory.updateNamedExports( 7348 exportDecl.exportClause, 7349 replacements 7350 ), 7351 exportDecl.moduleSpecifier, 7352 exportDecl.assertClause 7353 ); 7354 } 7355 } 7356 return statements; 7357 } 7358 7359 function mergeRedundantStatements(statements: Statement[]) { 7360 statements = flattenExportAssignedNamespace(statements); 7361 statements = mergeExportDeclarations(statements); 7362 statements = inlineExportModifiers(statements); 7363 7364 // Not a cleanup, but as a final step: If there is a mix of `export` and non-`export` declarations, but no `export =` or `export {}` add a `export {};` so 7365 // declaration privacy is respected. 7366 if (enclosingDeclaration && 7367 ((isSourceFile(enclosingDeclaration) && isExternalOrCommonJsModule(enclosingDeclaration)) || isModuleDeclaration(enclosingDeclaration)) && 7368 (!some(statements, isExternalModuleIndicator) || (!hasScopeMarker(statements) && some(statements, needsScopeMarker)))) { 7369 statements.push(createEmptyExports(factory)); 7370 } 7371 return statements; 7372 } 7373 7374 function addExportModifier(node: Extract<HasModifiers, Statement>) { 7375 const flags = (getEffectiveModifierFlags(node) | ModifierFlags.Export) & ~ModifierFlags.Ambient; 7376 return factory.updateModifiers(node, flags); 7377 } 7378 7379 function removeExportModifier(node: Extract<HasModifiers, Statement>) { 7380 const flags = getEffectiveModifierFlags(node) & ~ModifierFlags.Export; 7381 return factory.updateModifiers(node, flags); 7382 } 7383 7384 function visitSymbolTable(symbolTable: SymbolTable, suppressNewPrivateContext?: boolean, propertyAsAlias?: boolean) { 7385 if (!suppressNewPrivateContext) { 7386 deferredPrivatesStack.push(new Map()); 7387 } 7388 symbolTable.forEach((symbol: Symbol) => { 7389 serializeSymbol(symbol, /*isPrivate*/ false, !!propertyAsAlias); 7390 }); 7391 if (!suppressNewPrivateContext) { 7392 // deferredPrivates will be filled up by visiting the symbol table 7393 // And will continue to iterate as elements are added while visited `deferredPrivates` 7394 // (As that's how a map iterator is defined to work) 7395 deferredPrivatesStack[deferredPrivatesStack.length - 1].forEach((symbol: Symbol) => { 7396 serializeSymbol(symbol, /*isPrivate*/ true, !!propertyAsAlias); 7397 }); 7398 deferredPrivatesStack.pop(); 7399 } 7400 } 7401 7402 function serializeSymbol(symbol: Symbol, isPrivate: boolean, propertyAsAlias: boolean): void { 7403 // cache visited list based on merged symbol, since we want to use the unmerged top-level symbol, but 7404 // still skip reserializing it if we encounter the merged product later on 7405 const visitedSym = getMergedSymbol(symbol); 7406 if (visitedSymbols.has(getSymbolId(visitedSym))) { 7407 return; // Already printed 7408 } 7409 visitedSymbols.add(getSymbolId(visitedSym)); 7410 // Only actually serialize symbols within the correct enclosing declaration, otherwise do nothing with the out-of-context symbol 7411 const skipMembershipCheck = !isPrivate; // We only call this on exported symbols when we know they're in the correct scope 7412 if (skipMembershipCheck || (!!length(symbol.declarations) && some(symbol.declarations, d => !!findAncestor(d, n => n === enclosingDeclaration)))) { 7413 const oldContext = context; 7414 context = cloneNodeBuilderContext(context); 7415 serializeSymbolWorker(symbol, isPrivate, propertyAsAlias); 7416 if (context.reportedDiagnostic) { 7417 oldcontext.reportedDiagnostic = context.reportedDiagnostic; // hoist diagnostic result into outer context 7418 } 7419 context = oldContext; 7420 } 7421 } 7422 7423 7424 // Synthesize declarations for a symbol - might be an Interface, a Class, a Namespace, a Type, a Variable (const, let, or var), an Alias 7425 // or a merge of some number of those. 7426 // An interesting challenge is ensuring that when classes merge with namespaces and interfaces, is keeping 7427 // each symbol in only one of the representations 7428 // Also, synthesizing a default export of some kind 7429 // If it's an alias: emit `export default ref` 7430 // If it's a property: emit `export default _default` with a `_default` prop 7431 // If it's a class/interface/function: emit a class/interface/function with a `default` modifier 7432 // These forms can merge, eg (`export default 12; export default interface A {}`) 7433 function serializeSymbolWorker(symbol: Symbol, isPrivate: boolean, propertyAsAlias: boolean): void { 7434 const symbolName = unescapeLeadingUnderscores(symbol.escapedName); 7435 const isDefault = symbol.escapedName === InternalSymbolName.Default; 7436 if (isPrivate && !(context.flags & NodeBuilderFlags.AllowAnonymousIdentifier) && isStringANonContextualKeyword(symbolName) && !isDefault) { 7437 // Oh no. We cannot use this symbol's name as it's name... It's likely some jsdoc had an invalid name like `export` or `default` :( 7438 context.encounteredError = true; 7439 // TODO: Issue error via symbol tracker? 7440 return; // If we need to emit a private with a keyword name, we're done for, since something else will try to refer to it by that name 7441 } 7442 let needsPostExportDefault = isDefault && !!( 7443 symbol.flags & SymbolFlags.ExportDoesNotSupportDefaultModifier 7444 || (symbol.flags & SymbolFlags.Function && length(getPropertiesOfType(getTypeOfSymbol(symbol)))) 7445 ) && !(symbol.flags & SymbolFlags.Alias); // An alias symbol should preclude needing to make an alias ourselves 7446 let needsExportDeclaration = !needsPostExportDefault && !isPrivate && isStringANonContextualKeyword(symbolName) && !isDefault; 7447 // `serializeVariableOrProperty` will handle adding the export declaration if it is run (since `getInternalSymbolName` will create the name mapping), so we need to ensuer we unset `needsExportDeclaration` if it is 7448 if (needsPostExportDefault || needsExportDeclaration) { 7449 isPrivate = true; 7450 } 7451 const modifierFlags = (!isPrivate ? ModifierFlags.Export : 0) | (isDefault && !needsPostExportDefault ? ModifierFlags.Default : 0); 7452 const isConstMergedWithNS = symbol.flags & SymbolFlags.Module && 7453 symbol.flags & (SymbolFlags.BlockScopedVariable | SymbolFlags.FunctionScopedVariable | SymbolFlags.Property) && 7454 symbol.escapedName !== InternalSymbolName.ExportEquals; 7455 const isConstMergedWithNSPrintableAsSignatureMerge = isConstMergedWithNS && isTypeRepresentableAsFunctionNamespaceMerge(getTypeOfSymbol(symbol), symbol); 7456 if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method) || isConstMergedWithNSPrintableAsSignatureMerge) { 7457 serializeAsFunctionNamespaceMerge(getTypeOfSymbol(symbol), symbol, getInternalSymbolName(symbol, symbolName), modifierFlags); 7458 } 7459 if (symbol.flags & SymbolFlags.TypeAlias) { 7460 serializeTypeAlias(symbol, symbolName, modifierFlags); 7461 } 7462 // Need to skip over export= symbols below - json source files get a single `Property` flagged 7463 // symbol of name `export=` which needs to be handled like an alias. It's not great, but it is what it is. 7464 if (symbol.flags & (SymbolFlags.BlockScopedVariable | SymbolFlags.FunctionScopedVariable | SymbolFlags.Property) 7465 && symbol.escapedName !== InternalSymbolName.ExportEquals 7466 && !(symbol.flags & SymbolFlags.Prototype) 7467 && !(symbol.flags & SymbolFlags.Class) 7468 && !(symbol.flags & SymbolFlags.Method) 7469 && !isConstMergedWithNSPrintableAsSignatureMerge) { 7470 if (propertyAsAlias) { 7471 const createdExport = serializeMaybeAliasAssignment(symbol); 7472 if (createdExport) { 7473 needsExportDeclaration = false; 7474 needsPostExportDefault = false; 7475 } 7476 } 7477 else { 7478 const type = getTypeOfSymbol(symbol); 7479 const localName = getInternalSymbolName(symbol, symbolName); 7480 if (!(symbol.flags & SymbolFlags.Function) && isTypeRepresentableAsFunctionNamespaceMerge(type, symbol)) { 7481 // If the type looks like a function declaration + ns could represent it, and it's type is sourced locally, rewrite it into a function declaration + ns 7482 serializeAsFunctionNamespaceMerge(type, symbol, localName, modifierFlags); 7483 } 7484 else { 7485 // A Class + Property merge is made for a `module.exports.Member = class {}`, and it doesn't serialize well as either a class _or_ a property symbol - in fact, _it behaves like an alias!_ 7486 // `var` is `FunctionScopedVariable`, `const` and `let` are `BlockScopedVariable`, and `module.exports.thing =` is `Property` 7487 const flags = !(symbol.flags & SymbolFlags.BlockScopedVariable) 7488 ? symbol.parent?.valueDeclaration && isSourceFile(symbol.parent?.valueDeclaration) 7489 ? NodeFlags.Const // exports are immutable in es6, which is what we emulate and check; so it's safe to mark all exports as `const` (there's no difference to consumers, but it allows unique symbol type declarations) 7490 : undefined 7491 : isConstVariable(symbol) 7492 ? NodeFlags.Const 7493 : NodeFlags.Let; 7494 const name = (needsPostExportDefault || !(symbol.flags & SymbolFlags.Property)) ? localName : getUnusedName(localName, symbol); 7495 let textRange: Node | undefined = symbol.declarations && find(symbol.declarations, d => isVariableDeclaration(d)); 7496 if (textRange && isVariableDeclarationList(textRange.parent) && textRange.parent.declarations.length === 1) { 7497 textRange = textRange.parent.parent; 7498 } 7499 const propertyAccessRequire = symbol.declarations?.find(isPropertyAccessExpression); 7500 if (propertyAccessRequire && isBinaryExpression(propertyAccessRequire.parent) && isIdentifier(propertyAccessRequire.parent.right) 7501 && type.symbol?.valueDeclaration && isSourceFile(type.symbol.valueDeclaration)) { 7502 const alias = localName === propertyAccessRequire.parent.right.escapedText ? undefined : propertyAccessRequire.parent.right; 7503 addResult( 7504 factory.createExportDeclaration( 7505 /*modifiers*/ undefined, 7506 /*isTypeOnly*/ false, 7507 factory.createNamedExports([factory.createExportSpecifier(/*isTypeOnly*/ false, alias, localName)]) 7508 ), 7509 ModifierFlags.None 7510 ); 7511 context.tracker.trackSymbol!(type.symbol, context.enclosingDeclaration, SymbolFlags.Value); 7512 } 7513 else { 7514 const statement = setTextRange(factory.createVariableStatement(/*modifiers*/ undefined, factory.createVariableDeclarationList([ 7515 factory.createVariableDeclaration(name, /*exclamationToken*/ undefined, serializeTypeForDeclaration(context, type, symbol, enclosingDeclaration, includePrivateSymbol, bundled)) 7516 ], flags)), textRange); 7517 addResult(statement, name !== localName ? modifierFlags & ~ModifierFlags.Export : modifierFlags); 7518 if (name !== localName && !isPrivate) { 7519 // We rename the variable declaration we generate for Property symbols since they may have a name which 7520 // conflicts with a local declaration. For example, given input: 7521 // ``` 7522 // function g() {} 7523 // module.exports.g = g 7524 // ``` 7525 // In such a situation, we have a local variable named `g`, and a separate exported variable named `g`. 7526 // Naively, we would emit 7527 // ``` 7528 // function g() {} 7529 // export const g: typeof g; 7530 // ``` 7531 // That's obviously incorrect - the `g` in the type annotation needs to refer to the local `g`, but 7532 // the export declaration shadows it. 7533 // To work around that, we instead write 7534 // ``` 7535 // function g() {} 7536 // const g_1: typeof g; 7537 // export { g_1 as g }; 7538 // ``` 7539 // To create an export named `g` that does _not_ shadow the local `g` 7540 addResult( 7541 factory.createExportDeclaration( 7542 /*modifiers*/ undefined, 7543 /*isTypeOnly*/ false, 7544 factory.createNamedExports([factory.createExportSpecifier(/*isTypeOnly*/ false, name, localName)]) 7545 ), 7546 ModifierFlags.None 7547 ); 7548 needsExportDeclaration = false; 7549 needsPostExportDefault = false; 7550 } 7551 } 7552 } 7553 } 7554 } 7555 if (symbol.flags & SymbolFlags.Enum) { 7556 serializeEnum(symbol, symbolName, modifierFlags); 7557 } 7558 if (symbol.flags & SymbolFlags.Class) { 7559 if (symbol.flags & SymbolFlags.Property 7560 && symbol.valueDeclaration 7561 && isBinaryExpression(symbol.valueDeclaration.parent) 7562 && isClassExpression(symbol.valueDeclaration.parent.right)) { 7563 // Looks like a `module.exports.Sub = class {}` - if we serialize `symbol` as a class, the result will have no members, 7564 // since the classiness is actually from the target of the effective alias the symbol is. yes. A BlockScopedVariable|Class|Property 7565 // _really_ acts like an Alias, and none of a BlockScopedVariable, Class, or Property. This is the travesty of JS binding today. 7566 serializeAsAlias(symbol, getInternalSymbolName(symbol, symbolName), modifierFlags); 7567 } 7568 else { 7569 serializeAsClass(symbol, getInternalSymbolName(symbol, symbolName), modifierFlags); 7570 } 7571 } 7572 if ((symbol.flags & (SymbolFlags.ValueModule | SymbolFlags.NamespaceModule) && (!isConstMergedWithNS || isTypeOnlyNamespace(symbol))) || isConstMergedWithNSPrintableAsSignatureMerge) { 7573 serializeModule(symbol, symbolName, modifierFlags); 7574 } 7575 // The class meaning serialization should handle serializing all interface members 7576 if (symbol.flags & SymbolFlags.Interface && !(symbol.flags & SymbolFlags.Class)) { 7577 serializeInterface(symbol, symbolName, modifierFlags); 7578 } 7579 if (symbol.flags & SymbolFlags.Alias) { 7580 serializeAsAlias(symbol, getInternalSymbolName(symbol, symbolName), modifierFlags); 7581 } 7582 if (symbol.flags & SymbolFlags.Property && symbol.escapedName === InternalSymbolName.ExportEquals) { 7583 serializeMaybeAliasAssignment(symbol); 7584 } 7585 if (symbol.flags & SymbolFlags.ExportStar) { 7586 // synthesize export * from "moduleReference" 7587 // Straightforward - only one thing to do - make an export declaration 7588 if (symbol.declarations) { 7589 for (const node of symbol.declarations) { 7590 const resolvedModule = resolveExternalModuleName(node, (node as ExportDeclaration).moduleSpecifier!); 7591 if (!resolvedModule) continue; 7592 addResult(factory.createExportDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ false, /*exportClause*/ undefined, factory.createStringLiteral(getSpecifierForModuleSymbol(resolvedModule, context))), ModifierFlags.None); 7593 } 7594 } 7595 } 7596 if (needsPostExportDefault) { 7597 addResult(factory.createExportAssignment(/*modifiers*/ undefined, /*isExportAssignment*/ false, factory.createIdentifier(getInternalSymbolName(symbol, symbolName))), ModifierFlags.None); 7598 } 7599 else if (needsExportDeclaration) { 7600 addResult(factory.createExportDeclaration( 7601 /*modifiers*/ undefined, 7602 /*isTypeOnly*/ false, 7603 factory.createNamedExports([factory.createExportSpecifier(/*isTypeOnly*/ false, getInternalSymbolName(symbol, symbolName), symbolName)]) 7604 ), ModifierFlags.None); 7605 } 7606 } 7607 7608 function includePrivateSymbol(symbol: Symbol) { 7609 if (some(symbol.declarations, isParameterDeclaration)) return; 7610 Debug.assertIsDefined(deferredPrivatesStack[deferredPrivatesStack.length - 1]); 7611 getUnusedName(unescapeLeadingUnderscores(symbol.escapedName), symbol); // Call to cache unique name for symbol 7612 // Blanket moving (import) aliases into the root private context should work, since imports are not valid within namespaces 7613 // (so they must have been in the root to begin with if they were real imports) cjs `require` aliases (an upcoming feature) 7614 // will throw a wrench in this, since those may have been nested, but we'll need to synthesize them in the outer scope 7615 // anyway, as that's the only place the import they translate to is valid. In such a case, we might need to use a unique name 7616 // for the moved import; which hopefully the above `getUnusedName` call should produce. 7617 const isExternalImportAlias = !!(symbol.flags & SymbolFlags.Alias) && !some(symbol.declarations, d => 7618 !!findAncestor(d, isExportDeclaration) || 7619 isNamespaceExport(d) || 7620 (isImportEqualsDeclaration(d) && !isExternalModuleReference(d.moduleReference)) 7621 ); 7622 deferredPrivatesStack[isExternalImportAlias ? 0 : (deferredPrivatesStack.length - 1)].set(getSymbolId(symbol), symbol); 7623 } 7624 7625 function isExportingScope(enclosingDeclaration: Node) { 7626 return ((isSourceFile(enclosingDeclaration) && (isExternalOrCommonJsModule(enclosingDeclaration) || isJsonSourceFile(enclosingDeclaration))) || 7627 (isAmbientModule(enclosingDeclaration) && !isGlobalScopeAugmentation(enclosingDeclaration))); 7628 } 7629 7630 // Prepends a `declare` and/or `export` modifier if the context requires it, and then adds `node` to `result` and returns `node` 7631 function addResult(node: Statement, additionalModifierFlags: ModifierFlags) { 7632 if (canHaveModifiers(node)) { 7633 let newModifierFlags: ModifierFlags = ModifierFlags.None; 7634 const enclosingDeclaration = context.enclosingDeclaration && 7635 (isJSDocTypeAlias(context.enclosingDeclaration) ? getSourceFileOfNode(context.enclosingDeclaration) : context.enclosingDeclaration); 7636 if (additionalModifierFlags & ModifierFlags.Export && 7637 enclosingDeclaration && (isExportingScope(enclosingDeclaration) || isModuleDeclaration(enclosingDeclaration)) && 7638 canHaveExportModifier(node) 7639 ) { 7640 // Classes, namespaces, variables, functions, interfaces, and types should all be `export`ed in a module context if not private 7641 newModifierFlags |= ModifierFlags.Export; 7642 } 7643 if (addingDeclare && !(newModifierFlags & ModifierFlags.Export) && 7644 (!enclosingDeclaration || !(enclosingDeclaration.flags & NodeFlags.Ambient)) && 7645 (isEnumDeclaration(node) || isVariableStatement(node) || isFunctionDeclaration(node) || isClassDeclaration(node) || isModuleDeclaration(node))) { 7646 // Classes, namespaces, variables, enums, and functions all need `declare` modifiers to be valid in a declaration file top-level scope 7647 newModifierFlags |= ModifierFlags.Ambient; 7648 } 7649 if ((additionalModifierFlags & ModifierFlags.Default) && (isClassDeclaration(node) || isInterfaceDeclaration(node) || isFunctionDeclaration(node))) { 7650 newModifierFlags |= ModifierFlags.Default; 7651 } 7652 if (newModifierFlags) { 7653 node = factory.updateModifiers(node, newModifierFlags | getEffectiveModifierFlags(node)); 7654 } 7655 } 7656 results.push(node); 7657 } 7658 7659 function serializeTypeAlias(symbol: Symbol, symbolName: string, modifierFlags: ModifierFlags) { 7660 const aliasType = getDeclaredTypeOfTypeAlias(symbol); 7661 const typeParams = getSymbolLinks(symbol).typeParameters; 7662 const typeParamDecls = map(typeParams, p => typeParameterToDeclaration(p, context)); 7663 const jsdocAliasDecl = symbol.declarations?.find(isJSDocTypeAlias); 7664 const commentText = getTextOfJSDocComment(jsdocAliasDecl ? jsdocAliasDecl.comment || jsdocAliasDecl.parent.comment : undefined); 7665 const oldFlags = context.flags; 7666 context.flags |= NodeBuilderFlags.InTypeAlias; 7667 const oldEnclosingDecl = context.enclosingDeclaration; 7668 context.enclosingDeclaration = jsdocAliasDecl; 7669 const typeNode = jsdocAliasDecl && jsdocAliasDecl.typeExpression 7670 && isJSDocTypeExpression(jsdocAliasDecl.typeExpression) 7671 && serializeExistingTypeNode(context, jsdocAliasDecl.typeExpression.type, includePrivateSymbol, bundled) 7672 || typeToTypeNodeHelper(aliasType, context); 7673 addResult(setSyntheticLeadingComments( 7674 factory.createTypeAliasDeclaration(/*modifiers*/ undefined, getInternalSymbolName(symbol, symbolName), typeParamDecls, typeNode), 7675 !commentText ? [] : [{ kind: SyntaxKind.MultiLineCommentTrivia, text: "*\n * " + commentText.replace(/\n/g, "\n * ") + "\n ", pos: -1, end: -1, hasTrailingNewLine: true }] 7676 ), modifierFlags); 7677 context.flags = oldFlags; 7678 context.enclosingDeclaration = oldEnclosingDecl; 7679 } 7680 7681 function serializeInterface(symbol: Symbol, symbolName: string, modifierFlags: ModifierFlags) { 7682 const interfaceType = getDeclaredTypeOfClassOrInterface(symbol); 7683 const localParams = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol); 7684 const typeParamDecls = map(localParams, p => typeParameterToDeclaration(p, context)); 7685 const baseTypes = getBaseTypes(interfaceType); 7686 const baseType = length(baseTypes) ? getIntersectionType(baseTypes) : undefined; 7687 const members = flatMap<Symbol, TypeElement>(getPropertiesOfType(interfaceType), p => serializePropertySymbolForInterface(p, baseType)); 7688 const callSignatures = serializeSignatures(SignatureKind.Call, interfaceType, baseType, SyntaxKind.CallSignature) as CallSignatureDeclaration[]; 7689 const constructSignatures = serializeSignatures(SignatureKind.Construct, interfaceType, baseType, SyntaxKind.ConstructSignature) as ConstructSignatureDeclaration[]; 7690 const indexSignatures = serializeIndexSignatures(interfaceType, baseType); 7691 7692 const heritageClauses = !length(baseTypes) ? undefined : [factory.createHeritageClause(SyntaxKind.ExtendsKeyword, mapDefined(baseTypes, b => trySerializeAsTypeReference(b, SymbolFlags.Value)))]; 7693 addResult(factory.createInterfaceDeclaration( 7694 /*modifiers*/ undefined, 7695 getInternalSymbolName(symbol, symbolName), 7696 typeParamDecls, 7697 heritageClauses, 7698 [...indexSignatures, ...constructSignatures, ...callSignatures, ...members] 7699 ), modifierFlags); 7700 } 7701 7702 function getNamespaceMembersForSerialization(symbol: Symbol) { 7703 return !symbol.exports ? [] : filter(arrayFrom(symbol.exports.values()), isNamespaceMember); 7704 } 7705 7706 function isTypeOnlyNamespace(symbol: Symbol) { 7707 return every(getNamespaceMembersForSerialization(symbol), m => !(getAllSymbolFlags(resolveSymbol(m)) & SymbolFlags.Value)); 7708 } 7709 7710 function serializeModule(symbol: Symbol, symbolName: string, modifierFlags: ModifierFlags) { 7711 const members = getNamespaceMembersForSerialization(symbol); 7712 // Split NS members up by declaration - members whose parent symbol is the ns symbol vs those whose is not (but were added in later via merging) 7713 const locationMap = arrayToMultiMap(members, m => m.parent && m.parent === symbol ? "real" : "merged"); 7714 const realMembers = locationMap.get("real") || emptyArray; 7715 const mergedMembers = locationMap.get("merged") || emptyArray; 7716 // TODO: `suppressNewPrivateContext` is questionable -we need to simply be emitting privates in whatever scope they were declared in, rather 7717 // than whatever scope we traverse to them in. That's a bit of a complex rewrite, since we're not _actually_ tracking privates at all in advance, 7718 // so we don't even have placeholders to fill in. 7719 if (length(realMembers)) { 7720 const localName = getInternalSymbolName(symbol, symbolName); 7721 serializeAsNamespaceDeclaration(realMembers, localName, modifierFlags, !!(symbol.flags & (SymbolFlags.Function | SymbolFlags.Assignment))); 7722 } 7723 if (length(mergedMembers)) { 7724 const containingFile = getSourceFileOfNode(context.enclosingDeclaration); 7725 const localName = getInternalSymbolName(symbol, symbolName); 7726 const nsBody = factory.createModuleBlock([factory.createExportDeclaration( 7727 /*modifiers*/ undefined, 7728 /*isTypeOnly*/ false, 7729 factory.createNamedExports(mapDefined(filter(mergedMembers, n => n.escapedName !== InternalSymbolName.ExportEquals), s => { 7730 const name = unescapeLeadingUnderscores(s.escapedName); 7731 const localName = getInternalSymbolName(s, name); 7732 const aliasDecl = s.declarations && getDeclarationOfAliasSymbol(s); 7733 if (containingFile && (aliasDecl ? containingFile !== getSourceFileOfNode(aliasDecl) : !some(s.declarations, d => getSourceFileOfNode(d) === containingFile))) { 7734 context.tracker?.reportNonlocalAugmentation?.(containingFile, symbol, s); 7735 return undefined; 7736 } 7737 const target = aliasDecl && getTargetOfAliasDeclaration(aliasDecl, /*dontRecursivelyResolve*/ true); 7738 includePrivateSymbol(target || s); 7739 const targetName = target ? getInternalSymbolName(target, unescapeLeadingUnderscores(target.escapedName)) : localName; 7740 return factory.createExportSpecifier(/*isTypeOnly*/ false, name === targetName ? undefined : targetName, name); 7741 })) 7742 )]); 7743 addResult(factory.createModuleDeclaration( 7744 /*modifiers*/ undefined, 7745 factory.createIdentifier(localName), 7746 nsBody, 7747 NodeFlags.Namespace 7748 ), ModifierFlags.None); 7749 } 7750 } 7751 7752 function serializeEnum(symbol: Symbol, symbolName: string, modifierFlags: ModifierFlags) { 7753 addResult(factory.createEnumDeclaration( 7754 factory.createModifiersFromModifierFlags(isConstEnumSymbol(symbol) ? ModifierFlags.Const : 0), 7755 getInternalSymbolName(symbol, symbolName), 7756 map(filter(getPropertiesOfType(getTypeOfSymbol(symbol)), p => !!(p.flags & SymbolFlags.EnumMember)), p => { 7757 // TODO: Handle computed names 7758 // I hate that to get the initialized value we need to walk back to the declarations here; but there's no 7759 // other way to get the possible const value of an enum member that I'm aware of, as the value is cached 7760 // _on the declaration_, not on the declaration's symbol... 7761 const initializedValue = p.declarations && p.declarations[0] && isEnumMember(p.declarations[0]) ? getConstantValue(p.declarations[0]) : undefined; 7762 return factory.createEnumMember(unescapeLeadingUnderscores(p.escapedName), initializedValue === undefined ? undefined : 7763 typeof initializedValue === "string" ? factory.createStringLiteral(initializedValue) : 7764 factory.createNumericLiteral(initializedValue)); 7765 }) 7766 ), modifierFlags); 7767 } 7768 7769 function serializeAsFunctionNamespaceMerge(type: Type, symbol: Symbol, localName: string, modifierFlags: ModifierFlags) { 7770 const signatures = getSignaturesOfType(type, SignatureKind.Call); 7771 for (const sig of signatures) { 7772 // Each overload becomes a separate function declaration, in order 7773 const decl = signatureToSignatureDeclarationHelper(sig, SyntaxKind.FunctionDeclaration, context, { name: factory.createIdentifier(localName), privateSymbolVisitor: includePrivateSymbol, bundledImports: bundled }) as FunctionDeclaration; 7774 addResult(setTextRange(decl, getSignatureTextRangeLocation(sig)), modifierFlags); 7775 } 7776 // Module symbol emit will take care of module-y members, provided it has exports 7777 if (!(symbol.flags & (SymbolFlags.ValueModule | SymbolFlags.NamespaceModule) && !!symbol.exports && !!symbol.exports.size)) { 7778 const props = filter(getPropertiesOfType(type), isNamespaceMember); 7779 serializeAsNamespaceDeclaration(props, localName, modifierFlags, /*suppressNewPrivateContext*/ true); 7780 } 7781 } 7782 7783 function getSignatureTextRangeLocation(signature: Signature) { 7784 if (signature.declaration && signature.declaration.parent) { 7785 if (isBinaryExpression(signature.declaration.parent) && getAssignmentDeclarationKind(signature.declaration.parent) === AssignmentDeclarationKind.Property) { 7786 return signature.declaration.parent; 7787 } 7788 // for expressions assigned to `var`s, use the `var` as the text range 7789 if (isVariableDeclaration(signature.declaration.parent) && signature.declaration.parent.parent) { 7790 return signature.declaration.parent.parent; 7791 } 7792 } 7793 return signature.declaration; 7794 } 7795 7796 function serializeAsNamespaceDeclaration(props: readonly Symbol[], localName: string, modifierFlags: ModifierFlags, suppressNewPrivateContext: boolean) { 7797 if (length(props)) { 7798 const localVsRemoteMap = arrayToMultiMap(props, p => 7799 !length(p.declarations) || some(p.declarations, d => 7800 getSourceFileOfNode(d) === getSourceFileOfNode(context.enclosingDeclaration!) 7801 ) ? "local" : "remote" 7802 ); 7803 const localProps = localVsRemoteMap.get("local") || emptyArray; 7804 // handle remote props first - we need to make an `import` declaration that points at the module containing each remote 7805 // prop in the outermost scope (TODO: a namespace within a namespace would need to be appropriately handled by this) 7806 // Example: 7807 // import Foo_1 = require("./exporter"); 7808 // export namespace ns { 7809 // import Foo = Foo_1.Foo; 7810 // export { Foo }; 7811 // export const c: number; 7812 // } 7813 // This is needed because in JS, statements like `const x = require("./f")` support both type and value lookup, even if they're 7814 // normally just value lookup (so it functions kinda like an alias even when it's not an alias) 7815 // _Usually_, we'll simply print the top-level as an alias instead of a `var` in such situations, however is is theoretically 7816 // possible to encounter a situation where a type has members from both the current file and other files - in those situations, 7817 // emit akin to the above would be needed. 7818 7819 // Add a namespace 7820 // Create namespace as non-synthetic so it is usable as an enclosing declaration 7821 let fakespace = parseNodeFactory.createModuleDeclaration(/*modifiers*/ undefined, factory.createIdentifier(localName), factory.createModuleBlock([]), NodeFlags.Namespace); 7822 setParent(fakespace, enclosingDeclaration as SourceFile | NamespaceDeclaration); 7823 fakespace.locals = createSymbolTable(props); 7824 fakespace.symbol = props[0].parent!; 7825 7826 const oldResults = results; 7827 results = []; 7828 const oldAddingDeclare = addingDeclare; 7829 addingDeclare = false; 7830 const subcontext = { ...context, enclosingDeclaration: fakespace }; 7831 const oldContext = context; 7832 context = subcontext; 7833 // TODO: implement handling for the localVsRemoteMap.get("remote") - should be difficult to trigger (see comment above), as only interesting cross-file js merges should make this possible 7834 visitSymbolTable(createSymbolTable(localProps), suppressNewPrivateContext, /*propertyAsAlias*/ true); 7835 context = oldContext; 7836 addingDeclare = oldAddingDeclare; 7837 const declarations = results; 7838 results = oldResults; 7839 // replace namespace with synthetic version 7840 const defaultReplaced = map(declarations, d => isExportAssignment(d) && !d.isExportEquals && isIdentifier(d.expression) ? factory.createExportDeclaration( 7841 /*modifiers*/ undefined, 7842 /*isTypeOnly*/ false, 7843 factory.createNamedExports([factory.createExportSpecifier(/*isTypeOnly*/ false, d.expression, factory.createIdentifier(InternalSymbolName.Default))]) 7844 ) : d); 7845 const exportModifierStripped = every(defaultReplaced, d => hasSyntacticModifier(d, ModifierFlags.Export)) ? map(defaultReplaced, removeExportModifier) : defaultReplaced; 7846 fakespace = factory.updateModuleDeclaration( 7847 fakespace, 7848 fakespace.modifiers, 7849 fakespace.name, 7850 factory.createModuleBlock(exportModifierStripped)); 7851 addResult(fakespace, modifierFlags); // namespaces can never be default exported 7852 } 7853 } 7854 7855 function isNamespaceMember(p: Symbol) { 7856 return !!(p.flags & (SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias)) || 7857 !(p.flags & SymbolFlags.Prototype || p.escapedName === "prototype" || p.valueDeclaration && isStatic(p.valueDeclaration) && isClassLike(p.valueDeclaration.parent)); 7858 } 7859 7860 function sanitizeJSDocImplements(clauses: readonly ExpressionWithTypeArguments[]): ExpressionWithTypeArguments[] | undefined { 7861 const result = mapDefined(clauses, e => { 7862 const oldEnclosing = context.enclosingDeclaration; 7863 context.enclosingDeclaration = e; 7864 let expr = e.expression; 7865 if (isEntityNameExpression(expr)) { 7866 if (isIdentifier(expr) && idText(expr) === "") { 7867 return cleanup(/*result*/ undefined); // Empty heritage clause, should be an error, but prefer emitting no heritage clauses to reemitting the empty one 7868 } 7869 let introducesError: boolean; 7870 ({ introducesError, node: expr } = trackExistingEntityName(expr, context, includePrivateSymbol)); 7871 if (introducesError) { 7872 return cleanup(/*result*/ undefined); 7873 } 7874 } 7875 return cleanup(factory.createExpressionWithTypeArguments(expr, 7876 map(e.typeArguments, a => 7877 serializeExistingTypeNode(context, a, includePrivateSymbol, bundled) 7878 || typeToTypeNodeHelper(getTypeFromTypeNode(a), context) 7879 ) 7880 )); 7881 7882 function cleanup<T>(result: T): T { 7883 context.enclosingDeclaration = oldEnclosing; 7884 return result; 7885 } 7886 }); 7887 if (result.length === clauses.length) { 7888 return result; 7889 } 7890 return undefined; 7891 } 7892 7893 function serializeAsClass(symbol: Symbol, localName: string, modifierFlags: ModifierFlags) { 7894 const originalDecl = symbol.declarations?.find(isClassLike); 7895 const oldEnclosing = context.enclosingDeclaration; 7896 context.enclosingDeclaration = originalDecl || oldEnclosing; 7897 const localParams = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol); 7898 const typeParamDecls = map(localParams, p => typeParameterToDeclaration(p, context)); 7899 const classType = getDeclaredTypeOfClassOrInterface(symbol); 7900 const baseTypes = getBaseTypes(classType); 7901 const originalImplements = originalDecl && getEffectiveImplementsTypeNodes(originalDecl); 7902 const implementsExpressions = originalImplements && sanitizeJSDocImplements(originalImplements) 7903 || mapDefined(getImplementsTypes(classType), serializeImplementedType); 7904 const staticType = getTypeOfSymbol(symbol); 7905 const isClass = !!staticType.symbol?.valueDeclaration && isClassLike(staticType.symbol.valueDeclaration); 7906 const staticBaseType = isClass 7907 ? getBaseConstructorTypeOfClass(staticType as InterfaceType) 7908 : anyType; 7909 const heritageClauses = [ 7910 ...!length(baseTypes) ? [] : [factory.createHeritageClause(SyntaxKind.ExtendsKeyword, map(baseTypes, b => serializeBaseType(b, staticBaseType, localName)))], 7911 ...!length(implementsExpressions) ? [] : [factory.createHeritageClause(SyntaxKind.ImplementsKeyword, implementsExpressions)] 7912 ]; 7913 const symbolProps = getNonInheritedProperties(classType, baseTypes, getPropertiesOfType(classType)); 7914 const publicSymbolProps = filter(symbolProps, s => { 7915 // `valueDeclaration` could be undefined if inherited from 7916 // a union/intersection base type, but inherited properties 7917 // don't matter here. 7918 const valueDecl = s.valueDeclaration; 7919 return !!valueDecl && !(isNamedDeclaration(valueDecl) && isPrivateIdentifier(valueDecl.name)); 7920 }); 7921 const hasPrivateIdentifier = some(symbolProps, s => { 7922 // `valueDeclaration` could be undefined if inherited from 7923 // a union/intersection base type, but inherited properties 7924 // don't matter here. 7925 const valueDecl = s.valueDeclaration; 7926 return !!valueDecl && isNamedDeclaration(valueDecl) && isPrivateIdentifier(valueDecl.name); 7927 }); 7928 // Boil down all private properties into a single one. 7929 const privateProperties = hasPrivateIdentifier ? 7930 [factory.createPropertyDeclaration( 7931 /*modifiers*/ undefined, 7932 factory.createPrivateIdentifier("#private"), 7933 /*questionOrExclamationToken*/ undefined, 7934 /*type*/ undefined, 7935 /*initializer*/ undefined, 7936 )] : 7937 emptyArray; 7938 const publicProperties = flatMap<Symbol, ClassElement>(publicSymbolProps, p => serializePropertySymbolForClass(p, /*isStatic*/ false, baseTypes[0])); 7939 // Consider static members empty if symbol also has function or module meaning - function namespacey emit will handle statics 7940 const staticMembers = flatMap( 7941 filter(getPropertiesOfType(staticType), p => !(p.flags & SymbolFlags.Prototype) && p.escapedName !== "prototype" && !isNamespaceMember(p)), 7942 p => serializePropertySymbolForClass(p, /*isStatic*/ true, staticBaseType)); 7943 // When we encounter an `X.prototype.y` assignment in a JS file, we bind `X` as a class regardless as to whether 7944 // the value is ever initialized with a class or function-like value. For cases where `X` could never be 7945 // created via `new`, we will inject a `private constructor()` declaration to indicate it is not createable. 7946 const isNonConstructableClassLikeInJsFile = 7947 !isClass && 7948 !!symbol.valueDeclaration && 7949 isInJSFile(symbol.valueDeclaration) && 7950 !some(getSignaturesOfType(staticType, SignatureKind.Construct)); 7951 const constructors = isNonConstructableClassLikeInJsFile ? 7952 [factory.createConstructorDeclaration(factory.createModifiersFromModifierFlags(ModifierFlags.Private), [], /*body*/ undefined)] : 7953 serializeSignatures(SignatureKind.Construct, staticType, staticBaseType, SyntaxKind.Constructor) as ConstructorDeclaration[]; 7954 const indexSignatures = serializeIndexSignatures(classType, baseTypes[0]); 7955 context.enclosingDeclaration = oldEnclosing; 7956 addResult(setTextRange(factory.createClassDeclaration( 7957 /*modifiers*/ undefined, 7958 localName, 7959 typeParamDecls, 7960 heritageClauses, 7961 [...indexSignatures, ...staticMembers, ...constructors, ...publicProperties, ...privateProperties] 7962 ), symbol.declarations && filter(symbol.declarations, d => isClassDeclaration(d) || isClassExpression(d))[0]), modifierFlags); 7963 } 7964 7965 function getSomeTargetNameFromDeclarations(declarations: Declaration[] | undefined) { 7966 return firstDefined(declarations, d => { 7967 if (isImportSpecifier(d) || isExportSpecifier(d)) { 7968 return idText(d.propertyName || d.name); 7969 } 7970 if (isBinaryExpression(d) || isExportAssignment(d)) { 7971 const expression = isExportAssignment(d) ? d.expression : d.right; 7972 if (isPropertyAccessExpression(expression)) { 7973 return idText(expression.name); 7974 } 7975 } 7976 if (isAliasSymbolDeclaration(d)) { 7977 // This is... heuristic, at best. But it's probably better than always printing the name of the shorthand ambient module. 7978 const name = getNameOfDeclaration(d); 7979 if (name && isIdentifier(name)) { 7980 return idText(name); 7981 } 7982 } 7983 return undefined; 7984 }); 7985 } 7986 7987 function serializeAsAlias(symbol: Symbol, localName: string, modifierFlags: ModifierFlags) { 7988 // synthesize an alias, eg `export { symbolName as Name }` 7989 // need to mark the alias `symbol` points at 7990 // as something we need to serialize as a private declaration as well 7991 const node = getDeclarationOfAliasSymbol(symbol); 7992 if (!node) return Debug.fail(); 7993 const target = getMergedSymbol(getTargetOfAliasDeclaration(node, /*dontRecursivelyResolve*/ true)); 7994 if (!target) { 7995 return; 7996 } 7997 // If `target` refers to a shorthand module symbol, the name we're trying to pull out isn;t recoverable from the target symbol 7998 // In such a scenario, we must fall back to looking for an alias declaration on `symbol` and pulling the target name from that 7999 let verbatimTargetName = isShorthandAmbientModuleSymbol(target) && getSomeTargetNameFromDeclarations(symbol.declarations) || unescapeLeadingUnderscores(target.escapedName); 8000 if (verbatimTargetName === InternalSymbolName.ExportEquals && (getESModuleInterop(compilerOptions) || compilerOptions.allowSyntheticDefaultImports)) { 8001 // target refers to an `export=` symbol that was hoisted into a synthetic default - rename here to match 8002 verbatimTargetName = InternalSymbolName.Default; 8003 } 8004 const targetName = getInternalSymbolName(target, verbatimTargetName); 8005 includePrivateSymbol(target); // the target may be within the same scope - attempt to serialize it first 8006 switch (node.kind) { 8007 case SyntaxKind.BindingElement: 8008 if (node.parent?.parent?.kind === SyntaxKind.VariableDeclaration) { 8009 // const { SomeClass } = require('./lib'); 8010 const specifier = getSpecifierForModuleSymbol(target.parent || target, context); // './lib' 8011 const { propertyName } = node as BindingElement; 8012 addResult(factory.createImportDeclaration( 8013 /*modifiers*/ undefined, 8014 factory.createImportClause(/*isTypeOnly*/ false, /*name*/ undefined, factory.createNamedImports([factory.createImportSpecifier( 8015 /*isTypeOnly*/ false, 8016 propertyName && isIdentifier(propertyName) ? factory.createIdentifier(idText(propertyName)) : undefined, 8017 factory.createIdentifier(localName) 8018 )])), 8019 factory.createStringLiteral(specifier), 8020 /*importClause*/ undefined 8021 ), ModifierFlags.None); 8022 break; 8023 } 8024 // We don't know how to serialize this (nested?) binding element 8025 Debug.failBadSyntaxKind(node.parent?.parent || node, "Unhandled binding element grandparent kind in declaration serialization"); 8026 case SyntaxKind.ShorthandPropertyAssignment: 8027 if (node.parent?.parent?.kind === SyntaxKind.BinaryExpression) { 8028 // module.exports = { SomeClass } 8029 serializeExportSpecifier( 8030 unescapeLeadingUnderscores(symbol.escapedName), 8031 targetName 8032 ); 8033 } 8034 break; 8035 case SyntaxKind.VariableDeclaration: 8036 // commonjs require: const x = require('y') 8037 if (isPropertyAccessExpression((node as VariableDeclaration).initializer!)) { 8038 // const x = require('y').z 8039 const initializer = (node as VariableDeclaration).initializer! as PropertyAccessExpression; // require('y').z 8040 const uniqueName = factory.createUniqueName(localName); // _x 8041 const specifier = getSpecifierForModuleSymbol(target.parent || target, context); // 'y' 8042 // import _x = require('y'); 8043 addResult(factory.createImportEqualsDeclaration( 8044 /*modifiers*/ undefined, 8045 /*isTypeOnly*/ false, 8046 uniqueName, 8047 factory.createExternalModuleReference(factory.createStringLiteral(specifier)) 8048 ), ModifierFlags.None); 8049 // import x = _x.z 8050 addResult(factory.createImportEqualsDeclaration( 8051 /*modifiers*/ undefined, 8052 /*isTypeOnly*/ false, 8053 factory.createIdentifier(localName), 8054 factory.createQualifiedName(uniqueName, initializer.name as Identifier), 8055 ), modifierFlags); 8056 break; 8057 } 8058 // else fall through and treat commonjs require just like import= 8059 case SyntaxKind.ImportEqualsDeclaration: 8060 // This _specifically_ only exists to handle json declarations - where we make aliases, but since 8061 // we emit no declarations for the json document, must not refer to it in the declarations 8062 if (target.escapedName === InternalSymbolName.ExportEquals && some(target.declarations, isJsonSourceFile)) { 8063 serializeMaybeAliasAssignment(symbol); 8064 break; 8065 } 8066 // Could be a local `import localName = ns.member` or 8067 // an external `import localName = require("whatever")` 8068 const isLocalImport = !(target.flags & SymbolFlags.ValueModule) && !isVariableDeclaration(node); 8069 addResult(factory.createImportEqualsDeclaration( 8070 /*modifiers*/ undefined, 8071 /*isTypeOnly*/ false, 8072 factory.createIdentifier(localName), 8073 isLocalImport 8074 ? symbolToName(target, context, SymbolFlags.All, /*expectsIdentifier*/ false) 8075 : factory.createExternalModuleReference(factory.createStringLiteral(getSpecifierForModuleSymbol(target, context))) 8076 ), isLocalImport ? modifierFlags : ModifierFlags.None); 8077 break; 8078 case SyntaxKind.NamespaceExportDeclaration: 8079 // export as namespace foo 8080 // TODO: Not part of a file's local or export symbol tables 8081 // Is bound into file.symbol.globalExports instead, which we don't currently traverse 8082 addResult(factory.createNamespaceExportDeclaration(idText((node as NamespaceExportDeclaration).name)), ModifierFlags.None); 8083 break; 8084 case SyntaxKind.ImportClause: 8085 addResult(factory.createImportDeclaration( 8086 /*modifiers*/ undefined, 8087 factory.createImportClause(/*isTypeOnly*/ false, factory.createIdentifier(localName), /*namedBindings*/ undefined), 8088 // We use `target.parent || target` below as `target.parent` is unset when the target is a module which has been export assigned 8089 // And then made into a default by the `esModuleInterop` or `allowSyntheticDefaultImports` flag 8090 // In such cases, the `target` refers to the module itself already 8091 factory.createStringLiteral(getSpecifierForModuleSymbol(target.parent || target, context)), 8092 /*assertClause*/ undefined 8093 ), ModifierFlags.None); 8094 break; 8095 case SyntaxKind.NamespaceImport: 8096 addResult(factory.createImportDeclaration( 8097 /*modifiers*/ undefined, 8098 factory.createImportClause(/*isTypeOnly*/ false, /*importClause*/ undefined, factory.createNamespaceImport(factory.createIdentifier(localName))), 8099 factory.createStringLiteral(getSpecifierForModuleSymbol(target, context)), 8100 /*assertClause*/ undefined 8101 ), ModifierFlags.None); 8102 break; 8103 case SyntaxKind.NamespaceExport: 8104 addResult(factory.createExportDeclaration( 8105 /*modifiers*/ undefined, 8106 /*isTypeOnly*/ false, 8107 factory.createNamespaceExport(factory.createIdentifier(localName)), 8108 factory.createStringLiteral(getSpecifierForModuleSymbol(target, context)) 8109 ), ModifierFlags.None); 8110 break; 8111 case SyntaxKind.ImportSpecifier: 8112 addResult(factory.createImportDeclaration( 8113 /*modifiers*/ undefined, 8114 factory.createImportClause( 8115 /*isTypeOnly*/ false, 8116 /*importClause*/ undefined, 8117 factory.createNamedImports([ 8118 factory.createImportSpecifier( 8119 /*isTypeOnly*/ false, 8120 localName !== verbatimTargetName ? factory.createIdentifier(verbatimTargetName) : undefined, 8121 factory.createIdentifier(localName) 8122 ) 8123 ])), 8124 factory.createStringLiteral(getSpecifierForModuleSymbol(target.parent || target, context)), 8125 /*assertClause*/ undefined 8126 ), ModifierFlags.None); 8127 break; 8128 case SyntaxKind.ExportSpecifier: 8129 // does not use localName because the symbol name in this case refers to the name in the exports table, 8130 // which we must exactly preserve 8131 const specifier = (node.parent.parent as ExportDeclaration).moduleSpecifier; 8132 // targetName is only used when the target is local, as otherwise the target is an alias that points at 8133 // another file 8134 serializeExportSpecifier( 8135 unescapeLeadingUnderscores(symbol.escapedName), 8136 specifier ? verbatimTargetName : targetName, 8137 specifier && isStringLiteralLike(specifier) ? factory.createStringLiteral(specifier.text) : undefined 8138 ); 8139 break; 8140 case SyntaxKind.ExportAssignment: 8141 serializeMaybeAliasAssignment(symbol); 8142 break; 8143 case SyntaxKind.BinaryExpression: 8144 case SyntaxKind.PropertyAccessExpression: 8145 case SyntaxKind.ElementAccessExpression: 8146 // Could be best encoded as though an export specifier or as though an export assignment 8147 // If name is default or export=, do an export assignment 8148 // Otherwise do an export specifier 8149 if (symbol.escapedName === InternalSymbolName.Default || symbol.escapedName === InternalSymbolName.ExportEquals) { 8150 serializeMaybeAliasAssignment(symbol); 8151 } 8152 else { 8153 serializeExportSpecifier(localName, targetName); 8154 } 8155 break; 8156 default: 8157 return Debug.failBadSyntaxKind(node, "Unhandled alias declaration kind in symbol serializer!"); 8158 } 8159 } 8160 8161 function serializeExportSpecifier(localName: string, targetName: string, specifier?: Expression) { 8162 addResult(factory.createExportDeclaration( 8163 /*modifiers*/ undefined, 8164 /*isTypeOnly*/ false, 8165 factory.createNamedExports([factory.createExportSpecifier(/*isTypeOnly*/ false, localName !== targetName ? targetName : undefined, localName)]), 8166 specifier 8167 ), ModifierFlags.None); 8168 } 8169 8170 /** 8171 * Returns `true` if an export assignment or declaration was produced for the symbol 8172 */ 8173 function serializeMaybeAliasAssignment(symbol: Symbol): boolean { 8174 if (symbol.flags & SymbolFlags.Prototype) { 8175 return false; 8176 } 8177 const name = unescapeLeadingUnderscores(symbol.escapedName); 8178 const isExportEquals = name === InternalSymbolName.ExportEquals; 8179 const isDefault = name === InternalSymbolName.Default; 8180 const isExportAssignmentCompatibleSymbolName = isExportEquals || isDefault; 8181 // synthesize export = ref 8182 // ref should refer to either be a locally scoped symbol which we need to emit, or 8183 // a reference to another namespace/module which we may need to emit an `import` statement for 8184 const aliasDecl = symbol.declarations && getDeclarationOfAliasSymbol(symbol); 8185 // serialize what the alias points to, preserve the declaration's initializer 8186 const target = aliasDecl && getTargetOfAliasDeclaration(aliasDecl, /*dontRecursivelyResolve*/ true); 8187 // If the target resolves and resolves to a thing defined in this file, emit as an alias, otherwise emit as a const 8188 if (target && length(target.declarations) && some(target.declarations, d => getSourceFileOfNode(d) === getSourceFileOfNode(enclosingDeclaration))) { 8189 // In case `target` refers to a namespace member, look at the declaration and serialize the leftmost symbol in it 8190 // eg, `namespace A { export class B {} }; exports = A.B;` 8191 // Technically, this is all that's required in the case where the assignment is an entity name expression 8192 const expr = aliasDecl && ((isExportAssignment(aliasDecl) || isBinaryExpression(aliasDecl)) ? getExportAssignmentExpression(aliasDecl) : getPropertyAssignmentAliasLikeExpression(aliasDecl as ShorthandPropertyAssignment | PropertyAssignment | PropertyAccessExpression)); 8193 const first = expr && isEntityNameExpression(expr) ? getFirstNonModuleExportsIdentifier(expr) : undefined; 8194 const referenced = first && resolveEntityName(first, SymbolFlags.All, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, enclosingDeclaration); 8195 if (referenced || target) { 8196 includePrivateSymbol(referenced || target); 8197 } 8198 8199 // We disable the context's symbol tracker for the duration of this name serialization 8200 // as, by virtue of being here, the name is required to print something, and we don't want to 8201 // issue a visibility error on it. Only anonymous classes that an alias points at _would_ issue 8202 // a visibility error here (as they're not visible within any scope), but we want to hoist them 8203 // into the containing scope anyway, so we want to skip the visibility checks. 8204 const oldTrack = context.tracker.trackSymbol; 8205 context.tracker.trackSymbol = () => false; 8206 if (isExportAssignmentCompatibleSymbolName) { 8207 results.push(factory.createExportAssignment( 8208 /*modifiers*/ undefined, 8209 isExportEquals, 8210 symbolToExpression(target, context, SymbolFlags.All) 8211 )); 8212 } 8213 else { 8214 if (first === expr && first) { 8215 // serialize as `export {target as name}` 8216 serializeExportSpecifier(name, idText(first)); 8217 } 8218 else if (expr && isClassExpression(expr)) { 8219 serializeExportSpecifier(name, getInternalSymbolName(target, symbolName(target))); 8220 } 8221 else { 8222 // serialize as `import _Ref = t.arg.et; export { _Ref as name }` 8223 const varName = getUnusedName(name, symbol); 8224 addResult(factory.createImportEqualsDeclaration( 8225 /*modifiers*/ undefined, 8226 /*isTypeOnly*/ false, 8227 factory.createIdentifier(varName), 8228 symbolToName(target, context, SymbolFlags.All, /*expectsIdentifier*/ false) 8229 ), ModifierFlags.None); 8230 serializeExportSpecifier(name, varName); 8231 } 8232 } 8233 context.tracker.trackSymbol = oldTrack; 8234 return true; 8235 } 8236 else { 8237 // serialize as an anonymous property declaration 8238 const varName = getUnusedName(name, symbol); 8239 // We have to use `getWidenedType` here since the object within a json file is unwidened within the file 8240 // (Unwidened types can only exist in expression contexts and should never be serialized) 8241 const typeToSerialize = getWidenedType(getTypeOfSymbol(getMergedSymbol(symbol))); 8242 if (isTypeRepresentableAsFunctionNamespaceMerge(typeToSerialize, symbol)) { 8243 // If there are no index signatures and `typeToSerialize` is an object type, emit as a namespace instead of a const 8244 serializeAsFunctionNamespaceMerge(typeToSerialize, symbol, varName, isExportAssignmentCompatibleSymbolName ? ModifierFlags.None : ModifierFlags.Export); 8245 } 8246 else { 8247 const statement = factory.createVariableStatement(/*modifiers*/ undefined, factory.createVariableDeclarationList([ 8248 factory.createVariableDeclaration(varName, /*exclamationToken*/ undefined, serializeTypeForDeclaration(context, typeToSerialize, symbol, enclosingDeclaration, includePrivateSymbol, bundled)) 8249 ], NodeFlags.Const)); 8250 // Inlined JSON types exported with [module.]exports= will already emit an export=, so should use `declare`. 8251 // Otherwise, the type itself should be exported. 8252 addResult(statement, 8253 target && target.flags & SymbolFlags.Property && target.escapedName === InternalSymbolName.ExportEquals ? ModifierFlags.Ambient 8254 : name === varName ? ModifierFlags.Export 8255 : ModifierFlags.None); 8256 } 8257 if (isExportAssignmentCompatibleSymbolName) { 8258 results.push(factory.createExportAssignment( 8259 /*modifiers*/ undefined, 8260 isExportEquals, 8261 factory.createIdentifier(varName) 8262 )); 8263 return true; 8264 } 8265 else if (name !== varName) { 8266 serializeExportSpecifier(name, varName); 8267 return true; 8268 } 8269 return false; 8270 } 8271 } 8272 8273 function isTypeRepresentableAsFunctionNamespaceMerge(typeToSerialize: Type, hostSymbol: Symbol) { 8274 // Only object types which are not constructable, or indexable, whose members all come from the 8275 // context source file, and whose property names are all valid identifiers and not late-bound, _and_ 8276 // whose input is not type annotated (if the input symbol has an annotation we can reuse, we should prefer it) 8277 const ctxSrc = getSourceFileOfNode(context.enclosingDeclaration); 8278 return getObjectFlags(typeToSerialize) & (ObjectFlags.Anonymous | ObjectFlags.Mapped) && 8279 !length(getIndexInfosOfType(typeToSerialize)) && 8280 !isClassInstanceSide(typeToSerialize) && // While a class instance is potentially representable as a NS, prefer printing a reference to the instance type and serializing the class 8281 !!(length(filter(getPropertiesOfType(typeToSerialize), isNamespaceMember)) || length(getSignaturesOfType(typeToSerialize, SignatureKind.Call))) && 8282 !length(getSignaturesOfType(typeToSerialize, SignatureKind.Construct)) && // TODO: could probably serialize as function + ns + class, now that that's OK 8283 !getDeclarationWithTypeAnnotation(hostSymbol, enclosingDeclaration) && 8284 !(typeToSerialize.symbol && some(typeToSerialize.symbol.declarations, d => getSourceFileOfNode(d) !== ctxSrc)) && 8285 !some(getPropertiesOfType(typeToSerialize), p => isLateBoundName(p.escapedName)) && 8286 !some(getPropertiesOfType(typeToSerialize), p => some(p.declarations, d => getSourceFileOfNode(d) !== ctxSrc)) && 8287 every(getPropertiesOfType(typeToSerialize), p => isIdentifierText(symbolName(p), languageVersion)); 8288 } 8289 8290 function makeSerializePropertySymbol<T extends Node>(createProperty: ( 8291 modifiers: readonly Modifier[] | undefined, 8292 name: string | PropertyName, 8293 questionOrExclamationToken: QuestionToken | undefined, 8294 type: TypeNode | undefined, 8295 initializer: Expression | undefined 8296 ) => T, methodKind: SignatureDeclaration["kind"], useAccessors: true): (p: Symbol, isStatic: boolean, baseType: Type | undefined) => (T | AccessorDeclaration | (T | AccessorDeclaration)[]); 8297 function makeSerializePropertySymbol<T extends Node>(createProperty: ( 8298 modifiers: readonly Modifier[] | undefined, 8299 name: string | PropertyName, 8300 questionOrExclamationToken: QuestionToken | undefined, 8301 type: TypeNode | undefined, 8302 initializer: Expression | undefined 8303 ) => T, methodKind: SignatureDeclaration["kind"], useAccessors: false): (p: Symbol, isStatic: boolean, baseType: Type | undefined) => (T | T[]); 8304 function makeSerializePropertySymbol<T extends Node>(createProperty: ( 8305 modifiers: readonly Modifier[] | undefined, 8306 name: string | PropertyName, 8307 questionOrExclamationToken: QuestionToken | undefined, 8308 type: TypeNode | undefined, 8309 initializer: Expression | undefined 8310 ) => T, methodKind: SignatureDeclaration["kind"], useAccessors: boolean): (p: Symbol, isStatic: boolean, baseType: Type | undefined) => (T | AccessorDeclaration | (T | AccessorDeclaration)[]) { 8311 return function serializePropertySymbol(p: Symbol, isStatic: boolean, baseType: Type | undefined): (T | AccessorDeclaration | (T | AccessorDeclaration)[]) { 8312 const modifierFlags = getDeclarationModifierFlagsFromSymbol(p); 8313 const isPrivate = !!(modifierFlags & ModifierFlags.Private); 8314 if (isStatic && (p.flags & (SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias))) { 8315 // Only value-only-meaning symbols can be correctly encoded as class statics, type/namespace/alias meaning symbols 8316 // need to be merged namespace members 8317 return []; 8318 } 8319 if (p.flags & SymbolFlags.Prototype || 8320 (baseType && getPropertyOfType(baseType, p.escapedName) 8321 && isReadonlySymbol(getPropertyOfType(baseType, p.escapedName)!) === isReadonlySymbol(p) 8322 && (p.flags & SymbolFlags.Optional) === (getPropertyOfType(baseType, p.escapedName)!.flags & SymbolFlags.Optional) 8323 && isTypeIdenticalTo(getTypeOfSymbol(p), getTypeOfPropertyOfType(baseType, p.escapedName)!))) { 8324 return []; 8325 } 8326 const flag = (modifierFlags & ~ModifierFlags.Async) | (isStatic ? ModifierFlags.Static : 0); 8327 const name = getPropertyNameNodeForSymbol(p, context); 8328 const firstPropertyLikeDecl = p.declarations?.find(or(isPropertyDeclaration, isAccessor, isVariableDeclaration, isPropertySignature, isBinaryExpression, isPropertyAccessExpression)); 8329 if (p.flags & SymbolFlags.Accessor && useAccessors) { 8330 const result: AccessorDeclaration[] = []; 8331 if (p.flags & SymbolFlags.SetAccessor) { 8332 result.push(setTextRange(factory.createSetAccessorDeclaration( 8333 factory.createModifiersFromModifierFlags(flag), 8334 name, 8335 [factory.createParameterDeclaration( 8336 /*modifiers*/ undefined, 8337 /*dotDotDotToken*/ undefined, 8338 "arg", 8339 /*questionToken*/ undefined, 8340 isPrivate ? undefined : serializeTypeForDeclaration(context, getTypeOfSymbol(p), p, enclosingDeclaration, includePrivateSymbol, bundled) 8341 )], 8342 /*body*/ undefined 8343 ), p.declarations?.find(isSetAccessor) || firstPropertyLikeDecl)); 8344 } 8345 if (p.flags & SymbolFlags.GetAccessor) { 8346 const isPrivate = modifierFlags & ModifierFlags.Private; 8347 result.push(setTextRange(factory.createGetAccessorDeclaration( 8348 factory.createModifiersFromModifierFlags(flag), 8349 name, 8350 [], 8351 isPrivate ? undefined : serializeTypeForDeclaration(context, getTypeOfSymbol(p), p, enclosingDeclaration, includePrivateSymbol, bundled), 8352 /*body*/ undefined 8353 ), p.declarations?.find(isGetAccessor) || firstPropertyLikeDecl)); 8354 } 8355 return result; 8356 } 8357 // This is an else/if as accessors and properties can't merge in TS, but might in JS 8358 // If this happens, we assume the accessor takes priority, as it imposes more constraints 8359 else if (p.flags & (SymbolFlags.Property | SymbolFlags.Variable | SymbolFlags.Accessor)) { 8360 return setTextRange(createProperty( 8361 factory.createModifiersFromModifierFlags((isReadonlySymbol(p) ? ModifierFlags.Readonly : 0) | flag), 8362 name, 8363 p.flags & SymbolFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined, 8364 isPrivate ? undefined : serializeTypeForDeclaration(context, getWriteTypeOfSymbol(p), p, enclosingDeclaration, includePrivateSymbol, bundled), 8365 // TODO: https://github.com/microsoft/TypeScript/pull/32372#discussion_r328386357 8366 // interface members can't have initializers, however class members _can_ 8367 /*initializer*/ undefined 8368 ), p.declarations?.find(or(isPropertyDeclaration, isVariableDeclaration)) || firstPropertyLikeDecl); 8369 } 8370 if (p.flags & (SymbolFlags.Method | SymbolFlags.Function)) { 8371 const type = getTypeOfSymbol(p); 8372 const signatures = getSignaturesOfType(type, SignatureKind.Call); 8373 if (flag & ModifierFlags.Private) { 8374 return setTextRange(createProperty( 8375 factory.createModifiersFromModifierFlags((isReadonlySymbol(p) ? ModifierFlags.Readonly : 0) | flag), 8376 name, 8377 p.flags & SymbolFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined, 8378 /*type*/ undefined, 8379 /*initializer*/ undefined 8380 ), p.declarations?.find(isFunctionLikeDeclaration) || signatures[0] && signatures[0].declaration || p.declarations && p.declarations[0]); 8381 } 8382 8383 const results = []; 8384 for (const sig of signatures) { 8385 // Each overload becomes a separate method declaration, in order 8386 const decl = signatureToSignatureDeclarationHelper( 8387 sig, 8388 methodKind, 8389 context, 8390 { 8391 name, 8392 questionToken: p.flags & SymbolFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined, 8393 modifiers: flag ? factory.createModifiersFromModifierFlags(flag) : undefined 8394 } 8395 ); 8396 const location = sig.declaration && isPrototypePropertyAssignment(sig.declaration.parent) ? sig.declaration.parent : sig.declaration; 8397 results.push(setTextRange(decl, location)); 8398 } 8399 return results as unknown as T[]; 8400 } 8401 // The `Constructor`'s symbol isn't in the class's properties lists, obviously, since it's a signature on the static 8402 return Debug.fail(`Unhandled class member kind! ${(p as any).__debugFlags || p.flags}`); 8403 }; 8404 } 8405 8406 function serializePropertySymbolForInterface(p: Symbol, baseType: Type | undefined) { 8407 return serializePropertySymbolForInterfaceWorker(p, /*isStatic*/ false, baseType); 8408 } 8409 8410 function serializeSignatures(kind: SignatureKind, input: Type, baseType: Type | undefined, outputKind: SignatureDeclaration["kind"]) { 8411 const signatures = getSignaturesOfType(input, kind); 8412 if (kind === SignatureKind.Construct) { 8413 if (!baseType && every(signatures, s => length(s.parameters) === 0)) { 8414 return []; // No base type, every constructor is empty - elide the extraneous `constructor()` 8415 } 8416 if (baseType) { 8417 // If there is a base type, if every signature in the class is identical to a signature in the baseType, elide all the declarations 8418 const baseSigs = getSignaturesOfType(baseType, SignatureKind.Construct); 8419 if (!length(baseSigs) && every(signatures, s => length(s.parameters) === 0)) { 8420 return []; // Base had no explicit signatures, if all our signatures are also implicit, return an empty list 8421 } 8422 if (baseSigs.length === signatures.length) { 8423 let failed = false; 8424 for (let i = 0; i < baseSigs.length; i++) { 8425 if (!compareSignaturesIdentical(signatures[i], baseSigs[i], /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ true, compareTypesIdentical)) { 8426 failed = true; 8427 break; 8428 } 8429 } 8430 if (!failed) { 8431 return []; // Every signature was identical - elide constructor list as it is inherited 8432 } 8433 } 8434 } 8435 let privateProtected: ModifierFlags = 0; 8436 for (const s of signatures) { 8437 if (s.declaration) { 8438 privateProtected |= getSelectedEffectiveModifierFlags(s.declaration, ModifierFlags.Private | ModifierFlags.Protected); 8439 } 8440 } 8441 if (privateProtected) { 8442 return [setTextRange(factory.createConstructorDeclaration( 8443 factory.createModifiersFromModifierFlags(privateProtected), 8444 /*parameters*/ [], 8445 /*body*/ undefined, 8446 ), signatures[0].declaration)]; 8447 } 8448 } 8449 8450 const results = []; 8451 for (const sig of signatures) { 8452 // Each overload becomes a separate constructor declaration, in order 8453 const decl = signatureToSignatureDeclarationHelper(sig, outputKind, context); 8454 results.push(setTextRange(decl, sig.declaration)); 8455 } 8456 return results; 8457 } 8458 8459 function serializeIndexSignatures(input: Type, baseType: Type | undefined) { 8460 const results: IndexSignatureDeclaration[] = []; 8461 for (const info of getIndexInfosOfType(input)) { 8462 if (baseType) { 8463 const baseInfo = getIndexInfoOfType(baseType, info.keyType); 8464 if (baseInfo) { 8465 if (isTypeIdenticalTo(info.type, baseInfo.type)) { 8466 continue; // elide identical index signatures 8467 } 8468 } 8469 } 8470 results.push(indexInfoToIndexSignatureDeclarationHelper(info, context, /*typeNode*/ undefined)); 8471 } 8472 return results; 8473 } 8474 8475 function serializeBaseType(t: Type, staticType: Type, rootName: string) { 8476 const ref = trySerializeAsTypeReference(t, SymbolFlags.Value); 8477 if (ref) { 8478 return ref; 8479 } 8480 const tempName = getUnusedName(`${rootName}_base`); 8481 const statement = factory.createVariableStatement(/*modifiers*/ undefined, factory.createVariableDeclarationList([ 8482 factory.createVariableDeclaration(tempName, /*exclamationToken*/ undefined, typeToTypeNodeHelper(staticType, context)) 8483 ], NodeFlags.Const)); 8484 addResult(statement, ModifierFlags.None); 8485 return factory.createExpressionWithTypeArguments(factory.createIdentifier(tempName), /*typeArgs*/ undefined); 8486 } 8487 8488 function trySerializeAsTypeReference(t: Type, flags: SymbolFlags) { 8489 let typeArgs: TypeNode[] | undefined; 8490 let reference: Expression | undefined; 8491 8492 // We don't use `isValueSymbolAccessible` below. since that considers alternative containers (like modules) 8493 // which we can't write out in a syntactically valid way as an expression 8494 if ((t as TypeReference).target && isSymbolAccessibleByFlags((t as TypeReference).target.symbol, enclosingDeclaration, flags)) { 8495 typeArgs = map(getTypeArguments(t as TypeReference), t => typeToTypeNodeHelper(t, context)); 8496 reference = symbolToExpression((t as TypeReference).target.symbol, context, SymbolFlags.Type); 8497 } 8498 else if (t.symbol && isSymbolAccessibleByFlags(t.symbol, enclosingDeclaration, flags)) { 8499 reference = symbolToExpression(t.symbol, context, SymbolFlags.Type); 8500 } 8501 if (reference) { 8502 return factory.createExpressionWithTypeArguments(reference, typeArgs); 8503 } 8504 } 8505 8506 function serializeImplementedType(t: Type) { 8507 const ref = trySerializeAsTypeReference(t, SymbolFlags.Type); 8508 if (ref) { 8509 return ref; 8510 } 8511 if (t.symbol) { 8512 return factory.createExpressionWithTypeArguments(symbolToExpression(t.symbol, context, SymbolFlags.Type), /*typeArgs*/ undefined); 8513 } 8514 } 8515 8516 function getUnusedName(input: string, symbol?: Symbol): string { 8517 const id = symbol ? getSymbolId(symbol) : undefined; 8518 if (id) { 8519 if (context.remappedSymbolNames!.has(id)) { 8520 return context.remappedSymbolNames!.get(id)!; 8521 } 8522 } 8523 if (symbol) { 8524 input = getNameCandidateWorker(symbol, input); 8525 } 8526 let i = 0; 8527 const original = input; 8528 while (context.usedSymbolNames?.has(input)) { 8529 i++; 8530 input = `${original}_${i}`; 8531 } 8532 context.usedSymbolNames?.add(input); 8533 if (id) { 8534 context.remappedSymbolNames!.set(id, input); 8535 } 8536 return input; 8537 } 8538 8539 function getNameCandidateWorker(symbol: Symbol, localName: string) { 8540 if (localName === InternalSymbolName.Default || localName === InternalSymbolName.Class || localName === InternalSymbolName.Function) { 8541 const flags = context.flags; 8542 context.flags |= NodeBuilderFlags.InInitialEntityName; 8543 const nameCandidate = getNameOfSymbolAsWritten(symbol, context); 8544 context.flags = flags; 8545 localName = nameCandidate.length > 0 && isSingleOrDoubleQuote(nameCandidate.charCodeAt(0)) ? stripQuotes(nameCandidate) : nameCandidate; 8546 } 8547 if (localName === InternalSymbolName.Default) { 8548 localName = "_default"; 8549 } 8550 else if (localName === InternalSymbolName.ExportEquals) { 8551 localName = "_exports"; 8552 } 8553 localName = isIdentifierText(localName, languageVersion) && !isStringANonContextualKeyword(localName) ? localName : "_" + localName.replace(/[^a-zA-Z0-9]/g, "_"); 8554 return localName; 8555 } 8556 8557 function getInternalSymbolName(symbol: Symbol, localName: string) { 8558 const id = getSymbolId(symbol); 8559 if (context.remappedSymbolNames!.has(id)) { 8560 return context.remappedSymbolNames!.get(id)!; 8561 } 8562 localName = getNameCandidateWorker(symbol, localName); 8563 // The result of this is going to be used as the symbol's name - lock it in, so `getUnusedName` will also pick it up 8564 context.remappedSymbolNames!.set(id, localName); 8565 return localName; 8566 } 8567 } 8568 } 8569 8570 function typePredicateToString(typePredicate: TypePredicate, enclosingDeclaration?: Node, flags: TypeFormatFlags = TypeFormatFlags.UseAliasDefinedOutsideCurrentScope, writer?: EmitTextWriter): string { 8571 return writer ? typePredicateToStringWorker(writer).getText() : usingSingleLineStringWriter(typePredicateToStringWorker); 8572 8573 function typePredicateToStringWorker(writer: EmitTextWriter) { 8574 const predicate = factory.createTypePredicateNode( 8575 typePredicate.kind === TypePredicateKind.AssertsThis || typePredicate.kind === TypePredicateKind.AssertsIdentifier ? factory.createToken(SyntaxKind.AssertsKeyword) : undefined, 8576 typePredicate.kind === TypePredicateKind.Identifier || typePredicate.kind === TypePredicateKind.AssertsIdentifier ? factory.createIdentifier(typePredicate.parameterName) : factory.createThisTypeNode(), 8577 typePredicate.type && nodeBuilder.typeToTypeNode(typePredicate.type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName)! // TODO: GH#18217 8578 ); 8579 const printer = createPrinter({ removeComments: true }); 8580 const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); 8581 printer.writeNode(EmitHint.Unspecified, predicate, /*sourceFile*/ sourceFile, writer); 8582 return writer; 8583 } 8584 } 8585 8586 function formatUnionTypes(types: readonly Type[]): Type[] { 8587 const result: Type[] = []; 8588 let flags: TypeFlags = 0; 8589 for (let i = 0; i < types.length; i++) { 8590 const t = types[i]; 8591 flags |= t.flags; 8592 if (!(t.flags & TypeFlags.Nullable)) { 8593 if (t.flags & (TypeFlags.BooleanLiteral | TypeFlags.EnumLiteral)) { 8594 const baseType = t.flags & TypeFlags.BooleanLiteral ? booleanType : getBaseTypeOfEnumLiteralType(t as LiteralType); 8595 if (baseType.flags & TypeFlags.Union) { 8596 const count = (baseType as UnionType).types.length; 8597 if (i + count <= types.length && getRegularTypeOfLiteralType(types[i + count - 1]) === getRegularTypeOfLiteralType((baseType as UnionType).types[count - 1])) { 8598 result.push(baseType); 8599 i += count - 1; 8600 continue; 8601 } 8602 } 8603 } 8604 result.push(t); 8605 } 8606 } 8607 if (flags & TypeFlags.Null) result.push(nullType); 8608 if (flags & TypeFlags.Undefined) result.push(undefinedType); 8609 return result || types; 8610 } 8611 8612 function visibilityToString(flags: ModifierFlags): string | undefined { 8613 if (flags === ModifierFlags.Private) { 8614 return "private"; 8615 } 8616 if (flags === ModifierFlags.Protected) { 8617 return "protected"; 8618 } 8619 return "public"; 8620 } 8621 8622 function getTypeAliasForTypeLiteral(type: Type): Symbol | undefined { 8623 if (type.symbol && type.symbol.flags & SymbolFlags.TypeLiteral && type.symbol.declarations) { 8624 const node = walkUpParenthesizedTypes(type.symbol.declarations[0].parent); 8625 if (node.kind === SyntaxKind.TypeAliasDeclaration) { 8626 return getSymbolOfNode(node); 8627 } 8628 } 8629 return undefined; 8630 } 8631 8632 function isTopLevelInExternalModuleAugmentation(node: Node): boolean { 8633 return node && node.parent && 8634 node.parent.kind === SyntaxKind.ModuleBlock && 8635 isExternalModuleAugmentation(node.parent.parent); 8636 } 8637 8638 interface NodeBuilderContext { 8639 enclosingDeclaration: Node | undefined; 8640 flags: NodeBuilderFlags; 8641 tracker: SymbolTracker; 8642 8643 // State 8644 encounteredError: boolean; 8645 reportedDiagnostic: boolean; 8646 visitedTypes: Set<number> | undefined; 8647 symbolDepth: ESMap<string, number> | undefined; 8648 inferTypeParameters: TypeParameter[] | undefined; 8649 approximateLength: number; 8650 truncating?: boolean; 8651 typeParameterSymbolList?: Set<number>; 8652 typeParameterNames?: ESMap<TypeId, Identifier>; 8653 typeParameterNamesByText?: Set<string>; 8654 typeParameterNamesByTextNextNameCount?: ESMap<string, number>; 8655 usedSymbolNames?: Set<string>; 8656 remappedSymbolNames?: ESMap<SymbolId, string>; 8657 reverseMappedStack?: ReverseMappedSymbol[]; 8658 } 8659 8660 function isDefaultBindingContext(location: Node) { 8661 return location.kind === SyntaxKind.SourceFile || isAmbientModule(location); 8662 } 8663 8664 function getNameOfSymbolFromNameType(symbol: Symbol, context?: NodeBuilderContext) { 8665 const nameType = getSymbolLinks(symbol).nameType; 8666 if (nameType) { 8667 if (nameType.flags & TypeFlags.StringOrNumberLiteral) { 8668 const name = "" + (nameType as StringLiteralType | NumberLiteralType).value; 8669 if (!isIdentifierText(name, getEmitScriptTarget(compilerOptions)) && !isNumericLiteralName(name)) { 8670 return `"${escapeString(name, CharacterCodes.doubleQuote)}"`; 8671 } 8672 if (isNumericLiteralName(name) && startsWith(name, "-")) { 8673 return `[${name}]`; 8674 } 8675 return name; 8676 } 8677 if (nameType.flags & TypeFlags.UniqueESSymbol) { 8678 return `[${getNameOfSymbolAsWritten((nameType as UniqueESSymbolType).symbol, context)}]`; 8679 } 8680 } 8681 } 8682 8683 /** 8684 * Gets a human-readable name for a symbol. 8685 * Should *not* be used for the right-hand side of a `.` -- use `symbolName(symbol)` for that instead. 8686 * 8687 * Unlike `symbolName(symbol)`, this will include quotes if the name is from a string literal. 8688 * It will also use a representation of a number as written instead of a decimal form, e.g. `0o11` instead of `9`. 8689 */ 8690 function getNameOfSymbolAsWritten(symbol: Symbol, context?: NodeBuilderContext): string { 8691 if (context && symbol.escapedName === InternalSymbolName.Default && !(context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope) && 8692 // If it's not the first part of an entity name, it must print as `default` 8693 (!(context.flags & NodeBuilderFlags.InInitialEntityName) || 8694 // if the symbol is synthesized, it will only be referenced externally it must print as `default` 8695 !symbol.declarations || 8696 // if not in the same binding context (source file, module declaration), it must print as `default` 8697 (context.enclosingDeclaration && findAncestor(symbol.declarations[0], isDefaultBindingContext) !== findAncestor(context.enclosingDeclaration, isDefaultBindingContext)))) { 8698 return "default"; 8699 } 8700 if (symbol.declarations && symbol.declarations.length) { 8701 let declaration = firstDefined(symbol.declarations, d => getNameOfDeclaration(d) ? d : undefined); // Try using a declaration with a name, first 8702 const name = declaration && getNameOfDeclaration(declaration); 8703 if (declaration && name) { 8704 if (isCallExpression(declaration) && isBindableObjectDefinePropertyCall(declaration)) { 8705 return symbolName(symbol); 8706 } 8707 if (isComputedPropertyName(name) && !(getCheckFlags(symbol) & CheckFlags.Late)) { 8708 const nameType = getSymbolLinks(symbol).nameType; 8709 if (nameType && nameType.flags & TypeFlags.StringOrNumberLiteral) { 8710 // Computed property name isn't late bound, but has a well-known name type - use name type to generate a symbol name 8711 const result = getNameOfSymbolFromNameType(symbol, context); 8712 if (result !== undefined) { 8713 return result; 8714 } 8715 } 8716 } 8717 return declarationNameToString(name); 8718 } 8719 if (!declaration) { 8720 declaration = symbol.declarations[0]; // Declaration may be nameless, but we'll try anyway 8721 } 8722 if (declaration.parent && declaration.parent.kind === SyntaxKind.VariableDeclaration) { 8723 return declarationNameToString((declaration.parent as VariableDeclaration).name); 8724 } 8725 switch (declaration.kind) { 8726 case SyntaxKind.ClassExpression: 8727 case SyntaxKind.FunctionExpression: 8728 case SyntaxKind.ArrowFunction: 8729 if (context && !context.encounteredError && !(context.flags & NodeBuilderFlags.AllowAnonymousIdentifier)) { 8730 context.encounteredError = true; 8731 } 8732 return declaration.kind === SyntaxKind.ClassExpression ? "(Anonymous class)" : "(Anonymous function)"; 8733 } 8734 } 8735 const name = getNameOfSymbolFromNameType(symbol, context); 8736 return name !== undefined ? name : symbolName(symbol); 8737 } 8738 8739 function isDeclarationVisible(node: Node): boolean { 8740 if (node) { 8741 const links = getNodeLinks(node); 8742 if (links.isVisible === undefined) { 8743 links.isVisible = !!determineIfDeclarationIsVisible(); 8744 } 8745 return links.isVisible; 8746 } 8747 8748 return false; 8749 8750 function determineIfDeclarationIsVisible() { 8751 switch (node.kind) { 8752 case SyntaxKind.JSDocCallbackTag: 8753 case SyntaxKind.JSDocTypedefTag: 8754 case SyntaxKind.JSDocEnumTag: 8755 // Top-level jsdoc type aliases are considered exported 8756 // First parent is comment node, second is hosting declaration or token; we only care about those tokens or declarations whose parent is a source file 8757 return !!(node.parent && node.parent.parent && node.parent.parent.parent && isSourceFile(node.parent.parent.parent)); 8758 case SyntaxKind.BindingElement: 8759 return isDeclarationVisible(node.parent.parent); 8760 case SyntaxKind.VariableDeclaration: 8761 if (isBindingPattern((node as VariableDeclaration).name) && 8762 !((node as VariableDeclaration).name as BindingPattern).elements.length) { 8763 // If the binding pattern is empty, this variable declaration is not visible 8764 return false; 8765 } 8766 // falls through 8767 case SyntaxKind.ModuleDeclaration: 8768 case SyntaxKind.ClassDeclaration: 8769 case SyntaxKind.StructDeclaration: 8770 case SyntaxKind.InterfaceDeclaration: 8771 case SyntaxKind.TypeAliasDeclaration: 8772 case SyntaxKind.FunctionDeclaration: 8773 case SyntaxKind.EnumDeclaration: 8774 case SyntaxKind.ImportEqualsDeclaration: 8775 // external module augmentation is always visible 8776 if (isExternalModuleAugmentation(node)) { 8777 return true; 8778 } 8779 const parent = getDeclarationContainer(node); 8780 // If the node is not exported or it is not ambient module element (except import declaration) 8781 if (!(getCombinedModifierFlags(node as Declaration) & ModifierFlags.Export) && 8782 !(node.kind !== SyntaxKind.ImportEqualsDeclaration && parent.kind !== SyntaxKind.SourceFile && parent.flags & NodeFlags.Ambient)) { 8783 return isGlobalSourceFile(parent); 8784 } 8785 // Exported members/ambient module elements (exception import declaration) are visible if parent is visible 8786 return isDeclarationVisible(parent); 8787 8788 case SyntaxKind.PropertyDeclaration: 8789 case SyntaxKind.PropertySignature: 8790 case SyntaxKind.GetAccessor: 8791 case SyntaxKind.SetAccessor: 8792 case SyntaxKind.MethodDeclaration: 8793 case SyntaxKind.MethodSignature: 8794 if (hasEffectiveModifier(node, ModifierFlags.Private | ModifierFlags.Protected)) { 8795 // Private/protected properties/methods are not visible 8796 return false; 8797 } 8798 // Public properties/methods are visible if its parents are visible, so: 8799 // falls through 8800 8801 case SyntaxKind.Constructor: 8802 case SyntaxKind.ConstructSignature: 8803 case SyntaxKind.CallSignature: 8804 case SyntaxKind.IndexSignature: 8805 case SyntaxKind.Parameter: 8806 case SyntaxKind.ModuleBlock: 8807 case SyntaxKind.FunctionType: 8808 case SyntaxKind.ConstructorType: 8809 case SyntaxKind.TypeLiteral: 8810 case SyntaxKind.TypeReference: 8811 case SyntaxKind.ArrayType: 8812 case SyntaxKind.TupleType: 8813 case SyntaxKind.UnionType: 8814 case SyntaxKind.IntersectionType: 8815 case SyntaxKind.ParenthesizedType: 8816 case SyntaxKind.NamedTupleMember: 8817 return isDeclarationVisible(node.parent); 8818 8819 // Default binding, import specifier and namespace import is visible 8820 // only on demand so by default it is not visible 8821 case SyntaxKind.ImportClause: 8822 case SyntaxKind.NamespaceImport: 8823 case SyntaxKind.ImportSpecifier: 8824 return false; 8825 8826 // Type parameters are always visible 8827 case SyntaxKind.TypeParameter: 8828 8829 // Source file and namespace export are always visible 8830 // falls through 8831 case SyntaxKind.SourceFile: 8832 case SyntaxKind.NamespaceExportDeclaration: 8833 return true; 8834 8835 // Export assignments do not create name bindings outside the module 8836 case SyntaxKind.ExportAssignment: 8837 return false; 8838 8839 default: 8840 return false; 8841 } 8842 } 8843 } 8844 8845 function collectLinkedAliases(node: Identifier, setVisibility?: boolean): Node[] | undefined { 8846 let exportSymbol: Symbol | undefined; 8847 if (node.parent && node.parent.kind === SyntaxKind.ExportAssignment) { 8848 exportSymbol = resolveName(node, node.escapedText, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, /*nameNotFoundMessage*/ undefined, node, /*isUse*/ false); 8849 } 8850 else if (node.parent.kind === SyntaxKind.ExportSpecifier) { 8851 exportSymbol = getTargetOfExportSpecifier(node.parent as ExportSpecifier, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias); 8852 } 8853 let result: Node[] | undefined; 8854 let visited: Set<number> | undefined; 8855 if (exportSymbol) { 8856 visited = new Set(); 8857 visited.add(getSymbolId(exportSymbol)); 8858 buildVisibleNodeList(exportSymbol.declarations); 8859 } 8860 return result; 8861 8862 function buildVisibleNodeList(declarations: Declaration[] | undefined) { 8863 forEach(declarations, declaration => { 8864 const resultNode = getAnyImportSyntax(declaration) || declaration; 8865 if (setVisibility) { 8866 getNodeLinks(declaration).isVisible = true; 8867 } 8868 else { 8869 result = result || []; 8870 pushIfUnique(result, resultNode); 8871 } 8872 8873 if (isInternalModuleImportEqualsDeclaration(declaration)) { 8874 // Add the referenced top container visible 8875 const internalModuleReference = declaration.moduleReference as Identifier | QualifiedName; 8876 const firstIdentifier = getFirstIdentifier(internalModuleReference); 8877 const importSymbol = resolveName(declaration, firstIdentifier.escapedText, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, 8878 undefined, undefined, /*isUse*/ false); 8879 if (importSymbol && visited) { 8880 if (tryAddToSet(visited, getSymbolId(importSymbol))) { 8881 buildVisibleNodeList(importSymbol.declarations); 8882 } 8883 } 8884 } 8885 }); 8886 } 8887 } 8888 8889 /** 8890 * Push an entry on the type resolution stack. If an entry with the given target and the given property name 8891 * is already on the stack, and no entries in between already have a type, then a circularity has occurred. 8892 * In this case, the result values of the existing entry and all entries pushed after it are changed to false, 8893 * and the value false is returned. Otherwise, the new entry is just pushed onto the stack, and true is returned. 8894 * In order to see if the same query has already been done before, the target object and the propertyName both 8895 * must match the one passed in. 8896 * 8897 * @param target The symbol, type, or signature whose type is being queried 8898 * @param propertyName The property name that should be used to query the target for its type 8899 */ 8900 function pushTypeResolution(target: TypeSystemEntity, propertyName: TypeSystemPropertyName): boolean { 8901 const resolutionCycleStartIndex = findResolutionCycleStartIndex(target, propertyName); 8902 if (resolutionCycleStartIndex >= 0) { 8903 // A cycle was found 8904 const { length } = resolutionTargets; 8905 for (let i = resolutionCycleStartIndex; i < length; i++) { 8906 resolutionResults[i] = false; 8907 } 8908 return false; 8909 } 8910 resolutionTargets.push(target); 8911 resolutionResults.push(/*items*/ true); 8912 resolutionPropertyNames.push(propertyName); 8913 return true; 8914 } 8915 8916 function findResolutionCycleStartIndex(target: TypeSystemEntity, propertyName: TypeSystemPropertyName): number { 8917 for (let i = resolutionTargets.length - 1; i >= 0; i--) { 8918 if (hasType(resolutionTargets[i], resolutionPropertyNames[i])) { 8919 return -1; 8920 } 8921 if (resolutionTargets[i] === target && resolutionPropertyNames[i] === propertyName) { 8922 return i; 8923 } 8924 } 8925 return -1; 8926 } 8927 8928 function hasType(target: TypeSystemEntity, propertyName: TypeSystemPropertyName): boolean { 8929 switch (propertyName) { 8930 case TypeSystemPropertyName.Type: 8931 return !!getSymbolLinks(target as Symbol).type; 8932 case TypeSystemPropertyName.EnumTagType: 8933 return !!(getNodeLinks(target as JSDocEnumTag).resolvedEnumType); 8934 case TypeSystemPropertyName.DeclaredType: 8935 return !!getSymbolLinks(target as Symbol).declaredType; 8936 case TypeSystemPropertyName.ResolvedBaseConstructorType: 8937 return !!(target as InterfaceType).resolvedBaseConstructorType; 8938 case TypeSystemPropertyName.ResolvedReturnType: 8939 return !!(target as Signature).resolvedReturnType; 8940 case TypeSystemPropertyName.ImmediateBaseConstraint: 8941 return !!(target as Type).immediateBaseConstraint; 8942 case TypeSystemPropertyName.ResolvedTypeArguments: 8943 return !!(target as TypeReference).resolvedTypeArguments; 8944 case TypeSystemPropertyName.ResolvedBaseTypes: 8945 return !!(target as InterfaceType).baseTypesResolved; 8946 case TypeSystemPropertyName.WriteType: 8947 return !!getSymbolLinks(target as Symbol).writeType; 8948 } 8949 } 8950 8951 /** 8952 * Pop an entry from the type resolution stack and return its associated result value. The result value will 8953 * be true if no circularities were detected, or false if a circularity was found. 8954 */ 8955 function popTypeResolution(): boolean { 8956 resolutionTargets.pop(); 8957 resolutionPropertyNames.pop(); 8958 return resolutionResults.pop()!; 8959 } 8960 8961 function getDeclarationContainer(node: Node): Node { 8962 return findAncestor(getRootDeclaration(node), node => { 8963 switch (node.kind) { 8964 case SyntaxKind.VariableDeclaration: 8965 case SyntaxKind.VariableDeclarationList: 8966 case SyntaxKind.ImportSpecifier: 8967 case SyntaxKind.NamedImports: 8968 case SyntaxKind.NamespaceImport: 8969 case SyntaxKind.ImportClause: 8970 return false; 8971 default: 8972 return true; 8973 } 8974 })!.parent; 8975 } 8976 8977 function getTypeOfPrototypeProperty(prototype: Symbol): Type { 8978 // TypeScript 1.0 spec (April 2014): 8.4 8979 // Every class automatically contains a static property member named 'prototype', 8980 // the type of which is an instantiation of the class type with type Any supplied as a type argument for each type parameter. 8981 // It is an error to explicitly declare a static property member with the name 'prototype'. 8982 const classType = getDeclaredTypeOfSymbol(getParentOfSymbol(prototype)!) as InterfaceType; 8983 return classType.typeParameters ? createTypeReference(classType as GenericType, map(classType.typeParameters, _ => anyType)) : classType; 8984 } 8985 8986 // Return the type of the given property in the given type, or undefined if no such property exists 8987 function getTypeOfPropertyOfType(type: Type, name: __String): Type | undefined { 8988 const prop = getPropertyOfType(type, name); 8989 return prop ? getTypeOfSymbol(prop) : undefined; 8990 } 8991 8992 function getTypeOfPropertyOrIndexSignature(type: Type, name: __String): Type { 8993 return getTypeOfPropertyOfType(type, name) || getApplicableIndexInfoForName(type, name)?.type || unknownType; 8994 } 8995 8996 function isTypeAny(type: Type | undefined) { 8997 return type && (type.flags & TypeFlags.Any) !== 0; 8998 } 8999 9000 function isErrorType(type: Type) { 9001 // The only 'any' types that have alias symbols are those manufactured by getTypeFromTypeAliasReference for 9002 // a reference to an unresolved symbol. We want those to behave like the errorType. 9003 return type === errorType || !!(type.flags & TypeFlags.Any && type.aliasSymbol); 9004 } 9005 9006 // Return the type of a binding element parent. We check SymbolLinks first to see if a type has been 9007 // assigned by contextual typing. 9008 function getTypeForBindingElementParent(node: BindingElementGrandparent, checkMode: CheckMode) { 9009 if (checkMode !== CheckMode.Normal) { 9010 return getTypeForVariableLikeDeclaration(node, /*includeOptionality*/ false, checkMode); 9011 } 9012 const symbol = getSymbolOfNode(node); 9013 return symbol && getSymbolLinks(symbol).type || getTypeForVariableLikeDeclaration(node, /*includeOptionality*/ false, checkMode); 9014 } 9015 9016 function getRestType(source: Type, properties: PropertyName[], symbol: Symbol | undefined): Type { 9017 source = filterType(source, t => !(t.flags & TypeFlags.Nullable)); 9018 if (source.flags & TypeFlags.Never) { 9019 return emptyObjectType; 9020 } 9021 if (source.flags & TypeFlags.Union) { 9022 return mapType(source, t => getRestType(t, properties, symbol)); 9023 } 9024 9025 let omitKeyType = getUnionType(map(properties, getLiteralTypeFromPropertyName)); 9026 9027 const spreadableProperties: Symbol[] = []; 9028 const unspreadableToRestKeys: Type[] = []; 9029 9030 for (const prop of getPropertiesOfType(source)) { 9031 const literalTypeFromProperty = getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique); 9032 if (!isTypeAssignableTo(literalTypeFromProperty, omitKeyType) 9033 && !(getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected)) 9034 && isSpreadableProperty(prop)) { 9035 spreadableProperties.push(prop); 9036 } 9037 else { 9038 unspreadableToRestKeys.push(literalTypeFromProperty); 9039 } 9040 } 9041 9042 if (isGenericObjectType(source) || isGenericIndexType(omitKeyType)) { 9043 if (unspreadableToRestKeys.length) { 9044 // If the type we're spreading from has properties that cannot 9045 // be spread into the rest type (e.g. getters, methods), ensure 9046 // they are explicitly omitted, as they would in the non-generic case. 9047 omitKeyType = getUnionType([omitKeyType, ...unspreadableToRestKeys]); 9048 } 9049 9050 if (omitKeyType.flags & TypeFlags.Never) { 9051 return source; 9052 } 9053 9054 const omitTypeAlias = getGlobalOmitSymbol(); 9055 if (!omitTypeAlias) { 9056 return errorType; 9057 } 9058 return getTypeAliasInstantiation(omitTypeAlias, [source, omitKeyType]); 9059 } 9060 const members = createSymbolTable(); 9061 for (const prop of spreadableProperties) { 9062 members.set(prop.escapedName, getSpreadSymbol(prop, /*readonly*/ false)); 9063 } 9064 const result = createAnonymousType(symbol, members, emptyArray, emptyArray, getIndexInfosOfType(source)); 9065 result.objectFlags |= ObjectFlags.ObjectRestType; 9066 return result; 9067 } 9068 9069 function isGenericTypeWithUndefinedConstraint(type: Type) { 9070 return !!(type.flags & TypeFlags.Instantiable) && maybeTypeOfKind(getBaseConstraintOfType(type) || unknownType, TypeFlags.Undefined); 9071 } 9072 9073 function getNonUndefinedType(type: Type) { 9074 const typeOrConstraint = someType(type, isGenericTypeWithUndefinedConstraint) ? mapType(type, t => t.flags & TypeFlags.Instantiable ? getBaseConstraintOrType(t) : t) : type; 9075 return getTypeWithFacts(typeOrConstraint, TypeFacts.NEUndefined); 9076 } 9077 9078 // Determine the control flow type associated with a destructuring declaration or assignment. The following 9079 // forms of destructuring are possible: 9080 // let { x } = obj; // BindingElement 9081 // let [ x ] = obj; // BindingElement 9082 // { x } = obj; // ShorthandPropertyAssignment 9083 // { x: v } = obj; // PropertyAssignment 9084 // [ x ] = obj; // Expression 9085 // We construct a synthetic element access expression corresponding to 'obj.x' such that the control 9086 // flow analyzer doesn't have to handle all the different syntactic forms. 9087 function getFlowTypeOfDestructuring(node: BindingElement | PropertyAssignment | ShorthandPropertyAssignment | Expression, declaredType: Type) { 9088 const reference = getSyntheticElementAccess(node); 9089 return reference ? getFlowTypeOfReference(reference, declaredType) : declaredType; 9090 } 9091 9092 function getSyntheticElementAccess(node: BindingElement | PropertyAssignment | ShorthandPropertyAssignment | Expression): ElementAccessExpression | undefined { 9093 const parentAccess = getParentElementAccess(node); 9094 if (parentAccess && parentAccess.flowNode) { 9095 const propName = getDestructuringPropertyName(node); 9096 if (propName) { 9097 const literal = setTextRange(parseNodeFactory.createStringLiteral(propName), node); 9098 const lhsExpr = isLeftHandSideExpression(parentAccess) ? parentAccess : parseNodeFactory.createParenthesizedExpression(parentAccess); 9099 const result = setTextRange(parseNodeFactory.createElementAccessExpression(lhsExpr, literal), node); 9100 setParent(literal, result); 9101 setParent(result, node); 9102 if (lhsExpr !== parentAccess) { 9103 setParent(lhsExpr, result); 9104 } 9105 result.flowNode = parentAccess.flowNode; 9106 return result; 9107 } 9108 } 9109 } 9110 9111 function getParentElementAccess(node: BindingElement | PropertyAssignment | ShorthandPropertyAssignment | Expression) { 9112 const ancestor = node.parent.parent; 9113 switch (ancestor.kind) { 9114 case SyntaxKind.BindingElement: 9115 case SyntaxKind.PropertyAssignment: 9116 return getSyntheticElementAccess(ancestor as BindingElement | PropertyAssignment); 9117 case SyntaxKind.ArrayLiteralExpression: 9118 return getSyntheticElementAccess(node.parent as Expression); 9119 case SyntaxKind.VariableDeclaration: 9120 return (ancestor as VariableDeclaration).initializer; 9121 case SyntaxKind.BinaryExpression: 9122 return (ancestor as BinaryExpression).right; 9123 } 9124 } 9125 9126 function getDestructuringPropertyName(node: BindingElement | PropertyAssignment | ShorthandPropertyAssignment | Expression) { 9127 const parent = node.parent; 9128 if (node.kind === SyntaxKind.BindingElement && parent.kind === SyntaxKind.ObjectBindingPattern) { 9129 return getLiteralPropertyNameText((node as BindingElement).propertyName || (node as BindingElement).name as Identifier); 9130 } 9131 if (node.kind === SyntaxKind.PropertyAssignment || node.kind === SyntaxKind.ShorthandPropertyAssignment) { 9132 return getLiteralPropertyNameText((node as PropertyAssignment | ShorthandPropertyAssignment).name); 9133 } 9134 return "" + ((parent as BindingPattern | ArrayLiteralExpression).elements as NodeArray<Node>).indexOf(node); 9135 } 9136 9137 function getLiteralPropertyNameText(name: PropertyName) { 9138 const type = getLiteralTypeFromPropertyName(name); 9139 return type.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral) ? "" + (type as StringLiteralType | NumberLiteralType).value : undefined; 9140 } 9141 9142 /** Return the inferred type for a binding element */ 9143 function getTypeForBindingElement(declaration: BindingElement): Type | undefined { 9144 const checkMode = declaration.dotDotDotToken ? CheckMode.RestBindingElement : CheckMode.Normal; 9145 const parentType = getTypeForBindingElementParent(declaration.parent.parent, checkMode); 9146 return parentType && getBindingElementTypeFromParentType(declaration, parentType); 9147 } 9148 9149 function getBindingElementTypeFromParentType(declaration: BindingElement, parentType: Type): Type { 9150 // If an any type was inferred for parent, infer that for the binding element 9151 if (isTypeAny(parentType)) { 9152 return parentType; 9153 } 9154 const pattern = declaration.parent; 9155 // Relax null check on ambient destructuring parameters, since the parameters have no implementation and are just documentation 9156 if (strictNullChecks && declaration.flags & NodeFlags.Ambient && isParameterDeclaration(declaration)) { 9157 parentType = getNonNullableType(parentType); 9158 } 9159 // Filter `undefined` from the type we check against if the parent has an initializer and that initializer is not possibly `undefined` 9160 else if (strictNullChecks && pattern.parent.initializer && !(getTypeFacts(getTypeOfInitializer(pattern.parent.initializer)) & TypeFacts.EQUndefined)) { 9161 parentType = getTypeWithFacts(parentType, TypeFacts.NEUndefined); 9162 } 9163 9164 let type: Type | undefined; 9165 if (pattern.kind === SyntaxKind.ObjectBindingPattern) { 9166 if (declaration.dotDotDotToken) { 9167 parentType = getReducedType(parentType); 9168 if (parentType.flags & TypeFlags.Unknown || !isValidSpreadType(parentType)) { 9169 error(declaration, Diagnostics.Rest_types_may_only_be_created_from_object_types); 9170 return errorType; 9171 } 9172 const literalMembers: PropertyName[] = []; 9173 for (const element of pattern.elements) { 9174 if (!element.dotDotDotToken) { 9175 literalMembers.push(element.propertyName || element.name as Identifier); 9176 } 9177 } 9178 type = getRestType(parentType, literalMembers, declaration.symbol); 9179 } 9180 else { 9181 // Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form) 9182 const name = declaration.propertyName || declaration.name as Identifier; 9183 const indexType = getLiteralTypeFromPropertyName(name); 9184 const declaredType = getIndexedAccessType(parentType, indexType, AccessFlags.ExpressionPosition, name); 9185 type = getFlowTypeOfDestructuring(declaration, declaredType); 9186 } 9187 } 9188 else { 9189 // This elementType will be used if the specific property corresponding to this index is not 9190 // present (aka the tuple element property). This call also checks that the parentType is in 9191 // fact an iterable or array (depending on target language). 9192 const elementType = checkIteratedTypeOrElementType(IterationUse.Destructuring | (declaration.dotDotDotToken ? 0 : IterationUse.PossiblyOutOfBounds), parentType, undefinedType, pattern); 9193 const index = pattern.elements.indexOf(declaration); 9194 if (declaration.dotDotDotToken) { 9195 // If the parent is a tuple type, the rest element has a tuple type of the 9196 // remaining tuple element types. Otherwise, the rest element has an array type with same 9197 // element type as the parent type. 9198 type = everyType(parentType, isTupleType) ? 9199 mapType(parentType, t => sliceTupleType(t as TupleTypeReference, index)) : 9200 createArrayType(elementType); 9201 } 9202 else if (isArrayLikeType(parentType)) { 9203 const indexType = getNumberLiteralType(index); 9204 const accessFlags = AccessFlags.ExpressionPosition | (hasDefaultValue(declaration) ? AccessFlags.NoTupleBoundsCheck : 0); 9205 const declaredType = getIndexedAccessTypeOrUndefined(parentType, indexType, accessFlags, declaration.name) || errorType; 9206 type = getFlowTypeOfDestructuring(declaration, declaredType); 9207 } 9208 else { 9209 type = elementType; 9210 } 9211 } 9212 if (!declaration.initializer) { 9213 return type; 9214 } 9215 if (getEffectiveTypeAnnotationNode(walkUpBindingElementsAndPatterns(declaration))) { 9216 // In strict null checking mode, if a default value of a non-undefined type is specified, remove 9217 // undefined from the final type. 9218 return strictNullChecks && !(getTypeFacts(checkDeclarationInitializer(declaration, CheckMode.Normal)) & TypeFacts.IsUndefined) ? getNonUndefinedType(type) : type; 9219 } 9220 return widenTypeInferredFromInitializer(declaration, getUnionType([getNonUndefinedType(type), checkDeclarationInitializer(declaration, CheckMode.Normal)], UnionReduction.Subtype)); 9221 } 9222 9223 function getTypeForDeclarationFromJSDocComment(declaration: Node) { 9224 const jsdocType = getJSDocType(declaration); 9225 if (jsdocType) { 9226 return getTypeFromTypeNode(jsdocType); 9227 } 9228 return undefined; 9229 } 9230 9231 function isNullOrUndefined(node: Expression) { 9232 const expr = skipParentheses(node, /*excludeJSDocTypeAssertions*/ true); 9233 return expr.kind === SyntaxKind.NullKeyword || expr.kind === SyntaxKind.Identifier && getResolvedSymbol(expr as Identifier) === undefinedSymbol; 9234 } 9235 9236 function isEmptyArrayLiteral(node: Expression) { 9237 const expr = skipParentheses(node, /*excludeJSDocTypeAssertions*/ true); 9238 return expr.kind === SyntaxKind.ArrayLiteralExpression && (expr as ArrayLiteralExpression).elements.length === 0; 9239 } 9240 9241 function addOptionality(type: Type, isProperty = false, isOptional = true): Type { 9242 return strictNullChecks && isOptional ? getOptionalType(type, isProperty) : type; 9243 } 9244 9245 // Return the inferred type for a variable, parameter, or property declaration 9246 function getTypeForVariableLikeDeclaration( 9247 declaration: ParameterDeclaration | PropertyDeclaration | PropertySignature | AnnotationPropertyDeclaration | VariableDeclaration | BindingElement | JSDocPropertyLikeTag, 9248 includeOptionality: boolean, 9249 checkMode: CheckMode, 9250 ): Type | undefined { 9251 // A variable declared in a for..in statement is of type string, or of type keyof T when the 9252 // right hand expression is of a type parameter type. 9253 if (isVariableDeclaration(declaration) && declaration.parent.parent.kind === SyntaxKind.ForInStatement) { 9254 const indexType = getIndexType(getNonNullableTypeIfNeeded(checkExpression(declaration.parent.parent.expression, /*checkMode*/ checkMode))); 9255 return indexType.flags & (TypeFlags.TypeParameter | TypeFlags.Index) ? getExtractStringType(indexType) : stringType; 9256 } 9257 9258 if (isVariableDeclaration(declaration) && declaration.parent.parent.kind === SyntaxKind.ForOfStatement) { 9259 // checkRightHandSideOfForOf will return undefined if the for-of expression type was 9260 // missing properties/signatures required to get its iteratedType (like 9261 // [Symbol.iterator] or next). This may be because we accessed properties from anyType, 9262 // or it may have led to an error inside getElementTypeOfIterable. 9263 const forOfStatement = declaration.parent.parent; 9264 return checkRightHandSideOfForOf(forOfStatement) || anyType; 9265 } 9266 9267 if (isBindingPattern(declaration.parent)) { 9268 return getTypeForBindingElement(declaration as BindingElement); 9269 } 9270 9271 const isProperty = isPropertyDeclaration(declaration) && !hasAccessorModifier(declaration) || isPropertySignature(declaration); 9272 const isOptional = includeOptionality && ( 9273 isProperty && !!declaration.questionToken || 9274 isParameter(declaration) && (!!declaration.questionToken || isJSDocOptionalParameter(declaration)) || 9275 isOptionalJSDocPropertyLikeTag(declaration)); 9276 9277 // Use type from type annotation if one is present 9278 const declaredType = tryGetTypeFromEffectiveTypeNode(declaration); 9279 if (declaredType) { 9280 return addOptionality(declaredType, isProperty, isOptional); 9281 } 9282 9283 if ((noImplicitAny || isInJSFile(declaration)) && 9284 isVariableDeclaration(declaration) && !isBindingPattern(declaration.name) && 9285 !(getCombinedModifierFlags(declaration) & ModifierFlags.Export) && !(declaration.flags & NodeFlags.Ambient)) { 9286 // If --noImplicitAny is on or the declaration is in a Javascript file, 9287 // use control flow tracked 'any' type for non-ambient, non-exported var or let variables with no 9288 // initializer or a 'null' or 'undefined' initializer. 9289 if (!(getCombinedNodeFlags(declaration) & NodeFlags.Const) && (!declaration.initializer || isNullOrUndefined(declaration.initializer))) { 9290 return autoType; 9291 } 9292 // Use control flow tracked 'any[]' type for non-ambient, non-exported variables with an empty array 9293 // literal initializer. 9294 if (declaration.initializer && isEmptyArrayLiteral(declaration.initializer)) { 9295 return autoArrayType; 9296 } 9297 } 9298 9299 if (isParameter(declaration)) { 9300 const func = declaration.parent as FunctionLikeDeclaration; 9301 // For a parameter of a set accessor, use the type of the get accessor if one is present 9302 if (func.kind === SyntaxKind.SetAccessor && hasBindableName(func)) { 9303 const getter = getDeclarationOfKind<AccessorDeclaration>(getSymbolOfNode(declaration.parent), SyntaxKind.GetAccessor); 9304 if (getter) { 9305 const getterSignature = getSignatureFromDeclaration(getter); 9306 const thisParameter = getAccessorThisParameter(func as AccessorDeclaration); 9307 if (thisParameter && declaration === thisParameter) { 9308 // Use the type from the *getter* 9309 Debug.assert(!thisParameter.type); 9310 return getTypeOfSymbol(getterSignature.thisParameter!); 9311 } 9312 return getReturnTypeOfSignature(getterSignature); 9313 } 9314 } 9315 const parameterTypeOfTypeTag = getParameterTypeOfTypeTag(func, declaration); 9316 if (parameterTypeOfTypeTag) return parameterTypeOfTypeTag; 9317 // Use contextual parameter type if one is available 9318 const type = declaration.symbol.escapedName === InternalSymbolName.This ? getContextualThisParameterType(func) : getContextuallyTypedParameterType(declaration); 9319 if (type) { 9320 return addOptionality(type, /*isProperty*/ false, isOptional); 9321 } 9322 } 9323 9324 // Use the type of the initializer expression if one is present and the declaration is 9325 // not a parameter of a contextually typed function 9326 if (hasOnlyExpressionInitializer(declaration) && !!declaration.initializer) { 9327 if (isInJSFile(declaration) && !isParameter(declaration)) { 9328 const containerObjectType = getJSContainerObjectType(declaration, getSymbolOfNode(declaration), getDeclaredExpandoInitializer(declaration)); 9329 if (containerObjectType) { 9330 return containerObjectType; 9331 } 9332 } 9333 const type = widenTypeInferredFromInitializer(declaration, checkDeclarationInitializer(declaration, checkMode)); 9334 return addOptionality(type, isProperty, isOptional); 9335 } 9336 9337 if (isPropertyDeclaration(declaration) && (noImplicitAny || isInJSFile(declaration))) { 9338 // We have a property declaration with no type annotation or initializer, in noImplicitAny mode or a .js file. 9339 // Use control flow analysis of this.xxx assignments in the constructor or static block to determine the type of the property. 9340 if (!hasStaticModifier(declaration)) { 9341 const constructor = findConstructorDeclaration(declaration.parent); 9342 const type = constructor ? getFlowTypeInConstructor(declaration.symbol, constructor) : 9343 getEffectiveModifierFlags(declaration) & ModifierFlags.Ambient ? getTypeOfPropertyInBaseClass(declaration.symbol) : 9344 undefined; 9345 return type && addOptionality(type, /*isProperty*/ true, isOptional); 9346 } 9347 else { 9348 const staticBlocks = filter(declaration.parent.members, isClassStaticBlockDeclaration); 9349 const type = staticBlocks.length ? getFlowTypeInStaticBlocks(declaration.symbol, staticBlocks) : 9350 getEffectiveModifierFlags(declaration) & ModifierFlags.Ambient ? getTypeOfPropertyInBaseClass(declaration.symbol) : 9351 undefined; 9352 return type && addOptionality(type, /*isProperty*/ true, isOptional); 9353 } 9354 } 9355 9356 if (isJsxAttribute(declaration)) { 9357 // if JSX attribute doesn't have initializer, by default the attribute will have boolean value of true. 9358 // I.e <Elem attr /> is sugar for <Elem attr={true} /> 9359 return trueType; 9360 } 9361 9362 // If the declaration specifies a binding pattern and is not a parameter of a contextually 9363 // typed function, use the type implied by the binding pattern 9364 if (isBindingPattern(declaration.name)) { 9365 return getTypeFromBindingPattern(declaration.name, /*includePatternInType*/ false, /*reportErrors*/ true); 9366 } 9367 9368 // No type specified and nothing can be inferred 9369 return undefined; 9370 } 9371 9372 function isConstructorDeclaredProperty(symbol: Symbol) { 9373 // A property is considered a constructor declared property when all declaration sites are this.xxx assignments, 9374 // when no declaration sites have JSDoc type annotations, and when at least one declaration site is in the body of 9375 // a class constructor. 9376 if (symbol.valueDeclaration && isBinaryExpression(symbol.valueDeclaration)) { 9377 const links = getSymbolLinks(symbol); 9378 if (links.isConstructorDeclaredProperty === undefined) { 9379 links.isConstructorDeclaredProperty = false; 9380 links.isConstructorDeclaredProperty = !!getDeclaringConstructor(symbol) && every(symbol.declarations, declaration => 9381 isBinaryExpression(declaration) && 9382 isPossiblyAliasedThisProperty(declaration) && 9383 (declaration.left.kind !== SyntaxKind.ElementAccessExpression || isStringOrNumericLiteralLike((declaration.left as ElementAccessExpression).argumentExpression)) && 9384 !getAnnotatedTypeForAssignmentDeclaration(/*declaredType*/ undefined, declaration, symbol, declaration)); 9385 } 9386 return links.isConstructorDeclaredProperty; 9387 } 9388 return false; 9389 } 9390 9391 function isAutoTypedProperty(symbol: Symbol) { 9392 // A property is auto-typed when its declaration has no type annotation or initializer and we're in 9393 // noImplicitAny mode or a .js file. 9394 const declaration = symbol.valueDeclaration; 9395 return declaration && isPropertyDeclaration(declaration) && !getEffectiveTypeAnnotationNode(declaration) && 9396 !declaration.initializer && (noImplicitAny || isInJSFile(declaration)); 9397 } 9398 9399 function getDeclaringConstructor(symbol: Symbol) { 9400 if (!symbol.declarations) { 9401 return; 9402 } 9403 for (const declaration of symbol.declarations) { 9404 const container = getThisContainer(declaration, /*includeArrowFunctions*/ false); 9405 if (container && (container.kind === SyntaxKind.Constructor || isJSConstructor(container))) { 9406 return container as ConstructorDeclaration; 9407 } 9408 } 9409 } 9410 9411 /** Create a synthetic property access flow node after the last statement of the file */ 9412 function getFlowTypeFromCommonJSExport(symbol: Symbol) { 9413 const file = getSourceFileOfNode(symbol.declarations![0]); 9414 const accessName = unescapeLeadingUnderscores(symbol.escapedName); 9415 const areAllModuleExports = symbol.declarations!.every(d => isInJSFile(d) && isAccessExpression(d) && isModuleExportsAccessExpression(d.expression)); 9416 const reference = areAllModuleExports 9417 ? factory.createPropertyAccessExpression(factory.createPropertyAccessExpression(factory.createIdentifier("module"), factory.createIdentifier("exports")), accessName) 9418 : factory.createPropertyAccessExpression(factory.createIdentifier("exports"), accessName); 9419 if (areAllModuleExports) { 9420 setParent((reference.expression as PropertyAccessExpression).expression, reference.expression); 9421 } 9422 setParent(reference.expression, reference); 9423 setParent(reference, file); 9424 reference.flowNode = file.endFlowNode; 9425 return getFlowTypeOfReference(reference, autoType, undefinedType); 9426 } 9427 9428 function getFlowTypeInStaticBlocks(symbol: Symbol, staticBlocks: readonly ClassStaticBlockDeclaration[]) { 9429 const accessName = startsWith(symbol.escapedName as string, "__#") 9430 ? factory.createPrivateIdentifier((symbol.escapedName as string).split("@")[1]) 9431 : unescapeLeadingUnderscores(symbol.escapedName); 9432 for (const staticBlock of staticBlocks) { 9433 const reference = factory.createPropertyAccessExpression(factory.createThis(), accessName); 9434 setParent(reference.expression, reference); 9435 setParent(reference, staticBlock); 9436 reference.flowNode = staticBlock.returnFlowNode; 9437 const flowType = getFlowTypeOfProperty(reference, symbol); 9438 if (noImplicitAny && (flowType === autoType || flowType === autoArrayType)) { 9439 error(symbol.valueDeclaration, Diagnostics.Member_0_implicitly_has_an_1_type, symbolToString(symbol), typeToString(flowType)); 9440 } 9441 // We don't infer a type if assignments are only null or undefined. 9442 if (everyType(flowType, isNullableType)) { 9443 continue; 9444 } 9445 return convertAutoToAny(flowType); 9446 } 9447 } 9448 9449 function getFlowTypeInConstructor(symbol: Symbol, constructor: ConstructorDeclaration) { 9450 const accessName = startsWith(symbol.escapedName as string, "__#") 9451 ? factory.createPrivateIdentifier((symbol.escapedName as string).split("@")[1]) 9452 : unescapeLeadingUnderscores(symbol.escapedName); 9453 const reference = factory.createPropertyAccessExpression(factory.createThis(), accessName); 9454 setParent(reference.expression, reference); 9455 setParent(reference, constructor); 9456 reference.flowNode = constructor.returnFlowNode; 9457 const flowType = getFlowTypeOfProperty(reference, symbol); 9458 if (noImplicitAny && (flowType === autoType || flowType === autoArrayType)) { 9459 error(symbol.valueDeclaration, Diagnostics.Member_0_implicitly_has_an_1_type, symbolToString(symbol), typeToString(flowType)); 9460 } 9461 // We don't infer a type if assignments are only null or undefined. 9462 return everyType(flowType, isNullableType) ? undefined : convertAutoToAny(flowType); 9463 } 9464 9465 function getFlowTypeOfProperty(reference: Node, prop: Symbol | undefined) { 9466 const initialType = prop?.valueDeclaration 9467 && (!isAutoTypedProperty(prop) || getEffectiveModifierFlags(prop.valueDeclaration) & ModifierFlags.Ambient) 9468 && getTypeOfPropertyInBaseClass(prop) 9469 || undefinedType; 9470 return getFlowTypeOfReference(reference, autoType, initialType); 9471 } 9472 9473 function getWidenedTypeForAssignmentDeclaration(symbol: Symbol, resolvedSymbol?: Symbol) { 9474 // function/class/{} initializers are themselves containers, so they won't merge in the same way as other initializers 9475 const container = getAssignedExpandoInitializer(symbol.valueDeclaration); 9476 if (container) { 9477 const tag = getJSDocTypeTag(container); 9478 if (tag && tag.typeExpression) { 9479 return getTypeFromTypeNode(tag.typeExpression); 9480 } 9481 const containerObjectType = symbol.valueDeclaration && getJSContainerObjectType(symbol.valueDeclaration, symbol, container); 9482 return containerObjectType || getWidenedLiteralType(checkExpressionCached(container)); 9483 } 9484 let type; 9485 let definedInConstructor = false; 9486 let definedInMethod = false; 9487 // We use control flow analysis to determine the type of the property if the property qualifies as a constructor 9488 // declared property and the resulting control flow type isn't just undefined or null. 9489 if (isConstructorDeclaredProperty(symbol)) { 9490 type = getFlowTypeInConstructor(symbol, getDeclaringConstructor(symbol)!); 9491 } 9492 if (!type) { 9493 let types: Type[] | undefined; 9494 if (symbol.declarations) { 9495 let jsdocType: Type | undefined; 9496 for (const declaration of symbol.declarations) { 9497 const expression = (isBinaryExpression(declaration) || isCallExpression(declaration)) ? declaration : 9498 isAccessExpression(declaration) ? isBinaryExpression(declaration.parent) ? declaration.parent : declaration : 9499 undefined; 9500 if (!expression) { 9501 continue; // Non-assignment declaration merged in (eg, an Identifier to mark the thing as a namespace) - skip over it and pull type info from elsewhere 9502 } 9503 9504 const kind = isAccessExpression(expression) 9505 ? getAssignmentDeclarationPropertyAccessKind(expression) 9506 : getAssignmentDeclarationKind(expression); 9507 if (kind === AssignmentDeclarationKind.ThisProperty || isBinaryExpression(expression) && isPossiblyAliasedThisProperty(expression, kind)) { 9508 if (isDeclarationInConstructor(expression)) { 9509 definedInConstructor = true; 9510 } 9511 else { 9512 definedInMethod = true; 9513 } 9514 } 9515 if (!isCallExpression(expression)) { 9516 jsdocType = getAnnotatedTypeForAssignmentDeclaration(jsdocType, expression, symbol, declaration); 9517 } 9518 if (!jsdocType) { 9519 (types || (types = [])).push((isBinaryExpression(expression) || isCallExpression(expression)) ? getInitializerTypeFromAssignmentDeclaration(symbol, resolvedSymbol, expression, kind) : neverType); 9520 } 9521 } 9522 type = jsdocType; 9523 } 9524 if (!type) { 9525 if (!length(types)) { 9526 return errorType; // No types from any declarations :( 9527 } 9528 let constructorTypes = definedInConstructor && symbol.declarations ? getConstructorDefinedThisAssignmentTypes(types!, symbol.declarations) : undefined; 9529 // use only the constructor types unless they were only assigned null | undefined (including widening variants) 9530 if (definedInMethod) { 9531 const propType = getTypeOfPropertyInBaseClass(symbol); 9532 if (propType) { 9533 (constructorTypes || (constructorTypes = [])).push(propType); 9534 definedInConstructor = true; 9535 } 9536 } 9537 const sourceTypes = some(constructorTypes, t => !!(t.flags & ~TypeFlags.Nullable)) ? constructorTypes : types; // TODO: GH#18217 9538 type = getUnionType(sourceTypes!); 9539 } 9540 } 9541 const widened = getWidenedType(addOptionality(type, /*isProperty*/ false, definedInMethod && !definedInConstructor)); 9542 if (symbol.valueDeclaration && filterType(widened, t => !!(t.flags & ~TypeFlags.Nullable)) === neverType) { 9543 reportImplicitAny(symbol.valueDeclaration, anyType); 9544 return anyType; 9545 } 9546 return widened; 9547 } 9548 9549 function getJSContainerObjectType(decl: Node, symbol: Symbol, init: Expression | undefined): Type | undefined { 9550 if (!isInJSFile(decl) || !init || !isObjectLiteralExpression(init) || init.properties.length) { 9551 return undefined; 9552 } 9553 const exports = createSymbolTable(); 9554 while (isBinaryExpression(decl) || isPropertyAccessExpression(decl)) { 9555 const s = getSymbolOfNode(decl); 9556 if (s?.exports?.size) { 9557 mergeSymbolTable(exports, s.exports); 9558 } 9559 decl = isBinaryExpression(decl) ? decl.parent : decl.parent.parent; 9560 } 9561 const s = getSymbolOfNode(decl); 9562 if (s?.exports?.size) { 9563 mergeSymbolTable(exports, s.exports); 9564 } 9565 const type = createAnonymousType(symbol, exports, emptyArray, emptyArray, emptyArray); 9566 type.objectFlags |= ObjectFlags.JSLiteral; 9567 return type; 9568 } 9569 9570 function getAnnotatedTypeForAssignmentDeclaration(declaredType: Type | undefined, expression: Expression, symbol: Symbol, declaration: Declaration) { 9571 const typeNode = getEffectiveTypeAnnotationNode(expression.parent); 9572 if (typeNode) { 9573 const type = getWidenedType(getTypeFromTypeNode(typeNode)); 9574 if (!declaredType) { 9575 return type; 9576 } 9577 else if (!isErrorType(declaredType) && !isErrorType(type) && !isTypeIdenticalTo(declaredType, type)) { 9578 errorNextVariableOrPropertyDeclarationMustHaveSameType(/*firstDeclaration*/ undefined, declaredType, declaration, type); 9579 } 9580 } 9581 if (symbol.parent?.valueDeclaration) { 9582 const typeNode = getEffectiveTypeAnnotationNode(symbol.parent.valueDeclaration); 9583 if (typeNode) { 9584 const annotationSymbol = getPropertyOfType(getTypeFromTypeNode(typeNode), symbol.escapedName); 9585 if (annotationSymbol) { 9586 return getNonMissingTypeOfSymbol(annotationSymbol); 9587 } 9588 } 9589 } 9590 9591 return declaredType; 9592 } 9593 9594 /** If we don't have an explicit JSDoc type, get the type from the initializer. */ 9595 function getInitializerTypeFromAssignmentDeclaration(symbol: Symbol, resolvedSymbol: Symbol | undefined, expression: BinaryExpression | CallExpression, kind: AssignmentDeclarationKind) { 9596 if (isCallExpression(expression)) { 9597 if (resolvedSymbol) { 9598 return getTypeOfSymbol(resolvedSymbol); // This shouldn't happen except under some hopefully forbidden merges of export assignments and object define assignments 9599 } 9600 const objectLitType = checkExpressionCached((expression as BindableObjectDefinePropertyCall).arguments[2]); 9601 const valueType = getTypeOfPropertyOfType(objectLitType, "value" as __String); 9602 if (valueType) { 9603 return valueType; 9604 } 9605 const getFunc = getTypeOfPropertyOfType(objectLitType, "get" as __String); 9606 if (getFunc) { 9607 const getSig = getSingleCallSignature(getFunc); 9608 if (getSig) { 9609 return getReturnTypeOfSignature(getSig); 9610 } 9611 } 9612 const setFunc = getTypeOfPropertyOfType(objectLitType, "set" as __String); 9613 if (setFunc) { 9614 const setSig = getSingleCallSignature(setFunc); 9615 if (setSig) { 9616 return getTypeOfFirstParameterOfSignature(setSig); 9617 } 9618 } 9619 return anyType; 9620 } 9621 if (containsSameNamedThisProperty(expression.left, expression.right)) { 9622 return anyType; 9623 } 9624 const isDirectExport = kind === AssignmentDeclarationKind.ExportsProperty && (isPropertyAccessExpression(expression.left) || isElementAccessExpression(expression.left)) && (isModuleExportsAccessExpression(expression.left.expression) || (isIdentifier(expression.left.expression) && isExportsIdentifier(expression.left.expression))); 9625 const type = resolvedSymbol ? getTypeOfSymbol(resolvedSymbol) 9626 : isDirectExport ? getRegularTypeOfLiteralType(checkExpressionCached(expression.right)) 9627 : getWidenedLiteralType(checkExpressionCached(expression.right)); 9628 if (type.flags & TypeFlags.Object && 9629 kind === AssignmentDeclarationKind.ModuleExports && 9630 symbol.escapedName === InternalSymbolName.ExportEquals) { 9631 const exportedType = resolveStructuredTypeMembers(type as ObjectType); 9632 const members = createSymbolTable(); 9633 copyEntries(exportedType.members, members); 9634 const initialSize = members.size; 9635 if (resolvedSymbol && !resolvedSymbol.exports) { 9636 resolvedSymbol.exports = createSymbolTable(); 9637 } 9638 (resolvedSymbol || symbol).exports!.forEach((s, name) => { 9639 const exportedMember = members.get(name)!; 9640 if (exportedMember && exportedMember !== s && !(s.flags & SymbolFlags.Alias)) { 9641 if (s.flags & SymbolFlags.Value && exportedMember.flags & SymbolFlags.Value) { 9642 // If the member has an additional value-like declaration, union the types from the two declarations, 9643 // but issue an error if they occurred in two different files. The purpose is to support a JS file with 9644 // a pattern like: 9645 // 9646 // module.exports = { a: true }; 9647 // module.exports.a = 3; 9648 // 9649 // but we may have a JS file with `module.exports = { a: true }` along with a TypeScript module augmentation 9650 // declaring an `export const a: number`. In that case, we issue a duplicate identifier error, because 9651 // it's unclear what that's supposed to mean, so it's probably a mistake. 9652 if (s.valueDeclaration && exportedMember.valueDeclaration && getSourceFileOfNode(s.valueDeclaration) !== getSourceFileOfNode(exportedMember.valueDeclaration)) { 9653 const unescapedName = unescapeLeadingUnderscores(s.escapedName); 9654 const exportedMemberName = tryCast(exportedMember.valueDeclaration, isNamedDeclaration)?.name || exportedMember.valueDeclaration; 9655 addRelatedInfo( 9656 error(s.valueDeclaration, Diagnostics.Duplicate_identifier_0, unescapedName), 9657 createDiagnosticForNode(exportedMemberName, Diagnostics._0_was_also_declared_here, unescapedName)); 9658 addRelatedInfo( 9659 error(exportedMemberName, Diagnostics.Duplicate_identifier_0, unescapedName), 9660 createDiagnosticForNode(s.valueDeclaration, Diagnostics._0_was_also_declared_here, unescapedName)); 9661 } 9662 const union = createSymbol(s.flags | exportedMember.flags, name); 9663 union.type = getUnionType([getTypeOfSymbol(s), getTypeOfSymbol(exportedMember)]); 9664 union.valueDeclaration = exportedMember.valueDeclaration; 9665 union.declarations = concatenate(exportedMember.declarations, s.declarations); 9666 members.set(name, union); 9667 } 9668 else { 9669 members.set(name, mergeSymbol(s, exportedMember)); 9670 } 9671 } 9672 else { 9673 members.set(name, s); 9674 } 9675 }); 9676 const result = createAnonymousType( 9677 initialSize !== members.size ? undefined : exportedType.symbol, // Only set the type's symbol if it looks to be the same as the original type 9678 members, 9679 exportedType.callSignatures, 9680 exportedType.constructSignatures, 9681 exportedType.indexInfos); 9682 if (initialSize === members.size) { 9683 if (type.aliasSymbol) { 9684 result.aliasSymbol = type.aliasSymbol; 9685 result.aliasTypeArguments = type.aliasTypeArguments; 9686 } 9687 if (getObjectFlags(type) & ObjectFlags.Reference) { 9688 result.aliasSymbol = (type as TypeReference).symbol; 9689 const args = getTypeArguments(type as TypeReference); 9690 result.aliasTypeArguments = length(args) ? args : undefined; 9691 } 9692 } 9693 result.objectFlags |= (getObjectFlags(type) & ObjectFlags.JSLiteral); // Propagate JSLiteral flag 9694 if (result.symbol && result.symbol.flags & SymbolFlags.Class && type === getDeclaredTypeOfClassOrInterface(result.symbol)) { 9695 result.objectFlags |= ObjectFlags.IsClassInstanceClone; // Propagate the knowledge that this type is equivalent to the symbol's class instance type 9696 } 9697 return result; 9698 } 9699 if (isEmptyArrayLiteralType(type)) { 9700 reportImplicitAny(expression, anyArrayType); 9701 return anyArrayType; 9702 } 9703 return type; 9704 } 9705 9706 function containsSameNamedThisProperty(thisProperty: Expression, expression: Expression) { 9707 return isPropertyAccessExpression(thisProperty) 9708 && thisProperty.expression.kind === SyntaxKind.ThisKeyword 9709 && forEachChildRecursively(expression, n => isMatchingReference(thisProperty, n)); 9710 } 9711 9712 function isDeclarationInConstructor(expression: Expression) { 9713 const thisContainer = getThisContainer(expression, /*includeArrowFunctions*/ false); 9714 // Properties defined in a constructor (or base constructor, or javascript constructor function) don't get undefined added. 9715 // Function expressions that are assigned to the prototype count as methods. 9716 return thisContainer.kind === SyntaxKind.Constructor || 9717 thisContainer.kind === SyntaxKind.FunctionDeclaration || 9718 (thisContainer.kind === SyntaxKind.FunctionExpression && !isPrototypePropertyAssignment(thisContainer.parent)); 9719 } 9720 9721 function getConstructorDefinedThisAssignmentTypes(types: Type[], declarations: Declaration[]): Type[] | undefined { 9722 Debug.assert(types.length === declarations.length); 9723 return types.filter((_, i) => { 9724 const declaration = declarations[i]; 9725 const expression = isBinaryExpression(declaration) ? declaration : 9726 isBinaryExpression(declaration.parent) ? declaration.parent : undefined; 9727 return expression && isDeclarationInConstructor(expression); 9728 }); 9729 } 9730 9731 // Return the type implied by a binding pattern element. This is the type of the initializer of the element if 9732 // one is present. Otherwise, if the element is itself a binding pattern, it is the type implied by the binding 9733 // pattern. Otherwise, it is the type any. 9734 function getTypeFromBindingElement(element: BindingElement, includePatternInType?: boolean, reportErrors?: boolean): Type { 9735 if (element.initializer) { 9736 // The type implied by a binding pattern is independent of context, so we check the initializer with no 9737 // contextual type or, if the element itself is a binding pattern, with the type implied by that binding 9738 // pattern. 9739 const contextualType = isBindingPattern(element.name) ? getTypeFromBindingPattern(element.name, /*includePatternInType*/ true, /*reportErrors*/ false) : unknownType; 9740 return addOptionality(widenTypeInferredFromInitializer(element, checkDeclarationInitializer(element, CheckMode.Normal, contextualType))); 9741 } 9742 if (isBindingPattern(element.name)) { 9743 return getTypeFromBindingPattern(element.name, includePatternInType, reportErrors); 9744 } 9745 if (reportErrors && !declarationBelongsToPrivateAmbientMember(element)) { 9746 reportImplicitAny(element, anyType); 9747 } 9748 // When we're including the pattern in the type (an indication we're obtaining a contextual type), we 9749 // use a non-inferrable any type. Inference will never directly infer this type, but it is possible 9750 // to infer a type that contains it, e.g. for a binding pattern like [foo] or { foo }. In such cases, 9751 // widening of the binding pattern type substitutes a regular any for the non-inferrable any. 9752 return includePatternInType ? nonInferrableAnyType : anyType; 9753 } 9754 9755 // Return the type implied by an object binding pattern 9756 function getTypeFromObjectBindingPattern(pattern: ObjectBindingPattern, includePatternInType: boolean, reportErrors: boolean): Type { 9757 const members = createSymbolTable(); 9758 let stringIndexInfo: IndexInfo | undefined; 9759 let objectFlags = ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral; 9760 forEach(pattern.elements, e => { 9761 const name = e.propertyName || e.name as Identifier; 9762 if (e.dotDotDotToken) { 9763 stringIndexInfo = createIndexInfo(stringType, anyType, /*isReadonly*/ false); 9764 return; 9765 } 9766 9767 const exprType = getLiteralTypeFromPropertyName(name); 9768 if (!isTypeUsableAsPropertyName(exprType)) { 9769 // do not include computed properties in the implied type 9770 objectFlags |= ObjectFlags.ObjectLiteralPatternWithComputedProperties; 9771 return; 9772 } 9773 const text = getPropertyNameFromType(exprType); 9774 const flags = SymbolFlags.Property | (e.initializer ? SymbolFlags.Optional : 0); 9775 const symbol = createSymbol(flags, text); 9776 symbol.type = getTypeFromBindingElement(e, includePatternInType, reportErrors); 9777 symbol.bindingElement = e; 9778 members.set(symbol.escapedName, symbol); 9779 }); 9780 const result = createAnonymousType(undefined, members, emptyArray, emptyArray, stringIndexInfo ? [stringIndexInfo] : emptyArray); 9781 result.objectFlags |= objectFlags; 9782 if (includePatternInType) { 9783 result.pattern = pattern; 9784 result.objectFlags |= ObjectFlags.ContainsObjectOrArrayLiteral; 9785 } 9786 return result; 9787 } 9788 9789 // Return the type implied by an array binding pattern 9790 function getTypeFromArrayBindingPattern(pattern: BindingPattern, includePatternInType: boolean, reportErrors: boolean): Type { 9791 const elements = pattern.elements; 9792 const lastElement = lastOrUndefined(elements); 9793 const restElement = lastElement && lastElement.kind === SyntaxKind.BindingElement && lastElement.dotDotDotToken ? lastElement : undefined; 9794 if (elements.length === 0 || elements.length === 1 && restElement) { 9795 return languageVersion >= ScriptTarget.ES2015 ? createIterableType(anyType) : anyArrayType; 9796 } 9797 const elementTypes = map(elements, e => isOmittedExpression(e) ? anyType : getTypeFromBindingElement(e, includePatternInType, reportErrors)); 9798 const minLength = findLastIndex(elements, e => !(e === restElement || isOmittedExpression(e) || hasDefaultValue(e)), elements.length - 1) + 1; 9799 const elementFlags = map(elements, (e, i) => e === restElement ? ElementFlags.Rest : i >= minLength ? ElementFlags.Optional : ElementFlags.Required); 9800 let result = createTupleType(elementTypes, elementFlags) as TypeReference; 9801 if (includePatternInType) { 9802 result = cloneTypeReference(result); 9803 result.pattern = pattern; 9804 result.objectFlags |= ObjectFlags.ContainsObjectOrArrayLiteral; 9805 } 9806 return result; 9807 } 9808 9809 // Return the type implied by a binding pattern. This is the type implied purely by the binding pattern itself 9810 // and without regard to its context (i.e. without regard any type annotation or initializer associated with the 9811 // declaration in which the binding pattern is contained). For example, the implied type of [x, y] is [any, any] 9812 // and the implied type of { x, y: z = 1 } is { x: any; y: number; }. The type implied by a binding pattern is 9813 // used as the contextual type of an initializer associated with the binding pattern. Also, for a destructuring 9814 // parameter with no type annotation or initializer, the type implied by the binding pattern becomes the type of 9815 // the parameter. 9816 function getTypeFromBindingPattern(pattern: BindingPattern, includePatternInType = false, reportErrors = false): Type { 9817 return pattern.kind === SyntaxKind.ObjectBindingPattern 9818 ? getTypeFromObjectBindingPattern(pattern, includePatternInType, reportErrors) 9819 : getTypeFromArrayBindingPattern(pattern, includePatternInType, reportErrors); 9820 } 9821 9822 // Return the type associated with a variable, parameter, or property declaration. In the simple case this is the type 9823 // specified in a type annotation or inferred from an initializer. However, in the case of a destructuring declaration it 9824 // is a bit more involved. For example: 9825 // 9826 // var [x, s = ""] = [1, "one"]; 9827 // 9828 // Here, the array literal [1, "one"] is contextually typed by the type [any, string], which is the implied type of the 9829 // binding pattern [x, s = ""]. Because the contextual type is a tuple type, the resulting type of [1, "one"] is the 9830 // tuple type [number, string]. Thus, the type inferred for 'x' is number and the type inferred for 's' is string. 9831 function getWidenedTypeForVariableLikeDeclaration(declaration: ParameterDeclaration | PropertyDeclaration | PropertySignature | AnnotationPropertyDeclaration | VariableDeclaration | BindingElement | JSDocPropertyLikeTag, reportErrors?: boolean): Type { 9832 return widenTypeForVariableLikeDeclaration(getTypeForVariableLikeDeclaration(declaration, /*includeOptionality*/ true, CheckMode.Normal), declaration, reportErrors); 9833 } 9834 9835 function isGlobalSymbolConstructor(node: Node) { 9836 const symbol = getSymbolOfNode(node); 9837 const globalSymbol = getGlobalESSymbolConstructorTypeSymbol(/*reportErrors*/ false); 9838 return globalSymbol && symbol && symbol === globalSymbol; 9839 } 9840 9841 function widenTypeForVariableLikeDeclaration(type: Type | undefined, declaration: any, reportErrors?: boolean) { 9842 if (type) { 9843 // TODO: If back compat with pre-3.0/4.0 libs isn't required, remove the following SymbolConstructor special case transforming `symbol` into `unique symbol` 9844 if (type.flags & TypeFlags.ESSymbol && isGlobalSymbolConstructor(declaration.parent)) { 9845 type = getESSymbolLikeTypeForNode(declaration); 9846 } 9847 if (reportErrors) { 9848 reportErrorsFromWidening(declaration, type); 9849 } 9850 9851 // always widen a 'unique symbol' type if the type was created for a different declaration. 9852 if (type.flags & TypeFlags.UniqueESSymbol && (isBindingElement(declaration) || !declaration.type) && type.symbol !== getSymbolOfNode(declaration)) { 9853 type = esSymbolType; 9854 } 9855 9856 return getWidenedType(type); 9857 } 9858 9859 // Rest parameters default to type any[], other parameters default to type any 9860 type = isParameter(declaration) && declaration.dotDotDotToken ? anyArrayType : anyType; 9861 9862 // Report implicit any errors unless this is a private property within an ambient declaration 9863 if (reportErrors) { 9864 if (!declarationBelongsToPrivateAmbientMember(declaration)) { 9865 reportImplicitAny(declaration, type); 9866 } 9867 } 9868 return type; 9869 } 9870 9871 function declarationBelongsToPrivateAmbientMember(declaration: VariableLikeDeclaration) { 9872 const root = getRootDeclaration(declaration); 9873 const memberDeclaration = root.kind === SyntaxKind.Parameter ? root.parent : root; 9874 return isPrivateWithinAmbient(memberDeclaration); 9875 } 9876 9877 function tryGetTypeFromEffectiveTypeNode(node: Node) { 9878 const typeNode = getEffectiveTypeAnnotationNode(node); 9879 if (typeNode) { 9880 return getTypeFromTypeNode(typeNode); 9881 } 9882 } 9883 9884 function getTypeOfVariableOrParameterOrProperty(symbol: Symbol): Type { 9885 const links = getSymbolLinks(symbol); 9886 if (!links.type) { 9887 const type = getTypeOfVariableOrParameterOrPropertyWorker(symbol); 9888 // For a contextually typed parameter it is possible that a type has already 9889 // been assigned (in assignTypeToParameterAndFixTypeParameters), and we want 9890 // to preserve this type. 9891 if (!links.type) { 9892 links.type = type; 9893 } 9894 } 9895 return links.type; 9896 } 9897 9898 function getTypeOfVariableOrParameterOrPropertyWorker(symbol: Symbol): Type { 9899 // Handle prototype property 9900 if (symbol.flags & SymbolFlags.Prototype) { 9901 return getTypeOfPrototypeProperty(symbol); 9902 } 9903 // CommonsJS require and module both have type any. 9904 if (symbol === requireSymbol) { 9905 return anyType; 9906 } 9907 if (symbol.flags & SymbolFlags.ModuleExports && symbol.valueDeclaration) { 9908 const fileSymbol = getSymbolOfNode(getSourceFileOfNode(symbol.valueDeclaration)); 9909 const result = createSymbol(fileSymbol.flags, "exports" as __String); 9910 result.declarations = fileSymbol.declarations ? fileSymbol.declarations.slice() : []; 9911 result.parent = symbol; 9912 result.target = fileSymbol; 9913 if (fileSymbol.valueDeclaration) result.valueDeclaration = fileSymbol.valueDeclaration; 9914 if (fileSymbol.members) result.members = new Map(fileSymbol.members); 9915 if (fileSymbol.exports) result.exports = new Map(fileSymbol.exports); 9916 const members = createSymbolTable(); 9917 members.set("exports" as __String, result); 9918 return createAnonymousType(symbol, members, emptyArray, emptyArray, emptyArray); 9919 } 9920 // Handle catch clause variables 9921 Debug.assertIsDefined(symbol.valueDeclaration); 9922 const declaration = symbol.valueDeclaration; 9923 if (isCatchClauseVariableDeclarationOrBindingElement(declaration)) { 9924 const typeNode = getEffectiveTypeAnnotationNode(declaration); 9925 if (typeNode === undefined) { 9926 return useUnknownInCatchVariables ? unknownType : anyType; 9927 } 9928 const type = getTypeOfNode(typeNode); 9929 // an errorType will make `checkTryStatement` issue an error 9930 return isTypeAny(type) || type === unknownType ? type : errorType; 9931 } 9932 // Handle export default expressions 9933 if (isSourceFile(declaration) && isJsonSourceFile(declaration)) { 9934 if (!declaration.statements.length) { 9935 return emptyObjectType; 9936 } 9937 return getWidenedType(getWidenedLiteralType(checkExpression(declaration.statements[0].expression))); 9938 } 9939 if (isAccessor(declaration)) { 9940 // Binding of certain patterns in JS code will occasionally mark symbols as both properties 9941 // and accessors. Here we dispatch to accessor resolution if needed. 9942 return getTypeOfAccessors(symbol); 9943 } 9944 9945 // Handle variable, parameter or property 9946 if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) { 9947 // Symbol is property of some kind that is merged with something - should use `getTypeOfFuncClassEnumModule` and not `getTypeOfVariableOrParameterOrProperty` 9948 if (symbol.flags & SymbolFlags.ValueModule && !(symbol.flags & SymbolFlags.Assignment)) { 9949 return getTypeOfFuncClassEnumModule(symbol); 9950 } 9951 return reportCircularityError(symbol); 9952 } 9953 let type: Type; 9954 if (declaration.kind === SyntaxKind.ExportAssignment) { 9955 type = widenTypeForVariableLikeDeclaration(tryGetTypeFromEffectiveTypeNode(declaration) || checkExpressionCached((declaration as ExportAssignment).expression), declaration); 9956 } 9957 else if ( 9958 isBinaryExpression(declaration) || 9959 (isInJSFile(declaration) && 9960 (isCallExpression(declaration) || (isPropertyAccessExpression(declaration) || isBindableStaticElementAccessExpression(declaration)) && isBinaryExpression(declaration.parent)))) { 9961 type = getWidenedTypeForAssignmentDeclaration(symbol); 9962 } 9963 else if (isPropertyAccessExpression(declaration) 9964 || isElementAccessExpression(declaration) 9965 || isIdentifier(declaration) 9966 || isStringLiteralLike(declaration) 9967 || isNumericLiteral(declaration) 9968 || isClassDeclaration(declaration) 9969 || isFunctionDeclaration(declaration) 9970 || (isMethodDeclaration(declaration) && !isObjectLiteralMethod(declaration)) 9971 || isMethodSignature(declaration) 9972 || isSourceFile(declaration)) { 9973 // Symbol is property of some kind that is merged with something - should use `getTypeOfFuncClassEnumModule` and not `getTypeOfVariableOrParameterOrProperty` 9974 if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) { 9975 return getTypeOfFuncClassEnumModule(symbol); 9976 } 9977 type = isBinaryExpression(declaration.parent) ? 9978 getWidenedTypeForAssignmentDeclaration(symbol) : 9979 tryGetTypeFromEffectiveTypeNode(declaration) || anyType; 9980 } 9981 else if (isPropertyAssignment(declaration)) { 9982 type = tryGetTypeFromEffectiveTypeNode(declaration) || checkPropertyAssignment(declaration); 9983 } 9984 else if (isJsxAttribute(declaration)) { 9985 type = tryGetTypeFromEffectiveTypeNode(declaration) || checkJsxAttribute(declaration); 9986 } 9987 else if (isShorthandPropertyAssignment(declaration)) { 9988 type = tryGetTypeFromEffectiveTypeNode(declaration) || checkExpressionForMutableLocation(declaration.name, CheckMode.Normal); 9989 } 9990 else if (isObjectLiteralMethod(declaration)) { 9991 type = tryGetTypeFromEffectiveTypeNode(declaration) || checkObjectLiteralMethod(declaration, CheckMode.Normal); 9992 } 9993 else if (isParameter(declaration) 9994 || isPropertyDeclaration(declaration) 9995 || isPropertySignature(declaration) 9996 || isAnnotationPropertyDeclaration(declaration) 9997 || isVariableDeclaration(declaration) 9998 || isBindingElement(declaration) 9999 || isJSDocPropertyLikeTag(declaration)) { 10000 type = getWidenedTypeForVariableLikeDeclaration(declaration, /*includeOptionality*/ true); 10001 } 10002 // getTypeOfSymbol dispatches some JS merges incorrectly because their symbol flags are not mutually exclusive. 10003 // Re-dispatch based on valueDeclaration.kind instead. 10004 else if (isEnumDeclaration(declaration)) { 10005 type = getTypeOfFuncClassEnumModule(symbol); 10006 } 10007 else if (isEnumMember(declaration)) { 10008 type = getTypeOfEnumMember(symbol); 10009 } 10010 else { 10011 return Debug.fail("Unhandled declaration kind! " + Debug.formatSyntaxKind(declaration.kind) + " for " + Debug.formatSymbol(symbol)); 10012 } 10013 10014 if (!popTypeResolution()) { 10015 // Symbol is property of some kind that is merged with something - should use `getTypeOfFuncClassEnumModule` and not `getTypeOfVariableOrParameterOrProperty` 10016 if (symbol.flags & SymbolFlags.ValueModule && !(symbol.flags & SymbolFlags.Assignment)) { 10017 return getTypeOfFuncClassEnumModule(symbol); 10018 } 10019 return reportCircularityError(symbol); 10020 } 10021 return type; 10022 } 10023 10024 function getAnnotatedAccessorTypeNode(accessor: AccessorDeclaration | PropertyDeclaration | undefined): TypeNode | undefined { 10025 if (accessor) { 10026 switch (accessor.kind) { 10027 case SyntaxKind.GetAccessor: 10028 const getterTypeAnnotation = getEffectiveReturnTypeNode(accessor); 10029 return getterTypeAnnotation; 10030 case SyntaxKind.SetAccessor: 10031 const setterTypeAnnotation = getEffectiveSetAccessorTypeAnnotationNode(accessor); 10032 return setterTypeAnnotation; 10033 case SyntaxKind.PropertyDeclaration: 10034 Debug.assert(hasAccessorModifier(accessor)); 10035 const accessorTypeAnnotation = getEffectiveTypeAnnotationNode(accessor); 10036 return accessorTypeAnnotation; 10037 } 10038 } 10039 return undefined; 10040 } 10041 10042 function getAnnotatedAccessorType(accessor: AccessorDeclaration | PropertyDeclaration | undefined): Type | undefined { 10043 const node = getAnnotatedAccessorTypeNode(accessor); 10044 return node && getTypeFromTypeNode(node); 10045 } 10046 10047 function getAnnotatedAccessorThisParameter(accessor: AccessorDeclaration): Symbol | undefined { 10048 const parameter = getAccessorThisParameter(accessor); 10049 return parameter && parameter.symbol; 10050 } 10051 10052 function getThisTypeOfDeclaration(declaration: SignatureDeclaration): Type | undefined { 10053 return getThisTypeOfSignature(getSignatureFromDeclaration(declaration)); 10054 } 10055 10056 function getTypeOfAccessors(symbol: Symbol): Type { 10057 const links = getSymbolLinks(symbol); 10058 if (!links.type) { 10059 if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) { 10060 return errorType; 10061 } 10062 const getter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.GetAccessor); 10063 const setter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.SetAccessor); 10064 const accessor = tryCast(getDeclarationOfKind<PropertyDeclaration>(symbol, SyntaxKind.PropertyDeclaration), isAutoAccessorPropertyDeclaration); 10065 10066 // We try to resolve a getter type annotation, a setter type annotation, or a getter function 10067 // body return type inference, in that order. 10068 let type = getter && isInJSFile(getter) && getTypeForDeclarationFromJSDocComment(getter) || 10069 getAnnotatedAccessorType(getter) || 10070 getAnnotatedAccessorType(setter) || 10071 getAnnotatedAccessorType(accessor) || 10072 getter && getter.body && getReturnTypeFromBody(getter) || 10073 accessor && accessor.initializer && getWidenedTypeForVariableLikeDeclaration(accessor, /*includeOptionality*/ true); 10074 if (!type) { 10075 if (setter && !isPrivateWithinAmbient(setter)) { 10076 errorOrSuggestion(noImplicitAny, setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation, symbolToString(symbol)); 10077 } 10078 else if (getter && !isPrivateWithinAmbient(getter)) { 10079 errorOrSuggestion(noImplicitAny, getter, Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation, symbolToString(symbol)); 10080 } 10081 else if (accessor && !isPrivateWithinAmbient(accessor)) { 10082 errorOrSuggestion(noImplicitAny, accessor, Diagnostics.Member_0_implicitly_has_an_1_type, symbolToString(symbol), "any"); 10083 } 10084 type = anyType; 10085 } 10086 if (!popTypeResolution()) { 10087 if (getAnnotatedAccessorTypeNode(getter)) { 10088 error(getter, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol)); 10089 } 10090 else if (getAnnotatedAccessorTypeNode(setter)) { 10091 error(setter, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol)); 10092 } 10093 else if (getAnnotatedAccessorTypeNode(accessor)) { 10094 error(setter, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol)); 10095 } 10096 else if (getter && noImplicitAny) { 10097 error(getter, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, symbolToString(symbol)); 10098 } 10099 type = anyType; 10100 } 10101 links.type = type; 10102 } 10103 return links.type; 10104 } 10105 10106 function getWriteTypeOfAccessors(symbol: Symbol): Type { 10107 const links = getSymbolLinks(symbol); 10108 if (!links.writeType) { 10109 if (!pushTypeResolution(symbol, TypeSystemPropertyName.WriteType)) { 10110 return errorType; 10111 } 10112 10113 const setter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.SetAccessor) 10114 ?? tryCast(getDeclarationOfKind<PropertyDeclaration>(symbol, SyntaxKind.PropertyDeclaration), isAutoAccessorPropertyDeclaration); 10115 let writeType = getAnnotatedAccessorType(setter); 10116 if (!popTypeResolution()) { 10117 if (getAnnotatedAccessorTypeNode(setter)) { 10118 error(setter, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol)); 10119 } 10120 writeType = anyType; 10121 } 10122 // Absent an explicit setter type annotation we use the read type of the accessor. 10123 links.writeType = writeType || getTypeOfAccessors(symbol); 10124 } 10125 return links.writeType; 10126 } 10127 10128 function getBaseTypeVariableOfClass(symbol: Symbol) { 10129 const baseConstructorType = getBaseConstructorTypeOfClass(getDeclaredTypeOfClassOrInterface(symbol)); 10130 return baseConstructorType.flags & TypeFlags.TypeVariable ? baseConstructorType : 10131 baseConstructorType.flags & TypeFlags.Intersection ? find((baseConstructorType as IntersectionType).types, t => !!(t.flags & TypeFlags.TypeVariable)) : 10132 undefined; 10133 } 10134 10135 function getTypeOfFuncClassEnumModule(symbol: Symbol): Type { 10136 let links = getSymbolLinks(symbol); 10137 const originalLinks = links; 10138 if (!links.type) { 10139 const expando = symbol.valueDeclaration && getSymbolOfExpando(symbol.valueDeclaration, /*allowDeclaration*/ false); 10140 if (expando) { 10141 const merged = mergeJSSymbols(symbol, expando); 10142 if (merged) { 10143 // note:we overwrite links because we just cloned the symbol 10144 symbol = links = merged; 10145 } 10146 } 10147 originalLinks.type = links.type = getTypeOfFuncClassEnumModuleWorker(symbol); 10148 } 10149 return links.type; 10150 } 10151 10152 function getTypeOfFuncClassEnumModuleWorker(symbol: Symbol): Type { 10153 const declaration = symbol.valueDeclaration; 10154 if (symbol.flags & SymbolFlags.Module && isShorthandAmbientModuleSymbol(symbol)) { 10155 return anyType; 10156 } 10157 else if (declaration && (declaration.kind === SyntaxKind.BinaryExpression || 10158 isAccessExpression(declaration) && 10159 declaration.parent.kind === SyntaxKind.BinaryExpression)) { 10160 return getWidenedTypeForAssignmentDeclaration(symbol); 10161 } 10162 else if (symbol.flags & SymbolFlags.ValueModule && declaration && isSourceFile(declaration) && declaration.commonJsModuleIndicator) { 10163 const resolvedModule = resolveExternalModuleSymbol(symbol); 10164 if (resolvedModule !== symbol) { 10165 if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) { 10166 return errorType; 10167 } 10168 const exportEquals = getMergedSymbol(symbol.exports!.get(InternalSymbolName.ExportEquals)!); 10169 const type = getWidenedTypeForAssignmentDeclaration(exportEquals, exportEquals === resolvedModule ? undefined : resolvedModule); 10170 if (!popTypeResolution()) { 10171 return reportCircularityError(symbol); 10172 } 10173 return type; 10174 } 10175 } 10176 const type = createObjectType(ObjectFlags.Anonymous, symbol); 10177 if (symbol.flags & SymbolFlags.Class) { 10178 const baseTypeVariable = getBaseTypeVariableOfClass(symbol); 10179 return baseTypeVariable ? getIntersectionType([type, baseTypeVariable]) : type; 10180 } 10181 else { 10182 return strictNullChecks && symbol.flags & SymbolFlags.Optional ? getOptionalType(type) : type; 10183 } 10184 } 10185 10186 function getTypeOfEnumMember(symbol: Symbol): Type { 10187 const links = getSymbolLinks(symbol); 10188 return links.type || (links.type = getDeclaredTypeOfEnumMember(symbol)); 10189 } 10190 10191 function getTypeOfAlias(symbol: Symbol): Type { 10192 const links = getSymbolLinks(symbol); 10193 if (!links.type) { 10194 const targetSymbol = resolveAlias(symbol); 10195 const exportSymbol = symbol.declarations && getTargetOfAliasDeclaration(getDeclarationOfAliasSymbol(symbol)!, /*dontResolveAlias*/ true); 10196 const declaredType = firstDefined(exportSymbol?.declarations, d => isExportAssignment(d) ? tryGetTypeFromEffectiveTypeNode(d) : undefined); 10197 // It only makes sense to get the type of a value symbol. If the result of resolving 10198 // the alias is not a value, then it has no type. To get the type associated with a 10199 // type symbol, call getDeclaredTypeOfSymbol. 10200 // This check is important because without it, a call to getTypeOfSymbol could end 10201 // up recursively calling getTypeOfAlias, causing a stack overflow. 10202 links.type = exportSymbol?.declarations && isDuplicatedCommonJSExport(exportSymbol.declarations) && symbol.declarations!.length ? getFlowTypeFromCommonJSExport(exportSymbol) 10203 : isDuplicatedCommonJSExport(symbol.declarations) ? autoType 10204 : declaredType ? declaredType 10205 : getAllSymbolFlags(targetSymbol) & SymbolFlags.Value ? getTypeOfSymbol(targetSymbol) 10206 : errorType; 10207 } 10208 return links.type; 10209 } 10210 10211 function getTypeOfInstantiatedSymbol(symbol: Symbol): Type { 10212 const links = getSymbolLinks(symbol); 10213 return links.type || (links.type = instantiateType(getTypeOfSymbol(links.target!), links.mapper)); 10214 } 10215 10216 function getWriteTypeOfInstantiatedSymbol(symbol: Symbol): Type { 10217 const links = getSymbolLinks(symbol); 10218 return links.writeType || (links.writeType = instantiateType(getWriteTypeOfSymbol(links.target!), links.mapper)); 10219 } 10220 10221 function reportCircularityError(symbol: Symbol) { 10222 const declaration = symbol.valueDeclaration as VariableLikeDeclaration; 10223 // Check if variable has type annotation that circularly references the variable itself 10224 if (getEffectiveTypeAnnotationNode(declaration)) { 10225 error(symbol.valueDeclaration, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, 10226 symbolToString(symbol)); 10227 return errorType; 10228 } 10229 // Check if variable has initializer that circularly references the variable itself 10230 if (noImplicitAny && (declaration.kind !== SyntaxKind.Parameter || (declaration as HasInitializer).initializer)) { 10231 error(symbol.valueDeclaration, Diagnostics._0_implicitly_has_type_any_because_it_does_not_have_a_type_annotation_and_is_referenced_directly_or_indirectly_in_its_own_initializer, 10232 symbolToString(symbol)); 10233 } 10234 // Circularities could also result from parameters in function expressions that end up 10235 // having themselves as contextual types following type argument inference. In those cases 10236 // we have already reported an implicit any error so we don't report anything here. 10237 return anyType; 10238 } 10239 10240 function getTypeOfSymbolWithDeferredType(symbol: Symbol) { 10241 const links = getSymbolLinks(symbol); 10242 if (!links.type) { 10243 Debug.assertIsDefined(links.deferralParent); 10244 Debug.assertIsDefined(links.deferralConstituents); 10245 links.type = links.deferralParent.flags & TypeFlags.Union ? getUnionType(links.deferralConstituents) : getIntersectionType(links.deferralConstituents); 10246 } 10247 return links.type; 10248 } 10249 10250 function getWriteTypeOfSymbolWithDeferredType(symbol: Symbol): Type | undefined { 10251 const links = getSymbolLinks(symbol); 10252 if (!links.writeType && links.deferralWriteConstituents) { 10253 Debug.assertIsDefined(links.deferralParent); 10254 Debug.assertIsDefined(links.deferralConstituents); 10255 links.writeType = links.deferralParent.flags & TypeFlags.Union ? getUnionType(links.deferralWriteConstituents) : getIntersectionType(links.deferralWriteConstituents); 10256 } 10257 return links.writeType; 10258 } 10259 10260 /** 10261 * Distinct write types come only from set accessors, but synthetic union and intersection 10262 * properties deriving from set accessors will either pre-compute or defer the union or 10263 * intersection of the writeTypes of their constituents. 10264 */ 10265 function getWriteTypeOfSymbol(symbol: Symbol): Type { 10266 const checkFlags = getCheckFlags(symbol); 10267 if (symbol.flags & SymbolFlags.Property) { 10268 return checkFlags & CheckFlags.SyntheticProperty ? 10269 checkFlags & CheckFlags.DeferredType ? 10270 getWriteTypeOfSymbolWithDeferredType(symbol) || getTypeOfSymbolWithDeferredType(symbol) : 10271 (symbol as TransientSymbol).writeType || (symbol as TransientSymbol).type! : 10272 getTypeOfSymbol(symbol); 10273 } 10274 if (symbol.flags & SymbolFlags.Accessor) { 10275 return checkFlags & CheckFlags.Instantiated ? 10276 getWriteTypeOfInstantiatedSymbol(symbol) : 10277 getWriteTypeOfAccessors(symbol); 10278 } 10279 return getTypeOfSymbol(symbol); 10280 } 10281 10282 function getTypeOfSymbol(symbol: Symbol): Type { 10283 const checkFlags = getCheckFlags(symbol); 10284 if (checkFlags & CheckFlags.DeferredType) { 10285 return getTypeOfSymbolWithDeferredType(symbol); 10286 } 10287 if (checkFlags & CheckFlags.Instantiated) { 10288 return getTypeOfInstantiatedSymbol(symbol); 10289 } 10290 if (checkFlags & CheckFlags.Mapped) { 10291 return getTypeOfMappedSymbol(symbol as MappedSymbol); 10292 } 10293 if (checkFlags & CheckFlags.ReverseMapped) { 10294 return getTypeOfReverseMappedSymbol(symbol as ReverseMappedSymbol); 10295 } 10296 if (symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property)) { 10297 return getTypeOfVariableOrParameterOrProperty(symbol); 10298 } 10299 if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) { 10300 return getTypeOfFuncClassEnumModule(symbol); 10301 } 10302 if (symbol.flags & SymbolFlags.EnumMember) { 10303 return getTypeOfEnumMember(symbol); 10304 } 10305 if (symbol.flags & SymbolFlags.Accessor) { 10306 return getTypeOfAccessors(symbol); 10307 } 10308 if (symbol.flags & SymbolFlags.Alias) { 10309 return getTypeOfAlias(symbol); 10310 } 10311 return errorType; 10312 } 10313 10314 function getNonMissingTypeOfSymbol(symbol: Symbol) { 10315 return removeMissingType(getTypeOfSymbol(symbol), !!(symbol.flags & SymbolFlags.Optional)); 10316 } 10317 10318 function isReferenceToType(type: Type, target: Type) { 10319 return type !== undefined 10320 && target !== undefined 10321 && (getObjectFlags(type) & ObjectFlags.Reference) !== 0 10322 && (type as TypeReference).target === target; 10323 } 10324 10325 function getTargetType(type: Type): Type { 10326 return getObjectFlags(type) & ObjectFlags.Reference ? (type as TypeReference).target : type; 10327 } 10328 10329 // TODO: GH#18217 If `checkBase` is undefined, we should not call this because this will always return false. 10330 function hasBaseType(type: Type, checkBase: Type | undefined) { 10331 return check(type); 10332 function check(type: Type): boolean { 10333 if (getObjectFlags(type) & (ObjectFlags.ClassOrInterface | ObjectFlags.Reference)) { 10334 const target = getTargetType(type) as InterfaceType; 10335 return target === checkBase || some(getBaseTypes(target), check); 10336 } 10337 else if (type.flags & TypeFlags.Intersection) { 10338 return some((type as IntersectionType).types, check); 10339 } 10340 return false; 10341 } 10342 } 10343 10344 // Appends the type parameters given by a list of declarations to a set of type parameters and returns the resulting set. 10345 // The function allocates a new array if the input type parameter set is undefined, but otherwise it modifies the set 10346 // in-place and returns the same array. 10347 function appendTypeParameters(typeParameters: TypeParameter[] | undefined, declarations: readonly TypeParameterDeclaration[]): TypeParameter[] | undefined { 10348 for (const declaration of declarations) { 10349 typeParameters = appendIfUnique(typeParameters, getDeclaredTypeOfTypeParameter(getSymbolOfNode(declaration))); 10350 } 10351 return typeParameters; 10352 } 10353 10354 // Return the outer type parameters of a node or undefined if the node has no outer type parameters. 10355 function getOuterTypeParameters(node: Node, includeThisTypes?: boolean): TypeParameter[] | undefined { 10356 while (true) { 10357 node = node.parent; // TODO: GH#18217 Use SourceFile kind check instead 10358 if (node && isBinaryExpression(node)) { 10359 // prototype assignments get the outer type parameters of their constructor function 10360 const assignmentKind = getAssignmentDeclarationKind(node); 10361 if (assignmentKind === AssignmentDeclarationKind.Prototype || assignmentKind === AssignmentDeclarationKind.PrototypeProperty) { 10362 const symbol = getSymbolOfNode(node.left); 10363 if (symbol && symbol.parent && !findAncestor(symbol.parent.valueDeclaration, d => node === d)) { 10364 node = symbol.parent.valueDeclaration!; 10365 } 10366 } 10367 } 10368 if (!node) { 10369 return undefined; 10370 } 10371 switch (node.kind) { 10372 case SyntaxKind.ClassDeclaration: 10373 case SyntaxKind.ClassExpression: 10374 case SyntaxKind.InterfaceDeclaration: 10375 case SyntaxKind.CallSignature: 10376 case SyntaxKind.ConstructSignature: 10377 case SyntaxKind.MethodSignature: 10378 case SyntaxKind.FunctionType: 10379 case SyntaxKind.ConstructorType: 10380 case SyntaxKind.JSDocFunctionType: 10381 case SyntaxKind.FunctionDeclaration: 10382 case SyntaxKind.MethodDeclaration: 10383 case SyntaxKind.FunctionExpression: 10384 case SyntaxKind.ArrowFunction: 10385 case SyntaxKind.TypeAliasDeclaration: 10386 case SyntaxKind.JSDocTemplateTag: 10387 case SyntaxKind.JSDocTypedefTag: 10388 case SyntaxKind.JSDocEnumTag: 10389 case SyntaxKind.JSDocCallbackTag: 10390 case SyntaxKind.MappedType: 10391 case SyntaxKind.ConditionalType: { 10392 const outerTypeParameters = getOuterTypeParameters(node, includeThisTypes); 10393 if (node.kind === SyntaxKind.MappedType) { 10394 return append(outerTypeParameters, getDeclaredTypeOfTypeParameter(getSymbolOfNode((node as MappedTypeNode).typeParameter))); 10395 } 10396 else if (node.kind === SyntaxKind.ConditionalType) { 10397 return concatenate(outerTypeParameters, getInferTypeParameters(node as ConditionalTypeNode)); 10398 } 10399 const outerAndOwnTypeParameters = appendTypeParameters(outerTypeParameters, getEffectiveTypeParameterDeclarations(node as DeclarationWithTypeParameters)); 10400 const thisType = includeThisTypes && 10401 (node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression || node.kind === SyntaxKind.InterfaceDeclaration || isJSConstructor(node)) && 10402 getDeclaredTypeOfClassOrInterface(getSymbolOfNode(node as ClassLikeDeclaration | InterfaceDeclaration)).thisType; 10403 return thisType ? append(outerAndOwnTypeParameters, thisType) : outerAndOwnTypeParameters; 10404 } 10405 case SyntaxKind.JSDocParameterTag: 10406 const paramSymbol = getParameterSymbolFromJSDoc(node as JSDocParameterTag); 10407 if (paramSymbol) { 10408 node = paramSymbol.valueDeclaration!; 10409 } 10410 break; 10411 case SyntaxKind.JSDoc: { 10412 const outerTypeParameters = getOuterTypeParameters(node, includeThisTypes); 10413 return (node as JSDoc).tags 10414 ? appendTypeParameters(outerTypeParameters, flatMap((node as JSDoc).tags, t => isJSDocTemplateTag(t) ? t.typeParameters : undefined)) 10415 : outerTypeParameters; 10416 } 10417 } 10418 } 10419 } 10420 10421 // The outer type parameters are those defined by enclosing generic classes, methods, or functions. 10422 function getOuterTypeParametersOfClassOrInterface(symbol: Symbol): TypeParameter[] | undefined { 10423 const declaration = symbol.flags & SymbolFlags.Class ? symbol.valueDeclaration : getDeclarationOfKind(symbol, SyntaxKind.InterfaceDeclaration)!; 10424 Debug.assert(!!declaration, "Class was missing valueDeclaration -OR- non-class had no interface declarations"); 10425 return getOuterTypeParameters(declaration); 10426 } 10427 10428 // The local type parameters are the combined set of type parameters from all declarations of the class, 10429 // interface, or type alias. 10430 function getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol: Symbol): TypeParameter[] | undefined { 10431 if (!symbol.declarations) { 10432 return; 10433 } 10434 let result: TypeParameter[] | undefined; 10435 for (const node of symbol.declarations) { 10436 if (node.kind === SyntaxKind.InterfaceDeclaration || 10437 node.kind === SyntaxKind.ClassDeclaration || 10438 node.kind === SyntaxKind.ClassExpression || 10439 isJSConstructor(node) || 10440 isTypeAlias(node)) { 10441 const declaration = node as InterfaceDeclaration | TypeAliasDeclaration | JSDocTypedefTag | JSDocCallbackTag; 10442 result = appendTypeParameters(result, getEffectiveTypeParameterDeclarations(declaration)); 10443 } 10444 } 10445 return result; 10446 } 10447 10448 // The full set of type parameters for a generic class or interface type consists of its outer type parameters plus 10449 // its locally declared type parameters. 10450 function getTypeParametersOfClassOrInterface(symbol: Symbol): TypeParameter[] | undefined { 10451 return concatenate(getOuterTypeParametersOfClassOrInterface(symbol), getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol)); 10452 } 10453 10454 // A type is a mixin constructor if it has a single construct signature taking no type parameters and a single 10455 // rest parameter of type any[]. 10456 function isMixinConstructorType(type: Type) { 10457 const signatures = getSignaturesOfType(type, SignatureKind.Construct); 10458 if (signatures.length === 1) { 10459 const s = signatures[0]; 10460 if (!s.typeParameters && s.parameters.length === 1 && signatureHasRestParameter(s)) { 10461 const paramType = getTypeOfParameter(s.parameters[0]); 10462 return isTypeAny(paramType) || getElementTypeOfArrayType(paramType) === anyType; 10463 } 10464 } 10465 return false; 10466 } 10467 10468 function isConstructorType(type: Type): boolean { 10469 if (getSignaturesOfType(type, SignatureKind.Construct).length > 0) { 10470 return true; 10471 } 10472 if (type.flags & TypeFlags.TypeVariable) { 10473 const constraint = getBaseConstraintOfType(type); 10474 return !!constraint && isMixinConstructorType(constraint); 10475 } 10476 return false; 10477 } 10478 10479 function getBaseTypeNodeOfClass(type: InterfaceType): ExpressionWithTypeArguments | undefined { 10480 const decl = getClassLikeDeclarationOfSymbol(type.symbol); 10481 return decl && getEffectiveBaseTypeNode(decl); 10482 } 10483 10484 function getConstructorsForTypeArguments(type: Type, typeArgumentNodes: readonly TypeNode[] | undefined, location: Node): readonly Signature[] { 10485 const typeArgCount = length(typeArgumentNodes); 10486 const isJavascript = isInJSFile(location); 10487 return filter(getSignaturesOfType(type, SignatureKind.Construct), 10488 sig => (isJavascript || typeArgCount >= getMinTypeArgumentCount(sig.typeParameters)) && typeArgCount <= length(sig.typeParameters)); 10489 } 10490 10491 function getInstantiatedConstructorsForTypeArguments(type: Type, typeArgumentNodes: readonly TypeNode[] | undefined, location: Node): readonly Signature[] { 10492 const signatures = getConstructorsForTypeArguments(type, typeArgumentNodes, location); 10493 const typeArguments = map(typeArgumentNodes, getTypeFromTypeNode); 10494 return sameMap<Signature>(signatures, sig => some(sig.typeParameters) ? getSignatureInstantiation(sig, typeArguments, isInJSFile(location)) : sig); 10495 } 10496 10497 /** 10498 * The base constructor of a class can resolve to 10499 * * undefinedType if the class has no extends clause, 10500 * * unknownType if an error occurred during resolution of the extends expression, 10501 * * nullType if the extends expression is the null value, 10502 * * anyType if the extends expression has type any, or 10503 * * an object type with at least one construct signature. 10504 */ 10505 function getBaseConstructorTypeOfClass(type: InterfaceType): Type { 10506 if (!type.resolvedBaseConstructorType) { 10507 const decl = getClassLikeDeclarationOfSymbol(type.symbol); 10508 const extended = decl && getEffectiveBaseTypeNode(decl); 10509 const baseTypeNode = getBaseTypeNodeOfClass(type); 10510 if (!baseTypeNode) { 10511 return type.resolvedBaseConstructorType = undefinedType; 10512 } 10513 if (!pushTypeResolution(type, TypeSystemPropertyName.ResolvedBaseConstructorType)) { 10514 return errorType; 10515 } 10516 const baseConstructorType = checkExpression(baseTypeNode.expression); 10517 if (extended && baseTypeNode !== extended) { 10518 Debug.assert(!extended.typeArguments); // Because this is in a JS file, and baseTypeNode is in an @extends tag 10519 checkExpression(extended.expression); 10520 } 10521 if (baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection)) { 10522 // Resolving the members of a class requires us to resolve the base class of that class. 10523 // We force resolution here such that we catch circularities now. 10524 resolveStructuredTypeMembers(baseConstructorType as ObjectType); 10525 } 10526 if (!popTypeResolution()) { 10527 error(type.symbol.valueDeclaration, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_base_expression, symbolToString(type.symbol)); 10528 return type.resolvedBaseConstructorType = errorType; 10529 } 10530 if (!(baseConstructorType.flags & TypeFlags.Any) && baseConstructorType !== nullWideningType && !isConstructorType(baseConstructorType)) { 10531 const err = error(baseTypeNode.expression, Diagnostics.Type_0_is_not_a_constructor_function_type, typeToString(baseConstructorType)); 10532 if (baseConstructorType.flags & TypeFlags.TypeParameter) { 10533 const constraint = getConstraintFromTypeParameter(baseConstructorType); 10534 let ctorReturn: Type = unknownType; 10535 if (constraint) { 10536 const ctorSig = getSignaturesOfType(constraint, SignatureKind.Construct); 10537 if (ctorSig[0]) { 10538 ctorReturn = getReturnTypeOfSignature(ctorSig[0]); 10539 } 10540 } 10541 if (baseConstructorType.symbol.declarations) { 10542 addRelatedInfo(err, createDiagnosticForNode(baseConstructorType.symbol.declarations[0], Diagnostics.Did_you_mean_for_0_to_be_constrained_to_type_new_args_Colon_any_1, symbolToString(baseConstructorType.symbol), typeToString(ctorReturn))); 10543 } 10544 } 10545 return type.resolvedBaseConstructorType = errorType; 10546 } 10547 type.resolvedBaseConstructorType = baseConstructorType; 10548 } 10549 return type.resolvedBaseConstructorType; 10550 } 10551 10552 function getImplementsTypes(type: InterfaceType): BaseType[] { 10553 let resolvedImplementsTypes: BaseType[] = emptyArray; 10554 if (type.symbol.declarations) { 10555 for (const declaration of type.symbol.declarations) { 10556 const implementsTypeNodes = getEffectiveImplementsTypeNodes(declaration as ClassLikeDeclaration); 10557 if (!implementsTypeNodes) continue; 10558 for (const node of implementsTypeNodes) { 10559 const implementsType = getTypeFromTypeNode(node); 10560 if (!isErrorType(implementsType)) { 10561 if (resolvedImplementsTypes === emptyArray) { 10562 resolvedImplementsTypes = [implementsType as ObjectType]; 10563 } 10564 else { 10565 resolvedImplementsTypes.push(implementsType); 10566 } 10567 } 10568 } 10569 } 10570 } 10571 return resolvedImplementsTypes; 10572 } 10573 10574 function reportCircularBaseType(node: Node, type: Type) { 10575 error(node, Diagnostics.Type_0_recursively_references_itself_as_a_base_type, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType)); 10576 } 10577 10578 function getBaseTypes(type: InterfaceType): BaseType[] { 10579 if (!type.baseTypesResolved) { 10580 if (pushTypeResolution(type, TypeSystemPropertyName.ResolvedBaseTypes)) { 10581 if (type.objectFlags & ObjectFlags.Tuple) { 10582 type.resolvedBaseTypes = [getTupleBaseType(type as TupleType)]; 10583 } 10584 else if (type.symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { 10585 if (type.symbol.flags & SymbolFlags.Class) { 10586 resolveBaseTypesOfClass(type); 10587 } 10588 if (type.symbol.flags & SymbolFlags.Interface) { 10589 resolveBaseTypesOfInterface(type); 10590 } 10591 } 10592 else { 10593 Debug.fail("type must be class or interface"); 10594 } 10595 if (!popTypeResolution() && type.symbol.declarations) { 10596 for (const declaration of type.symbol.declarations) { 10597 if (declaration.kind === SyntaxKind.ClassDeclaration || declaration.kind === SyntaxKind.InterfaceDeclaration) { 10598 reportCircularBaseType(declaration, type); 10599 } 10600 } 10601 } 10602 } 10603 type.baseTypesResolved = true; 10604 } 10605 return type.resolvedBaseTypes; 10606 } 10607 10608 function getTupleBaseType(type: TupleType) { 10609 const elementTypes = sameMap(type.typeParameters, (t, i) => type.elementFlags[i] & ElementFlags.Variadic ? getIndexedAccessType(t, numberType) : t); 10610 return createArrayType(getUnionType(elementTypes || emptyArray), type.readonly); 10611 } 10612 10613 function resolveBaseTypesOfClass(type: InterfaceType) { 10614 type.resolvedBaseTypes = resolvingEmptyArray; 10615 const baseConstructorType = getApparentType(getBaseConstructorTypeOfClass(type)); 10616 if (!(baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.Any))) { 10617 return type.resolvedBaseTypes = emptyArray; 10618 } 10619 const baseTypeNode = getBaseTypeNodeOfClass(type)!; 10620 let baseType: Type; 10621 const originalBaseType = baseConstructorType.symbol ? getDeclaredTypeOfSymbol(baseConstructorType.symbol) : undefined; 10622 if (baseConstructorType.symbol && baseConstructorType.symbol.flags & SymbolFlags.Class && 10623 areAllOuterTypeParametersApplied(originalBaseType!)) { 10624 // When base constructor type is a class with no captured type arguments we know that the constructors all have the same type parameters as the 10625 // class and all return the instance type of the class. There is no need for further checks and we can apply the 10626 // type arguments in the same manner as a type reference to get the same error reporting experience. 10627 baseType = getTypeFromClassOrInterfaceReference(baseTypeNode, baseConstructorType.symbol); 10628 } 10629 else if (baseConstructorType.flags & TypeFlags.Any) { 10630 baseType = baseConstructorType; 10631 } 10632 else { 10633 // The class derives from a "class-like" constructor function, check that we have at least one construct signature 10634 // with a matching number of type parameters and use the return type of the first instantiated signature. Elsewhere 10635 // we check that all instantiated signatures return the same type. 10636 const constructors = getInstantiatedConstructorsForTypeArguments(baseConstructorType, baseTypeNode.typeArguments, baseTypeNode); 10637 if (!constructors.length) { 10638 error(baseTypeNode.expression, Diagnostics.No_base_constructor_has_the_specified_number_of_type_arguments); 10639 return type.resolvedBaseTypes = emptyArray; 10640 } 10641 baseType = getReturnTypeOfSignature(constructors[0]); 10642 } 10643 10644 if (isErrorType(baseType)) { 10645 return type.resolvedBaseTypes = emptyArray; 10646 } 10647 const reducedBaseType = getReducedType(baseType); 10648 if (!isValidBaseType(reducedBaseType)) { 10649 const elaboration = elaborateNeverIntersection(/*errorInfo*/ undefined, baseType); 10650 const diagnostic = chainDiagnosticMessages(elaboration, Diagnostics.Base_constructor_return_type_0_is_not_an_object_type_or_intersection_of_object_types_with_statically_known_members, typeToString(reducedBaseType)); 10651 diagnostics.add(createDiagnosticForNodeFromMessageChain(baseTypeNode.expression, diagnostic)); 10652 return type.resolvedBaseTypes = emptyArray; 10653 } 10654 if (type === reducedBaseType || hasBaseType(reducedBaseType, type)) { 10655 error(type.symbol.valueDeclaration, Diagnostics.Type_0_recursively_references_itself_as_a_base_type, 10656 typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType)); 10657 return type.resolvedBaseTypes = emptyArray; 10658 } 10659 if (type.resolvedBaseTypes === resolvingEmptyArray) { 10660 // Circular reference, likely through instantiation of default parameters 10661 // (otherwise there'd be an error from hasBaseType) - this is fine, but `.members` should be reset 10662 // as `getIndexedAccessType` via `instantiateType` via `getTypeFromClassOrInterfaceReference` forces a 10663 // partial instantiation of the members without the base types fully resolved 10664 type.members = undefined; 10665 } 10666 return type.resolvedBaseTypes = [reducedBaseType]; 10667 } 10668 10669 function areAllOuterTypeParametersApplied(type: Type): boolean { // TODO: GH#18217 Shouldn't this take an InterfaceType? 10670 // An unapplied type parameter has its symbol still the same as the matching argument symbol. 10671 // Since parameters are applied outer-to-inner, only the last outer parameter needs to be checked. 10672 const outerTypeParameters = (type as InterfaceType).outerTypeParameters; 10673 if (outerTypeParameters) { 10674 const last = outerTypeParameters.length - 1; 10675 const typeArguments = getTypeArguments(type as TypeReference); 10676 return outerTypeParameters[last].symbol !== typeArguments[last].symbol; 10677 } 10678 return true; 10679 } 10680 10681 // A valid base type is `any`, an object type or intersection of object types. 10682 function isValidBaseType(type: Type): type is BaseType { 10683 if ((type.flags & TypeFlags.Object) && ((type as ObjectType).objectFlags & ObjectFlags.Annotation)) { 10684 return false; 10685 } 10686 if (type.flags & TypeFlags.TypeParameter) { 10687 const constraint = getBaseConstraintOfType(type); 10688 if (constraint) { 10689 return isValidBaseType(constraint); 10690 } 10691 } 10692 // TODO: Given that we allow type parmeters here now, is this `!isGenericMappedType(type)` check really needed? 10693 // There's no reason a `T` should be allowed while a `Readonly<T>` should not. 10694 return !!(type.flags & (TypeFlags.Object | TypeFlags.NonPrimitive | TypeFlags.Any) && !isGenericMappedType(type) || 10695 type.flags & TypeFlags.Intersection && every((type as IntersectionType).types, isValidBaseType)); 10696 } 10697 10698 function resolveBaseTypesOfInterface(type: InterfaceType): void { 10699 type.resolvedBaseTypes = type.resolvedBaseTypes || emptyArray; 10700 if (type.symbol.declarations) { 10701 for (const declaration of type.symbol.declarations) { 10702 if (declaration.kind === SyntaxKind.InterfaceDeclaration && getInterfaceBaseTypeNodes(declaration as InterfaceDeclaration)) { 10703 for (const node of getInterfaceBaseTypeNodes(declaration as InterfaceDeclaration)!) { 10704 const baseType = getReducedType(getTypeFromTypeNode(node)); 10705 if (!isErrorType(baseType)) { 10706 if (isValidBaseType(baseType)) { 10707 if (type !== baseType && !hasBaseType(baseType, type)) { 10708 if (type.resolvedBaseTypes === emptyArray) { 10709 type.resolvedBaseTypes = [baseType as ObjectType]; 10710 } 10711 else { 10712 type.resolvedBaseTypes.push(baseType); 10713 } 10714 } 10715 else { 10716 reportCircularBaseType(declaration, type); 10717 } 10718 } 10719 else { 10720 error(node, Diagnostics.An_interface_can_only_extend_an_object_type_or_intersection_of_object_types_with_statically_known_members); 10721 } 10722 } 10723 } 10724 } 10725 } 10726 } 10727 } 10728 10729 /** 10730 * Returns true if the interface given by the symbol is free of "this" references. 10731 * 10732 * Specifically, the result is true if the interface itself contains no references 10733 * to "this" in its body, if all base types are interfaces, 10734 * and if none of the base interfaces have a "this" type. 10735 */ 10736 function isThislessInterface(symbol: Symbol): boolean { 10737 if (!symbol.declarations) { 10738 return true; 10739 } 10740 for (const declaration of symbol.declarations) { 10741 if (declaration.kind === SyntaxKind.InterfaceDeclaration) { 10742 if (declaration.flags & NodeFlags.ContainsThis) { 10743 return false; 10744 } 10745 const baseTypeNodes = getInterfaceBaseTypeNodes(declaration as InterfaceDeclaration); 10746 if (baseTypeNodes) { 10747 for (const node of baseTypeNodes) { 10748 if (isEntityNameExpression(node.expression)) { 10749 const baseSymbol = resolveEntityName(node.expression, SymbolFlags.Type, /*ignoreErrors*/ true); 10750 if (!baseSymbol || !(baseSymbol.flags & SymbolFlags.Interface) || getDeclaredTypeOfClassOrInterface(baseSymbol).thisType) { 10751 return false; 10752 } 10753 } 10754 } 10755 } 10756 } 10757 } 10758 return true; 10759 } 10760 10761 function getDeclaredTypeOfClassOrInterface(symbol: Symbol): InterfaceType { 10762 let links = getSymbolLinks(symbol); 10763 const originalLinks = links; 10764 if (!links.declaredType) { 10765 const kind = (symbol.flags & SymbolFlags.Class ? ObjectFlags.Class : ObjectFlags.Interface) | (symbol.flags & SymbolFlags.Annotation ? ObjectFlags.Annotation : 0); 10766 const merged = mergeJSSymbols(symbol, symbol.valueDeclaration && getAssignedClassSymbol(symbol.valueDeclaration)); 10767 if (merged) { 10768 // note:we overwrite links because we just cloned the symbol 10769 symbol = links = merged; 10770 } 10771 10772 const type = originalLinks.declaredType = links.declaredType = createObjectType(kind, symbol) as InterfaceType; 10773 const outerTypeParameters = getOuterTypeParametersOfClassOrInterface(symbol); 10774 const localTypeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol); 10775 // A class or interface is generic if it has type parameters or a "this" type. We always give classes a "this" type 10776 // because it is not feasible to analyze all members to determine if the "this" type escapes the class (in particular, 10777 // property types inferred from initializers and method return types inferred from return statements are very hard 10778 // to exhaustively analyze). We give interfaces a "this" type if we can't definitely determine that they are free of 10779 // "this" references. 10780 if (outerTypeParameters || localTypeParameters || kind === ObjectFlags.Class || !isThislessInterface(symbol)) { 10781 type.objectFlags |= ObjectFlags.Reference; 10782 type.typeParameters = concatenate(outerTypeParameters, localTypeParameters); 10783 type.outerTypeParameters = outerTypeParameters; 10784 type.localTypeParameters = localTypeParameters; 10785 (type as GenericType).instantiations = new Map<string, TypeReference>(); 10786 (type as GenericType).instantiations.set(getTypeListId(type.typeParameters), type as GenericType); 10787 (type as GenericType).target = type as GenericType; 10788 (type as GenericType).resolvedTypeArguments = type.typeParameters; 10789 type.thisType = createTypeParameter(symbol); 10790 type.thisType.isThisType = true; 10791 type.thisType.constraint = type; 10792 } 10793 } 10794 return links.declaredType as InterfaceType; 10795 } 10796 10797 function getDeclaredTypeOfTypeAlias(symbol: Symbol): Type { 10798 const links = getSymbolLinks(symbol); 10799 if (!links.declaredType) { 10800 // Note that we use the links object as the target here because the symbol object is used as the unique 10801 // identity for resolution of the 'type' property in SymbolLinks. 10802 if (!pushTypeResolution(symbol, TypeSystemPropertyName.DeclaredType)) { 10803 return errorType; 10804 } 10805 10806 const declaration = Debug.checkDefined(symbol.declarations?.find(isTypeAlias), "Type alias symbol with no valid declaration found"); 10807 const typeNode = isJSDocTypeAlias(declaration) ? declaration.typeExpression : declaration.type; 10808 // If typeNode is missing, we will error in checkJSDocTypedefTag. 10809 let type = typeNode ? getTypeFromTypeNode(typeNode) : errorType; 10810 10811 if (popTypeResolution()) { 10812 const typeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol); 10813 if (typeParameters) { 10814 // Initialize the instantiation cache for generic type aliases. The declared type corresponds to 10815 // an instantiation of the type alias with the type parameters supplied as type arguments. 10816 links.typeParameters = typeParameters; 10817 links.instantiations = new Map<string, Type>(); 10818 links.instantiations.set(getTypeListId(typeParameters), type); 10819 } 10820 } 10821 else { 10822 type = errorType; 10823 if (declaration.kind === SyntaxKind.JSDocEnumTag) { 10824 error(declaration.typeExpression.type, Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol)); 10825 } 10826 else { 10827 error(isNamedDeclaration(declaration) ? declaration.name || declaration : declaration, Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol)); 10828 } 10829 } 10830 links.declaredType = type; 10831 } 10832 return links.declaredType; 10833 } 10834 10835 function isStringConcatExpression(expr: Node): boolean { 10836 if (isStringLiteralLike(expr)) { 10837 return true; 10838 } 10839 else if (expr.kind === SyntaxKind.BinaryExpression) { 10840 return isStringConcatExpression((expr as BinaryExpression).left) && isStringConcatExpression((expr as BinaryExpression).right); 10841 } 10842 return false; 10843 } 10844 10845 function isLiteralEnumMember(member: EnumMember) { 10846 const expr = member.initializer; 10847 if (!expr) { 10848 return !(member.flags & NodeFlags.Ambient); 10849 } 10850 switch (expr.kind) { 10851 case SyntaxKind.StringLiteral: 10852 case SyntaxKind.NumericLiteral: 10853 case SyntaxKind.NoSubstitutionTemplateLiteral: 10854 return true; 10855 case SyntaxKind.PrefixUnaryExpression: 10856 return (expr as PrefixUnaryExpression).operator === SyntaxKind.MinusToken && 10857 (expr as PrefixUnaryExpression).operand.kind === SyntaxKind.NumericLiteral; 10858 case SyntaxKind.Identifier: 10859 return nodeIsMissing(expr) || !!getSymbolOfNode(member.parent).exports!.get((expr as Identifier).escapedText); 10860 case SyntaxKind.BinaryExpression: 10861 return isStringConcatExpression(expr); 10862 default: 10863 return false; 10864 } 10865 } 10866 10867 function getEnumKind(symbol: Symbol): EnumKind { 10868 const links = getSymbolLinks(symbol); 10869 if (links.enumKind !== undefined) { 10870 return links.enumKind; 10871 } 10872 let hasNonLiteralMember = false; 10873 if (symbol.declarations) { 10874 for (const declaration of symbol.declarations) { 10875 if (declaration.kind === SyntaxKind.EnumDeclaration) { 10876 for (const member of (declaration as EnumDeclaration).members) { 10877 if (member.initializer && isStringLiteralLike(member.initializer)) { 10878 return links.enumKind = EnumKind.Literal; 10879 } 10880 if (!isLiteralEnumMember(member)) { 10881 hasNonLiteralMember = true; 10882 } 10883 } 10884 } 10885 } 10886 } 10887 return links.enumKind = hasNonLiteralMember ? EnumKind.Numeric : EnumKind.Literal; 10888 } 10889 10890 function getBaseTypeOfEnumLiteralType(type: Type) { 10891 return type.flags & TypeFlags.EnumLiteral && !(type.flags & TypeFlags.Union) ? getDeclaredTypeOfSymbol(getParentOfSymbol(type.symbol)!) : type; 10892 } 10893 10894 function getDeclaredTypeOfEnum(symbol: Symbol): Type { 10895 const links = getSymbolLinks(symbol); 10896 if (links.declaredType) { 10897 return links.declaredType; 10898 } 10899 if (getEnumKind(symbol) === EnumKind.Literal) { 10900 enumCount++; 10901 const memberTypeList: Type[] = []; 10902 if (symbol.declarations) { 10903 for (const declaration of symbol.declarations) { 10904 if (declaration.kind === SyntaxKind.EnumDeclaration) { 10905 for (const member of (declaration as EnumDeclaration).members) { 10906 const value = getEnumMemberValue(member); 10907 const memberType = getFreshTypeOfLiteralType(getEnumLiteralType(value !== undefined ? value : 0, enumCount, getSymbolOfNode(member))); 10908 getSymbolLinks(getSymbolOfNode(member)).declaredType = memberType; 10909 memberTypeList.push(getRegularTypeOfLiteralType(memberType)); 10910 } 10911 } 10912 } 10913 } 10914 if (memberTypeList.length) { 10915 const enumType = getUnionType(memberTypeList, UnionReduction.Literal, symbol, /*aliasTypeArguments*/ undefined); 10916 if (enumType.flags & TypeFlags.Union) { 10917 enumType.flags |= TypeFlags.EnumLiteral; 10918 enumType.symbol = symbol; 10919 } 10920 return links.declaredType = enumType; 10921 } 10922 } 10923 const enumType = createType(TypeFlags.Enum); 10924 enumType.symbol = symbol; 10925 return links.declaredType = enumType; 10926 } 10927 10928 function getDeclaredTypeOfEnumMember(symbol: Symbol): Type { 10929 const links = getSymbolLinks(symbol); 10930 if (!links.declaredType) { 10931 const enumType = getDeclaredTypeOfEnum(getParentOfSymbol(symbol)!); 10932 if (!links.declaredType) { 10933 links.declaredType = enumType; 10934 } 10935 } 10936 return links.declaredType; 10937 } 10938 10939 function getDeclaredTypeOfTypeParameter(symbol: Symbol): TypeParameter { 10940 const links = getSymbolLinks(symbol); 10941 return links.declaredType || (links.declaredType = createTypeParameter(symbol)); 10942 } 10943 10944 function getDeclaredTypeOfAlias(symbol: Symbol): Type { 10945 const links = getSymbolLinks(symbol); 10946 return links.declaredType || (links.declaredType = getDeclaredTypeOfSymbol(resolveAlias(symbol))); 10947 } 10948 10949 function getDeclaredTypeOfSymbol(symbol: Symbol): Type { 10950 return tryGetDeclaredTypeOfSymbol(symbol) || errorType; 10951 } 10952 10953 function tryGetDeclaredTypeOfSymbol(symbol: Symbol): Type | undefined { 10954 if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { 10955 return getDeclaredTypeOfClassOrInterface(symbol); 10956 } 10957 if (symbol.flags & SymbolFlags.TypeAlias) { 10958 return getDeclaredTypeOfTypeAlias(symbol); 10959 } 10960 if (symbol.flags & SymbolFlags.TypeParameter) { 10961 return getDeclaredTypeOfTypeParameter(symbol); 10962 } 10963 if (symbol.flags & SymbolFlags.Enum) { 10964 return getDeclaredTypeOfEnum(symbol); 10965 } 10966 if (symbol.flags & SymbolFlags.EnumMember) { 10967 return getDeclaredTypeOfEnumMember(symbol); 10968 } 10969 if (symbol.flags & SymbolFlags.Alias) { 10970 return getDeclaredTypeOfAlias(symbol); 10971 } 10972 return undefined; 10973 } 10974 10975 /** 10976 * A type is free of this references if it's the any, string, number, boolean, symbol, or void keyword, a string 10977 * literal type, an array with an element type that is free of this references, or a type reference that is 10978 * free of this references. 10979 */ 10980 function isThislessType(node: TypeNode): boolean { 10981 switch (node.kind) { 10982 case SyntaxKind.AnyKeyword: 10983 case SyntaxKind.UnknownKeyword: 10984 case SyntaxKind.StringKeyword: 10985 case SyntaxKind.NumberKeyword: 10986 case SyntaxKind.BigIntKeyword: 10987 case SyntaxKind.BooleanKeyword: 10988 case SyntaxKind.SymbolKeyword: 10989 case SyntaxKind.ObjectKeyword: 10990 case SyntaxKind.VoidKeyword: 10991 case SyntaxKind.UndefinedKeyword: 10992 case SyntaxKind.NeverKeyword: 10993 case SyntaxKind.LiteralType: 10994 return true; 10995 case SyntaxKind.ArrayType: 10996 return isThislessType((node as ArrayTypeNode).elementType); 10997 case SyntaxKind.TypeReference: 10998 return !(node as TypeReferenceNode).typeArguments || (node as TypeReferenceNode).typeArguments!.every(isThislessType); 10999 } 11000 return false; 11001 } 11002 11003 /** A type parameter is thisless if its constraint is thisless, or if it has no constraint. */ 11004 function isThislessTypeParameter(node: TypeParameterDeclaration) { 11005 const constraint = getEffectiveConstraintOfTypeParameter(node); 11006 return !constraint || isThislessType(constraint); 11007 } 11008 11009 /** 11010 * A variable-like declaration is free of this references if it has a type annotation 11011 * that is thisless, or if it has no type annotation and no initializer (and is thus of type any). 11012 */ 11013 function isThislessVariableLikeDeclaration(node: VariableLikeDeclaration): boolean { 11014 const typeNode = getEffectiveTypeAnnotationNode(node); 11015 return typeNode ? isThislessType(typeNode) : !hasInitializer(node); 11016 } 11017 11018 /** 11019 * A function-like declaration is considered free of `this` references if it has a return type 11020 * annotation that is free of this references and if each parameter is thisless and if 11021 * each type parameter (if present) is thisless. 11022 */ 11023 function isThislessFunctionLikeDeclaration(node: FunctionLikeDeclaration): boolean { 11024 const returnType = getEffectiveReturnTypeNode(node); 11025 const typeParameters = getEffectiveTypeParameterDeclarations(node); 11026 return (node.kind === SyntaxKind.Constructor || (!!returnType && isThislessType(returnType))) && 11027 node.parameters.every(isThislessVariableLikeDeclaration) && 11028 typeParameters.every(isThislessTypeParameter); 11029 } 11030 11031 /** 11032 * Returns true if the class or interface member given by the symbol is free of "this" references. The 11033 * function may return false for symbols that are actually free of "this" references because it is not 11034 * feasible to perform a complete analysis in all cases. In particular, property members with types 11035 * inferred from their initializers and function members with inferred return types are conservatively 11036 * assumed not to be free of "this" references. 11037 */ 11038 function isThisless(symbol: Symbol): boolean { 11039 if (symbol.declarations && symbol.declarations.length === 1) { 11040 const declaration = symbol.declarations[0]; 11041 if (declaration) { 11042 switch (declaration.kind) { 11043 case SyntaxKind.PropertyDeclaration: 11044 case SyntaxKind.PropertySignature: 11045 return isThislessVariableLikeDeclaration(declaration as VariableLikeDeclaration); 11046 case SyntaxKind.MethodDeclaration: 11047 case SyntaxKind.MethodSignature: 11048 case SyntaxKind.Constructor: 11049 case SyntaxKind.GetAccessor: 11050 case SyntaxKind.SetAccessor: 11051 return isThislessFunctionLikeDeclaration(declaration as FunctionLikeDeclaration | AccessorDeclaration); 11052 } 11053 } 11054 } 11055 return false; 11056 } 11057 11058 // The mappingThisOnly flag indicates that the only type parameter being mapped is "this". When the flag is true, 11059 // we check symbols to see if we can quickly conclude they are free of "this" references, thus needing no instantiation. 11060 function createInstantiatedSymbolTable(symbols: Symbol[], mapper: TypeMapper, mappingThisOnly: boolean): SymbolTable { 11061 const result = createSymbolTable(); 11062 for (const symbol of symbols) { 11063 result.set(symbol.escapedName, mappingThisOnly && isThisless(symbol) ? symbol : instantiateSymbol(symbol, mapper)); 11064 } 11065 return result; 11066 } 11067 11068 function addInheritedMembers(symbols: SymbolTable, baseSymbols: Symbol[]) { 11069 for (const s of baseSymbols) { 11070 if (!symbols.has(s.escapedName) && !isStaticPrivateIdentifierProperty(s)) { 11071 symbols.set(s.escapedName, s); 11072 } 11073 } 11074 } 11075 11076 function isStaticPrivateIdentifierProperty(s: Symbol): boolean { 11077 return !!s.valueDeclaration && isPrivateIdentifierClassElementDeclaration(s.valueDeclaration) && isStatic(s.valueDeclaration); 11078 } 11079 11080 function resolveDeclaredMembers(type: InterfaceType): InterfaceTypeWithDeclaredMembers { 11081 if (!(type as InterfaceTypeWithDeclaredMembers).declaredProperties) { 11082 const symbol = type.symbol; 11083 const members = getMembersOfSymbol(symbol); 11084 (type as InterfaceTypeWithDeclaredMembers).declaredProperties = getNamedMembers(members); 11085 // Start with signatures at empty array in case of recursive types 11086 (type as InterfaceTypeWithDeclaredMembers).declaredCallSignatures = emptyArray; 11087 (type as InterfaceTypeWithDeclaredMembers).declaredConstructSignatures = emptyArray; 11088 (type as InterfaceTypeWithDeclaredMembers).declaredIndexInfos = emptyArray; 11089 11090 (type as InterfaceTypeWithDeclaredMembers).declaredCallSignatures = getSignaturesOfSymbol(members.get(InternalSymbolName.Call)); 11091 (type as InterfaceTypeWithDeclaredMembers).declaredConstructSignatures = getSignaturesOfSymbol(members.get(InternalSymbolName.New)); 11092 (type as InterfaceTypeWithDeclaredMembers).declaredIndexInfos = getIndexInfosOfSymbol(symbol); 11093 } 11094 return type as InterfaceTypeWithDeclaredMembers; 11095 } 11096 11097 /** 11098 * Indicates whether a type can be used as a property name. 11099 */ 11100 function isTypeUsableAsPropertyName(type: Type): type is StringLiteralType | NumberLiteralType | UniqueESSymbolType { 11101 return !!(type.flags & TypeFlags.StringOrNumberLiteralOrUnique); 11102 } 11103 11104 /** 11105 * Indicates whether a declaration name is definitely late-bindable. 11106 * A declaration name is only late-bindable if: 11107 * - It is a `ComputedPropertyName`. 11108 * - Its expression is an `Identifier` or either a `PropertyAccessExpression` an 11109 * `ElementAccessExpression` consisting only of these same three types of nodes. 11110 * - The type of its expression is a string or numeric literal type, or is a `unique symbol` type. 11111 */ 11112 function isLateBindableName(node: DeclarationName): node is LateBoundName { 11113 if (!isComputedPropertyName(node) && !isElementAccessExpression(node)) { 11114 return false; 11115 } 11116 const expr = isComputedPropertyName(node) ? node.expression : node.argumentExpression; 11117 return isEntityNameExpression(expr) 11118 && isTypeUsableAsPropertyName(isComputedPropertyName(node) ? checkComputedPropertyName(node) : checkExpressionCached(expr)); 11119 } 11120 11121 function isLateBoundName(name: __String): boolean { 11122 return (name as string).charCodeAt(0) === CharacterCodes._ && 11123 (name as string).charCodeAt(1) === CharacterCodes._ && 11124 (name as string).charCodeAt(2) === CharacterCodes.at; 11125 } 11126 11127 /** 11128 * Indicates whether a declaration has a late-bindable dynamic name. 11129 */ 11130 function hasLateBindableName(node: Declaration): node is LateBoundDeclaration | LateBoundBinaryExpressionDeclaration { 11131 const name = getNameOfDeclaration(node); 11132 return !!name && isLateBindableName(name); 11133 } 11134 11135 /** 11136 * Indicates whether a declaration has an early-bound name or a dynamic name that can be late-bound. 11137 */ 11138 function hasBindableName(node: Declaration) { 11139 return !hasDynamicName(node) || hasLateBindableName(node); 11140 } 11141 11142 /** 11143 * Indicates whether a declaration name is a dynamic name that cannot be late-bound. 11144 */ 11145 function isNonBindableDynamicName(node: DeclarationName) { 11146 return isDynamicName(node) && !isLateBindableName(node); 11147 } 11148 11149 /** 11150 * Gets the symbolic name for a member from its type. 11151 */ 11152 function getPropertyNameFromType(type: StringLiteralType | NumberLiteralType | UniqueESSymbolType): __String { 11153 if (type.flags & TypeFlags.UniqueESSymbol) { 11154 return (type as UniqueESSymbolType).escapedName; 11155 } 11156 if (type.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) { 11157 return escapeLeadingUnderscores("" + (type as StringLiteralType | NumberLiteralType).value); 11158 } 11159 return Debug.fail(); 11160 } 11161 11162 /** 11163 * Adds a declaration to a late-bound dynamic member. This performs the same function for 11164 * late-bound members that `addDeclarationToSymbol` in binder.ts performs for early-bound 11165 * members. 11166 */ 11167 function addDeclarationToLateBoundSymbol(symbol: Symbol, member: LateBoundDeclaration | BinaryExpression, symbolFlags: SymbolFlags) { 11168 Debug.assert(!!(getCheckFlags(symbol) & CheckFlags.Late), "Expected a late-bound symbol."); 11169 symbol.flags |= symbolFlags; 11170 getSymbolLinks(member.symbol).lateSymbol = symbol; 11171 if (!symbol.declarations) { 11172 symbol.declarations = [member]; 11173 } 11174 else if(!member.symbol.isReplaceableByMethod) { 11175 symbol.declarations.push(member); 11176 } 11177 if (symbolFlags & SymbolFlags.Value) { 11178 if (!symbol.valueDeclaration || symbol.valueDeclaration.kind !== member.kind) { 11179 symbol.valueDeclaration = member; 11180 } 11181 } 11182 } 11183 11184 /** 11185 * Performs late-binding of a dynamic member. This performs the same function for 11186 * late-bound members that `declareSymbol` in binder.ts performs for early-bound 11187 * members. 11188 * 11189 * If a symbol is a dynamic name from a computed property, we perform an additional "late" 11190 * binding phase to attempt to resolve the name for the symbol from the type of the computed 11191 * property's expression. If the type of the expression is a string-literal, numeric-literal, 11192 * or unique symbol type, we can use that type as the name of the symbol. 11193 * 11194 * For example, given: 11195 * 11196 * const x = Symbol(); 11197 * 11198 * interface I { 11199 * [x]: number; 11200 * } 11201 * 11202 * The binder gives the property `[x]: number` a special symbol with the name "__computed". 11203 * In the late-binding phase we can type-check the expression `x` and see that it has a 11204 * unique symbol type which we can then use as the name of the member. This allows users 11205 * to define custom symbols that can be used in the members of an object type. 11206 * 11207 * @param parent The containing symbol for the member. 11208 * @param earlySymbols The early-bound symbols of the parent. 11209 * @param lateSymbols The late-bound symbols of the parent. 11210 * @param decl The member to bind. 11211 */ 11212 function lateBindMember(parent: Symbol, earlySymbols: SymbolTable | undefined, lateSymbols: UnderscoreEscapedMap<TransientSymbol>, decl: LateBoundDeclaration | LateBoundBinaryExpressionDeclaration) { 11213 Debug.assert(!!decl.symbol, "The member is expected to have a symbol."); 11214 const links = getNodeLinks(decl); 11215 if (!links.resolvedSymbol) { 11216 // In the event we attempt to resolve the late-bound name of this member recursively, 11217 // fall back to the early-bound name of this member. 11218 links.resolvedSymbol = decl.symbol; 11219 const declName = isBinaryExpression(decl) ? decl.left : decl.name; 11220 const type = isElementAccessExpression(declName) ? checkExpressionCached(declName.argumentExpression) : checkComputedPropertyName(declName); 11221 if (isTypeUsableAsPropertyName(type)) { 11222 const memberName = getPropertyNameFromType(type); 11223 const symbolFlags = decl.symbol.flags; 11224 11225 // Get or add a late-bound symbol for the member. This allows us to merge late-bound accessor declarations. 11226 let lateSymbol = lateSymbols.get(memberName); 11227 if (!lateSymbol) lateSymbols.set(memberName, lateSymbol = createSymbol(SymbolFlags.None, memberName, CheckFlags.Late)); 11228 11229 // Report an error if a late-bound member has the same name as an early-bound member, 11230 // or if we have another early-bound symbol declaration with the same name and 11231 // conflicting flags. 11232 const earlySymbol = earlySymbols && earlySymbols.get(memberName); 11233 if (lateSymbol.flags & getExcludedSymbolFlags(symbolFlags) || earlySymbol) { 11234 // If we have an existing early-bound member, combine its declarations so that we can 11235 // report an error at each declaration. 11236 const declarations = earlySymbol ? concatenate(earlySymbol.declarations, lateSymbol.declarations) : lateSymbol.declarations; 11237 const name = !(type.flags & TypeFlags.UniqueESSymbol) && unescapeLeadingUnderscores(memberName) || declarationNameToString(declName); 11238 forEach(declarations, declaration => error(getNameOfDeclaration(declaration) || declaration, Diagnostics.Property_0_was_also_declared_here, name)); 11239 error(declName || decl, Diagnostics.Duplicate_property_0, name); 11240 lateSymbol = createSymbol(SymbolFlags.None, memberName, CheckFlags.Late); 11241 } 11242 lateSymbol.nameType = type; 11243 addDeclarationToLateBoundSymbol(lateSymbol, decl, symbolFlags); 11244 if (lateSymbol.parent) { 11245 Debug.assert(lateSymbol.parent === parent, "Existing symbol parent should match new one"); 11246 } 11247 else { 11248 lateSymbol.parent = parent; 11249 } 11250 return links.resolvedSymbol = lateSymbol; 11251 } 11252 } 11253 return links.resolvedSymbol; 11254 } 11255 11256 function getResolvedMembersOrExportsOfSymbol(symbol: Symbol, resolutionKind: MembersOrExportsResolutionKind): UnderscoreEscapedMap<Symbol> { 11257 const links = getSymbolLinks(symbol); 11258 if (!links[resolutionKind]) { 11259 const isStatic = resolutionKind === MembersOrExportsResolutionKind.resolvedExports; 11260 const earlySymbols = !isStatic ? symbol.members : 11261 symbol.flags & SymbolFlags.Module ? getExportsOfModuleWorker(symbol) : 11262 symbol.exports; 11263 11264 // In the event we recursively resolve the members/exports of the symbol, we 11265 // set the initial value of resolvedMembers/resolvedExports to the early-bound 11266 // members/exports of the symbol. 11267 links[resolutionKind] = earlySymbols || emptySymbols; 11268 11269 // fill in any as-yet-unresolved late-bound members. 11270 const lateSymbols = createSymbolTable() as UnderscoreEscapedMap<TransientSymbol>; 11271 for (const decl of symbol.declarations || emptyArray) { 11272 const members = getMembersOfDeclaration(decl); 11273 if (members) { 11274 for (const member of members) { 11275 if (isStatic === hasStaticModifier(member)) { 11276 if (hasLateBindableName(member)) { 11277 lateBindMember(symbol, earlySymbols, lateSymbols, member); 11278 } 11279 } 11280 } 11281 } 11282 } 11283 const assignments = symbol.assignmentDeclarationMembers; 11284 if (assignments) { 11285 const decls = arrayFrom(assignments.values()); 11286 for (const member of decls) { 11287 const assignmentKind = getAssignmentDeclarationKind(member as BinaryExpression | CallExpression); 11288 const isInstanceMember = assignmentKind === AssignmentDeclarationKind.PrototypeProperty 11289 || isBinaryExpression(member) && isPossiblyAliasedThisProperty(member, assignmentKind) 11290 || assignmentKind === AssignmentDeclarationKind.ObjectDefinePrototypeProperty 11291 || assignmentKind === AssignmentDeclarationKind.Prototype; // A straight `Prototype` assignment probably can never have a computed name 11292 if (isStatic === !isInstanceMember) { 11293 if (hasLateBindableName(member)) { 11294 lateBindMember(symbol, earlySymbols, lateSymbols, member); 11295 } 11296 } 11297 } 11298 } 11299 11300 links[resolutionKind] = combineSymbolTables(earlySymbols, lateSymbols) || emptySymbols; 11301 } 11302 11303 return links[resolutionKind]!; 11304 } 11305 11306 /** 11307 * Gets a SymbolTable containing both the early- and late-bound members of a symbol. 11308 * 11309 * For a description of late-binding, see `lateBindMember`. 11310 */ 11311 function getMembersOfSymbol(symbol: Symbol) { 11312 return symbol.flags & SymbolFlags.LateBindingContainer 11313 ? getResolvedMembersOrExportsOfSymbol(symbol, MembersOrExportsResolutionKind.resolvedMembers) 11314 : symbol.members || emptySymbols; 11315 } 11316 11317 /** 11318 * If a symbol is the dynamic name of the member of an object type, get the late-bound 11319 * symbol of the member. 11320 * 11321 * For a description of late-binding, see `lateBindMember`. 11322 */ 11323 function getLateBoundSymbol(symbol: Symbol): Symbol { 11324 if (symbol.flags & SymbolFlags.ClassMember && symbol.escapedName === InternalSymbolName.Computed) { 11325 const links = getSymbolLinks(symbol); 11326 if (!links.lateSymbol && some(symbol.declarations, hasLateBindableName)) { 11327 // force late binding of members/exports. This will set the late-bound symbol 11328 const parent = getMergedSymbol(symbol.parent)!; 11329 if (some(symbol.declarations, hasStaticModifier)) { 11330 getExportsOfSymbol(parent); 11331 } 11332 else { 11333 getMembersOfSymbol(parent); 11334 } 11335 } 11336 return links.lateSymbol || (links.lateSymbol = symbol); 11337 } 11338 return symbol; 11339 } 11340 11341 function getTypeWithThisArgument(type: Type, thisArgument?: Type, needApparentType?: boolean): Type { 11342 if (getObjectFlags(type) & ObjectFlags.Reference) { 11343 const target = (type as TypeReference).target; 11344 const typeArguments = getTypeArguments(type as TypeReference); 11345 if (length(target.typeParameters) === length(typeArguments)) { 11346 const ref = createTypeReference(target, concatenate(typeArguments, [thisArgument || target.thisType!])); 11347 return needApparentType ? getApparentType(ref) : ref; 11348 } 11349 } 11350 else if (type.flags & TypeFlags.Intersection) { 11351 const types = sameMap((type as IntersectionType).types, t => getTypeWithThisArgument(t, thisArgument, needApparentType)); 11352 return types !== (type as IntersectionType).types ? getIntersectionType(types) : type; 11353 } 11354 return needApparentType ? getApparentType(type) : type; 11355 } 11356 11357 function resolveObjectTypeMembers(type: ObjectType, source: InterfaceTypeWithDeclaredMembers, typeParameters: readonly TypeParameter[], typeArguments: readonly Type[]) { 11358 let mapper: TypeMapper | undefined; 11359 let members: SymbolTable; 11360 let callSignatures: readonly Signature[]; 11361 let constructSignatures: readonly Signature[]; 11362 let indexInfos: readonly IndexInfo[]; 11363 if (rangeEquals(typeParameters, typeArguments, 0, typeParameters.length)) { 11364 members = source.symbol ? getMembersOfSymbol(source.symbol) : createSymbolTable(source.declaredProperties); 11365 callSignatures = source.declaredCallSignatures; 11366 constructSignatures = source.declaredConstructSignatures; 11367 indexInfos = source.declaredIndexInfos; 11368 } 11369 else { 11370 mapper = createTypeMapper(typeParameters, typeArguments); 11371 members = createInstantiatedSymbolTable(source.declaredProperties, mapper, /*mappingThisOnly*/ typeParameters.length === 1); 11372 callSignatures = instantiateSignatures(source.declaredCallSignatures, mapper); 11373 constructSignatures = instantiateSignatures(source.declaredConstructSignatures, mapper); 11374 indexInfos = instantiateIndexInfos(source.declaredIndexInfos, mapper); 11375 } 11376 const baseTypes = getBaseTypes(source); 11377 if (baseTypes.length) { 11378 if (source.symbol && members === getMembersOfSymbol(source.symbol)) { 11379 members = createSymbolTable(source.declaredProperties); 11380 } 11381 setStructuredTypeMembers(type, members, callSignatures, constructSignatures, indexInfos); 11382 const thisArgument = lastOrUndefined(typeArguments); 11383 for (const baseType of baseTypes) { 11384 const instantiatedBaseType = thisArgument ? getTypeWithThisArgument(instantiateType(baseType, mapper), thisArgument) : baseType; 11385 addInheritedMembers(members, getPropertiesOfType(instantiatedBaseType)); 11386 callSignatures = concatenate(callSignatures, getSignaturesOfType(instantiatedBaseType, SignatureKind.Call)); 11387 constructSignatures = concatenate(constructSignatures, getSignaturesOfType(instantiatedBaseType, SignatureKind.Construct)); 11388 const inheritedIndexInfos = instantiatedBaseType !== anyType ? getIndexInfosOfType(instantiatedBaseType) : [createIndexInfo(stringType, anyType, /*isReadonly*/ false)]; 11389 indexInfos = concatenate(indexInfos, filter(inheritedIndexInfos, info => !findIndexInfo(indexInfos, info.keyType))); 11390 } 11391 } 11392 setStructuredTypeMembers(type, members, callSignatures, constructSignatures, indexInfos); 11393 } 11394 11395 function resolveClassOrInterfaceMembers(type: InterfaceType): void { 11396 resolveObjectTypeMembers(type, resolveDeclaredMembers(type), emptyArray, emptyArray); 11397 } 11398 11399 function resolveTypeReferenceMembers(type: TypeReference): void { 11400 const source = resolveDeclaredMembers(type.target); 11401 const typeParameters = concatenate(source.typeParameters!, [source.thisType!]); 11402 const typeArguments = getTypeArguments(type); 11403 const paddedTypeArguments = typeArguments.length === typeParameters.length ? typeArguments : concatenate(typeArguments, [type]); 11404 resolveObjectTypeMembers(type, source, typeParameters, paddedTypeArguments); 11405 } 11406 11407 function createSignature( 11408 declaration: SignatureDeclaration | JSDocSignature | undefined, 11409 typeParameters: readonly TypeParameter[] | undefined, 11410 thisParameter: Symbol | undefined, 11411 parameters: readonly Symbol[], 11412 resolvedReturnType: Type | undefined, 11413 resolvedTypePredicate: TypePredicate | undefined, 11414 minArgumentCount: number, 11415 flags: SignatureFlags 11416 ): Signature { 11417 const sig = new Signature(checker, flags); 11418 sig.declaration = declaration; 11419 sig.typeParameters = typeParameters; 11420 sig.parameters = parameters; 11421 sig.thisParameter = thisParameter; 11422 sig.resolvedReturnType = resolvedReturnType; 11423 sig.resolvedTypePredicate = resolvedTypePredicate; 11424 sig.minArgumentCount = minArgumentCount; 11425 sig.resolvedMinArgumentCount = undefined; 11426 sig.target = undefined; 11427 sig.mapper = undefined; 11428 sig.compositeSignatures = undefined; 11429 sig.compositeKind = undefined; 11430 return sig; 11431 } 11432 11433 function cloneSignature(sig: Signature): Signature { 11434 const result = createSignature(sig.declaration, sig.typeParameters, sig.thisParameter, sig.parameters, /*resolvedReturnType*/ undefined, 11435 /*resolvedTypePredicate*/ undefined, sig.minArgumentCount, sig.flags & SignatureFlags.PropagatingFlags); 11436 result.target = sig.target; 11437 result.mapper = sig.mapper; 11438 result.compositeSignatures = sig.compositeSignatures; 11439 result.compositeKind = sig.compositeKind; 11440 return result; 11441 } 11442 11443 function createUnionSignature(signature: Signature, unionSignatures: Signature[]) { 11444 const result = cloneSignature(signature); 11445 result.compositeSignatures = unionSignatures; 11446 result.compositeKind = TypeFlags.Union; 11447 result.target = undefined; 11448 result.mapper = undefined; 11449 return result; 11450 } 11451 11452 function getOptionalCallSignature(signature: Signature, callChainFlags: SignatureFlags): Signature { 11453 if ((signature.flags & SignatureFlags.CallChainFlags) === callChainFlags) { 11454 return signature; 11455 } 11456 if (!signature.optionalCallSignatureCache) { 11457 signature.optionalCallSignatureCache = {}; 11458 } 11459 const key = callChainFlags === SignatureFlags.IsInnerCallChain ? "inner" : "outer"; 11460 return signature.optionalCallSignatureCache[key] 11461 || (signature.optionalCallSignatureCache[key] = createOptionalCallSignature(signature, callChainFlags)); 11462 } 11463 11464 function createOptionalCallSignature(signature: Signature, callChainFlags: SignatureFlags) { 11465 Debug.assert(callChainFlags === SignatureFlags.IsInnerCallChain || callChainFlags === SignatureFlags.IsOuterCallChain, 11466 "An optional call signature can either be for an inner call chain or an outer call chain, but not both."); 11467 const result = cloneSignature(signature); 11468 result.flags |= callChainFlags; 11469 return result; 11470 } 11471 11472 function getExpandedParameters(sig: Signature, skipUnionExpanding?: boolean): readonly (readonly Symbol[])[] { 11473 if (signatureHasRestParameter(sig)) { 11474 const restIndex = sig.parameters.length - 1; 11475 const restType = getTypeOfSymbol(sig.parameters[restIndex]); 11476 if (isTupleType(restType)) { 11477 return [expandSignatureParametersWithTupleMembers(restType, restIndex)]; 11478 } 11479 else if (!skipUnionExpanding && restType.flags & TypeFlags.Union && every((restType as UnionType).types, isTupleType)) { 11480 return map((restType as UnionType).types, t => expandSignatureParametersWithTupleMembers(t as TupleTypeReference, restIndex)); 11481 } 11482 } 11483 return [sig.parameters]; 11484 11485 function expandSignatureParametersWithTupleMembers(restType: TupleTypeReference, restIndex: number) { 11486 const elementTypes = getTypeArguments(restType); 11487 const associatedNames = restType.target.labeledElementDeclarations; 11488 const restParams = map(elementTypes, (t, i) => { 11489 // Lookup the label from the individual tuple passed in before falling back to the signature `rest` parameter name 11490 const tupleLabelName = !!associatedNames && getTupleElementLabel(associatedNames[i]); 11491 const name = tupleLabelName || getParameterNameAtPosition(sig, restIndex + i, restType); 11492 const flags = restType.target.elementFlags[i]; 11493 const checkFlags = flags & ElementFlags.Variable ? CheckFlags.RestParameter : 11494 flags & ElementFlags.Optional ? CheckFlags.OptionalParameter : 0; 11495 const symbol = createSymbol(SymbolFlags.FunctionScopedVariable, name, checkFlags); 11496 symbol.type = flags & ElementFlags.Rest ? createArrayType(t) : t; 11497 return symbol; 11498 }); 11499 return concatenate(sig.parameters.slice(0, restIndex), restParams); 11500 } 11501 } 11502 11503 function getDefaultConstructSignatures(classType: InterfaceType): Signature[] { 11504 const baseConstructorType = getBaseConstructorTypeOfClass(classType); 11505 const baseSignatures = getSignaturesOfType(baseConstructorType, SignatureKind.Construct); 11506 const declaration = getClassLikeDeclarationOfSymbol(classType.symbol); 11507 const isAbstract = !!declaration && hasSyntacticModifier(declaration, ModifierFlags.Abstract); 11508 if (baseSignatures.length === 0) { 11509 return [createSignature(undefined, classType.localTypeParameters, undefined, emptyArray, classType, /*resolvedTypePredicate*/ undefined, 0, isAbstract ? SignatureFlags.Abstract : SignatureFlags.None)]; 11510 } 11511 const baseTypeNode = getBaseTypeNodeOfClass(classType)!; 11512 const isJavaScript = isInJSFile(baseTypeNode); 11513 const typeArguments = typeArgumentsFromTypeReferenceNode(baseTypeNode); 11514 const typeArgCount = length(typeArguments); 11515 const result: Signature[] = []; 11516 for (const baseSig of baseSignatures) { 11517 const minTypeArgumentCount = getMinTypeArgumentCount(baseSig.typeParameters); 11518 const typeParamCount = length(baseSig.typeParameters); 11519 if (isJavaScript || typeArgCount >= minTypeArgumentCount && typeArgCount <= typeParamCount) { 11520 const sig = typeParamCount ? createSignatureInstantiation(baseSig, fillMissingTypeArguments(typeArguments, baseSig.typeParameters, minTypeArgumentCount, isJavaScript)) : cloneSignature(baseSig); 11521 sig.typeParameters = classType.localTypeParameters; 11522 sig.resolvedReturnType = classType; 11523 sig.flags = isAbstract ? sig.flags | SignatureFlags.Abstract : sig.flags & ~SignatureFlags.Abstract; 11524 result.push(sig); 11525 } 11526 } 11527 return result; 11528 } 11529 11530 function findMatchingSignature(signatureList: readonly Signature[], signature: Signature, partialMatch: boolean, ignoreThisTypes: boolean, ignoreReturnTypes: boolean): Signature | undefined { 11531 for (const s of signatureList) { 11532 if (compareSignaturesIdentical(s, signature, partialMatch, ignoreThisTypes, ignoreReturnTypes, partialMatch ? compareTypesSubtypeOf : compareTypesIdentical)) { 11533 return s; 11534 } 11535 } 11536 } 11537 11538 function findMatchingSignatures(signatureLists: readonly (readonly Signature[])[], signature: Signature, listIndex: number): Signature[] | undefined { 11539 if (signature.typeParameters) { 11540 // We require an exact match for generic signatures, so we only return signatures from the first 11541 // signature list and only if they have exact matches in the other signature lists. 11542 if (listIndex > 0) { 11543 return undefined; 11544 } 11545 for (let i = 1; i < signatureLists.length; i++) { 11546 if (!findMatchingSignature(signatureLists[i], signature, /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ false)) { 11547 return undefined; 11548 } 11549 } 11550 return [signature]; 11551 } 11552 let result: Signature[] | undefined; 11553 for (let i = 0; i < signatureLists.length; i++) { 11554 // Allow matching non-generic signatures to have excess parameters and different return types. 11555 // Prefer matching this types if possible. 11556 const match = i === listIndex ? signature : findMatchingSignature(signatureLists[i], signature, /*partialMatch*/ true, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ true); 11557 if (!match) { 11558 return undefined; 11559 } 11560 result = appendIfUnique(result, match); 11561 } 11562 return result; 11563 } 11564 11565 // The signatures of a union type are those signatures that are present in each of the constituent types. 11566 // Generic signatures must match exactly, but non-generic signatures are allowed to have extra optional 11567 // parameters and may differ in return types. When signatures differ in return types, the resulting return 11568 // type is the union of the constituent return types. 11569 function getUnionSignatures(signatureLists: readonly (readonly Signature[])[]): Signature[] { 11570 let result: Signature[] | undefined; 11571 let indexWithLengthOverOne: number | undefined; 11572 for (let i = 0; i < signatureLists.length; i++) { 11573 if (signatureLists[i].length === 0) return emptyArray; 11574 if (signatureLists[i].length > 1) { 11575 indexWithLengthOverOne = indexWithLengthOverOne === undefined ? i : -1; // -1 is a signal there are multiple overload sets 11576 } 11577 for (const signature of signatureLists[i]) { 11578 // Only process signatures with parameter lists that aren't already in the result list 11579 if (!result || !findMatchingSignature(result, signature, /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ true)) { 11580 const unionSignatures = findMatchingSignatures(signatureLists, signature, i); 11581 if (unionSignatures) { 11582 let s = signature; 11583 // Union the result types when more than one signature matches 11584 if (unionSignatures.length > 1) { 11585 let thisParameter = signature.thisParameter; 11586 const firstThisParameterOfUnionSignatures = forEach(unionSignatures, sig => sig.thisParameter); 11587 if (firstThisParameterOfUnionSignatures) { 11588 const thisType = getIntersectionType(mapDefined(unionSignatures, sig => sig.thisParameter && getTypeOfSymbol(sig.thisParameter))); 11589 thisParameter = createSymbolWithType(firstThisParameterOfUnionSignatures, thisType); 11590 } 11591 s = createUnionSignature(signature, unionSignatures); 11592 s.thisParameter = thisParameter; 11593 } 11594 (result || (result = [])).push(s); 11595 } 11596 } 11597 } 11598 } 11599 if (!length(result) && indexWithLengthOverOne !== -1) { 11600 // No sufficiently similar signature existed to subsume all the other signatures in the union - time to see if we can make a single 11601 // signature that handles all over them. We only do this when there are overloads in only one constituent. 11602 // (Overloads are conditional in nature and having overloads in multiple constituents would necessitate making a power set of 11603 // signatures from the type, whose ordering would be non-obvious) 11604 const masterList = signatureLists[indexWithLengthOverOne !== undefined ? indexWithLengthOverOne : 0]; 11605 let results: Signature[] | undefined = masterList.slice(); 11606 for (const signatures of signatureLists) { 11607 if (signatures !== masterList) { 11608 const signature = signatures[0]; 11609 Debug.assert(!!signature, "getUnionSignatures bails early on empty signature lists and should not have empty lists on second pass"); 11610 results = !!signature.typeParameters && some(results, s => !!s.typeParameters && !compareTypeParametersIdentical(signature.typeParameters, s.typeParameters)) ? undefined : map(results, sig => combineSignaturesOfUnionMembers(sig, signature)); 11611 if (!results) { 11612 break; 11613 } 11614 } 11615 } 11616 result = results; 11617 } 11618 return result || emptyArray; 11619 } 11620 11621 function compareTypeParametersIdentical(sourceParams: readonly TypeParameter[] | undefined, targetParams: readonly TypeParameter[] | undefined): boolean { 11622 if (length(sourceParams) !== length(targetParams)) { 11623 return false; 11624 } 11625 if (!sourceParams || !targetParams) { 11626 return true; 11627 } 11628 11629 const mapper = createTypeMapper(targetParams, sourceParams); 11630 for (let i = 0; i < sourceParams.length; i++) { 11631 const source = sourceParams[i]; 11632 const target = targetParams[i]; 11633 if (source === target) continue; 11634 // We instantiate the target type parameter constraints into the source types so we can recognize `<T, U extends T>` as the same as `<A, B extends A>` 11635 if (!isTypeIdenticalTo(getConstraintFromTypeParameter(source) || unknownType, instantiateType(getConstraintFromTypeParameter(target) || unknownType, mapper))) return false; 11636 // We don't compare defaults - we just use the type parameter defaults from the first signature that seems to match. 11637 // It might make sense to combine these defaults in the future, but doing so intelligently requires knowing 11638 // if the parameter is used covariantly or contravariantly (so we intersect if it's used like a parameter or union if used like a return type) 11639 // and, since it's just an inference _default_, just picking one arbitrarily works OK. 11640 } 11641 11642 return true; 11643 } 11644 11645 function combineUnionThisParam(left: Symbol | undefined, right: Symbol | undefined, mapper: TypeMapper | undefined): Symbol | undefined { 11646 if (!left || !right) { 11647 return left || right; 11648 } 11649 // A signature `this` type might be a read or a write position... It's very possible that it should be invariant 11650 // and we should refuse to merge signatures if there are `this` types and they do not match. However, so as to be 11651 // permissive when calling, for now, we'll intersect the `this` types just like we do for param types in union signatures. 11652 const thisType = getIntersectionType([getTypeOfSymbol(left), instantiateType(getTypeOfSymbol(right), mapper)]); 11653 return createSymbolWithType(left, thisType); 11654 } 11655 11656 function combineUnionParameters(left: Signature, right: Signature, mapper: TypeMapper | undefined) { 11657 const leftCount = getParameterCount(left); 11658 const rightCount = getParameterCount(right); 11659 const longest = leftCount >= rightCount ? left : right; 11660 const shorter = longest === left ? right : left; 11661 const longestCount = longest === left ? leftCount : rightCount; 11662 const eitherHasEffectiveRest = (hasEffectiveRestParameter(left) || hasEffectiveRestParameter(right)); 11663 const needsExtraRestElement = eitherHasEffectiveRest && !hasEffectiveRestParameter(longest); 11664 const params = new Array<Symbol>(longestCount + (needsExtraRestElement ? 1 : 0)); 11665 for (let i = 0; i < longestCount; i++) { 11666 let longestParamType = tryGetTypeAtPosition(longest, i)!; 11667 if (longest === right) { 11668 longestParamType = instantiateType(longestParamType, mapper); 11669 } 11670 let shorterParamType = tryGetTypeAtPosition(shorter, i) || unknownType; 11671 if (shorter === right) { 11672 shorterParamType = instantiateType(shorterParamType, mapper); 11673 } 11674 const unionParamType = getIntersectionType([longestParamType, shorterParamType]); 11675 const isRestParam = eitherHasEffectiveRest && !needsExtraRestElement && i === (longestCount - 1); 11676 const isOptional = i >= getMinArgumentCount(longest) && i >= getMinArgumentCount(shorter); 11677 const leftName = i >= leftCount ? undefined : getParameterNameAtPosition(left, i); 11678 const rightName = i >= rightCount ? undefined : getParameterNameAtPosition(right, i); 11679 11680 const paramName = leftName === rightName ? leftName : 11681 !leftName ? rightName : 11682 !rightName ? leftName : 11683 undefined; 11684 const paramSymbol = createSymbol( 11685 SymbolFlags.FunctionScopedVariable | (isOptional && !isRestParam ? SymbolFlags.Optional : 0), 11686 paramName || `arg${i}` as __String 11687 ); 11688 paramSymbol.type = isRestParam ? createArrayType(unionParamType) : unionParamType; 11689 params[i] = paramSymbol; 11690 } 11691 if (needsExtraRestElement) { 11692 const restParamSymbol = createSymbol(SymbolFlags.FunctionScopedVariable, "args" as __String); 11693 restParamSymbol.type = createArrayType(getTypeAtPosition(shorter, longestCount)); 11694 if (shorter === right) { 11695 restParamSymbol.type = instantiateType(restParamSymbol.type, mapper); 11696 } 11697 params[longestCount] = restParamSymbol; 11698 } 11699 return params; 11700 } 11701 11702 function combineSignaturesOfUnionMembers(left: Signature, right: Signature): Signature { 11703 const typeParams = left.typeParameters || right.typeParameters; 11704 let paramMapper: TypeMapper | undefined; 11705 if (left.typeParameters && right.typeParameters) { 11706 paramMapper = createTypeMapper(right.typeParameters, left.typeParameters); 11707 // We just use the type parameter defaults from the first signature 11708 } 11709 const declaration = left.declaration; 11710 const params = combineUnionParameters(left, right, paramMapper); 11711 const thisParam = combineUnionThisParam(left.thisParameter, right.thisParameter, paramMapper); 11712 const minArgCount = Math.max(left.minArgumentCount, right.minArgumentCount); 11713 const result = createSignature( 11714 declaration, 11715 typeParams, 11716 thisParam, 11717 params, 11718 /*resolvedReturnType*/ undefined, 11719 /*resolvedTypePredicate*/ undefined, 11720 minArgCount, 11721 (left.flags | right.flags) & SignatureFlags.PropagatingFlags 11722 ); 11723 result.compositeKind = TypeFlags.Union; 11724 result.compositeSignatures = concatenate(left.compositeKind !== TypeFlags.Intersection && left.compositeSignatures || [left], [right]); 11725 if (paramMapper) { 11726 result.mapper = left.compositeKind !== TypeFlags.Intersection && left.mapper && left.compositeSignatures ? combineTypeMappers(left.mapper, paramMapper) : paramMapper; 11727 } 11728 return result; 11729 } 11730 11731 function getUnionIndexInfos(types: readonly Type[]): IndexInfo[] { 11732 const sourceInfos = getIndexInfosOfType(types[0]); 11733 if (sourceInfos) { 11734 const result = []; 11735 for (const info of sourceInfos) { 11736 const indexType = info.keyType; 11737 if (every(types, t => !!getIndexInfoOfType(t, indexType))) { 11738 result.push(createIndexInfo(indexType, getUnionType(map(types, t => getIndexTypeOfType(t, indexType)!)), 11739 some(types, t => getIndexInfoOfType(t, indexType)!.isReadonly))); 11740 } 11741 } 11742 return result; 11743 } 11744 return emptyArray; 11745 } 11746 11747 function resolveUnionTypeMembers(type: UnionType) { 11748 // The members and properties collections are empty for union types. To get all properties of a union 11749 // type use getPropertiesOfType (only the language service uses this). 11750 const callSignatures = getUnionSignatures(map(type.types, t => t === globalFunctionType ? [unknownSignature] : getSignaturesOfType(t, SignatureKind.Call))); 11751 const constructSignatures = getUnionSignatures(map(type.types, t => getSignaturesOfType(t, SignatureKind.Construct))); 11752 const indexInfos = getUnionIndexInfos(type.types); 11753 setStructuredTypeMembers(type, emptySymbols, callSignatures, constructSignatures, indexInfos); 11754 } 11755 11756 function intersectTypes(type1: Type, type2: Type): Type; 11757 function intersectTypes(type1: Type | undefined, type2: Type | undefined): Type | undefined; 11758 function intersectTypes(type1: Type | undefined, type2: Type | undefined): Type | undefined { 11759 return !type1 ? type2 : !type2 ? type1 : getIntersectionType([type1, type2]); 11760 } 11761 11762 function findMixins(types: readonly Type[]): readonly boolean[] { 11763 const constructorTypeCount = countWhere(types, (t) => getSignaturesOfType(t, SignatureKind.Construct).length > 0); 11764 const mixinFlags = map(types, isMixinConstructorType); 11765 if (constructorTypeCount > 0 && constructorTypeCount === countWhere(mixinFlags, (b) => b)) { 11766 const firstMixinIndex = mixinFlags.indexOf(/*searchElement*/ true); 11767 mixinFlags[firstMixinIndex] = false; 11768 } 11769 return mixinFlags; 11770 } 11771 11772 function includeMixinType(type: Type, types: readonly Type[], mixinFlags: readonly boolean[], index: number): Type { 11773 const mixedTypes: Type[] = []; 11774 for (let i = 0; i < types.length; i++) { 11775 if (i === index) { 11776 mixedTypes.push(type); 11777 } 11778 else if (mixinFlags[i]) { 11779 mixedTypes.push(getReturnTypeOfSignature(getSignaturesOfType(types[i], SignatureKind.Construct)[0])); 11780 } 11781 } 11782 return getIntersectionType(mixedTypes); 11783 } 11784 11785 function resolveIntersectionTypeMembers(type: IntersectionType) { 11786 // The members and properties collections are empty for intersection types. To get all properties of an 11787 // intersection type use getPropertiesOfType (only the language service uses this). 11788 let callSignatures: Signature[] | undefined; 11789 let constructSignatures: Signature[] | undefined; 11790 let indexInfos: IndexInfo[] | undefined; 11791 const types = type.types; 11792 const mixinFlags = findMixins(types); 11793 const mixinCount = countWhere(mixinFlags, (b) => b); 11794 for (let i = 0; i < types.length; i++) { 11795 const t = type.types[i]; 11796 // When an intersection type contains mixin constructor types, the construct signatures from 11797 // those types are discarded and their return types are mixed into the return types of all 11798 // other construct signatures in the intersection type. For example, the intersection type 11799 // '{ new(...args: any[]) => A } & { new(s: string) => B }' has a single construct signature 11800 // 'new(s: string) => A & B'. 11801 if (!mixinFlags[i]) { 11802 let signatures = getSignaturesOfType(t, SignatureKind.Construct); 11803 if (signatures.length && mixinCount > 0) { 11804 signatures = map(signatures, s => { 11805 const clone = cloneSignature(s); 11806 clone.resolvedReturnType = includeMixinType(getReturnTypeOfSignature(s), types, mixinFlags, i); 11807 return clone; 11808 }); 11809 } 11810 constructSignatures = appendSignatures(constructSignatures, signatures); 11811 } 11812 callSignatures = appendSignatures(callSignatures, getSignaturesOfType(t, SignatureKind.Call)); 11813 indexInfos = reduceLeft(getIndexInfosOfType(t), (infos, newInfo) => appendIndexInfo(infos, newInfo, /*union*/ false), indexInfos); 11814 } 11815 setStructuredTypeMembers(type, emptySymbols, callSignatures || emptyArray, constructSignatures || emptyArray, indexInfos || emptyArray); 11816 } 11817 11818 function appendSignatures(signatures: Signature[] | undefined, newSignatures: readonly Signature[]) { 11819 for (const sig of newSignatures) { 11820 if (!signatures || every(signatures, s => !compareSignaturesIdentical(s, sig, /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ false, compareTypesIdentical))) { 11821 signatures = append(signatures, sig); 11822 } 11823 } 11824 return signatures; 11825 } 11826 11827 function appendIndexInfo(indexInfos: IndexInfo[] | undefined, newInfo: IndexInfo, union: boolean) { 11828 if (indexInfos) { 11829 for (let i = 0; i < indexInfos.length; i++) { 11830 const info = indexInfos[i]; 11831 if (info.keyType === newInfo.keyType) { 11832 indexInfos[i] = createIndexInfo(info.keyType, 11833 union ? getUnionType([info.type, newInfo.type]) : getIntersectionType([info.type, newInfo.type]), 11834 union ? info.isReadonly || newInfo.isReadonly : info.isReadonly && newInfo.isReadonly); 11835 return indexInfos; 11836 } 11837 } 11838 } 11839 return append(indexInfos, newInfo); 11840 } 11841 11842 /** 11843 * Converts an AnonymousType to a ResolvedType. 11844 */ 11845 function resolveAnonymousTypeMembers(type: AnonymousType) { 11846 if (type.target) { 11847 setStructuredTypeMembers(type, emptySymbols, emptyArray, emptyArray, emptyArray); 11848 const members = createInstantiatedSymbolTable(getPropertiesOfObjectType(type.target), type.mapper!, /*mappingThisOnly*/ false); 11849 const callSignatures = instantiateSignatures(getSignaturesOfType(type.target, SignatureKind.Call), type.mapper!); 11850 const constructSignatures = instantiateSignatures(getSignaturesOfType(type.target, SignatureKind.Construct), type.mapper!); 11851 const indexInfos = instantiateIndexInfos(getIndexInfosOfType(type.target), type.mapper!); 11852 setStructuredTypeMembers(type, members, callSignatures, constructSignatures, indexInfos); 11853 return; 11854 } 11855 const symbol = getMergedSymbol(type.symbol); 11856 if (symbol.flags & SymbolFlags.TypeLiteral) { 11857 setStructuredTypeMembers(type, emptySymbols, emptyArray, emptyArray, emptyArray); 11858 const members = getMembersOfSymbol(symbol); 11859 const callSignatures = getSignaturesOfSymbol(members.get(InternalSymbolName.Call)); 11860 const constructSignatures = getSignaturesOfSymbol(members.get(InternalSymbolName.New)); 11861 const indexInfos = getIndexInfosOfSymbol(symbol); 11862 setStructuredTypeMembers(type, members, callSignatures, constructSignatures, indexInfos); 11863 return; 11864 } 11865 // Combinations of function, class, enum and module 11866 let members = emptySymbols; 11867 let indexInfos: IndexInfo[] | undefined; 11868 if (symbol.exports) { 11869 members = getExportsOfSymbol(symbol); 11870 if (symbol === globalThisSymbol) { 11871 const varsOnly = new Map<string, Symbol>() as SymbolTable; 11872 members.forEach(p => { 11873 if (!(p.flags & SymbolFlags.BlockScoped) && !(p.flags & SymbolFlags.ValueModule && p.declarations?.length && every(p.declarations, isAmbientModule))) { 11874 varsOnly.set(p.escapedName, p); 11875 } 11876 }); 11877 members = varsOnly; 11878 } 11879 } 11880 let baseConstructorIndexInfo: IndexInfo | undefined; 11881 setStructuredTypeMembers(type, members, emptyArray, emptyArray, emptyArray); 11882 if (symbol.flags & SymbolFlags.Class) { 11883 const classType = getDeclaredTypeOfClassOrInterface(symbol); 11884 const baseConstructorType = getBaseConstructorTypeOfClass(classType); 11885 if (baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.TypeVariable)) { 11886 members = createSymbolTable(getNamedOrIndexSignatureMembers(members)); 11887 addInheritedMembers(members, getPropertiesOfType(baseConstructorType)); 11888 } 11889 else if (baseConstructorType === anyType) { 11890 baseConstructorIndexInfo = createIndexInfo(stringType, anyType, /*isReadonly*/ false); 11891 } 11892 } 11893 11894 const indexSymbol = getIndexSymbolFromSymbolTable(members); 11895 if (indexSymbol) { 11896 indexInfos = getIndexInfosOfIndexSymbol(indexSymbol); 11897 } 11898 else { 11899 if (baseConstructorIndexInfo) { 11900 indexInfos = append(indexInfos, baseConstructorIndexInfo); 11901 } 11902 if (symbol.flags & SymbolFlags.Enum && (getDeclaredTypeOfSymbol(symbol).flags & TypeFlags.Enum || 11903 some(type.properties, prop => !!(getTypeOfSymbol(prop).flags & TypeFlags.NumberLike)))) { 11904 indexInfos = append(indexInfos, enumNumberIndexInfo); 11905 } 11906 } 11907 setStructuredTypeMembers(type, members, emptyArray, emptyArray, indexInfos || emptyArray); 11908 // We resolve the members before computing the signatures because a signature may use 11909 // typeof with a qualified name expression that circularly references the type we are 11910 // in the process of resolving (see issue #6072). The temporarily empty signature list 11911 // will never be observed because a qualified name can't reference signatures. 11912 if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method)) { 11913 type.callSignatures = getSignaturesOfSymbol(symbol); 11914 } 11915 // And likewise for construct signatures for classes 11916 if (symbol.flags & SymbolFlags.Class) { 11917 const classType = getDeclaredTypeOfClassOrInterface(symbol); 11918 if (symbol.flags & SymbolFlags.Annotation) { 11919 // Make call signature "(annotationType): voidType" 11920 const proto = getPropertyOfType(getTypeOfSymbol(symbol), "prototype" as __String)!; 11921 type.callSignatures = [createSignature( 11922 /*declaration*/ undefined, 11923 /*typeParameters*/ undefined, 11924 /*thisParameter*/ undefined, 11925 /*parameters*/ [proto], 11926 /*resolvedReturnType*/ voidType, 11927 /*resolvedTypePredicate*/ undefined, 11928 /*resolvedReturnType*/ 1, 11929 /*flags*/ SignatureFlags.None)]; 11930 type.constructSignatures = []; 11931 return; 11932 } 11933 let constructSignatures = symbol.members ? getSignaturesOfSymbol(symbol.members.get(InternalSymbolName.Constructor)) : emptyArray; 11934 if (symbol.flags & SymbolFlags.Function) { 11935 constructSignatures = addRange(constructSignatures.slice(), mapDefined( 11936 type.callSignatures, 11937 sig => isJSConstructor(sig.declaration) ? 11938 createSignature(sig.declaration, sig.typeParameters, sig.thisParameter, sig.parameters, classType, /*resolvedTypePredicate*/ undefined, sig.minArgumentCount, sig.flags & SignatureFlags.PropagatingFlags) : 11939 undefined)); 11940 } 11941 if (!constructSignatures.length) { 11942 constructSignatures = getDefaultConstructSignatures(classType); 11943 } 11944 type.constructSignatures = constructSignatures; 11945 } 11946 } 11947 11948 type ReplaceableIndexedAccessType = IndexedAccessType & { objectType: TypeParameter, indexType: TypeParameter }; 11949 function replaceIndexedAccess(instantiable: Type, type: ReplaceableIndexedAccessType, replacement: Type) { 11950 // map type.indexType to 0 11951 // map type.objectType to `[TReplacement]` 11952 // thus making the indexed access `[TReplacement][0]` or `TReplacement` 11953 return instantiateType(instantiable, createTypeMapper([type.indexType, type.objectType], [getNumberLiteralType(0), createTupleType([replacement])])); 11954 } 11955 11956 function resolveReverseMappedTypeMembers(type: ReverseMappedType) { 11957 const indexInfo = getIndexInfoOfType(type.source, stringType); 11958 const modifiers = getMappedTypeModifiers(type.mappedType); 11959 const readonlyMask = modifiers & MappedTypeModifiers.IncludeReadonly ? false : true; 11960 const optionalMask = modifiers & MappedTypeModifiers.IncludeOptional ? 0 : SymbolFlags.Optional; 11961 const indexInfos = indexInfo ? [createIndexInfo(stringType, inferReverseMappedType(indexInfo.type, type.mappedType, type.constraintType), readonlyMask && indexInfo.isReadonly)] : emptyArray; 11962 const members = createSymbolTable(); 11963 for (const prop of getPropertiesOfType(type.source)) { 11964 const checkFlags = CheckFlags.ReverseMapped | (readonlyMask && isReadonlySymbol(prop) ? CheckFlags.Readonly : 0); 11965 const inferredProp = createSymbol(SymbolFlags.Property | prop.flags & optionalMask, prop.escapedName, checkFlags) as ReverseMappedSymbol; 11966 inferredProp.declarations = prop.declarations; 11967 inferredProp.nameType = getSymbolLinks(prop).nameType; 11968 inferredProp.propertyType = getTypeOfSymbol(prop); 11969 if (type.constraintType.type.flags & TypeFlags.IndexedAccess 11970 && (type.constraintType.type as IndexedAccessType).objectType.flags & TypeFlags.TypeParameter 11971 && (type.constraintType.type as IndexedAccessType).indexType.flags & TypeFlags.TypeParameter) { 11972 // A reverse mapping of `{[K in keyof T[K_1]]: T[K_1]}` is the same as that of `{[K in keyof T]: T}`, since all we care about is 11973 // inferring to the "type parameter" (or indexed access) shared by the constraint and template. So, to reduce the number of 11974 // type identities produced, we simplify such indexed access occurences 11975 const newTypeParam = (type.constraintType.type as IndexedAccessType).objectType; 11976 const newMappedType = replaceIndexedAccess(type.mappedType, type.constraintType.type as ReplaceableIndexedAccessType, newTypeParam); 11977 inferredProp.mappedType = newMappedType as MappedType; 11978 inferredProp.constraintType = getIndexType(newTypeParam) as IndexType; 11979 } 11980 else { 11981 inferredProp.mappedType = type.mappedType; 11982 inferredProp.constraintType = type.constraintType; 11983 } 11984 members.set(prop.escapedName, inferredProp); 11985 } 11986 setStructuredTypeMembers(type, members, emptyArray, emptyArray, indexInfos); 11987 } 11988 11989 // Return the lower bound of the key type in a mapped type. Intuitively, the lower 11990 // bound includes those keys that are known to always be present, for example because 11991 // because of constraints on type parameters (e.g. 'keyof T' for a constrained T). 11992 function getLowerBoundOfKeyType(type: Type): Type { 11993 if (type.flags & TypeFlags.Index) { 11994 const t = getApparentType((type as IndexType).type); 11995 return isGenericTupleType(t) ? getKnownKeysOfTupleType(t) : getIndexType(t); 11996 } 11997 if (type.flags & TypeFlags.Conditional) { 11998 if ((type as ConditionalType).root.isDistributive) { 11999 const checkType = (type as ConditionalType).checkType; 12000 const constraint = getLowerBoundOfKeyType(checkType); 12001 if (constraint !== checkType) { 12002 return getConditionalTypeInstantiation(type as ConditionalType, prependTypeMapping((type as ConditionalType).root.checkType, constraint, (type as ConditionalType).mapper)); 12003 } 12004 } 12005 return type; 12006 } 12007 if (type.flags & TypeFlags.Union) { 12008 return mapType(type as UnionType, getLowerBoundOfKeyType); 12009 } 12010 if (type.flags & TypeFlags.Intersection) { 12011 // Similarly to getTypeFromIntersectionTypeNode, we preserve the special string & {}, number & {}, 12012 // and bigint & {} intersections that are used to prevent subtype reduction in union types. 12013 const types = (type as IntersectionType).types; 12014 if (types.length === 2 && !!(types[0].flags & (TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt)) && types[1] === emptyTypeLiteralType) { 12015 return type; 12016 } 12017 return getIntersectionType(sameMap((type as UnionType).types, getLowerBoundOfKeyType)); 12018 } 12019 return type; 12020 } 12021 12022 function getIsLateCheckFlag(s: Symbol): CheckFlags { 12023 return getCheckFlags(s) & CheckFlags.Late; 12024 } 12025 12026 function forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType(type: Type, include: TypeFlags, stringsOnly: boolean, cb: (keyType: Type) => void) { 12027 for (const prop of getPropertiesOfType(type)) { 12028 cb(getLiteralTypeFromProperty(prop, include)); 12029 } 12030 if (type.flags & TypeFlags.Any) { 12031 cb(stringType); 12032 } 12033 else { 12034 for (const info of getIndexInfosOfType(type)) { 12035 if (!stringsOnly || info.keyType.flags & (TypeFlags.String | TypeFlags.TemplateLiteral)) { 12036 cb(info.keyType); 12037 } 12038 } 12039 } 12040 } 12041 12042 /** Resolve the members of a mapped type { [P in K]: T } */ 12043 function resolveMappedTypeMembers(type: MappedType) { 12044 const members: SymbolTable = createSymbolTable(); 12045 let indexInfos: IndexInfo[] | undefined; 12046 // Resolve upfront such that recursive references see an empty object type. 12047 setStructuredTypeMembers(type, emptySymbols, emptyArray, emptyArray, emptyArray); 12048 // In { [P in K]: T }, we refer to P as the type parameter type, K as the constraint type, 12049 // and T as the template type. 12050 const typeParameter = getTypeParameterFromMappedType(type); 12051 const constraintType = getConstraintTypeFromMappedType(type); 12052 const nameType = getNameTypeFromMappedType(type.target as MappedType || type); 12053 const templateType = getTemplateTypeFromMappedType(type.target as MappedType || type); 12054 const modifiersType = getApparentType(getModifiersTypeFromMappedType(type)); // The 'T' in 'keyof T' 12055 const templateModifiers = getMappedTypeModifiers(type); 12056 const include = keyofStringsOnly ? TypeFlags.StringLiteral : TypeFlags.StringOrNumberLiteralOrUnique; 12057 if (isMappedTypeWithKeyofConstraintDeclaration(type)) { 12058 // We have a { [P in keyof T]: X } 12059 forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType(modifiersType, include, keyofStringsOnly, addMemberForKeyType); 12060 } 12061 else { 12062 forEachType(getLowerBoundOfKeyType(constraintType), addMemberForKeyType); 12063 } 12064 setStructuredTypeMembers(type, members, emptyArray, emptyArray, indexInfos || emptyArray); 12065 12066 function addMemberForKeyType(keyType: Type) { 12067 const propNameType = nameType ? instantiateType(nameType, appendTypeMapping(type.mapper, typeParameter, keyType)) : keyType; 12068 forEachType(propNameType, t => addMemberForKeyTypeWorker(keyType, t)); 12069 } 12070 12071 function addMemberForKeyTypeWorker(keyType: Type, propNameType: Type) { 12072 // If the current iteration type constituent is a string literal type, create a property. 12073 // Otherwise, for type string create a string index signature. 12074 if (isTypeUsableAsPropertyName(propNameType)) { 12075 const propName = getPropertyNameFromType(propNameType); 12076 // String enum members from separate enums with identical values 12077 // are distinct types with the same property name. Make the resulting 12078 // property symbol's name type be the union of those enum member types. 12079 const existingProp = members.get(propName) as MappedSymbol | undefined; 12080 if (existingProp) { 12081 existingProp.nameType = getUnionType([existingProp.nameType!, propNameType]); 12082 existingProp.keyType = getUnionType([existingProp.keyType, keyType]); 12083 } 12084 else { 12085 const modifiersProp = isTypeUsableAsPropertyName(keyType) ? getPropertyOfType(modifiersType, getPropertyNameFromType(keyType)) : undefined; 12086 const isOptional = !!(templateModifiers & MappedTypeModifiers.IncludeOptional || 12087 !(templateModifiers & MappedTypeModifiers.ExcludeOptional) && modifiersProp && modifiersProp.flags & SymbolFlags.Optional); 12088 const isReadonly = !!(templateModifiers & MappedTypeModifiers.IncludeReadonly || 12089 !(templateModifiers & MappedTypeModifiers.ExcludeReadonly) && modifiersProp && isReadonlySymbol(modifiersProp)); 12090 const stripOptional = strictNullChecks && !isOptional && modifiersProp && modifiersProp.flags & SymbolFlags.Optional; 12091 const lateFlag: CheckFlags = modifiersProp ? getIsLateCheckFlag(modifiersProp) : 0; 12092 const prop = createSymbol(SymbolFlags.Property | (isOptional ? SymbolFlags.Optional : 0), propName, 12093 lateFlag | CheckFlags.Mapped | (isReadonly ? CheckFlags.Readonly : 0) | (stripOptional ? CheckFlags.StripOptional : 0)) as MappedSymbol; 12094 prop.mappedType = type; 12095 prop.nameType = propNameType; 12096 prop.keyType = keyType; 12097 if (modifiersProp) { 12098 prop.syntheticOrigin = modifiersProp; 12099 // If the mapped type has an `as XXX` clause, the property name likely won't match the declaration name and 12100 // multiple properties may map to the same name. Thus, we attach no declarations to the symbol. 12101 prop.declarations = nameType ? undefined : modifiersProp.declarations; 12102 } 12103 members.set(propName, prop); 12104 } 12105 } 12106 else if (isValidIndexKeyType(propNameType) || propNameType.flags & (TypeFlags.Any | TypeFlags.Enum)) { 12107 const indexKeyType = propNameType.flags & (TypeFlags.Any | TypeFlags.String) ? stringType : 12108 propNameType.flags & (TypeFlags.Number | TypeFlags.Enum) ? numberType : 12109 propNameType; 12110 const propType = instantiateType(templateType, appendTypeMapping(type.mapper, typeParameter, keyType)); 12111 const indexInfo = createIndexInfo(indexKeyType, propType, !!(templateModifiers & MappedTypeModifiers.IncludeReadonly)); 12112 indexInfos = appendIndexInfo(indexInfos, indexInfo, /*union*/ true); 12113 } 12114 } 12115 } 12116 12117 function getTypeOfMappedSymbol(symbol: MappedSymbol) { 12118 if (!symbol.type) { 12119 const mappedType = symbol.mappedType; 12120 if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) { 12121 mappedType.containsError = true; 12122 return errorType; 12123 } 12124 const templateType = getTemplateTypeFromMappedType(mappedType.target as MappedType || mappedType); 12125 const mapper = appendTypeMapping(mappedType.mapper, getTypeParameterFromMappedType(mappedType), symbol.keyType); 12126 const propType = instantiateType(templateType, mapper); 12127 // When creating an optional property in strictNullChecks mode, if 'undefined' isn't assignable to the 12128 // type, we include 'undefined' in the type. Similarly, when creating a non-optional property in strictNullChecks 12129 // mode, if the underlying property is optional we remove 'undefined' from the type. 12130 let type = strictNullChecks && symbol.flags & SymbolFlags.Optional && !maybeTypeOfKind(propType, TypeFlags.Undefined | TypeFlags.Void) ? getOptionalType(propType, /*isProperty*/ true) : 12131 symbol.checkFlags & CheckFlags.StripOptional ? removeMissingOrUndefinedType(propType) : 12132 propType; 12133 if (!popTypeResolution()) { 12134 error(currentNode, Diagnostics.Type_of_property_0_circularly_references_itself_in_mapped_type_1, symbolToString(symbol), typeToString(mappedType)); 12135 type = errorType; 12136 } 12137 symbol.type = type; 12138 } 12139 return symbol.type; 12140 } 12141 12142 function getTypeParameterFromMappedType(type: MappedType) { 12143 return type.typeParameter || 12144 (type.typeParameter = getDeclaredTypeOfTypeParameter(getSymbolOfNode(type.declaration.typeParameter))); 12145 } 12146 12147 function getConstraintTypeFromMappedType(type: MappedType) { 12148 return type.constraintType || 12149 (type.constraintType = getConstraintOfTypeParameter(getTypeParameterFromMappedType(type)) || errorType); 12150 } 12151 12152 function getNameTypeFromMappedType(type: MappedType) { 12153 return type.declaration.nameType ? 12154 type.nameType || (type.nameType = instantiateType(getTypeFromTypeNode(type.declaration.nameType), type.mapper)) : 12155 undefined; 12156 } 12157 12158 function getTemplateTypeFromMappedType(type: MappedType) { 12159 return type.templateType || 12160 (type.templateType = type.declaration.type ? 12161 instantiateType(addOptionality(getTypeFromTypeNode(type.declaration.type), /*isProperty*/ true, !!(getMappedTypeModifiers(type) & MappedTypeModifiers.IncludeOptional)), type.mapper) : 12162 errorType); 12163 } 12164 12165 function getConstraintDeclarationForMappedType(type: MappedType) { 12166 return getEffectiveConstraintOfTypeParameter(type.declaration.typeParameter); 12167 } 12168 12169 function isMappedTypeWithKeyofConstraintDeclaration(type: MappedType) { 12170 const constraintDeclaration = getConstraintDeclarationForMappedType(type)!; // TODO: GH#18217 12171 return constraintDeclaration.kind === SyntaxKind.TypeOperator && 12172 (constraintDeclaration as TypeOperatorNode).operator === SyntaxKind.KeyOfKeyword; 12173 } 12174 12175 function getModifiersTypeFromMappedType(type: MappedType) { 12176 if (!type.modifiersType) { 12177 if (isMappedTypeWithKeyofConstraintDeclaration(type)) { 12178 // If the constraint declaration is a 'keyof T' node, the modifiers type is T. We check 12179 // AST nodes here because, when T is a non-generic type, the logic below eagerly resolves 12180 // 'keyof T' to a literal union type and we can't recover T from that type. 12181 type.modifiersType = instantiateType(getTypeFromTypeNode((getConstraintDeclarationForMappedType(type) as TypeOperatorNode).type), type.mapper); 12182 } 12183 else { 12184 // Otherwise, get the declared constraint type, and if the constraint type is a type parameter, 12185 // get the constraint of that type parameter. If the resulting type is an indexed type 'keyof T', 12186 // the modifiers type is T. Otherwise, the modifiers type is unknown. 12187 const declaredType = getTypeFromMappedTypeNode(type.declaration) as MappedType; 12188 const constraint = getConstraintTypeFromMappedType(declaredType); 12189 const extendedConstraint = constraint && constraint.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(constraint as TypeParameter) : constraint; 12190 type.modifiersType = extendedConstraint && extendedConstraint.flags & TypeFlags.Index ? instantiateType((extendedConstraint as IndexType).type, type.mapper) : unknownType; 12191 } 12192 } 12193 return type.modifiersType; 12194 } 12195 12196 function getMappedTypeModifiers(type: MappedType): MappedTypeModifiers { 12197 const declaration = type.declaration; 12198 return (declaration.readonlyToken ? declaration.readonlyToken.kind === SyntaxKind.MinusToken ? MappedTypeModifiers.ExcludeReadonly : MappedTypeModifiers.IncludeReadonly : 0) | 12199 (declaration.questionToken ? declaration.questionToken.kind === SyntaxKind.MinusToken ? MappedTypeModifiers.ExcludeOptional : MappedTypeModifiers.IncludeOptional : 0); 12200 } 12201 12202 function getMappedTypeOptionality(type: MappedType): number { 12203 const modifiers = getMappedTypeModifiers(type); 12204 return modifiers & MappedTypeModifiers.ExcludeOptional ? -1 : modifiers & MappedTypeModifiers.IncludeOptional ? 1 : 0; 12205 } 12206 12207 function getCombinedMappedTypeOptionality(type: MappedType): number { 12208 const optionality = getMappedTypeOptionality(type); 12209 const modifiersType = getModifiersTypeFromMappedType(type); 12210 return optionality || (isGenericMappedType(modifiersType) ? getMappedTypeOptionality(modifiersType) : 0); 12211 } 12212 12213 function isPartialMappedType(type: Type) { 12214 return !!(getObjectFlags(type) & ObjectFlags.Mapped && getMappedTypeModifiers(type as MappedType) & MappedTypeModifiers.IncludeOptional); 12215 } 12216 12217 function isGenericMappedType(type: Type): type is MappedType { 12218 if (getObjectFlags(type) & ObjectFlags.Mapped) { 12219 const constraint = getConstraintTypeFromMappedType(type as MappedType); 12220 if (isGenericIndexType(constraint)) { 12221 return true; 12222 } 12223 // A mapped type is generic if the 'as' clause references generic types other than the iteration type. 12224 // To determine this, we substitute the constraint type (that we now know isn't generic) for the iteration 12225 // type and check whether the resulting type is generic. 12226 const nameType = getNameTypeFromMappedType(type as MappedType); 12227 if (nameType && isGenericIndexType(instantiateType(nameType, makeUnaryTypeMapper(getTypeParameterFromMappedType(type as MappedType), constraint)))) { 12228 return true; 12229 } 12230 } 12231 return false; 12232 } 12233 12234 function resolveStructuredTypeMembers(type: StructuredType): ResolvedType { 12235 if (!(type as ResolvedType).members) { 12236 if (type.flags & TypeFlags.Object) { 12237 if ((type as ObjectType).objectFlags & ObjectFlags.Reference) { 12238 resolveTypeReferenceMembers(type as TypeReference); 12239 } 12240 else if ((type as ObjectType).objectFlags & ObjectFlags.ClassOrInterface) { 12241 resolveClassOrInterfaceMembers(type as InterfaceType); 12242 } 12243 else if ((type as ReverseMappedType).objectFlags & ObjectFlags.ReverseMapped) { 12244 resolveReverseMappedTypeMembers(type as ReverseMappedType); 12245 } 12246 else if ((type as ObjectType).objectFlags & ObjectFlags.Anonymous) { 12247 resolveAnonymousTypeMembers(type as AnonymousType); 12248 } 12249 else if ((type as MappedType).objectFlags & ObjectFlags.Mapped) { 12250 resolveMappedTypeMembers(type as MappedType); 12251 } 12252 else { 12253 Debug.fail("Unhandled object type " + Debug.formatObjectFlags(type.objectFlags)); 12254 } 12255 } 12256 else if (type.flags & TypeFlags.Union) { 12257 resolveUnionTypeMembers(type as UnionType); 12258 } 12259 else if (type.flags & TypeFlags.Intersection) { 12260 resolveIntersectionTypeMembers(type as IntersectionType); 12261 } 12262 else { 12263 Debug.fail("Unhandled type " + Debug.formatTypeFlags(type.flags)); 12264 } 12265 } 12266 return type as ResolvedType; 12267 } 12268 12269 /** Return properties of an object type or an empty array for other types */ 12270 function getPropertiesOfObjectType(type: Type): Symbol[] { 12271 if (type.flags & TypeFlags.Object) { 12272 return resolveStructuredTypeMembers(type as ObjectType).properties; 12273 } 12274 return emptyArray; 12275 } 12276 12277 /** If the given type is an object type and that type has a property by the given name, 12278 * return the symbol for that property. Otherwise return undefined. 12279 */ 12280 function getPropertyOfObjectType(type: Type, name: __String): Symbol | undefined { 12281 if (type.flags & TypeFlags.Object) { 12282 const resolved = resolveStructuredTypeMembers(type as ObjectType); 12283 const symbol = resolved.members.get(name); 12284 if (symbol && symbolIsValue(symbol)) { 12285 return symbol; 12286 } 12287 } 12288 } 12289 12290 function getPropertiesOfUnionOrIntersectionType(type: UnionOrIntersectionType): Symbol[] { 12291 if (!type.resolvedProperties) { 12292 const members = createSymbolTable(); 12293 for (const current of type.types) { 12294 for (const prop of getPropertiesOfType(current)) { 12295 if (!members.has(prop.escapedName)) { 12296 const combinedProp = getPropertyOfUnionOrIntersectionType(type, prop.escapedName); 12297 if (combinedProp) { 12298 members.set(prop.escapedName, combinedProp); 12299 } 12300 } 12301 } 12302 // The properties of a union type are those that are present in all constituent types, so 12303 // we only need to check the properties of the first type without index signature 12304 if (type.flags & TypeFlags.Union && getIndexInfosOfType(current).length === 0) { 12305 break; 12306 } 12307 } 12308 type.resolvedProperties = getNamedMembers(members); 12309 } 12310 return type.resolvedProperties; 12311 } 12312 12313 function getPropertiesOfType(type: Type): Symbol[] { 12314 type = getReducedApparentType(type); 12315 return type.flags & TypeFlags.UnionOrIntersection ? 12316 getPropertiesOfUnionOrIntersectionType(type as UnionType) : 12317 getPropertiesOfObjectType(type); 12318 } 12319 12320 function forEachPropertyOfType(type: Type, action: (symbol: Symbol, escapedName: __String) => void): void { 12321 type = getReducedApparentType(type); 12322 if (type.flags & TypeFlags.StructuredType) { 12323 resolveStructuredTypeMembers(type as StructuredType).members.forEach((symbol, escapedName) => { 12324 if (isNamedMember(symbol, escapedName)) { 12325 action(symbol, escapedName); 12326 } 12327 }); 12328 } 12329 } 12330 12331 function isTypeInvalidDueToUnionDiscriminant(contextualType: Type, obj: ObjectLiteralExpression | JsxAttributes): boolean { 12332 const list = obj.properties as NodeArray<ObjectLiteralElementLike | JsxAttributeLike>; 12333 return list.some(property => { 12334 const nameType = property.name && getLiteralTypeFromPropertyName(property.name); 12335 const name = nameType && isTypeUsableAsPropertyName(nameType) ? getPropertyNameFromType(nameType) : undefined; 12336 const expected = name === undefined ? undefined : getTypeOfPropertyOfType(contextualType, name); 12337 return !!expected && isLiteralType(expected) && !isTypeAssignableTo(getTypeOfNode(property), expected); 12338 }); 12339 } 12340 12341 function getAllPossiblePropertiesOfTypes(types: readonly Type[]): Symbol[] { 12342 const unionType = getUnionType(types); 12343 if (!(unionType.flags & TypeFlags.Union)) { 12344 return getAugmentedPropertiesOfType(unionType); 12345 } 12346 12347 const props = createSymbolTable(); 12348 for (const memberType of types) { 12349 for (const { escapedName } of getAugmentedPropertiesOfType(memberType)) { 12350 if (!props.has(escapedName)) { 12351 const prop = createUnionOrIntersectionProperty(unionType as UnionType, escapedName); 12352 // May be undefined if the property is private 12353 if (prop) props.set(escapedName, prop); 12354 } 12355 } 12356 } 12357 return arrayFrom(props.values()); 12358 } 12359 12360 function getConstraintOfType(type: InstantiableType | UnionOrIntersectionType): Type | undefined { 12361 return type.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(type as TypeParameter) : 12362 type.flags & TypeFlags.IndexedAccess ? getConstraintOfIndexedAccess(type as IndexedAccessType) : 12363 type.flags & TypeFlags.Conditional ? getConstraintOfConditionalType(type as ConditionalType) : 12364 getBaseConstraintOfType(type); 12365 } 12366 12367 function getConstraintOfTypeParameter(typeParameter: TypeParameter): Type | undefined { 12368 return hasNonCircularBaseConstraint(typeParameter) ? getConstraintFromTypeParameter(typeParameter) : undefined; 12369 } 12370 12371 function getConstraintOfIndexedAccess(type: IndexedAccessType) { 12372 return hasNonCircularBaseConstraint(type) ? getConstraintFromIndexedAccess(type) : undefined; 12373 } 12374 12375 function getSimplifiedTypeOrConstraint(type: Type) { 12376 const simplified = getSimplifiedType(type, /*writing*/ false); 12377 return simplified !== type ? simplified : getConstraintOfType(type); 12378 } 12379 12380 function getConstraintFromIndexedAccess(type: IndexedAccessType) { 12381 if (isMappedTypeGenericIndexedAccess(type)) { 12382 // For indexed access types of the form { [P in K]: E }[X], where K is non-generic and X is generic, 12383 // we substitute an instantiation of E where P is replaced with X. 12384 return substituteIndexedMappedType(type.objectType as MappedType, type.indexType); 12385 } 12386 const indexConstraint = getSimplifiedTypeOrConstraint(type.indexType); 12387 if (indexConstraint && indexConstraint !== type.indexType) { 12388 const indexedAccess = getIndexedAccessTypeOrUndefined(type.objectType, indexConstraint, type.accessFlags); 12389 if (indexedAccess) { 12390 return indexedAccess; 12391 } 12392 } 12393 const objectConstraint = getSimplifiedTypeOrConstraint(type.objectType); 12394 if (objectConstraint && objectConstraint !== type.objectType) { 12395 return getIndexedAccessTypeOrUndefined(objectConstraint, type.indexType, type.accessFlags); 12396 } 12397 return undefined; 12398 } 12399 12400 function getDefaultConstraintOfConditionalType(type: ConditionalType) { 12401 if (!type.resolvedDefaultConstraint) { 12402 // An `any` branch of a conditional type would normally be viral - specifically, without special handling here, 12403 // a conditional type with a single branch of type `any` would be assignable to anything, since it's constraint would simplify to 12404 // just `any`. This result is _usually_ unwanted - so instead here we elide an `any` branch from the constraint type, 12405 // in effect treating `any` like `never` rather than `unknown` in this location. 12406 const trueConstraint = getInferredTrueTypeFromConditionalType(type); 12407 const falseConstraint = getFalseTypeFromConditionalType(type); 12408 type.resolvedDefaultConstraint = isTypeAny(trueConstraint) ? falseConstraint : isTypeAny(falseConstraint) ? trueConstraint : getUnionType([trueConstraint, falseConstraint]); 12409 } 12410 return type.resolvedDefaultConstraint; 12411 } 12412 12413 function getConstraintOfDistributiveConditionalType(type: ConditionalType): Type | undefined { 12414 // Check if we have a conditional type of the form 'T extends U ? X : Y', where T is a constrained 12415 // type parameter. If so, create an instantiation of the conditional type where T is replaced 12416 // with its constraint. We do this because if the constraint is a union type it will be distributed 12417 // over the conditional type and possibly reduced. For example, 'T extends undefined ? never : T' 12418 // removes 'undefined' from T. 12419 // We skip returning a distributive constraint for a restrictive instantiation of a conditional type 12420 // as the constraint for all type params (check type included) have been replace with `unknown`, which 12421 // is going to produce even more false positive/negative results than the distribute constraint already does. 12422 // Please note: the distributive constraint is a kludge for emulating what a negated type could to do filter 12423 // a union - once negated types exist and are applied to the conditional false branch, this "constraint" 12424 // likely doesn't need to exist. 12425 if (type.root.isDistributive && type.restrictiveInstantiation !== type) { 12426 const simplified = getSimplifiedType(type.checkType, /*writing*/ false); 12427 const constraint = simplified === type.checkType ? getConstraintOfType(simplified) : simplified; 12428 if (constraint && constraint !== type.checkType) { 12429 const instantiated = getConditionalTypeInstantiation(type, prependTypeMapping(type.root.checkType, constraint, type.mapper)); 12430 if (!(instantiated.flags & TypeFlags.Never)) { 12431 return instantiated; 12432 } 12433 } 12434 } 12435 return undefined; 12436 } 12437 12438 function getConstraintFromConditionalType(type: ConditionalType) { 12439 return getConstraintOfDistributiveConditionalType(type) || getDefaultConstraintOfConditionalType(type); 12440 } 12441 12442 function getConstraintOfConditionalType(type: ConditionalType) { 12443 return hasNonCircularBaseConstraint(type) ? getConstraintFromConditionalType(type) : undefined; 12444 } 12445 12446 function getEffectiveConstraintOfIntersection(types: readonly Type[], targetIsUnion: boolean) { 12447 let constraints: Type[] | undefined; 12448 let hasDisjointDomainType = false; 12449 for (const t of types) { 12450 if (t.flags & TypeFlags.Instantiable) { 12451 // We keep following constraints as long as we have an instantiable type that is known 12452 // not to be circular or infinite (hence we stop on index access types). 12453 let constraint = getConstraintOfType(t); 12454 while (constraint && constraint.flags & (TypeFlags.TypeParameter | TypeFlags.Index | TypeFlags.Conditional)) { 12455 constraint = getConstraintOfType(constraint); 12456 } 12457 if (constraint) { 12458 constraints = append(constraints, constraint); 12459 if (targetIsUnion) { 12460 constraints = append(constraints, t); 12461 } 12462 } 12463 } 12464 else if (t.flags & TypeFlags.DisjointDomains || isEmptyAnonymousObjectType(t)) { 12465 hasDisjointDomainType = true; 12466 } 12467 } 12468 // If the target is a union type or if we are intersecting with types belonging to one of the 12469 // disjoint domains, we may end up producing a constraint that hasn't been examined before. 12470 if (constraints && (targetIsUnion || hasDisjointDomainType)) { 12471 if (hasDisjointDomainType) { 12472 // We add any types belong to one of the disjoint domains because they might cause the final 12473 // intersection operation to reduce the union constraints. 12474 for (const t of types) { 12475 if (t.flags & TypeFlags.DisjointDomains || isEmptyAnonymousObjectType(t)) { 12476 constraints = append(constraints, t); 12477 } 12478 } 12479 } 12480 // The source types were normalized; ensure the result is normalized too. 12481 return getNormalizedType(getIntersectionType(constraints), /*writing*/ false); 12482 } 12483 return undefined; 12484 } 12485 12486 function getBaseConstraintOfType(type: Type): Type | undefined { 12487 if (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral | TypeFlags.StringMapping)) { 12488 const constraint = getResolvedBaseConstraint(type as InstantiableType | UnionOrIntersectionType); 12489 return constraint !== noConstraintType && constraint !== circularConstraintType ? constraint : undefined; 12490 } 12491 return type.flags & TypeFlags.Index ? keyofConstraintType : undefined; 12492 } 12493 12494 /** 12495 * This is similar to `getBaseConstraintOfType` except it returns the input type if there's no base constraint, instead of `undefined` 12496 * It also doesn't map indexes to `string`, as where this is used this would be unneeded (and likely undesirable) 12497 */ 12498 function getBaseConstraintOrType(type: Type) { 12499 return getBaseConstraintOfType(type) || type; 12500 } 12501 12502 function hasNonCircularBaseConstraint(type: InstantiableType): boolean { 12503 return getResolvedBaseConstraint(type) !== circularConstraintType; 12504 } 12505 12506 /** 12507 * Return the resolved base constraint of a type variable. The noConstraintType singleton is returned if the 12508 * type variable has no constraint, and the circularConstraintType singleton is returned if the constraint 12509 * circularly references the type variable. 12510 */ 12511 function getResolvedBaseConstraint(type: InstantiableType | UnionOrIntersectionType): Type { 12512 if (type.resolvedBaseConstraint) { 12513 return type.resolvedBaseConstraint; 12514 } 12515 const stack: object[] = []; 12516 return type.resolvedBaseConstraint = getTypeWithThisArgument(getImmediateBaseConstraint(type), type); 12517 12518 function getImmediateBaseConstraint(t: Type): Type { 12519 if (!t.immediateBaseConstraint) { 12520 if (!pushTypeResolution(t, TypeSystemPropertyName.ImmediateBaseConstraint)) { 12521 return circularConstraintType; 12522 } 12523 let result; 12524 // We always explore at least 10 levels of nested constraints. Thereafter, we continue to explore 12525 // up to 50 levels of nested constraints provided there are no "deeply nested" types on the stack 12526 // (i.e. no types for which five instantiations have been recorded on the stack). If we reach 50 12527 // levels of nesting, we are presumably exploring a repeating pattern with a long cycle that hasn't 12528 // yet triggered the deeply nested limiter. We have no test cases that actually get to 50 levels of 12529 // nesting, so it is effectively just a safety stop. 12530 const identity = getRecursionIdentity(t); 12531 if (stack.length < 10 || stack.length < 50 && !contains(stack, identity)) { 12532 stack.push(identity); 12533 result = computeBaseConstraint(getSimplifiedType(t, /*writing*/ false)); 12534 stack.pop(); 12535 } 12536 if (!popTypeResolution()) { 12537 if (t.flags & TypeFlags.TypeParameter) { 12538 const errorNode = getConstraintDeclaration(t as TypeParameter); 12539 if (errorNode) { 12540 const diagnostic = error(errorNode, Diagnostics.Type_parameter_0_has_a_circular_constraint, typeToString(t)); 12541 if (currentNode && !isNodeDescendantOf(errorNode, currentNode) && !isNodeDescendantOf(currentNode, errorNode)) { 12542 addRelatedInfo(diagnostic, createDiagnosticForNode(currentNode, Diagnostics.Circularity_originates_in_type_at_this_location)); 12543 } 12544 } 12545 } 12546 result = circularConstraintType; 12547 } 12548 t.immediateBaseConstraint = result || noConstraintType; 12549 } 12550 return t.immediateBaseConstraint; 12551 } 12552 12553 function getBaseConstraint(t: Type): Type | undefined { 12554 const c = getImmediateBaseConstraint(t); 12555 return c !== noConstraintType && c !== circularConstraintType ? c : undefined; 12556 } 12557 12558 function computeBaseConstraint(t: Type): Type | undefined { 12559 if (t.flags & TypeFlags.TypeParameter) { 12560 const constraint = getConstraintFromTypeParameter(t as TypeParameter); 12561 return (t as TypeParameter).isThisType || !constraint ? 12562 constraint : 12563 getBaseConstraint(constraint); 12564 } 12565 if (t.flags & TypeFlags.UnionOrIntersection) { 12566 const types = (t as UnionOrIntersectionType).types; 12567 const baseTypes: Type[] = []; 12568 let different = false; 12569 for (const type of types) { 12570 const baseType = getBaseConstraint(type); 12571 if (baseType) { 12572 if (baseType !== type) { 12573 different = true; 12574 } 12575 baseTypes.push(baseType); 12576 } 12577 else { 12578 different = true; 12579 } 12580 } 12581 if (!different) { 12582 return t; 12583 } 12584 return t.flags & TypeFlags.Union && baseTypes.length === types.length ? getUnionType(baseTypes) : 12585 t.flags & TypeFlags.Intersection && baseTypes.length ? getIntersectionType(baseTypes) : 12586 undefined; 12587 } 12588 if (t.flags & TypeFlags.Index) { 12589 return keyofConstraintType; 12590 } 12591 if (t.flags & TypeFlags.TemplateLiteral) { 12592 const types = (t as TemplateLiteralType).types; 12593 const constraints = mapDefined(types, getBaseConstraint); 12594 return constraints.length === types.length ? getTemplateLiteralType((t as TemplateLiteralType).texts, constraints) : stringType; 12595 } 12596 if (t.flags & TypeFlags.StringMapping) { 12597 const constraint = getBaseConstraint((t as StringMappingType).type); 12598 return constraint && constraint !== (t as StringMappingType).type ? getStringMappingType((t as StringMappingType).symbol, constraint) : stringType; 12599 } 12600 if (t.flags & TypeFlags.IndexedAccess) { 12601 if (isMappedTypeGenericIndexedAccess(t)) { 12602 // For indexed access types of the form { [P in K]: E }[X], where K is non-generic and X is generic, 12603 // we substitute an instantiation of E where P is replaced with X. 12604 return getBaseConstraint(substituteIndexedMappedType((t as IndexedAccessType).objectType as MappedType, (t as IndexedAccessType).indexType)); 12605 } 12606 const baseObjectType = getBaseConstraint((t as IndexedAccessType).objectType); 12607 const baseIndexType = getBaseConstraint((t as IndexedAccessType).indexType); 12608 const baseIndexedAccess = baseObjectType && baseIndexType && getIndexedAccessTypeOrUndefined(baseObjectType, baseIndexType, (t as IndexedAccessType).accessFlags); 12609 return baseIndexedAccess && getBaseConstraint(baseIndexedAccess); 12610 } 12611 if (t.flags & TypeFlags.Conditional) { 12612 const constraint = getConstraintFromConditionalType(t as ConditionalType); 12613 return constraint && getBaseConstraint(constraint); 12614 } 12615 if (t.flags & TypeFlags.Substitution) { 12616 return getBaseConstraint(getSubstitutionIntersection(t as SubstitutionType)); 12617 } 12618 return t; 12619 } 12620 } 12621 12622 function getApparentTypeOfIntersectionType(type: IntersectionType) { 12623 return type.resolvedApparentType || (type.resolvedApparentType = getTypeWithThisArgument(type, type, /*apparentType*/ true)); 12624 } 12625 12626 function getResolvedTypeParameterDefault(typeParameter: TypeParameter): Type | undefined { 12627 if (!typeParameter.default) { 12628 if (typeParameter.target) { 12629 const targetDefault = getResolvedTypeParameterDefault(typeParameter.target); 12630 typeParameter.default = targetDefault ? instantiateType(targetDefault, typeParameter.mapper) : noConstraintType; 12631 } 12632 else { 12633 // To block recursion, set the initial value to the resolvingDefaultType. 12634 typeParameter.default = resolvingDefaultType; 12635 const defaultDeclaration = typeParameter.symbol && forEach(typeParameter.symbol.declarations, decl => isTypeParameterDeclaration(decl) && decl.default); 12636 const defaultType = defaultDeclaration ? getTypeFromTypeNode(defaultDeclaration) : noConstraintType; 12637 if (typeParameter.default === resolvingDefaultType) { 12638 // If we have not been called recursively, set the correct default type. 12639 typeParameter.default = defaultType; 12640 } 12641 } 12642 } 12643 else if (typeParameter.default === resolvingDefaultType) { 12644 // If we are called recursively for this type parameter, mark the default as circular. 12645 typeParameter.default = circularConstraintType; 12646 } 12647 return typeParameter.default; 12648 } 12649 12650 /** 12651 * Gets the default type for a type parameter. 12652 * 12653 * If the type parameter is the result of an instantiation, this gets the instantiated 12654 * default type of its target. If the type parameter has no default type or the default is 12655 * circular, `undefined` is returned. 12656 */ 12657 function getDefaultFromTypeParameter(typeParameter: TypeParameter): Type | undefined { 12658 const defaultType = getResolvedTypeParameterDefault(typeParameter); 12659 return defaultType !== noConstraintType && defaultType !== circularConstraintType ? defaultType : undefined; 12660 } 12661 12662 function hasNonCircularTypeParameterDefault(typeParameter: TypeParameter) { 12663 return getResolvedTypeParameterDefault(typeParameter) !== circularConstraintType; 12664 } 12665 12666 /** 12667 * Indicates whether the declaration of a typeParameter has a default type. 12668 */ 12669 function hasTypeParameterDefault(typeParameter: TypeParameter): boolean { 12670 return !!(typeParameter.symbol && forEach(typeParameter.symbol.declarations, decl => isTypeParameterDeclaration(decl) && decl.default)); 12671 } 12672 12673 function getApparentTypeOfMappedType(type: MappedType) { 12674 return type.resolvedApparentType || (type.resolvedApparentType = getResolvedApparentTypeOfMappedType(type)); 12675 } 12676 12677 function getResolvedApparentTypeOfMappedType(type: MappedType) { 12678 const typeVariable = getHomomorphicTypeVariable(type); 12679 if (typeVariable && !type.declaration.nameType) { 12680 const constraint = getConstraintOfTypeParameter(typeVariable); 12681 if (constraint && isArrayOrTupleType(constraint)) { 12682 return instantiateType(type, prependTypeMapping(typeVariable, constraint, type.mapper)); 12683 } 12684 } 12685 return type; 12686 } 12687 12688 function isMappedTypeGenericIndexedAccess(type: Type) { 12689 let objectType; 12690 return !!(type.flags & TypeFlags.IndexedAccess && getObjectFlags(objectType = (type as IndexedAccessType).objectType) & ObjectFlags.Mapped && 12691 !isGenericMappedType(objectType) && isGenericIndexType((type as IndexedAccessType).indexType) && 12692 !(getMappedTypeModifiers(objectType as MappedType) & MappedTypeModifiers.ExcludeOptional) && !(objectType as MappedType).declaration.nameType); 12693 } 12694 12695 /** 12696 * For a type parameter, return the base constraint of the type parameter. For the string, number, 12697 * boolean, and symbol primitive types, return the corresponding object types. Otherwise return the 12698 * type itself. 12699 */ 12700 function getApparentType(type: Type): Type { 12701 const t = !(type.flags & TypeFlags.Instantiable) ? type : getBaseConstraintOfType(type) || unknownType; 12702 return getObjectFlags(t) & ObjectFlags.Mapped ? getApparentTypeOfMappedType(t as MappedType) : 12703 t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(t as IntersectionType) : 12704 t.flags & TypeFlags.StringLike ? globalStringType : 12705 t.flags & TypeFlags.NumberLike ? globalNumberType : 12706 t.flags & TypeFlags.BigIntLike ? getGlobalBigIntType() : 12707 t.flags & TypeFlags.BooleanLike ? globalBooleanType : 12708 t.flags & TypeFlags.ESSymbolLike ? getGlobalESSymbolType() : 12709 t.flags & TypeFlags.NonPrimitive ? emptyObjectType : 12710 t.flags & TypeFlags.Index ? keyofConstraintType : 12711 t.flags & TypeFlags.Unknown && !strictNullChecks ? emptyObjectType : 12712 t; 12713 } 12714 12715 function getReducedApparentType(type: Type): Type { 12716 // Since getApparentType may return a non-reduced union or intersection type, we need to perform 12717 // type reduction both before and after obtaining the apparent type. For example, given a type parameter 12718 // 'T extends A | B', the type 'T & X' becomes 'A & X | B & X' after obtaining the apparent type, and 12719 // that type may need further reduction to remove empty intersections. 12720 return getReducedType(getApparentType(getReducedType(type))); 12721 } 12722 12723 function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: __String, skipObjectFunctionPropertyAugment?: boolean): Symbol | undefined { 12724 let singleProp: Symbol | undefined; 12725 let propSet: ESMap<SymbolId, Symbol> | undefined; 12726 let indexTypes: Type[] | undefined; 12727 const isUnion = containingType.flags & TypeFlags.Union; 12728 // Flags we want to propagate to the result if they exist in all source symbols 12729 let optionalFlag: SymbolFlags | undefined; 12730 let syntheticFlag = CheckFlags.SyntheticMethod; 12731 let checkFlags = isUnion ? 0 : CheckFlags.Readonly; 12732 let mergedInstantiations = false; 12733 for (const current of containingType.types) { 12734 const type = getApparentType(current); 12735 if (!(isErrorType(type) || type.flags & TypeFlags.Never)) { 12736 const prop = getPropertyOfType(type, name, skipObjectFunctionPropertyAugment); 12737 const modifiers = prop ? getDeclarationModifierFlagsFromSymbol(prop) : 0; 12738 if (prop) { 12739 if (prop.flags & SymbolFlags.ClassMember) { 12740 optionalFlag ??= isUnion ? SymbolFlags.None : SymbolFlags.Optional; 12741 if (isUnion) { 12742 optionalFlag |= (prop.flags & SymbolFlags.Optional); 12743 } 12744 else { 12745 optionalFlag &= prop.flags; 12746 } 12747 } 12748 if (!singleProp) { 12749 singleProp = prop; 12750 } 12751 else if (prop !== singleProp) { 12752 const isInstantiation = (getTargetSymbol(prop) || prop) === (getTargetSymbol(singleProp) || singleProp); 12753 // If the symbols are instances of one another with identical types - consider the symbols 12754 // equivalent and just use the first one, which thus allows us to avoid eliding private 12755 // members when intersecting a (this-)instantiations of a class with its raw base or another instance 12756 if (isInstantiation && compareProperties(singleProp, prop, (a, b) => a === b ? Ternary.True : Ternary.False) === Ternary.True) { 12757 // If we merged instantiations of a generic type, we replicate the symbol parent resetting behavior we used 12758 // to do when we recorded multiple distinct symbols so that we still get, eg, `Array<T>.length` printed 12759 // back and not `Array<string>.length` when we're looking at a `.length` access on a `string[] | number[]` 12760 mergedInstantiations = !!singleProp.parent && !!length(getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(singleProp.parent)); 12761 } 12762 else { 12763 if (!propSet) { 12764 propSet = new Map<SymbolId, Symbol>(); 12765 propSet.set(getSymbolId(singleProp), singleProp); 12766 } 12767 const id = getSymbolId(prop); 12768 if (!propSet.has(id)) { 12769 propSet.set(id, prop); 12770 } 12771 } 12772 } 12773 if (isUnion && isReadonlySymbol(prop)) { 12774 checkFlags |= CheckFlags.Readonly; 12775 } 12776 else if (!isUnion && !isReadonlySymbol(prop)) { 12777 checkFlags &= ~CheckFlags.Readonly; 12778 } 12779 checkFlags |= (!(modifiers & ModifierFlags.NonPublicAccessibilityModifier) ? CheckFlags.ContainsPublic : 0) | 12780 (modifiers & ModifierFlags.Protected ? CheckFlags.ContainsProtected : 0) | 12781 (modifiers & ModifierFlags.Private ? CheckFlags.ContainsPrivate : 0) | 12782 (modifiers & ModifierFlags.Static ? CheckFlags.ContainsStatic : 0); 12783 if (!isPrototypeProperty(prop)) { 12784 syntheticFlag = CheckFlags.SyntheticProperty; 12785 } 12786 } 12787 else if (isUnion) { 12788 const indexInfo = !isLateBoundName(name) && getApplicableIndexInfoForName(type, name); 12789 if (indexInfo) { 12790 checkFlags |= CheckFlags.WritePartial | (indexInfo.isReadonly ? CheckFlags.Readonly : 0); 12791 indexTypes = append(indexTypes, isTupleType(type) ? getRestTypeOfTupleType(type) || undefinedType : indexInfo.type); 12792 } 12793 else if (isObjectLiteralType(type) && !(getObjectFlags(type) & ObjectFlags.ContainsSpread)) { 12794 checkFlags |= CheckFlags.WritePartial; 12795 indexTypes = append(indexTypes, undefinedType); 12796 } 12797 else { 12798 checkFlags |= CheckFlags.ReadPartial; 12799 } 12800 } 12801 } 12802 } 12803 if (!singleProp || 12804 isUnion && 12805 (propSet || checkFlags & CheckFlags.Partial) && 12806 checkFlags & (CheckFlags.ContainsPrivate | CheckFlags.ContainsProtected) && 12807 !(propSet && getCommonDeclarationsOfSymbols(arrayFrom(propSet.values()))) 12808 ) { 12809 // No property was found, or, in a union, a property has a private or protected declaration in one 12810 // constituent, but is missing or has a different declaration in another constituent. 12811 return undefined; 12812 } 12813 if (!propSet && !(checkFlags & CheckFlags.ReadPartial) && !indexTypes) { 12814 if (mergedInstantiations) { 12815 // No symbol from a union/intersection should have a `.parent` set (since unions/intersections don't act as symbol parents) 12816 // Unless that parent is "reconstituted" from the "first value declaration" on the symbol (which is likely different than its instantiated parent!) 12817 // They also have a `.containingType` set, which affects some services endpoints behavior, like `getRootSymbol` 12818 const clone = createSymbolWithType(singleProp, (singleProp as TransientSymbol).type); 12819 clone.parent = singleProp.valueDeclaration?.symbol?.parent; 12820 clone.containingType = containingType; 12821 clone.mapper = (singleProp as TransientSymbol).mapper; 12822 return clone; 12823 } 12824 else { 12825 return singleProp; 12826 } 12827 } 12828 const props = propSet ? arrayFrom(propSet.values()) : [singleProp]; 12829 let declarations: Declaration[] | undefined; 12830 let firstType: Type | undefined; 12831 let nameType: Type | undefined; 12832 const propTypes: Type[] = []; 12833 let writeTypes: Type[] | undefined; 12834 let firstValueDeclaration: Declaration | undefined; 12835 let hasNonUniformValueDeclaration = false; 12836 for (const prop of props) { 12837 if (!firstValueDeclaration) { 12838 firstValueDeclaration = prop.valueDeclaration; 12839 } 12840 else if (prop.valueDeclaration && prop.valueDeclaration !== firstValueDeclaration) { 12841 hasNonUniformValueDeclaration = true; 12842 } 12843 declarations = addRange(declarations, prop.declarations); 12844 const type = getTypeOfSymbol(prop); 12845 if (!firstType) { 12846 firstType = type; 12847 nameType = getSymbolLinks(prop).nameType; 12848 } 12849 const writeType = getWriteTypeOfSymbol(prop); 12850 if (writeTypes || writeType !== type) { 12851 writeTypes = append(!writeTypes ? propTypes.slice() : writeTypes, writeType); 12852 } 12853 else if (type !== firstType) { 12854 checkFlags |= CheckFlags.HasNonUniformType; 12855 } 12856 if (isLiteralType(type) || isPatternLiteralType(type) || type === uniqueLiteralType) { 12857 checkFlags |= CheckFlags.HasLiteralType; 12858 } 12859 if (type.flags & TypeFlags.Never && type !== uniqueLiteralType) { 12860 checkFlags |= CheckFlags.HasNeverType; 12861 } 12862 propTypes.push(type); 12863 } 12864 addRange(propTypes, indexTypes); 12865 const result = createSymbol(SymbolFlags.Property | (optionalFlag ?? 0), name, syntheticFlag | checkFlags); 12866 result.containingType = containingType; 12867 if (!hasNonUniformValueDeclaration && firstValueDeclaration) { 12868 result.valueDeclaration = firstValueDeclaration; 12869 12870 // Inherit information about parent type. 12871 if (firstValueDeclaration.symbol.parent) { 12872 result.parent = firstValueDeclaration.symbol.parent; 12873 } 12874 } 12875 12876 result.declarations = declarations; 12877 result.nameType = nameType; 12878 if (propTypes.length > 2) { 12879 // When `propTypes` has the potential to explode in size when normalized, defer normalization until absolutely needed 12880 result.checkFlags |= CheckFlags.DeferredType; 12881 result.deferralParent = containingType; 12882 result.deferralConstituents = propTypes; 12883 result.deferralWriteConstituents = writeTypes; 12884 } 12885 else { 12886 result.type = isUnion ? getUnionType(propTypes) : getIntersectionType(propTypes); 12887 if (writeTypes) { 12888 result.writeType = isUnion ? getUnionType(writeTypes) : getIntersectionType(writeTypes); 12889 } 12890 } 12891 return result; 12892 } 12893 12894 // Return the symbol for a given property in a union or intersection type, or undefined if the property 12895 // does not exist in any constituent type. Note that the returned property may only be present in some 12896 // constituents, in which case the isPartial flag is set when the containing type is union type. We need 12897 // these partial properties when identifying discriminant properties, but otherwise they are filtered out 12898 // and do not appear to be present in the union type. 12899 function getUnionOrIntersectionProperty(type: UnionOrIntersectionType, name: __String, skipObjectFunctionPropertyAugment?: boolean): Symbol | undefined { 12900 let property = type.propertyCacheWithoutObjectFunctionPropertyAugment?.get(name) || 12901 !skipObjectFunctionPropertyAugment ? type.propertyCache?.get(name) : undefined; 12902 if (!property) { 12903 property = createUnionOrIntersectionProperty(type, name, skipObjectFunctionPropertyAugment); 12904 if (property) { 12905 const properties = skipObjectFunctionPropertyAugment ? 12906 type.propertyCacheWithoutObjectFunctionPropertyAugment ||= createSymbolTable() : 12907 type.propertyCache ||= createSymbolTable(); 12908 properties.set(name, property); 12909 } 12910 } 12911 return property; 12912 } 12913 12914 function getCommonDeclarationsOfSymbols(symbols: readonly Symbol[]) { 12915 let commonDeclarations: Set<Node> | undefined; 12916 for (const symbol of symbols) { 12917 if (!symbol.declarations) { 12918 return undefined; 12919 } 12920 if (!commonDeclarations) { 12921 commonDeclarations = new Set(symbol.declarations); 12922 continue; 12923 } 12924 commonDeclarations.forEach(declaration => { 12925 if (!contains(symbol.declarations, declaration)) { 12926 commonDeclarations!.delete(declaration); 12927 } 12928 }); 12929 if (commonDeclarations.size === 0) { 12930 return undefined; 12931 } 12932 } 12933 return commonDeclarations; 12934 } 12935 12936 function getPropertyOfUnionOrIntersectionType(type: UnionOrIntersectionType, name: __String, skipObjectFunctionPropertyAugment?: boolean): Symbol | undefined { 12937 const property = getUnionOrIntersectionProperty(type, name, skipObjectFunctionPropertyAugment); 12938 // We need to filter out partial properties in union types 12939 return property && !(getCheckFlags(property) & CheckFlags.ReadPartial) ? property : undefined; 12940 } 12941 12942 /** 12943 * Return the reduced form of the given type. For a union type, it is a union of the normalized constituent types. 12944 * For an intersection of types containing one or more mututally exclusive discriminant properties, it is 'never'. 12945 * For all other types, it is simply the type itself. Discriminant properties are considered mutually exclusive when 12946 * no constituent property has type 'never', but the intersection of the constituent property types is 'never'. 12947 */ 12948 function getReducedType(type: Type): Type { 12949 if (type.flags & TypeFlags.Union && (type as UnionType).objectFlags & ObjectFlags.ContainsIntersections) { 12950 return (type as UnionType).resolvedReducedType || ((type as UnionType).resolvedReducedType = getReducedUnionType(type as UnionType)); 12951 } 12952 else if (type.flags & TypeFlags.Intersection) { 12953 if (!((type as IntersectionType).objectFlags & ObjectFlags.IsNeverIntersectionComputed)) { 12954 (type as IntersectionType).objectFlags |= ObjectFlags.IsNeverIntersectionComputed | 12955 (some(getPropertiesOfUnionOrIntersectionType(type as IntersectionType), isNeverReducedProperty) ? ObjectFlags.IsNeverIntersection : 0); 12956 } 12957 return (type as IntersectionType).objectFlags & ObjectFlags.IsNeverIntersection ? neverType : type; 12958 } 12959 return type; 12960 } 12961 12962 function getReducedUnionType(unionType: UnionType) { 12963 const reducedTypes = sameMap(unionType.types, getReducedType); 12964 if (reducedTypes === unionType.types) { 12965 return unionType; 12966 } 12967 const reduced = getUnionType(reducedTypes); 12968 if (reduced.flags & TypeFlags.Union) { 12969 (reduced as UnionType).resolvedReducedType = reduced; 12970 } 12971 return reduced; 12972 } 12973 12974 function isNeverReducedProperty(prop: Symbol) { 12975 return isDiscriminantWithNeverType(prop) || isConflictingPrivateProperty(prop); 12976 } 12977 12978 function isDiscriminantWithNeverType(prop: Symbol) { 12979 // Return true for a synthetic non-optional property with non-uniform types, where at least one is 12980 // a literal type and none is never, that reduces to never. 12981 return !(prop.flags & SymbolFlags.Optional) && 12982 (getCheckFlags(prop) & (CheckFlags.Discriminant | CheckFlags.HasNeverType)) === CheckFlags.Discriminant && 12983 !!(getTypeOfSymbol(prop).flags & TypeFlags.Never); 12984 } 12985 12986 function isConflictingPrivateProperty(prop: Symbol) { 12987 // Return true for a synthetic property with multiple declarations, at least one of which is private. 12988 return !prop.valueDeclaration && !!(getCheckFlags(prop) & CheckFlags.ContainsPrivate); 12989 } 12990 12991 function elaborateNeverIntersection(errorInfo: DiagnosticMessageChain | undefined, type: Type) { 12992 if (type.flags & TypeFlags.Intersection && getObjectFlags(type) & ObjectFlags.IsNeverIntersection) { 12993 const neverProp = find(getPropertiesOfUnionOrIntersectionType(type as IntersectionType), isDiscriminantWithNeverType); 12994 if (neverProp) { 12995 return chainDiagnosticMessages(errorInfo, Diagnostics.The_intersection_0_was_reduced_to_never_because_property_1_has_conflicting_types_in_some_constituents, 12996 typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.NoTypeReduction), symbolToString(neverProp)); 12997 } 12998 const privateProp = find(getPropertiesOfUnionOrIntersectionType(type as IntersectionType), isConflictingPrivateProperty); 12999 if (privateProp) { 13000 return chainDiagnosticMessages(errorInfo, Diagnostics.The_intersection_0_was_reduced_to_never_because_property_1_exists_in_multiple_constituents_and_is_private_in_some, 13001 typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.NoTypeReduction), symbolToString(privateProp)); 13002 } 13003 } 13004 return errorInfo; 13005 } 13006 13007 /** 13008 * Return the symbol for the property with the given name in the given type. Creates synthetic union properties when 13009 * necessary, maps primitive types and type parameters are to their apparent types, and augments with properties from 13010 * Object and Function as appropriate. 13011 * 13012 * @param type a type to look up property from 13013 * @param name a name of property to look up in a given type 13014 */ 13015 function getPropertyOfType(type: Type, name: __String, skipObjectFunctionPropertyAugment?: boolean, includeTypeOnlyMembers?: boolean): Symbol | undefined { 13016 type = getReducedApparentType(type); 13017 if (type.flags & TypeFlags.Object) { 13018 const resolved = resolveStructuredTypeMembers(type as ObjectType); 13019 const symbol = resolved.members.get(name); 13020 if (symbol && symbolIsValue(symbol, includeTypeOnlyMembers)) { 13021 return symbol; 13022 } 13023 if (skipObjectFunctionPropertyAugment) return undefined; 13024 const functionType = resolved === anyFunctionType ? globalFunctionType : 13025 resolved.callSignatures.length ? globalCallableFunctionType : 13026 resolved.constructSignatures.length ? globalNewableFunctionType : 13027 undefined; 13028 if (functionType) { 13029 const symbol = getPropertyOfObjectType(functionType, name); 13030 if (symbol) { 13031 return symbol; 13032 } 13033 } 13034 return getPropertyOfObjectType(globalObjectType, name); 13035 } 13036 if (type.flags & TypeFlags.UnionOrIntersection) { 13037 return getPropertyOfUnionOrIntersectionType(type as UnionOrIntersectionType, name, skipObjectFunctionPropertyAugment); 13038 } 13039 return undefined; 13040 } 13041 13042 function getSignaturesOfStructuredType(type: Type, kind: SignatureKind): readonly Signature[] { 13043 if (type.flags & TypeFlags.StructuredType) { 13044 const resolved = resolveStructuredTypeMembers(type as ObjectType); 13045 return kind === SignatureKind.Call ? resolved.callSignatures : resolved.constructSignatures; 13046 } 13047 return emptyArray; 13048 } 13049 13050 /** 13051 * Return the signatures of the given kind in the given type. Creates synthetic union signatures when necessary and 13052 * maps primitive types and type parameters are to their apparent types. 13053 */ 13054 function getSignaturesOfType(type: Type, kind: SignatureKind): readonly Signature[] { 13055 return getSignaturesOfStructuredType(getReducedApparentType(type), kind); 13056 } 13057 13058 function findIndexInfo(indexInfos: readonly IndexInfo[], keyType: Type) { 13059 return find(indexInfos, info => info.keyType === keyType); 13060 } 13061 13062 function findApplicableIndexInfo(indexInfos: readonly IndexInfo[], keyType: Type) { 13063 // Index signatures for type 'string' are considered only when no other index signatures apply. 13064 let stringIndexInfo: IndexInfo | undefined; 13065 let applicableInfo: IndexInfo | undefined; 13066 let applicableInfos: IndexInfo[] | undefined; 13067 for (const info of indexInfos) { 13068 if (info.keyType === stringType) { 13069 stringIndexInfo = info; 13070 } 13071 else if (isApplicableIndexType(keyType, info.keyType)) { 13072 if (!applicableInfo) { 13073 applicableInfo = info; 13074 } 13075 else { 13076 (applicableInfos || (applicableInfos = [applicableInfo])).push(info); 13077 } 13078 } 13079 } 13080 // When more than one index signature is applicable we create a synthetic IndexInfo. Instead of computing 13081 // the intersected key type, we just use unknownType for the key type as nothing actually depends on the 13082 // keyType property of the returned IndexInfo. 13083 return applicableInfos ? createIndexInfo(unknownType, getIntersectionType(map(applicableInfos, info => info.type)), 13084 reduceLeft(applicableInfos, (isReadonly, info) => isReadonly && info.isReadonly, /*initial*/ true)) : 13085 applicableInfo ? applicableInfo : 13086 stringIndexInfo && isApplicableIndexType(keyType, stringType) ? stringIndexInfo : 13087 undefined; 13088 } 13089 13090 function isApplicableIndexType(source: Type, target: Type): boolean { 13091 // A 'string' index signature applies to types assignable to 'string' or 'number', and a 'number' index 13092 // signature applies to types assignable to 'number', `${number}` and numeric string literal types. 13093 return isTypeAssignableTo(source, target) || 13094 target === stringType && isTypeAssignableTo(source, numberType) || 13095 target === numberType && (source === numericStringType || !!(source.flags & TypeFlags.StringLiteral) && isNumericLiteralName((source as StringLiteralType).value)); 13096 } 13097 13098 function getIndexInfosOfStructuredType(type: Type): readonly IndexInfo[] { 13099 if (type.flags & TypeFlags.StructuredType) { 13100 const resolved = resolveStructuredTypeMembers(type as ObjectType); 13101 return resolved.indexInfos; 13102 } 13103 return emptyArray; 13104 } 13105 13106 function getIndexInfosOfType(type: Type): readonly IndexInfo[] { 13107 return getIndexInfosOfStructuredType(getReducedApparentType(type)); 13108 } 13109 13110 // Return the indexing info of the given kind in the given type. Creates synthetic union index types when necessary and 13111 // maps primitive types and type parameters are to their apparent types. 13112 function getIndexInfoOfType(type: Type, keyType: Type): IndexInfo | undefined { 13113 return findIndexInfo(getIndexInfosOfType(type), keyType); 13114 } 13115 13116 // Return the index type of the given kind in the given type. Creates synthetic union index types when necessary and 13117 // maps primitive types and type parameters are to their apparent types. 13118 function getIndexTypeOfType(type: Type, keyType: Type): Type | undefined { 13119 return getIndexInfoOfType(type, keyType)?.type; 13120 } 13121 13122 function getApplicableIndexInfos(type: Type, keyType: Type): IndexInfo[] { 13123 return getIndexInfosOfType(type).filter(info => isApplicableIndexType(keyType, info.keyType)); 13124 } 13125 13126 function getApplicableIndexInfo(type: Type, keyType: Type): IndexInfo | undefined { 13127 return findApplicableIndexInfo(getIndexInfosOfType(type), keyType); 13128 } 13129 13130 function getApplicableIndexInfoForName(type: Type, name: __String): IndexInfo | undefined { 13131 return getApplicableIndexInfo(type, isLateBoundName(name) ? esSymbolType : getStringLiteralType(unescapeLeadingUnderscores(name))); 13132 } 13133 13134 // Return list of type parameters with duplicates removed (duplicate identifier errors are generated in the actual 13135 // type checking functions). 13136 function getTypeParametersFromDeclaration(declaration: DeclarationWithTypeParameters): readonly TypeParameter[] | undefined { 13137 let result: TypeParameter[] | undefined; 13138 for (const node of getEffectiveTypeParameterDeclarations(declaration)) { 13139 result = appendIfUnique(result, getDeclaredTypeOfTypeParameter(node.symbol)); 13140 } 13141 return result?.length ? result 13142 : isFunctionDeclaration(declaration) ? getSignatureOfTypeTag(declaration)?.typeParameters 13143 : undefined; 13144 } 13145 13146 function symbolsToArray(symbols: SymbolTable): Symbol[] { 13147 const result: Symbol[] = []; 13148 symbols.forEach((symbol, id) => { 13149 if (!isReservedMemberName(id)) { 13150 result.push(symbol); 13151 } 13152 }); 13153 return result; 13154 } 13155 13156 function isJSDocOptionalParameter(node: ParameterDeclaration) { 13157 return isInJSFile(node) && ( 13158 // node.type should only be a JSDocOptionalType when node is a parameter of a JSDocFunctionType 13159 node.type && node.type.kind === SyntaxKind.JSDocOptionalType 13160 || getJSDocParameterTags(node).some(({ isBracketed, typeExpression }) => 13161 isBracketed || !!typeExpression && typeExpression.type.kind === SyntaxKind.JSDocOptionalType)); 13162 } 13163 13164 function tryFindAmbientModule(moduleName: string, withAugmentations: boolean) { 13165 if (isExternalModuleNameRelative(moduleName)) { 13166 return undefined; 13167 } 13168 const symbol = getSymbol(globals, '"' + moduleName + '"' as __String, SymbolFlags.ValueModule); 13169 // merged symbol is module declaration symbol combined with all augmentations 13170 return symbol && withAugmentations ? getMergedSymbol(symbol) : symbol; 13171 } 13172 13173 function isOptionalParameter(node: ParameterDeclaration | JSDocParameterTag | JSDocPropertyTag) { 13174 if (hasQuestionToken(node) || isOptionalJSDocPropertyLikeTag(node) || isJSDocOptionalParameter(node)) { 13175 return true; 13176 } 13177 13178 if (node.initializer) { 13179 const signature = getSignatureFromDeclaration(node.parent); 13180 const parameterIndex = node.parent.parameters.indexOf(node); 13181 Debug.assert(parameterIndex >= 0); 13182 // Only consider syntactic or instantiated parameters as optional, not `void` parameters as this function is used 13183 // in grammar checks and checking for `void` too early results in parameter types widening too early 13184 // and causes some noImplicitAny errors to be lost. 13185 return parameterIndex >= getMinArgumentCount(signature, MinArgumentCountFlags.StrongArityForUntypedJS | MinArgumentCountFlags.VoidIsNonOptional); 13186 } 13187 const iife = getImmediatelyInvokedFunctionExpression(node.parent); 13188 if (iife) { 13189 return !node.type && 13190 !node.dotDotDotToken && 13191 node.parent.parameters.indexOf(node) >= iife.arguments.length; 13192 } 13193 13194 return false; 13195 } 13196 13197 function isOptionalPropertyDeclaration(node: Declaration) { 13198 return isPropertyDeclaration(node) && !hasAccessorModifier(node) && node.questionToken; 13199 } 13200 13201 function isOptionalJSDocPropertyLikeTag(node: Node): node is JSDocPropertyLikeTag { 13202 if (!isJSDocPropertyLikeTag(node)) { 13203 return false; 13204 } 13205 const { isBracketed, typeExpression } = node; 13206 return isBracketed || !!typeExpression && typeExpression.type.kind === SyntaxKind.JSDocOptionalType; 13207 } 13208 13209 function createTypePredicate(kind: TypePredicateKind, parameterName: string | undefined, parameterIndex: number | undefined, type: Type | undefined): TypePredicate { 13210 return { kind, parameterName, parameterIndex, type } as TypePredicate; 13211 } 13212 13213 /** 13214 * Gets the minimum number of type arguments needed to satisfy all non-optional type 13215 * parameters. 13216 */ 13217 function getMinTypeArgumentCount(typeParameters: readonly TypeParameter[] | undefined): number { 13218 let minTypeArgumentCount = 0; 13219 if (typeParameters) { 13220 for (let i = 0; i < typeParameters.length; i++) { 13221 if (!hasTypeParameterDefault(typeParameters[i])) { 13222 minTypeArgumentCount = i + 1; 13223 } 13224 } 13225 } 13226 return minTypeArgumentCount; 13227 } 13228 13229 /** 13230 * Fill in default types for unsupplied type arguments. If `typeArguments` is undefined 13231 * when a default type is supplied, a new array will be created and returned. 13232 * 13233 * @param typeArguments The supplied type arguments. 13234 * @param typeParameters The requested type parameters. 13235 * @param minTypeArgumentCount The minimum number of required type arguments. 13236 */ 13237 function fillMissingTypeArguments(typeArguments: readonly Type[], typeParameters: readonly TypeParameter[] | undefined, minTypeArgumentCount: number, isJavaScriptImplicitAny: boolean): Type[]; 13238 function fillMissingTypeArguments(typeArguments: readonly Type[] | undefined, typeParameters: readonly TypeParameter[] | undefined, minTypeArgumentCount: number, isJavaScriptImplicitAny: boolean): Type[] | undefined; 13239 function fillMissingTypeArguments(typeArguments: readonly Type[] | undefined, typeParameters: readonly TypeParameter[] | undefined, minTypeArgumentCount: number, isJavaScriptImplicitAny: boolean) { 13240 const numTypeParameters = length(typeParameters); 13241 if (!numTypeParameters) { 13242 return []; 13243 } 13244 const numTypeArguments = length(typeArguments); 13245 if (isJavaScriptImplicitAny || (numTypeArguments >= minTypeArgumentCount && numTypeArguments <= numTypeParameters)) { 13246 const result = typeArguments ? typeArguments.slice() : []; 13247 // Map invalid forward references in default types to the error type 13248 for (let i = numTypeArguments; i < numTypeParameters; i++) { 13249 result[i] = errorType; 13250 } 13251 const baseDefaultType = getDefaultTypeArgumentType(isJavaScriptImplicitAny); 13252 for (let i = numTypeArguments; i < numTypeParameters; i++) { 13253 let defaultType = getDefaultFromTypeParameter(typeParameters![i]); 13254 if (isJavaScriptImplicitAny && defaultType && (isTypeIdenticalTo(defaultType, unknownType) || isTypeIdenticalTo(defaultType, emptyObjectType))) { 13255 defaultType = anyType; 13256 } 13257 result[i] = defaultType ? instantiateType(defaultType, createTypeMapper(typeParameters!, result)) : baseDefaultType; 13258 } 13259 result.length = typeParameters!.length; 13260 return result; 13261 } 13262 return typeArguments && typeArguments.slice(); 13263 } 13264 13265 function getSignatureFromDeclaration(declaration: SignatureDeclaration | JSDocSignature): Signature { 13266 const links = getNodeLinks(declaration); 13267 if (!links.resolvedSignature) { 13268 const parameters: Symbol[] = []; 13269 let flags = SignatureFlags.None; 13270 let minArgumentCount = 0; 13271 let thisParameter: Symbol | undefined; 13272 let hasThisParameter = false; 13273 const iife = getImmediatelyInvokedFunctionExpression(declaration); 13274 const isJSConstructSignature = isJSDocConstructSignature(declaration); 13275 const isUntypedSignatureInJSFile = !iife && 13276 isInJSFile(declaration) && 13277 isValueSignatureDeclaration(declaration) && 13278 !hasJSDocParameterTags(declaration) && 13279 !getJSDocType(declaration); 13280 if (isUntypedSignatureInJSFile) { 13281 flags |= SignatureFlags.IsUntypedSignatureInJSFile; 13282 } 13283 13284 // If this is a JSDoc construct signature, then skip the first parameter in the 13285 // parameter list. The first parameter represents the return type of the construct 13286 // signature. 13287 for (let i = isJSConstructSignature ? 1 : 0; i < declaration.parameters.length; i++) { 13288 const param = declaration.parameters[i]; 13289 13290 let paramSymbol = param.symbol; 13291 const type = isJSDocParameterTag(param) ? (param.typeExpression && param.typeExpression.type) : param.type; 13292 // Include parameter symbol instead of property symbol in the signature 13293 if (paramSymbol && !!(paramSymbol.flags & SymbolFlags.Property) && !isBindingPattern(param.name)) { 13294 const resolvedSymbol = resolveName(param, paramSymbol.escapedName, SymbolFlags.Value, undefined, undefined, /*isUse*/ false); 13295 paramSymbol = resolvedSymbol!; 13296 } 13297 if (i === 0 && paramSymbol && paramSymbol.escapedName === InternalSymbolName.This) { 13298 hasThisParameter = true; 13299 thisParameter = param.symbol; 13300 } 13301 else { 13302 parameters.push(paramSymbol); 13303 } 13304 13305 if (type && type.kind === SyntaxKind.LiteralType) { 13306 flags |= SignatureFlags.HasLiteralTypes; 13307 } 13308 13309 // Record a new minimum argument count if this is not an optional parameter 13310 const isOptionalParameter = isOptionalJSDocPropertyLikeTag(param) || 13311 param.initializer || param.questionToken || isRestParameter(param) || 13312 iife && parameters.length > iife.arguments.length && !type || 13313 isJSDocOptionalParameter(param); 13314 if (!isOptionalParameter) { 13315 minArgumentCount = parameters.length; 13316 } 13317 } 13318 13319 // If only one accessor includes a this-type annotation, the other behaves as if it had the same type annotation 13320 if ((declaration.kind === SyntaxKind.GetAccessor || declaration.kind === SyntaxKind.SetAccessor) && 13321 hasBindableName(declaration) && 13322 (!hasThisParameter || !thisParameter)) { 13323 const otherKind = declaration.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor : SyntaxKind.GetAccessor; 13324 const other = getDeclarationOfKind<AccessorDeclaration>(getSymbolOfNode(declaration), otherKind); 13325 if (other) { 13326 thisParameter = getAnnotatedAccessorThisParameter(other); 13327 } 13328 } 13329 13330 const classType = declaration.kind === SyntaxKind.Constructor ? 13331 getDeclaredTypeOfClassOrInterface(getMergedSymbol((declaration.parent as ClassDeclaration).symbol)) 13332 : undefined; 13333 const typeParameters = classType ? classType.localTypeParameters : getTypeParametersFromDeclaration(declaration); 13334 if (hasRestParameter(declaration) || isInJSFile(declaration) && maybeAddJsSyntheticRestParameter(declaration, parameters)) { 13335 flags |= SignatureFlags.HasRestParameter; 13336 } 13337 if (isConstructorTypeNode(declaration) && hasSyntacticModifier(declaration, ModifierFlags.Abstract) || 13338 isConstructorDeclaration(declaration) && hasSyntacticModifier(declaration.parent, ModifierFlags.Abstract)) { 13339 flags |= SignatureFlags.Abstract; 13340 } 13341 links.resolvedSignature = createSignature(declaration, typeParameters, thisParameter, parameters, 13342 /*resolvedReturnType*/ undefined, /*resolvedTypePredicate*/ undefined, 13343 minArgumentCount, flags); 13344 } 13345 return links.resolvedSignature; 13346 } 13347 13348 /** 13349 * A JS function gets a synthetic rest parameter if it references `arguments` AND: 13350 * 1. It has no parameters but at least one `@param` with a type that starts with `...` 13351 * OR 13352 * 2. It has at least one parameter, and the last parameter has a matching `@param` with a type that starts with `...` 13353 */ 13354 function maybeAddJsSyntheticRestParameter(declaration: SignatureDeclaration | JSDocSignature, parameters: Symbol[]): boolean { 13355 if (isJSDocSignature(declaration) || !containsArgumentsReference(declaration)) { 13356 return false; 13357 } 13358 const lastParam = lastOrUndefined(declaration.parameters); 13359 const lastParamTags = lastParam ? getJSDocParameterTags(lastParam) : getJSDocTags(declaration).filter(isJSDocParameterTag); 13360 const lastParamVariadicType = firstDefined(lastParamTags, p => 13361 p.typeExpression && isJSDocVariadicType(p.typeExpression.type) ? p.typeExpression.type : undefined); 13362 13363 const syntheticArgsSymbol = createSymbol(SymbolFlags.Variable, "args" as __String, CheckFlags.RestParameter); 13364 if (lastParamVariadicType) { 13365 // Parameter has effective annotation, lock in type 13366 syntheticArgsSymbol.type = createArrayType(getTypeFromTypeNode(lastParamVariadicType.type)); 13367 } 13368 else { 13369 // Parameter has no annotation 13370 // By using a `DeferredType` symbol, we allow the type of this rest arg to be overriden by contextual type assignment so long as its type hasn't been 13371 // cached by `getTypeOfSymbol` yet. 13372 syntheticArgsSymbol.checkFlags |= CheckFlags.DeferredType; 13373 syntheticArgsSymbol.deferralParent = neverType; 13374 syntheticArgsSymbol.deferralConstituents = [anyArrayType]; 13375 syntheticArgsSymbol.deferralWriteConstituents = [anyArrayType]; 13376 } 13377 if (lastParamVariadicType) { 13378 // Replace the last parameter with a rest parameter. 13379 parameters.pop(); 13380 } 13381 parameters.push(syntheticArgsSymbol); 13382 return true; 13383 } 13384 13385 function getSignatureOfTypeTag(node: SignatureDeclaration | JSDocSignature) { 13386 // should be attached to a function declaration or expression 13387 if (!(isInJSFile(node) && isFunctionLikeDeclaration(node))) return undefined; 13388 const typeTag = getJSDocTypeTag(node); 13389 return typeTag?.typeExpression && getSingleCallSignature(getTypeFromTypeNode(typeTag.typeExpression)); 13390 } 13391 13392 function getParameterTypeOfTypeTag(func: FunctionLikeDeclaration, parameter: ParameterDeclaration) { 13393 const signature = getSignatureOfTypeTag(func); 13394 if (!signature) return undefined; 13395 const pos = func.parameters.indexOf(parameter); 13396 return parameter.dotDotDotToken ? getRestTypeAtPosition(signature, pos) : getTypeAtPosition(signature, pos); 13397 } 13398 13399 function getReturnTypeOfTypeTag(node: SignatureDeclaration | JSDocSignature) { 13400 const signature = getSignatureOfTypeTag(node); 13401 return signature && getReturnTypeOfSignature(signature); 13402 } 13403 13404 function containsArgumentsReference(declaration: SignatureDeclaration): boolean { 13405 const links = getNodeLinks(declaration); 13406 if (links.containsArgumentsReference === undefined) { 13407 if (links.flags & NodeCheckFlags.CaptureArguments) { 13408 links.containsArgumentsReference = true; 13409 } 13410 else { 13411 links.containsArgumentsReference = traverse((declaration as FunctionLikeDeclaration).body!); 13412 } 13413 } 13414 return links.containsArgumentsReference; 13415 13416 function traverse(node: Node): boolean { 13417 if (!node) return false; 13418 switch (node.kind) { 13419 case SyntaxKind.Identifier: 13420 return (node as Identifier).escapedText === argumentsSymbol.escapedName && getReferencedValueSymbol(node as Identifier) === argumentsSymbol; 13421 13422 case SyntaxKind.PropertyDeclaration: 13423 case SyntaxKind.MethodDeclaration: 13424 case SyntaxKind.GetAccessor: 13425 case SyntaxKind.SetAccessor: 13426 return (node as NamedDeclaration).name!.kind === SyntaxKind.ComputedPropertyName 13427 && traverse((node as NamedDeclaration).name!); 13428 13429 case SyntaxKind.PropertyAccessExpression: 13430 case SyntaxKind.ElementAccessExpression: 13431 return traverse((node as PropertyAccessExpression | ElementAccessExpression).expression); 13432 13433 case SyntaxKind.PropertyAssignment: 13434 return traverse((node as PropertyAssignment).initializer); 13435 13436 default: 13437 return !nodeStartsNewLexicalEnvironment(node) && !isPartOfTypeNode(node) && !!forEachChild(node, traverse); 13438 } 13439 } 13440 } 13441 13442 function getSignaturesOfSymbol(symbol: Symbol | undefined): Signature[] { 13443 if (!symbol || !symbol.declarations) return emptyArray; 13444 const result: Signature[] = []; 13445 for (let i = 0; i < symbol.declarations.length; i++) { 13446 const decl = symbol.declarations[i]; 13447 if (!isFunctionLike(decl)) continue; 13448 // Don't include signature if node is the implementation of an overloaded function. A node is considered 13449 // an implementation node if it has a body and the previous node is of the same kind and immediately 13450 // precedes the implementation node (i.e. has the same parent and ends where the implementation starts). 13451 if (i > 0 && (decl as FunctionLikeDeclaration).body) { 13452 const previous = symbol.declarations[i - 1]; 13453 if (decl.parent === previous.parent && decl.kind === previous.kind && decl.pos === previous.end) { 13454 continue; 13455 } 13456 } 13457 // If this is a function or method declaration, get the signature from the @type tag for the sake of optional parameters. 13458 // Exclude contextually-typed kinds because we already apply the @type tag to the context, plus applying it here to the initializer would supress checks that the two are compatible. 13459 result.push( 13460 (!isFunctionExpressionOrArrowFunction(decl) && 13461 !isObjectLiteralMethod(decl) && 13462 getSignatureOfTypeTag(decl)) || 13463 getSignatureFromDeclaration(decl) 13464 ); 13465 } 13466 return result; 13467 } 13468 13469 function resolveExternalModuleTypeByLiteral(name: StringLiteral) { 13470 const moduleSym = resolveExternalModuleName(name, name); 13471 if (moduleSym) { 13472 const resolvedModuleSymbol = resolveExternalModuleSymbol(moduleSym); 13473 if (resolvedModuleSymbol) { 13474 return getTypeOfSymbol(resolvedModuleSymbol); 13475 } 13476 } 13477 13478 return anyType; 13479 } 13480 13481 function getThisTypeOfSignature(signature: Signature): Type | undefined { 13482 if (signature.thisParameter) { 13483 return getTypeOfSymbol(signature.thisParameter); 13484 } 13485 } 13486 13487 function getTypePredicateOfSignature(signature: Signature): TypePredicate | undefined { 13488 if (!signature.resolvedTypePredicate) { 13489 if (signature.target) { 13490 const targetTypePredicate = getTypePredicateOfSignature(signature.target); 13491 signature.resolvedTypePredicate = targetTypePredicate ? instantiateTypePredicate(targetTypePredicate, signature.mapper!) : noTypePredicate; 13492 } 13493 else if (signature.compositeSignatures) { 13494 signature.resolvedTypePredicate = getUnionOrIntersectionTypePredicate(signature.compositeSignatures, signature.compositeKind) || noTypePredicate; 13495 } 13496 else { 13497 const type = signature.declaration && getEffectiveReturnTypeNode(signature.declaration); 13498 let jsdocPredicate: TypePredicate | undefined; 13499 if (!type) { 13500 const jsdocSignature = getSignatureOfTypeTag(signature.declaration!); 13501 if (jsdocSignature && signature !== jsdocSignature) { 13502 jsdocPredicate = getTypePredicateOfSignature(jsdocSignature); 13503 } 13504 } 13505 signature.resolvedTypePredicate = type && isTypePredicateNode(type) ? 13506 createTypePredicateFromTypePredicateNode(type, signature) : 13507 jsdocPredicate || noTypePredicate; 13508 } 13509 Debug.assert(!!signature.resolvedTypePredicate); 13510 } 13511 return signature.resolvedTypePredicate === noTypePredicate ? undefined : signature.resolvedTypePredicate; 13512 } 13513 13514 function createTypePredicateFromTypePredicateNode(node: TypePredicateNode, signature: Signature): TypePredicate { 13515 const parameterName = node.parameterName; 13516 const type = node.type && getTypeFromTypeNode(node.type); 13517 return parameterName.kind === SyntaxKind.ThisType ? 13518 createTypePredicate(node.assertsModifier ? TypePredicateKind.AssertsThis : TypePredicateKind.This, /*parameterName*/ undefined, /*parameterIndex*/ undefined, type) : 13519 createTypePredicate(node.assertsModifier ? TypePredicateKind.AssertsIdentifier : TypePredicateKind.Identifier, parameterName.escapedText as string, 13520 findIndex(signature.parameters, p => p.escapedName === parameterName.escapedText), type); 13521 } 13522 13523 function getUnionOrIntersectionType(types: Type[], kind: TypeFlags | undefined, unionReduction?: UnionReduction) { 13524 return kind !== TypeFlags.Intersection ? getUnionType(types, unionReduction) : getIntersectionType(types); 13525 } 13526 13527 function getReturnTypeOfSignature(signature: Signature): Type { 13528 if (!signature.resolvedReturnType) { 13529 if (!pushTypeResolution(signature, TypeSystemPropertyName.ResolvedReturnType)) { 13530 return errorType; 13531 } 13532 let type = signature.target ? instantiateType(getReturnTypeOfSignature(signature.target), signature.mapper) : 13533 signature.compositeSignatures ? instantiateType(getUnionOrIntersectionType(map(signature.compositeSignatures, getReturnTypeOfSignature), signature.compositeKind, UnionReduction.Subtype), signature.mapper) : 13534 getReturnTypeFromAnnotation(signature.declaration!) || 13535 (nodeIsMissing((signature.declaration as FunctionLikeDeclaration).body) ? anyType : getReturnTypeFromBody(signature.declaration as FunctionLikeDeclaration)); 13536 if (signature.flags & SignatureFlags.IsInnerCallChain) { 13537 type = addOptionalTypeMarker(type); 13538 } 13539 else if (signature.flags & SignatureFlags.IsOuterCallChain) { 13540 type = getOptionalType(type); 13541 } 13542 if (!popTypeResolution()) { 13543 if (signature.declaration) { 13544 const typeNode = getEffectiveReturnTypeNode(signature.declaration); 13545 if (typeNode) { 13546 error(typeNode, Diagnostics.Return_type_annotation_circularly_references_itself); 13547 } 13548 else if (noImplicitAny) { 13549 const declaration = signature.declaration as Declaration; 13550 const name = getNameOfDeclaration(declaration); 13551 if (name) { 13552 error(name, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, declarationNameToString(name)); 13553 } 13554 else { 13555 error(declaration, Diagnostics.Function_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions); 13556 } 13557 } 13558 } 13559 type = anyType; 13560 } 13561 signature.resolvedReturnType = type; 13562 } 13563 return signature.resolvedReturnType; 13564 } 13565 13566 function getReturnTypeFromAnnotation(declaration: SignatureDeclaration | JSDocSignature) { 13567 if (declaration.kind === SyntaxKind.Constructor) { 13568 return getDeclaredTypeOfClassOrInterface(getMergedSymbol((declaration.parent as ClassDeclaration).symbol)); 13569 } 13570 if (isJSDocConstructSignature(declaration)) { 13571 return getTypeFromTypeNode((declaration.parameters[0] as ParameterDeclaration).type!); // TODO: GH#18217 13572 } 13573 const typeNode = getEffectiveReturnTypeNode(declaration); 13574 if (typeNode) { 13575 return getTypeFromTypeNode(typeNode); 13576 } 13577 if (declaration.kind === SyntaxKind.GetAccessor && hasBindableName(declaration)) { 13578 const jsDocType = isInJSFile(declaration) && getTypeForDeclarationFromJSDocComment(declaration); 13579 if (jsDocType) { 13580 return jsDocType; 13581 } 13582 const setter = getDeclarationOfKind<AccessorDeclaration>(getSymbolOfNode(declaration), SyntaxKind.SetAccessor); 13583 const setterType = getAnnotatedAccessorType(setter); 13584 if (setterType) { 13585 return setterType; 13586 } 13587 } 13588 return getReturnTypeOfTypeTag(declaration); 13589 } 13590 13591 function isResolvingReturnTypeOfSignature(signature: Signature) { 13592 return !signature.resolvedReturnType && findResolutionCycleStartIndex(signature, TypeSystemPropertyName.ResolvedReturnType) >= 0; 13593 } 13594 13595 function getRestTypeOfSignature(signature: Signature): Type { 13596 return tryGetRestTypeOfSignature(signature) || anyType; 13597 } 13598 13599 function tryGetRestTypeOfSignature(signature: Signature): Type | undefined { 13600 if (signatureHasRestParameter(signature)) { 13601 const sigRestType = getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]); 13602 const restType = isTupleType(sigRestType) ? getRestTypeOfTupleType(sigRestType) : sigRestType; 13603 return restType && getIndexTypeOfType(restType, numberType); 13604 } 13605 return undefined; 13606 } 13607 13608 function getSignatureInstantiation(signature: Signature, typeArguments: Type[] | undefined, isJavascript: boolean, inferredTypeParameters?: readonly TypeParameter[]): Signature { 13609 const instantiatedSignature = getSignatureInstantiationWithoutFillingInTypeArguments(signature, fillMissingTypeArguments(typeArguments, signature.typeParameters, getMinTypeArgumentCount(signature.typeParameters), isJavascript)); 13610 if (inferredTypeParameters) { 13611 const returnSignature = getSingleCallOrConstructSignature(getReturnTypeOfSignature(instantiatedSignature)); 13612 if (returnSignature) { 13613 const newReturnSignature = cloneSignature(returnSignature); 13614 newReturnSignature.typeParameters = inferredTypeParameters; 13615 const newInstantiatedSignature = cloneSignature(instantiatedSignature); 13616 newInstantiatedSignature.resolvedReturnType = getOrCreateTypeFromSignature(newReturnSignature); 13617 return newInstantiatedSignature; 13618 } 13619 } 13620 return instantiatedSignature; 13621 } 13622 13623 function getSignatureInstantiationWithoutFillingInTypeArguments(signature: Signature, typeArguments: readonly Type[] | undefined): Signature { 13624 const instantiations = signature.instantiations || (signature.instantiations = new Map<string, Signature>()); 13625 const id = getTypeListId(typeArguments); 13626 let instantiation = instantiations.get(id); 13627 if (!instantiation) { 13628 instantiations.set(id, instantiation = createSignatureInstantiation(signature, typeArguments)); 13629 } 13630 return instantiation; 13631 } 13632 13633 function createSignatureInstantiation(signature: Signature, typeArguments: readonly Type[] | undefined): Signature { 13634 return instantiateSignature(signature, createSignatureTypeMapper(signature, typeArguments), /*eraseTypeParameters*/ true); 13635 } 13636 13637 function createSignatureTypeMapper(signature: Signature, typeArguments: readonly Type[] | undefined): TypeMapper { 13638 return createTypeMapper(signature.typeParameters!, typeArguments); 13639 } 13640 13641 function getErasedSignature(signature: Signature): Signature { 13642 return signature.typeParameters ? 13643 signature.erasedSignatureCache || (signature.erasedSignatureCache = createErasedSignature(signature)) : 13644 signature; 13645 } 13646 13647 function createErasedSignature(signature: Signature) { 13648 // Create an instantiation of the signature where all type arguments are the any type. 13649 return instantiateSignature(signature, createTypeEraser(signature.typeParameters!), /*eraseTypeParameters*/ true); 13650 } 13651 13652 function getCanonicalSignature(signature: Signature): Signature { 13653 return signature.typeParameters ? 13654 signature.canonicalSignatureCache || (signature.canonicalSignatureCache = createCanonicalSignature(signature)) : 13655 signature; 13656 } 13657 13658 function createCanonicalSignature(signature: Signature) { 13659 // Create an instantiation of the signature where each unconstrained type parameter is replaced with 13660 // its original. When a generic class or interface is instantiated, each generic method in the class or 13661 // interface is instantiated with a fresh set of cloned type parameters (which we need to handle scenarios 13662 // where different generations of the same type parameter are in scope). This leads to a lot of new type 13663 // identities, and potentially a lot of work comparing those identities, so here we create an instantiation 13664 // that uses the original type identities for all unconstrained type parameters. 13665 return getSignatureInstantiation( 13666 signature, 13667 map(signature.typeParameters, tp => tp.target && !getConstraintOfTypeParameter(tp.target) ? tp.target : tp), 13668 isInJSFile(signature.declaration)); 13669 } 13670 13671 function getBaseSignature(signature: Signature) { 13672 const typeParameters = signature.typeParameters; 13673 if (typeParameters) { 13674 if (signature.baseSignatureCache) { 13675 return signature.baseSignatureCache; 13676 } 13677 const typeEraser = createTypeEraser(typeParameters); 13678 const baseConstraintMapper = createTypeMapper(typeParameters, map(typeParameters, tp => getConstraintOfTypeParameter(tp) || unknownType)); 13679 let baseConstraints: readonly Type[] = map(typeParameters, tp => instantiateType(tp, baseConstraintMapper) || unknownType); 13680 // Run N type params thru the immediate constraint mapper up to N times 13681 // This way any noncircular interdependent type parameters are definitely resolved to their external dependencies 13682 for (let i = 0; i < typeParameters.length - 1; i++) { 13683 baseConstraints = instantiateTypes(baseConstraints, baseConstraintMapper); 13684 } 13685 // and then apply a type eraser to remove any remaining circularly dependent type parameters 13686 baseConstraints = instantiateTypes(baseConstraints, typeEraser); 13687 return signature.baseSignatureCache = instantiateSignature(signature, createTypeMapper(typeParameters, baseConstraints), /*eraseTypeParameters*/ true); 13688 } 13689 return signature; 13690 } 13691 13692 function getOrCreateTypeFromSignature(signature: Signature): ObjectType { 13693 // There are two ways to declare a construct signature, one is by declaring a class constructor 13694 // using the constructor keyword, and the other is declaring a bare construct signature in an 13695 // object type literal or interface (using the new keyword). Each way of declaring a constructor 13696 // will result in a different declaration kind. 13697 if (!signature.isolatedSignatureType) { 13698 const kind = signature.declaration?.kind; 13699 13700 // If declaration is undefined, it is likely to be the signature of the default constructor. 13701 const isConstructor = kind === undefined || kind === SyntaxKind.Constructor || kind === SyntaxKind.ConstructSignature || kind === SyntaxKind.ConstructorType; 13702 13703 const type = createObjectType(ObjectFlags.Anonymous); 13704 type.members = emptySymbols; 13705 type.properties = emptyArray; 13706 type.callSignatures = !isConstructor ? [signature] : emptyArray; 13707 type.constructSignatures = isConstructor ? [signature] : emptyArray; 13708 type.indexInfos = emptyArray; 13709 signature.isolatedSignatureType = type; 13710 } 13711 13712 return signature.isolatedSignatureType; 13713 } 13714 13715 function getIndexSymbol(symbol: Symbol): Symbol | undefined { 13716 return symbol.members ? getIndexSymbolFromSymbolTable(symbol.members) : undefined; 13717 } 13718 13719 function getIndexSymbolFromSymbolTable(symbolTable: SymbolTable): Symbol | undefined { 13720 return symbolTable.get(InternalSymbolName.Index); 13721 } 13722 13723 function createIndexInfo(keyType: Type, type: Type, isReadonly: boolean, declaration?: IndexSignatureDeclaration): IndexInfo { 13724 return { keyType, type, isReadonly, declaration }; 13725 } 13726 13727 function getIndexInfosOfSymbol(symbol: Symbol): IndexInfo[] { 13728 const indexSymbol = getIndexSymbol(symbol); 13729 return indexSymbol ? getIndexInfosOfIndexSymbol(indexSymbol) : emptyArray; 13730 } 13731 13732 function getIndexInfosOfIndexSymbol(indexSymbol: Symbol): IndexInfo[] { 13733 if (indexSymbol.declarations) { 13734 const indexInfos: IndexInfo[] = []; 13735 for (const declaration of (indexSymbol.declarations as IndexSignatureDeclaration[])) { 13736 if (declaration.parameters.length === 1) { 13737 const parameter = declaration.parameters[0]; 13738 if (parameter.type) { 13739 forEachType(getTypeFromTypeNode(parameter.type), keyType => { 13740 if (isValidIndexKeyType(keyType) && !findIndexInfo(indexInfos, keyType)) { 13741 indexInfos.push(createIndexInfo(keyType, declaration.type ? getTypeFromTypeNode(declaration.type) : anyType, 13742 hasEffectiveModifier(declaration, ModifierFlags.Readonly), declaration)); 13743 } 13744 }); 13745 } 13746 } 13747 } 13748 return indexInfos; 13749 } 13750 return emptyArray; 13751 } 13752 13753 function isValidIndexKeyType(type: Type): boolean { 13754 return !!(type.flags & (TypeFlags.String | TypeFlags.Number | TypeFlags.ESSymbol)) || isPatternLiteralType(type) || 13755 !!(type.flags & TypeFlags.Intersection) && !isGenericType(type) && some((type as IntersectionType).types, isValidIndexKeyType); 13756 } 13757 13758 function getConstraintDeclaration(type: TypeParameter): TypeNode | undefined { 13759 return mapDefined(filter(type.symbol && type.symbol.declarations, isTypeParameterDeclaration), getEffectiveConstraintOfTypeParameter)[0]; 13760 } 13761 13762 function getInferredTypeParameterConstraint(typeParameter: TypeParameter, omitTypeReferences?: boolean) { 13763 let inferences: Type[] | undefined; 13764 if (typeParameter.symbol?.declarations) { 13765 for (const declaration of typeParameter.symbol.declarations) { 13766 if (declaration.parent.kind === SyntaxKind.InferType) { 13767 // When an 'infer T' declaration is immediately contained in a type reference node 13768 // (such as 'Foo<infer T>'), T's constraint is inferred from the constraint of the 13769 // corresponding type parameter in 'Foo'. When multiple 'infer T' declarations are 13770 // present, we form an intersection of the inferred constraint types. 13771 const [childTypeParameter = declaration.parent, grandParent] = walkUpParenthesizedTypesAndGetParentAndChild(declaration.parent.parent); 13772 if (grandParent.kind === SyntaxKind.TypeReference && !omitTypeReferences) { 13773 const typeReference = grandParent as TypeReferenceNode; 13774 const typeParameters = getTypeParametersForTypeReference(typeReference); 13775 if (typeParameters) { 13776 const index = typeReference.typeArguments!.indexOf(childTypeParameter as TypeNode); 13777 if (index < typeParameters.length) { 13778 const declaredConstraint = getConstraintOfTypeParameter(typeParameters[index]); 13779 if (declaredConstraint) { 13780 // Type parameter constraints can reference other type parameters so 13781 // constraints need to be instantiated. If instantiation produces the 13782 // type parameter itself, we discard that inference. For example, in 13783 // type Foo<T extends string, U extends T> = [T, U]; 13784 // type Bar<T> = T extends Foo<infer X, infer X> ? Foo<X, X> : T; 13785 // the instantiated constraint for U is X, so we discard that inference. 13786 const mapper = makeDeferredTypeMapper(typeParameters, typeParameters.map((_, index) => () => { 13787 return getEffectiveTypeArgumentAtIndex(typeReference, typeParameters, index); 13788 })); 13789 const constraint = instantiateType(declaredConstraint, mapper); 13790 if (constraint !== typeParameter) { 13791 inferences = append(inferences, constraint); 13792 } 13793 } 13794 } 13795 } 13796 } 13797 // When an 'infer T' declaration is immediately contained in a rest parameter declaration, a rest type 13798 // or a named rest tuple element, we infer an 'unknown[]' constraint. 13799 else if (grandParent.kind === SyntaxKind.Parameter && (grandParent as ParameterDeclaration).dotDotDotToken || 13800 grandParent.kind === SyntaxKind.RestType || 13801 grandParent.kind === SyntaxKind.NamedTupleMember && (grandParent as NamedTupleMember).dotDotDotToken) { 13802 inferences = append(inferences, createArrayType(unknownType)); 13803 } 13804 // When an 'infer T' declaration is immediately contained in a string template type, we infer a 'string' 13805 // constraint. 13806 else if (grandParent.kind === SyntaxKind.TemplateLiteralTypeSpan) { 13807 inferences = append(inferences, stringType); 13808 } 13809 // When an 'infer T' declaration is in the constraint position of a mapped type, we infer a 'keyof any' 13810 // constraint. 13811 else if (grandParent.kind === SyntaxKind.TypeParameter && grandParent.parent.kind === SyntaxKind.MappedType) { 13812 inferences = append(inferences, keyofConstraintType); 13813 } 13814 // When an 'infer T' declaration is the template of a mapped type, and that mapped type is the extends 13815 // clause of a conditional whose check type is also a mapped type, give it a constraint equal to the template 13816 // of the check type's mapped type 13817 else if (grandParent.kind === SyntaxKind.MappedType && (grandParent as MappedTypeNode).type && 13818 skipParentheses((grandParent as MappedTypeNode).type!) === declaration.parent && grandParent.parent.kind === SyntaxKind.ConditionalType && 13819 (grandParent.parent as ConditionalTypeNode).extendsType === grandParent && (grandParent.parent as ConditionalTypeNode).checkType.kind === SyntaxKind.MappedType && 13820 ((grandParent.parent as ConditionalTypeNode).checkType as MappedTypeNode).type) { 13821 const checkMappedType = (grandParent.parent as ConditionalTypeNode).checkType as MappedTypeNode; 13822 const nodeType = getTypeFromTypeNode(checkMappedType.type!); 13823 inferences = append(inferences, instantiateType(nodeType, 13824 makeUnaryTypeMapper(getDeclaredTypeOfTypeParameter(getSymbolOfNode(checkMappedType.typeParameter)), checkMappedType.typeParameter.constraint ? getTypeFromTypeNode(checkMappedType.typeParameter.constraint) : keyofConstraintType) 13825 )); 13826 } 13827 } 13828 } 13829 } 13830 return inferences && getIntersectionType(inferences); 13831 } 13832 13833 /** This is a worker function. Use getConstraintOfTypeParameter which guards against circular constraints. */ 13834 function getConstraintFromTypeParameter(typeParameter: TypeParameter): Type | undefined { 13835 if (!typeParameter.constraint) { 13836 if (typeParameter.target) { 13837 const targetConstraint = getConstraintOfTypeParameter(typeParameter.target); 13838 typeParameter.constraint = targetConstraint ? instantiateType(targetConstraint, typeParameter.mapper) : noConstraintType; 13839 } 13840 else { 13841 const constraintDeclaration = getConstraintDeclaration(typeParameter); 13842 if (!constraintDeclaration) { 13843 typeParameter.constraint = getInferredTypeParameterConstraint(typeParameter) || noConstraintType; 13844 } 13845 else { 13846 let type = getTypeFromTypeNode(constraintDeclaration); 13847 if (type.flags & TypeFlags.Any && !isErrorType(type)) { // Allow errorType to propegate to keep downstream errors suppressed 13848 // use keyofConstraintType as the base constraint for mapped type key constraints (unknown isn;t assignable to that, but `any` was), 13849 // use unknown otherwise 13850 type = constraintDeclaration.parent.parent.kind === SyntaxKind.MappedType ? keyofConstraintType : unknownType; 13851 } 13852 typeParameter.constraint = type; 13853 } 13854 } 13855 } 13856 return typeParameter.constraint === noConstraintType ? undefined : typeParameter.constraint; 13857 } 13858 13859 function getParentSymbolOfTypeParameter(typeParameter: TypeParameter): Symbol | undefined { 13860 const tp = getDeclarationOfKind<TypeParameterDeclaration>(typeParameter.symbol, SyntaxKind.TypeParameter)!; 13861 const host = isJSDocTemplateTag(tp.parent) ? getEffectiveContainerForJSDocTemplateTag(tp.parent) : tp.parent; 13862 return host && getSymbolOfNode(host); 13863 } 13864 13865 function getTypeListId(types: readonly Type[] | undefined) { 13866 let result = ""; 13867 if (types) { 13868 const length = types.length; 13869 let i = 0; 13870 while (i < length) { 13871 const startId = types[i].id; 13872 let count = 1; 13873 while (i + count < length && types[i + count].id === startId + count) { 13874 count++; 13875 } 13876 if (result.length) { 13877 result += ","; 13878 } 13879 result += startId; 13880 if (count > 1) { 13881 result += ":" + count; 13882 } 13883 i += count; 13884 } 13885 } 13886 return result; 13887 } 13888 13889 function getAliasId(aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined) { 13890 return aliasSymbol ? `@${getSymbolId(aliasSymbol)}` + (aliasTypeArguments ? `:${getTypeListId(aliasTypeArguments)}` : "") : ""; 13891 } 13892 13893 // This function is used to propagate certain flags when creating new object type references and union types. 13894 // It is only necessary to do so if a constituent type might be the undefined type, the null type, the type 13895 // of an object literal or a non-inferrable type. This is because there are operations in the type checker 13896 // that care about the presence of such types at arbitrary depth in a containing type. 13897 function getPropagatingFlagsOfTypes(types: readonly Type[], excludeKinds?: TypeFlags): ObjectFlags { 13898 let result: ObjectFlags = 0; 13899 for (const type of types) { 13900 if (excludeKinds === undefined || !(type.flags & excludeKinds)) { 13901 result |= getObjectFlags(type); 13902 } 13903 } 13904 return result & ObjectFlags.PropagatingFlags; 13905 } 13906 13907 function createTypeReference(target: GenericType, typeArguments: readonly Type[] | undefined): TypeReference { 13908 const id = getTypeListId(typeArguments); 13909 let type = target.instantiations.get(id); 13910 if (!type) { 13911 type = createObjectType(ObjectFlags.Reference, target.symbol) as TypeReference; 13912 target.instantiations.set(id, type); 13913 type.objectFlags |= typeArguments ? getPropagatingFlagsOfTypes(typeArguments) : 0; 13914 type.target = target; 13915 type.resolvedTypeArguments = typeArguments; 13916 } 13917 return type; 13918 } 13919 13920 function cloneTypeReference(source: TypeReference): TypeReference { 13921 const type = createType(source.flags) as TypeReference; 13922 type.symbol = source.symbol; 13923 type.objectFlags = source.objectFlags; 13924 type.target = source.target; 13925 type.resolvedTypeArguments = source.resolvedTypeArguments; 13926 return type; 13927 } 13928 13929 function createDeferredTypeReference(target: GenericType, node: TypeReferenceNode | ArrayTypeNode | TupleTypeNode, mapper?: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): DeferredTypeReference { 13930 if (!aliasSymbol) { 13931 aliasSymbol = getAliasSymbolForTypeNode(node); 13932 const localAliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol); 13933 aliasTypeArguments = mapper ? instantiateTypes(localAliasTypeArguments, mapper) : localAliasTypeArguments; 13934 } 13935 const type = createObjectType(ObjectFlags.Reference, target.symbol) as DeferredTypeReference; 13936 type.target = target; 13937 type.node = node; 13938 type.mapper = mapper; 13939 type.aliasSymbol = aliasSymbol; 13940 type.aliasTypeArguments = aliasTypeArguments; 13941 return type; 13942 } 13943 13944 function getTypeArguments(type: TypeReference): readonly Type[] { 13945 if (!type.resolvedTypeArguments) { 13946 if (!pushTypeResolution(type, TypeSystemPropertyName.ResolvedTypeArguments)) { 13947 return type.target.localTypeParameters?.map(() => errorType) || emptyArray; 13948 } 13949 const node = type.node; 13950 const typeArguments = !node ? emptyArray : 13951 node.kind === SyntaxKind.TypeReference ? concatenate(type.target.outerTypeParameters, getEffectiveTypeArguments(node, type.target.localTypeParameters!)) : 13952 node.kind === SyntaxKind.ArrayType ? [getTypeFromTypeNode(node.elementType)] : 13953 map(node.elements, getTypeFromTypeNode); 13954 if (popTypeResolution()) { 13955 type.resolvedTypeArguments = type.mapper ? instantiateTypes(typeArguments, type.mapper) : typeArguments; 13956 } 13957 else { 13958 type.resolvedTypeArguments = type.target.localTypeParameters?.map(() => errorType) || emptyArray; 13959 error( 13960 type.node || currentNode, 13961 type.target.symbol ? Diagnostics.Type_arguments_for_0_circularly_reference_themselves : Diagnostics.Tuple_type_arguments_circularly_reference_themselves, 13962 type.target.symbol && symbolToString(type.target.symbol) 13963 ); 13964 } 13965 } 13966 return type.resolvedTypeArguments; 13967 } 13968 13969 function getTypeReferenceArity(type: TypeReference): number { 13970 return length(type.target.typeParameters); 13971 } 13972 13973 13974 /** 13975 * Get type from type-reference that reference to class or interface 13976 */ 13977 function getTypeFromClassOrInterfaceReference(node: NodeWithTypeArguments, symbol: Symbol): Type { 13978 const type = getDeclaredTypeOfSymbol(getMergedSymbol(symbol)) as InterfaceType; 13979 const typeParameters = type.localTypeParameters; 13980 if (typeParameters) { 13981 const numTypeArguments = length(node.typeArguments); 13982 const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters); 13983 const isJs = isInJSFile(node); 13984 const isJsImplicitAny = !noImplicitAny && isJs; 13985 if (!isJsImplicitAny && (numTypeArguments < minTypeArgumentCount || numTypeArguments > typeParameters.length)) { 13986 const missingAugmentsTag = isJs && isExpressionWithTypeArguments(node) && !isJSDocAugmentsTag(node.parent); 13987 const diag = minTypeArgumentCount === typeParameters.length ? 13988 missingAugmentsTag ? 13989 Diagnostics.Expected_0_type_arguments_provide_these_with_an_extends_tag : 13990 Diagnostics.Generic_type_0_requires_1_type_argument_s : 13991 missingAugmentsTag ? 13992 Diagnostics.Expected_0_1_type_arguments_provide_these_with_an_extends_tag : 13993 Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments; 13994 13995 const typeStr = typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType); 13996 error(node, diag, typeStr, minTypeArgumentCount, typeParameters.length); 13997 if (!isJs) { 13998 // TODO: Adopt same permissive behavior in TS as in JS to reduce follow-on editing experience failures (requires editing fillMissingTypeArguments) 13999 return errorType; 14000 } 14001 } 14002 if (node.kind === SyntaxKind.TypeReference && isDeferredTypeReferenceNode(node as TypeReferenceNode, length(node.typeArguments) !== typeParameters.length)) { 14003 return createDeferredTypeReference(type as GenericType, node as TypeReferenceNode, /*mapper*/ undefined); 14004 } 14005 // In a type reference, the outer type parameters of the referenced class or interface are automatically 14006 // supplied as type arguments and the type reference only specifies arguments for the local type parameters 14007 // of the class or interface. 14008 const typeArguments = concatenate(type.outerTypeParameters, fillMissingTypeArguments(typeArgumentsFromTypeReferenceNode(node), typeParameters, minTypeArgumentCount, isJs)); 14009 return createTypeReference(type as GenericType, typeArguments); 14010 } 14011 return checkNoTypeArguments(node, symbol) ? type : errorType; 14012 } 14013 14014 function getTypeAliasInstantiation(symbol: Symbol, typeArguments: readonly Type[] | undefined, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type { 14015 const type = getDeclaredTypeOfSymbol(symbol); 14016 if (type === intrinsicMarkerType && intrinsicTypeKinds.has(symbol.escapedName as string) && typeArguments && typeArguments.length === 1) { 14017 return getStringMappingType(symbol, typeArguments[0]); 14018 } 14019 const links = getSymbolLinks(symbol); 14020 const typeParameters = links.typeParameters!; 14021 const id = getTypeListId(typeArguments) + getAliasId(aliasSymbol, aliasTypeArguments); 14022 let instantiation = links.instantiations!.get(id); 14023 if (!instantiation) { 14024 links.instantiations!.set(id, instantiation = instantiateTypeWithAlias(type, 14025 createTypeMapper(typeParameters, fillMissingTypeArguments(typeArguments, typeParameters, getMinTypeArgumentCount(typeParameters), isInJSFile(symbol.valueDeclaration))), 14026 aliasSymbol, aliasTypeArguments)); 14027 } 14028 return instantiation; 14029 } 14030 14031 /** 14032 * Get type from reference to type alias. When a type alias is generic, the declared type of the type alias may include 14033 * references to the type parameters of the alias. We replace those with the actual type arguments by instantiating the 14034 * declared type. Instantiations are cached using the type identities of the type arguments as the key. 14035 */ 14036 function getTypeFromTypeAliasReference(node: NodeWithTypeArguments, symbol: Symbol): Type { 14037 if (getCheckFlags(symbol) & CheckFlags.Unresolved) { 14038 const typeArguments = typeArgumentsFromTypeReferenceNode(node); 14039 const id = getAliasId(symbol, typeArguments); 14040 let errorType = errorTypes.get(id); 14041 if (!errorType) { 14042 errorType = createIntrinsicType(TypeFlags.Any, "error"); 14043 errorType.aliasSymbol = symbol; 14044 errorType.aliasTypeArguments = typeArguments; 14045 errorTypes.set(id, errorType); 14046 } 14047 return errorType; 14048 } 14049 const type = getDeclaredTypeOfSymbol(symbol); 14050 const typeParameters = getSymbolLinks(symbol).typeParameters; 14051 if (typeParameters) { 14052 const numTypeArguments = length(node.typeArguments); 14053 const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters); 14054 if (numTypeArguments < minTypeArgumentCount || numTypeArguments > typeParameters.length) { 14055 error(node, 14056 minTypeArgumentCount === typeParameters.length ? 14057 Diagnostics.Generic_type_0_requires_1_type_argument_s : 14058 Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments, 14059 symbolToString(symbol), 14060 minTypeArgumentCount, 14061 typeParameters.length); 14062 return errorType; 14063 } 14064 // We refrain from associating a local type alias with an instantiation of a top-level type alias 14065 // because the local alias may end up being referenced in an inferred return type where it is not 14066 // accessible--which in turn may lead to a large structural expansion of the type when generating 14067 // a .d.ts file. See #43622 for an example. 14068 const aliasSymbol = getAliasSymbolForTypeNode(node); 14069 const newAliasSymbol = aliasSymbol && (isLocalTypeAlias(symbol) || !isLocalTypeAlias(aliasSymbol)) ? aliasSymbol : undefined; 14070 return getTypeAliasInstantiation(symbol, typeArgumentsFromTypeReferenceNode(node), newAliasSymbol, getTypeArgumentsForAliasSymbol(newAliasSymbol)); 14071 } 14072 return checkNoTypeArguments(node, symbol) ? type : errorType; 14073 } 14074 14075 function isLocalTypeAlias(symbol: Symbol) { 14076 const declaration = symbol.declarations?.find(isTypeAlias); 14077 return !!(declaration && getContainingFunction(declaration)); 14078 } 14079 14080 function getTypeReferenceName(node: TypeReferenceType): EntityNameOrEntityNameExpression | undefined { 14081 switch (node.kind) { 14082 case SyntaxKind.TypeReference: 14083 return node.typeName; 14084 case SyntaxKind.ExpressionWithTypeArguments: 14085 // We only support expressions that are simple qualified names. For other 14086 // expressions this produces undefined. 14087 const expr = node.expression; 14088 if (isEntityNameExpression(expr)) { 14089 return expr; 14090 } 14091 // fall through; 14092 } 14093 14094 return undefined; 14095 } 14096 14097 function getSymbolPath(symbol: Symbol): string { 14098 return symbol.parent ? `${getSymbolPath(symbol.parent)}.${symbol.escapedName}` : symbol.escapedName as string; 14099 } 14100 14101 function getUnresolvedSymbolForEntityName(name: EntityNameOrEntityNameExpression) { 14102 const identifier = name.kind === SyntaxKind.QualifiedName ? name.right : 14103 name.kind === SyntaxKind.PropertyAccessExpression ? name.name : 14104 name; 14105 const text = identifier.escapedText; 14106 if (text) { 14107 const parentSymbol = name.kind === SyntaxKind.QualifiedName ? getUnresolvedSymbolForEntityName(name.left) : 14108 name.kind === SyntaxKind.PropertyAccessExpression ? getUnresolvedSymbolForEntityName(name.expression) : 14109 undefined; 14110 const path = parentSymbol ? `${getSymbolPath(parentSymbol)}.${text}` : text as string; 14111 let result = unresolvedSymbols.get(path); 14112 if (!result) { 14113 unresolvedSymbols.set(path, result = createSymbol(SymbolFlags.TypeAlias, text, CheckFlags.Unresolved)); 14114 result.parent = parentSymbol; 14115 result.declaredType = unresolvedType; 14116 } 14117 return result; 14118 } 14119 return unknownSymbol; 14120 } 14121 14122 function resolveTypeReferenceName(typeReference: TypeReferenceType, meaning: SymbolFlags, ignoreErrors?: boolean) { 14123 const name = getTypeReferenceName(typeReference); 14124 if (!name) { 14125 return unknownSymbol; 14126 } 14127 const symbol = resolveEntityName(name, meaning, ignoreErrors); 14128 return symbol && symbol !== unknownSymbol ? symbol : 14129 ignoreErrors ? unknownSymbol : getUnresolvedSymbolForEntityName(name); 14130 } 14131 14132 function getTypeReferenceType(node: NodeWithTypeArguments, symbol: Symbol): Type { 14133 if (symbol === unknownSymbol) { 14134 return errorType; 14135 } 14136 symbol = getExpandoSymbol(symbol) || symbol; 14137 if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { 14138 return getTypeFromClassOrInterfaceReference(node, symbol); 14139 } 14140 if (symbol.flags & SymbolFlags.TypeAlias) { 14141 return getTypeFromTypeAliasReference(node, symbol); 14142 } 14143 // Get type from reference to named type that cannot be generic (enum or type parameter) 14144 const res = tryGetDeclaredTypeOfSymbol(symbol); 14145 if (res) { 14146 return checkNoTypeArguments(node, symbol) ? getRegularTypeOfLiteralType(res) : errorType; 14147 } 14148 if (symbol.flags & SymbolFlags.Value && isJSDocTypeReference(node)) { 14149 const jsdocType = getTypeFromJSDocValueReference(node, symbol); 14150 if (jsdocType) { 14151 return jsdocType; 14152 } 14153 else { 14154 // Resolve the type reference as a Type for the purpose of reporting errors. 14155 resolveTypeReferenceName(node, SymbolFlags.Type); 14156 return getTypeOfSymbol(symbol); 14157 } 14158 } 14159 return errorType; 14160 } 14161 14162 /** 14163 * A JSdoc TypeReference may be to a value, but resolve it as a type anyway. 14164 * Example: import('./b').ConstructorFunction 14165 */ 14166 function getTypeFromJSDocValueReference(node: NodeWithTypeArguments, symbol: Symbol): Type | undefined { 14167 const links = getNodeLinks(node); 14168 if (!links.resolvedJSDocType) { 14169 const valueType = getTypeOfSymbol(symbol); 14170 let typeType = valueType; 14171 if (symbol.valueDeclaration) { 14172 const isImportTypeWithQualifier = node.kind === SyntaxKind.ImportType && (node as ImportTypeNode).qualifier; 14173 // valueType might not have a symbol, eg, {import('./b').STRING_LITERAL} 14174 if (valueType.symbol && valueType.symbol !== symbol && isImportTypeWithQualifier) { 14175 typeType = getTypeReferenceType(node, valueType.symbol); 14176 } 14177 } 14178 links.resolvedJSDocType = typeType; 14179 } 14180 return links.resolvedJSDocType; 14181 } 14182 14183 function getSubstitutionType(baseType: Type, constraint: Type) { 14184 if (constraint.flags & TypeFlags.AnyOrUnknown || constraint === baseType || 14185 !isGenericType(baseType) && !isGenericType(constraint)) { 14186 return baseType; 14187 } 14188 const id = `${getTypeId(baseType)}>${getTypeId(constraint)}`; 14189 const cached = substitutionTypes.get(id); 14190 if (cached) { 14191 return cached; 14192 } 14193 const result = createType(TypeFlags.Substitution) as SubstitutionType; 14194 result.baseType = baseType; 14195 result.constraint = constraint; 14196 substitutionTypes.set(id, result); 14197 return result; 14198 } 14199 14200 function getSubstitutionIntersection(substitutionType: SubstitutionType) { 14201 return getIntersectionType([substitutionType.constraint, substitutionType.baseType]); 14202 } 14203 14204 function isUnaryTupleTypeNode(node: TypeNode) { 14205 return node.kind === SyntaxKind.TupleType && (node as TupleTypeNode).elements.length === 1; 14206 } 14207 14208 function getImpliedConstraint(type: Type, checkNode: TypeNode, extendsNode: TypeNode): Type | undefined { 14209 return isUnaryTupleTypeNode(checkNode) && isUnaryTupleTypeNode(extendsNode) ? getImpliedConstraint(type, (checkNode as TupleTypeNode).elements[0], (extendsNode as TupleTypeNode).elements[0]) : 14210 getActualTypeVariable(getTypeFromTypeNode(checkNode)) === getActualTypeVariable(type) ? getTypeFromTypeNode(extendsNode) : 14211 undefined; 14212 } 14213 14214 function getConditionalFlowTypeOfType(type: Type, node: Node) { 14215 let constraints: Type[] | undefined; 14216 let covariant = true; 14217 while (node && !isStatement(node) && node.kind !== SyntaxKind.JSDoc) { 14218 const parent = node.parent; 14219 // only consider variance flipped by parameter locations - `keyof` types would usually be considered variance inverting, but 14220 // often get used in indexed accesses where they behave sortof invariantly, but our checking is lax 14221 if (parent.kind === SyntaxKind.Parameter) { 14222 covariant = !covariant; 14223 } 14224 // Always substitute on type parameters, regardless of variance, since even 14225 // in contravariant positions, they may rely on substituted constraints to be valid 14226 if ((covariant || type.flags & TypeFlags.TypeVariable) && parent.kind === SyntaxKind.ConditionalType && node === (parent as ConditionalTypeNode).trueType) { 14227 const constraint = getImpliedConstraint(type, (parent as ConditionalTypeNode).checkType, (parent as ConditionalTypeNode).extendsType); 14228 if (constraint) { 14229 constraints = append(constraints, constraint); 14230 } 14231 } 14232 // Given a homomorphic mapped type { [K in keyof T]: XXX }, where T is constrained to an array or tuple type, in the 14233 // template type XXX, K has an added constraint of number | `${number}`. 14234 else if (type.flags & TypeFlags.TypeParameter && parent.kind === SyntaxKind.MappedType && node === (parent as MappedTypeNode).type) { 14235 const mappedType = getTypeFromTypeNode(parent as TypeNode) as MappedType; 14236 if (getTypeParameterFromMappedType(mappedType) === getActualTypeVariable(type)) { 14237 const typeParameter = getHomomorphicTypeVariable(mappedType); 14238 if (typeParameter) { 14239 const constraint = getConstraintOfTypeParameter(typeParameter); 14240 if (constraint && everyType(constraint, isArrayOrTupleType)) { 14241 constraints = append(constraints, getUnionType([numberType, numericStringType])); 14242 } 14243 } 14244 } 14245 } 14246 node = parent; 14247 } 14248 return constraints ? getSubstitutionType(type, getIntersectionType(constraints)) : type; 14249 } 14250 14251 function isJSDocTypeReference(node: Node): node is TypeReferenceNode { 14252 return !!(node.flags & NodeFlags.JSDoc) && (node.kind === SyntaxKind.TypeReference || node.kind === SyntaxKind.ImportType); 14253 } 14254 14255 function checkNoTypeArguments(node: NodeWithTypeArguments, symbol?: Symbol) { 14256 if (node.typeArguments) { 14257 error(node, Diagnostics.Type_0_is_not_generic, symbol ? symbolToString(symbol) : (node as TypeReferenceNode).typeName ? declarationNameToString((node as TypeReferenceNode).typeName) : anon); 14258 return false; 14259 } 14260 return true; 14261 } 14262 14263 function getIntendedTypeFromJSDocTypeReference(node: TypeReferenceNode): Type | undefined { 14264 if (isIdentifier(node.typeName)) { 14265 const typeArgs = node.typeArguments; 14266 switch (node.typeName.escapedText) { 14267 case "String": 14268 checkNoTypeArguments(node); 14269 return stringType; 14270 case "Number": 14271 checkNoTypeArguments(node); 14272 return numberType; 14273 case "Boolean": 14274 checkNoTypeArguments(node); 14275 return booleanType; 14276 case "Void": 14277 checkNoTypeArguments(node); 14278 return voidType; 14279 case "Undefined": 14280 checkNoTypeArguments(node); 14281 return undefinedType; 14282 case "Null": 14283 checkNoTypeArguments(node); 14284 return nullType; 14285 case "Function": 14286 case "function": 14287 checkNoTypeArguments(node); 14288 return globalFunctionType; 14289 case "array": 14290 return (!typeArgs || !typeArgs.length) && !noImplicitAny ? anyArrayType : undefined; 14291 case "promise": 14292 return (!typeArgs || !typeArgs.length) && !noImplicitAny ? createPromiseType(anyType) : undefined; 14293 case "Object": 14294 if (typeArgs && typeArgs.length === 2) { 14295 if (isJSDocIndexSignature(node)) { 14296 const indexed = getTypeFromTypeNode(typeArgs[0]); 14297 const target = getTypeFromTypeNode(typeArgs[1]); 14298 const indexInfo = indexed === stringType || indexed === numberType ? [createIndexInfo(indexed, target, /*isReadonly*/ false)] : emptyArray; 14299 return createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, indexInfo); 14300 } 14301 return anyType; 14302 } 14303 checkNoTypeArguments(node); 14304 return !noImplicitAny ? anyType : undefined; 14305 } 14306 } 14307 } 14308 14309 function getTypeFromJSDocNullableTypeNode(node: JSDocNullableType) { 14310 const type = getTypeFromTypeNode(node.type); 14311 return strictNullChecks ? getNullableType(type, TypeFlags.Null) : type; 14312 } 14313 14314 function getTypeFromTypeReference(node: TypeReferenceType): Type { 14315 const links = getNodeLinks(node); 14316 if (!links.resolvedType) { 14317 // handle LS queries on the `const` in `x as const` by resolving to the type of `x` 14318 if (isConstTypeReference(node) && isAssertionExpression(node.parent)) { 14319 links.resolvedSymbol = unknownSymbol; 14320 return links.resolvedType = checkExpressionCached(node.parent.expression); 14321 } 14322 let symbol: Symbol | undefined; 14323 let type: Type | undefined; 14324 const meaning = SymbolFlags.Type; 14325 if (isJSDocTypeReference(node)) { 14326 type = getIntendedTypeFromJSDocTypeReference(node); 14327 if (!type) { 14328 symbol = resolveTypeReferenceName(node, meaning, /*ignoreErrors*/ true); 14329 if (symbol === unknownSymbol) { 14330 symbol = resolveTypeReferenceName(node, meaning | SymbolFlags.Value); 14331 } 14332 else { 14333 resolveTypeReferenceName(node, meaning); // Resolve again to mark errors, if any 14334 } 14335 type = getTypeReferenceType(node, symbol); 14336 } 14337 } 14338 if (!type) { 14339 symbol = resolveTypeReferenceName(node, meaning); 14340 type = getTypeReferenceType(node, symbol); 14341 } 14342 // Cache both the resolved symbol and the resolved type. The resolved symbol is needed when we check the 14343 // type reference in checkTypeReferenceNode. 14344 links.resolvedSymbol = symbol; 14345 links.resolvedType = type; 14346 } 14347 return links.resolvedType; 14348 } 14349 14350 function typeArgumentsFromTypeReferenceNode(node: NodeWithTypeArguments): Type[] | undefined { 14351 return map(node.typeArguments, getTypeFromTypeNode); 14352 } 14353 14354 function getTypeFromTypeQueryNode(node: TypeQueryNode): Type { 14355 const links = getNodeLinks(node); 14356 if (!links.resolvedType) { 14357 // TypeScript 1.0 spec (April 2014): 3.6.3 14358 // The expression is processed as an identifier expression (section 4.3) 14359 // or property access expression(section 4.10), 14360 // the widened type(section 3.9) of which becomes the result. 14361 const type = checkExpressionWithTypeArguments(node); 14362 links.resolvedType = getRegularTypeOfLiteralType(getWidenedType(type)); 14363 } 14364 return links.resolvedType; 14365 } 14366 14367 function getTypeOfGlobalSymbol(symbol: Symbol | undefined, arity: number): ObjectType { 14368 14369 function getTypeDeclaration(symbol: Symbol): Declaration | undefined { 14370 const declarations = symbol.declarations; 14371 if (declarations) { 14372 for (const declaration of declarations) { 14373 switch (declaration.kind) { 14374 case SyntaxKind.ClassDeclaration: 14375 case SyntaxKind.InterfaceDeclaration: 14376 case SyntaxKind.EnumDeclaration: 14377 return declaration; 14378 } 14379 } 14380 } 14381 } 14382 14383 if (!symbol) { 14384 return arity ? emptyGenericType : emptyObjectType; 14385 } 14386 const type = getDeclaredTypeOfSymbol(symbol); 14387 if (!(type.flags & TypeFlags.Object)) { 14388 error(getTypeDeclaration(symbol), Diagnostics.Global_type_0_must_be_a_class_or_interface_type, symbolName(symbol)); 14389 return arity ? emptyGenericType : emptyObjectType; 14390 } 14391 if (length((type as InterfaceType).typeParameters) !== arity) { 14392 error(getTypeDeclaration(symbol), Diagnostics.Global_type_0_must_have_1_type_parameter_s, symbolName(symbol), arity); 14393 return arity ? emptyGenericType : emptyObjectType; 14394 } 14395 return type as ObjectType; 14396 } 14397 14398 function getGlobalValueSymbol(name: __String, reportErrors: boolean): Symbol | undefined { 14399 return getGlobalSymbol(name, SymbolFlags.Value, reportErrors ? Diagnostics.Cannot_find_global_value_0 : undefined); 14400 } 14401 14402 function getGlobalTypeSymbol(name: __String, reportErrors: boolean): Symbol | undefined { 14403 return getGlobalSymbol(name, SymbolFlags.Type, reportErrors ? Diagnostics.Cannot_find_global_type_0 : undefined); 14404 } 14405 14406 function getGlobalTypeAliasSymbol(name: __String, arity: number, reportErrors: boolean): Symbol | undefined { 14407 const symbol = getGlobalSymbol(name, SymbolFlags.Type, reportErrors ? Diagnostics.Cannot_find_global_type_0 : undefined); 14408 if (symbol) { 14409 // Resolve the declared type of the symbol. This resolves type parameters for the type 14410 // alias so that we can check arity. 14411 getDeclaredTypeOfSymbol(symbol); 14412 if (length(getSymbolLinks(symbol).typeParameters) !== arity) { 14413 const decl = symbol.declarations && find(symbol.declarations, isTypeAliasDeclaration); 14414 error(decl, Diagnostics.Global_type_0_must_have_1_type_parameter_s, symbolName(symbol), arity); 14415 return undefined; 14416 } 14417 } 14418 return symbol; 14419 } 14420 14421 function getGlobalSymbol(name: __String, meaning: SymbolFlags, diagnostic: DiagnosticMessage | undefined): Symbol | undefined { 14422 // Don't track references for global symbols anyway, so value if `isReference` is arbitrary 14423 return resolveName(undefined, name, meaning, diagnostic, name, /*isUse*/ false, /*excludeGlobals*/ false, /*getSpellingSuggestions*/ false); 14424 } 14425 14426 function getGlobalType(name: __String, arity: 0, reportErrors: true): ObjectType; 14427 function getGlobalType(name: __String, arity: 0, reportErrors: boolean): ObjectType | undefined; 14428 function getGlobalType(name: __String, arity: number, reportErrors: true): GenericType; 14429 function getGlobalType(name: __String, arity: number, reportErrors: boolean): GenericType | undefined; 14430 function getGlobalType(name: __String, arity: number, reportErrors: boolean): ObjectType | undefined { 14431 const symbol = getGlobalTypeSymbol(name, reportErrors); 14432 return symbol || reportErrors ? getTypeOfGlobalSymbol(symbol, arity) : undefined; 14433 } 14434 14435 function getGlobalTypedPropertyDescriptorType() { 14436 // We always report an error, so store a result in the event we could not resolve the symbol to prevent reporting it multiple times 14437 return deferredGlobalTypedPropertyDescriptorType ||= getGlobalType("TypedPropertyDescriptor" as __String, /*arity*/ 1, /*reportErrors*/ true) || emptyGenericType; 14438 } 14439 14440 function getGlobalTemplateStringsArrayType() { 14441 // We always report an error, so store a result in the event we could not resolve the symbol to prevent reporting it multiple times 14442 return deferredGlobalTemplateStringsArrayType ||= getGlobalType("TemplateStringsArray" as __String, /*arity*/ 0, /*reportErrors*/ true) || emptyObjectType; 14443 } 14444 14445 function getGlobalImportMetaType() { 14446 // We always report an error, so store a result in the event we could not resolve the symbol to prevent reporting it multiple times 14447 return deferredGlobalImportMetaType ||= getGlobalType("ImportMeta" as __String, /*arity*/ 0, /*reportErrors*/ true) || emptyObjectType; 14448 } 14449 14450 function getGlobalImportMetaExpressionType() { 14451 if (!deferredGlobalImportMetaExpressionType) { 14452 // Create a synthetic type `ImportMetaExpression { meta: MetaProperty }` 14453 const symbol = createSymbol(SymbolFlags.None, "ImportMetaExpression" as __String); 14454 const importMetaType = getGlobalImportMetaType(); 14455 14456 const metaPropertySymbol = createSymbol(SymbolFlags.Property, "meta" as __String, CheckFlags.Readonly); 14457 metaPropertySymbol.parent = symbol; 14458 metaPropertySymbol.type = importMetaType; 14459 14460 const members = createSymbolTable([metaPropertySymbol]); 14461 symbol.members = members; 14462 14463 deferredGlobalImportMetaExpressionType = createAnonymousType(symbol, members, emptyArray, emptyArray, emptyArray); 14464 } 14465 return deferredGlobalImportMetaExpressionType; 14466 } 14467 14468 function getGlobalImportCallOptionsType(reportErrors: boolean) { 14469 return (deferredGlobalImportCallOptionsType ||= getGlobalType("ImportCallOptions" as __String, /*arity*/ 0, reportErrors)) || emptyObjectType; 14470 } 14471 14472 function getGlobalESSymbolConstructorSymbol(reportErrors: boolean): Symbol | undefined { 14473 return deferredGlobalESSymbolConstructorSymbol ||= getGlobalValueSymbol("Symbol" as __String, reportErrors); 14474 } 14475 14476 function getGlobalESSymbolConstructorTypeSymbol(reportErrors: boolean): Symbol | undefined { 14477 return deferredGlobalESSymbolConstructorTypeSymbol ||= getGlobalTypeSymbol("SymbolConstructor" as __String, reportErrors); 14478 } 14479 14480 function getGlobalESSymbolType() { 14481 return (deferredGlobalESSymbolType ||= getGlobalType("Symbol" as __String, /*arity*/ 0, /*reportErrors*/ false)) || emptyObjectType; 14482 } 14483 14484 function getGlobalPromiseType(reportErrors: boolean) { 14485 return (deferredGlobalPromiseType ||= getGlobalType("Promise" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; 14486 } 14487 14488 function getGlobalPromiseLikeType(reportErrors: boolean) { 14489 return (deferredGlobalPromiseLikeType ||= getGlobalType("PromiseLike" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; 14490 } 14491 14492 function getGlobalPromiseConstructorSymbol(reportErrors: boolean): Symbol | undefined { 14493 return deferredGlobalPromiseConstructorSymbol ||= getGlobalValueSymbol("Promise" as __String, reportErrors); 14494 } 14495 14496 function getGlobalPromiseConstructorLikeType(reportErrors: boolean) { 14497 return (deferredGlobalPromiseConstructorLikeType ||= getGlobalType("PromiseConstructorLike" as __String, /*arity*/ 0, reportErrors)) || emptyObjectType; 14498 } 14499 14500 function getGlobalAsyncIterableType(reportErrors: boolean) { 14501 return (deferredGlobalAsyncIterableType ||= getGlobalType("AsyncIterable" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; 14502 } 14503 14504 function getGlobalAsyncIteratorType(reportErrors: boolean) { 14505 return (deferredGlobalAsyncIteratorType ||= getGlobalType("AsyncIterator" as __String, /*arity*/ 3, reportErrors)) || emptyGenericType; 14506 } 14507 14508 function getGlobalAsyncIterableIteratorType(reportErrors: boolean) { 14509 return (deferredGlobalAsyncIterableIteratorType ||= getGlobalType("AsyncIterableIterator" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; 14510 } 14511 14512 function getGlobalAsyncGeneratorType(reportErrors: boolean) { 14513 return (deferredGlobalAsyncGeneratorType ||= getGlobalType("AsyncGenerator" as __String, /*arity*/ 3, reportErrors)) || emptyGenericType; 14514 } 14515 14516 function getGlobalIterableType(reportErrors: boolean) { 14517 return (deferredGlobalIterableType ||= getGlobalType("Iterable" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; 14518 } 14519 14520 function getGlobalIteratorType(reportErrors: boolean) { 14521 return (deferredGlobalIteratorType ||= getGlobalType("Iterator" as __String, /*arity*/ 3, reportErrors)) || emptyGenericType; 14522 } 14523 14524 function getGlobalIterableIteratorType(reportErrors: boolean) { 14525 return (deferredGlobalIterableIteratorType ||= getGlobalType("IterableIterator" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; 14526 } 14527 14528 function getGlobalGeneratorType(reportErrors: boolean) { 14529 return (deferredGlobalGeneratorType ||= getGlobalType("Generator" as __String, /*arity*/ 3, reportErrors)) || emptyGenericType; 14530 } 14531 14532 function getGlobalIteratorYieldResultType(reportErrors: boolean) { 14533 return (deferredGlobalIteratorYieldResultType ||= getGlobalType("IteratorYieldResult" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; 14534 } 14535 14536 function getGlobalIteratorReturnResultType(reportErrors: boolean) { 14537 return (deferredGlobalIteratorReturnResultType ||= getGlobalType("IteratorReturnResult" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; 14538 } 14539 14540 function getGlobalTypeOrUndefined(name: __String, arity = 0): ObjectType | undefined { 14541 const symbol = getGlobalSymbol(name, SymbolFlags.Type, /*diagnostic*/ undefined); 14542 return symbol && getTypeOfGlobalSymbol(symbol, arity) as GenericType; 14543 } 14544 14545 function getGlobalExtractSymbol(): Symbol | undefined { 14546 // We always report an error, so cache a result in the event we could not resolve the symbol to prevent reporting it multiple times 14547 deferredGlobalExtractSymbol ||= getGlobalTypeAliasSymbol("Extract" as __String, /*arity*/ 2, /*reportErrors*/ true) || unknownSymbol; 14548 return deferredGlobalExtractSymbol === unknownSymbol ? undefined : deferredGlobalExtractSymbol; 14549 } 14550 14551 function getGlobalOmitSymbol(): Symbol | undefined { 14552 // We always report an error, so cache a result in the event we could not resolve the symbol to prevent reporting it multiple times 14553 deferredGlobalOmitSymbol ||= getGlobalTypeAliasSymbol("Omit" as __String, /*arity*/ 2, /*reportErrors*/ true) || unknownSymbol; 14554 return deferredGlobalOmitSymbol === unknownSymbol ? undefined : deferredGlobalOmitSymbol; 14555 } 14556 14557 function getGlobalAwaitedSymbol(reportErrors: boolean): Symbol | undefined { 14558 // Only cache `unknownSymbol` if we are reporting errors so that we don't report the error more than once. 14559 deferredGlobalAwaitedSymbol ||= getGlobalTypeAliasSymbol("Awaited" as __String, /*arity*/ 1, reportErrors) || (reportErrors ? unknownSymbol : undefined); 14560 return deferredGlobalAwaitedSymbol === unknownSymbol ? undefined : deferredGlobalAwaitedSymbol; 14561 } 14562 14563 function getGlobalBigIntType() { 14564 return (deferredGlobalBigIntType ||= getGlobalType("BigInt" as __String, /*arity*/ 0, /*reportErrors*/ false)) || emptyObjectType; 14565 } 14566 14567 function getGlobalNaNSymbol(): Symbol | undefined { 14568 return (deferredGlobalNaNSymbol ||= getGlobalValueSymbol("NaN" as __String, /*reportErrors*/ false)); 14569 } 14570 14571 function getGlobalRecordSymbol(): Symbol | undefined { 14572 deferredGlobalRecordSymbol ||= getGlobalTypeAliasSymbol("Record" as __String, /*arity*/ 2, /*reportErrors*/ true) || unknownSymbol; 14573 return deferredGlobalRecordSymbol === unknownSymbol ? undefined : deferredGlobalRecordSymbol; 14574 } 14575 14576 /** 14577 * Instantiates a global type that is generic with some element type, and returns that instantiation. 14578 */ 14579 function createTypeFromGenericGlobalType(genericGlobalType: GenericType, typeArguments: readonly Type[]): ObjectType { 14580 return genericGlobalType !== emptyGenericType ? createTypeReference(genericGlobalType, typeArguments) : emptyObjectType; 14581 } 14582 14583 function createTypedPropertyDescriptorType(propertyType: Type): Type { 14584 return createTypeFromGenericGlobalType(getGlobalTypedPropertyDescriptorType(), [propertyType]); 14585 } 14586 14587 function createIterableType(iteratedType: Type): Type { 14588 return createTypeFromGenericGlobalType(getGlobalIterableType(/*reportErrors*/ true), [iteratedType]); 14589 } 14590 14591 function createArrayType(elementType: Type, readonly?: boolean): ObjectType { 14592 return createTypeFromGenericGlobalType(readonly ? globalReadonlyArrayType : globalArrayType, [elementType]); 14593 } 14594 14595 function getTupleElementFlags(node: TypeNode) { 14596 switch (node.kind) { 14597 case SyntaxKind.OptionalType: 14598 return ElementFlags.Optional; 14599 case SyntaxKind.RestType: 14600 return getRestTypeElementFlags(node as RestTypeNode); 14601 case SyntaxKind.NamedTupleMember: 14602 return (node as NamedTupleMember).questionToken ? ElementFlags.Optional : 14603 (node as NamedTupleMember).dotDotDotToken ? getRestTypeElementFlags(node as NamedTupleMember) : 14604 ElementFlags.Required; 14605 default: 14606 return ElementFlags.Required; 14607 } 14608 } 14609 14610 function getRestTypeElementFlags(node: RestTypeNode | NamedTupleMember) { 14611 return getArrayElementTypeNode(node.type) ? ElementFlags.Rest : ElementFlags.Variadic; 14612 } 14613 14614 function getArrayOrTupleTargetType(node: ArrayTypeNode | TupleTypeNode): GenericType { 14615 const readonly = isReadonlyTypeOperator(node.parent); 14616 const elementType = getArrayElementTypeNode(node); 14617 if (elementType) { 14618 return readonly ? globalReadonlyArrayType : globalArrayType; 14619 } 14620 const elementFlags = map((node as TupleTypeNode).elements, getTupleElementFlags); 14621 const missingName = some((node as TupleTypeNode).elements, e => e.kind !== SyntaxKind.NamedTupleMember); 14622 return getTupleTargetType(elementFlags, readonly, /*associatedNames*/ missingName ? undefined : (node as TupleTypeNode).elements as readonly NamedTupleMember[]); 14623 } 14624 14625 // Return true if the given type reference node is directly aliased or if it needs to be deferred 14626 // because it is possibly contained in a circular chain of eagerly resolved types. 14627 function isDeferredTypeReferenceNode(node: TypeReferenceNode | ArrayTypeNode | TupleTypeNode, hasDefaultTypeArguments?: boolean) { 14628 return !!getAliasSymbolForTypeNode(node) || isResolvedByTypeAlias(node) && ( 14629 node.kind === SyntaxKind.ArrayType ? mayResolveTypeAlias(node.elementType) : 14630 node.kind === SyntaxKind.TupleType ? some(node.elements, mayResolveTypeAlias) : 14631 hasDefaultTypeArguments || some(node.typeArguments, mayResolveTypeAlias)); 14632 } 14633 14634 // Return true when the given node is transitively contained in type constructs that eagerly 14635 // resolve their constituent types. We include SyntaxKind.TypeReference because type arguments 14636 // of type aliases are eagerly resolved. 14637 function isResolvedByTypeAlias(node: Node): boolean { 14638 const parent = node.parent; 14639 switch (parent.kind) { 14640 case SyntaxKind.ParenthesizedType: 14641 case SyntaxKind.NamedTupleMember: 14642 case SyntaxKind.TypeReference: 14643 case SyntaxKind.UnionType: 14644 case SyntaxKind.IntersectionType: 14645 case SyntaxKind.IndexedAccessType: 14646 case SyntaxKind.ConditionalType: 14647 case SyntaxKind.TypeOperator: 14648 case SyntaxKind.ArrayType: 14649 case SyntaxKind.TupleType: 14650 return isResolvedByTypeAlias(parent); 14651 case SyntaxKind.TypeAliasDeclaration: 14652 return true; 14653 } 14654 return false; 14655 } 14656 14657 // Return true if resolving the given node (i.e. getTypeFromTypeNode) possibly causes resolution 14658 // of a type alias. 14659 function mayResolveTypeAlias(node: Node): boolean { 14660 switch (node.kind) { 14661 case SyntaxKind.TypeReference: 14662 return isJSDocTypeReference(node) || !!(resolveTypeReferenceName(node as TypeReferenceNode, SymbolFlags.Type).flags & SymbolFlags.TypeAlias); 14663 case SyntaxKind.TypeQuery: 14664 return true; 14665 case SyntaxKind.TypeOperator: 14666 return (node as TypeOperatorNode).operator !== SyntaxKind.UniqueKeyword && mayResolveTypeAlias((node as TypeOperatorNode).type); 14667 case SyntaxKind.ParenthesizedType: 14668 case SyntaxKind.OptionalType: 14669 case SyntaxKind.NamedTupleMember: 14670 case SyntaxKind.JSDocOptionalType: 14671 case SyntaxKind.JSDocNullableType: 14672 case SyntaxKind.JSDocNonNullableType: 14673 case SyntaxKind.JSDocTypeExpression: 14674 return mayResolveTypeAlias((node as ParenthesizedTypeNode | OptionalTypeNode | JSDocTypeReferencingNode | NamedTupleMember).type); 14675 case SyntaxKind.RestType: 14676 return (node as RestTypeNode).type.kind !== SyntaxKind.ArrayType || mayResolveTypeAlias(((node as RestTypeNode).type as ArrayTypeNode).elementType); 14677 case SyntaxKind.UnionType: 14678 case SyntaxKind.IntersectionType: 14679 return some((node as UnionOrIntersectionTypeNode).types, mayResolveTypeAlias); 14680 case SyntaxKind.IndexedAccessType: 14681 return mayResolveTypeAlias((node as IndexedAccessTypeNode).objectType) || mayResolveTypeAlias((node as IndexedAccessTypeNode).indexType); 14682 case SyntaxKind.ConditionalType: 14683 return mayResolveTypeAlias((node as ConditionalTypeNode).checkType) || mayResolveTypeAlias((node as ConditionalTypeNode).extendsType) || 14684 mayResolveTypeAlias((node as ConditionalTypeNode).trueType) || mayResolveTypeAlias((node as ConditionalTypeNode).falseType); 14685 } 14686 return false; 14687 } 14688 14689 function getTypeFromArrayOrTupleTypeNode(node: ArrayTypeNode | TupleTypeNode): Type { 14690 const links = getNodeLinks(node); 14691 if (!links.resolvedType) { 14692 const target = getArrayOrTupleTargetType(node); 14693 if (target === emptyGenericType) { 14694 links.resolvedType = emptyObjectType; 14695 } 14696 else if (!(node.kind === SyntaxKind.TupleType && some(node.elements, e => !!(getTupleElementFlags(e) & ElementFlags.Variadic))) && isDeferredTypeReferenceNode(node)) { 14697 links.resolvedType = node.kind === SyntaxKind.TupleType && node.elements.length === 0 ? target : 14698 createDeferredTypeReference(target, node, /*mapper*/ undefined); 14699 } 14700 else { 14701 const elementTypes = node.kind === SyntaxKind.ArrayType ? [getTypeFromTypeNode(node.elementType)] : map(node.elements, getTypeFromTypeNode); 14702 links.resolvedType = createNormalizedTypeReference(target, elementTypes); 14703 } 14704 } 14705 return links.resolvedType; 14706 } 14707 14708 function isReadonlyTypeOperator(node: Node) { 14709 return isTypeOperatorNode(node) && node.operator === SyntaxKind.ReadonlyKeyword; 14710 } 14711 14712 function createTupleType(elementTypes: readonly Type[], elementFlags?: readonly ElementFlags[], readonly = false, namedMemberDeclarations?: readonly (NamedTupleMember | ParameterDeclaration)[]) { 14713 const tupleTarget = getTupleTargetType(elementFlags || map(elementTypes, _ => ElementFlags.Required), readonly, namedMemberDeclarations); 14714 return tupleTarget === emptyGenericType ? emptyObjectType : 14715 elementTypes.length ? createNormalizedTypeReference(tupleTarget, elementTypes) : 14716 tupleTarget; 14717 } 14718 14719 function getTupleTargetType(elementFlags: readonly ElementFlags[], readonly: boolean, namedMemberDeclarations?: readonly (NamedTupleMember | ParameterDeclaration)[]): GenericType { 14720 if (elementFlags.length === 1 && elementFlags[0] & ElementFlags.Rest) { 14721 // [...X[]] is equivalent to just X[] 14722 return readonly ? globalReadonlyArrayType : globalArrayType; 14723 } 14724 const key = map(elementFlags, f => f & ElementFlags.Required ? "#" : f & ElementFlags.Optional ? "?" : f & ElementFlags.Rest ? "." : "*").join() + 14725 (readonly ? "R" : "") + 14726 (namedMemberDeclarations && namedMemberDeclarations.length ? "," + map(namedMemberDeclarations, getNodeId).join(",") : ""); 14727 let type = tupleTypes.get(key); 14728 if (!type) { 14729 tupleTypes.set(key, type = createTupleTargetType(elementFlags, readonly, namedMemberDeclarations)); 14730 } 14731 return type; 14732 } 14733 14734 // We represent tuple types as type references to synthesized generic interface types created by 14735 // this function. The types are of the form: 14736 // 14737 // interface Tuple<T0, T1, T2, ...> extends Array<T0 | T1 | T2 | ...> { 0: T0, 1: T1, 2: T2, ... } 14738 // 14739 // Note that the generic type created by this function has no symbol associated with it. The same 14740 // is true for each of the synthesized type parameters. 14741 function createTupleTargetType(elementFlags: readonly ElementFlags[], readonly: boolean, namedMemberDeclarations: readonly (NamedTupleMember | ParameterDeclaration)[] | undefined): TupleType { 14742 const arity = elementFlags.length; 14743 const minLength = countWhere(elementFlags, f => !!(f & (ElementFlags.Required | ElementFlags.Variadic))); 14744 let typeParameters: TypeParameter[] | undefined; 14745 const properties: Symbol[] = []; 14746 let combinedFlags: ElementFlags = 0; 14747 if (arity) { 14748 typeParameters = new Array(arity); 14749 for (let i = 0; i < arity; i++) { 14750 const typeParameter = typeParameters[i] = createTypeParameter(); 14751 const flags = elementFlags[i]; 14752 combinedFlags |= flags; 14753 if (!(combinedFlags & ElementFlags.Variable)) { 14754 const property = createSymbol(SymbolFlags.Property | (flags & ElementFlags.Optional ? SymbolFlags.Optional : 0), 14755 "" + i as __String, readonly ? CheckFlags.Readonly : 0); 14756 property.tupleLabelDeclaration = namedMemberDeclarations?.[i]; 14757 property.type = typeParameter; 14758 properties.push(property); 14759 } 14760 } 14761 } 14762 const fixedLength = properties.length; 14763 const lengthSymbol = createSymbol(SymbolFlags.Property, "length" as __String, readonly ? CheckFlags.Readonly : 0); 14764 if (combinedFlags & ElementFlags.Variable) { 14765 lengthSymbol.type = numberType; 14766 } 14767 else { 14768 const literalTypes = []; 14769 for (let i = minLength; i <= arity; i++) literalTypes.push(getNumberLiteralType(i)); 14770 lengthSymbol.type = getUnionType(literalTypes); 14771 } 14772 properties.push(lengthSymbol); 14773 const type = createObjectType(ObjectFlags.Tuple | ObjectFlags.Reference) as TupleType & InterfaceTypeWithDeclaredMembers; 14774 type.typeParameters = typeParameters; 14775 type.outerTypeParameters = undefined; 14776 type.localTypeParameters = typeParameters; 14777 type.instantiations = new Map<string, TypeReference>(); 14778 type.instantiations.set(getTypeListId(type.typeParameters), type as GenericType); 14779 type.target = type as GenericType; 14780 type.resolvedTypeArguments = type.typeParameters; 14781 type.thisType = createTypeParameter(); 14782 type.thisType.isThisType = true; 14783 type.thisType.constraint = type; 14784 type.declaredProperties = properties; 14785 type.declaredCallSignatures = emptyArray; 14786 type.declaredConstructSignatures = emptyArray; 14787 type.declaredIndexInfos = emptyArray; 14788 type.elementFlags = elementFlags; 14789 type.minLength = minLength; 14790 type.fixedLength = fixedLength; 14791 type.hasRestElement = !!(combinedFlags & ElementFlags.Variable); 14792 type.combinedFlags = combinedFlags; 14793 type.readonly = readonly; 14794 type.labeledElementDeclarations = namedMemberDeclarations; 14795 return type; 14796 } 14797 14798 function createNormalizedTypeReference(target: GenericType, typeArguments: readonly Type[] | undefined) { 14799 return target.objectFlags & ObjectFlags.Tuple ? createNormalizedTupleType(target as TupleType, typeArguments!) : createTypeReference(target, typeArguments); 14800 } 14801 14802 function createNormalizedTupleType(target: TupleType, elementTypes: readonly Type[]): Type { 14803 if (!(target.combinedFlags & ElementFlags.NonRequired)) { 14804 // No need to normalize when we only have regular required elements 14805 return createTypeReference(target, elementTypes); 14806 } 14807 if (target.combinedFlags & ElementFlags.Variadic) { 14808 // Transform [A, ...(X | Y | Z)] into [A, ...X] | [A, ...Y] | [A, ...Z] 14809 const unionIndex = findIndex(elementTypes, (t, i) => !!(target.elementFlags[i] & ElementFlags.Variadic && t.flags & (TypeFlags.Never | TypeFlags.Union))); 14810 if (unionIndex >= 0) { 14811 return checkCrossProductUnion(map(elementTypes, (t, i) => target.elementFlags[i] & ElementFlags.Variadic ? t : unknownType)) ? 14812 mapType(elementTypes[unionIndex], t => createNormalizedTupleType(target, replaceElement(elementTypes, unionIndex, t))) : 14813 errorType; 14814 } 14815 } 14816 // We have optional, rest, or variadic elements that may need normalizing. Normalization ensures that all variadic 14817 // elements are generic and that the tuple type has one of the following layouts, disregarding variadic elements: 14818 // (1) Zero or more required elements, followed by zero or more optional elements, followed by zero or one rest element. 14819 // (2) Zero or more required elements, followed by a rest element, followed by zero or more required elements. 14820 // In either layout, zero or more generic variadic elements may be present at any location. 14821 const expandedTypes: Type[] = []; 14822 const expandedFlags: ElementFlags[] = []; 14823 let expandedDeclarations: (NamedTupleMember | ParameterDeclaration)[] | undefined = []; 14824 let lastRequiredIndex = -1; 14825 let firstRestIndex = -1; 14826 let lastOptionalOrRestIndex = -1; 14827 for (let i = 0; i < elementTypes.length; i++) { 14828 const type = elementTypes[i]; 14829 const flags = target.elementFlags[i]; 14830 if (flags & ElementFlags.Variadic) { 14831 if (type.flags & TypeFlags.InstantiableNonPrimitive || isGenericMappedType(type)) { 14832 // Generic variadic elements stay as they are. 14833 addElement(type, ElementFlags.Variadic, target.labeledElementDeclarations?.[i]); 14834 } 14835 else if (isTupleType(type)) { 14836 const elements = getTypeArguments(type); 14837 if (elements.length + expandedTypes.length >= 10_000) { 14838 error(currentNode, isPartOfTypeNode(currentNode!) 14839 ? Diagnostics.Type_produces_a_tuple_type_that_is_too_large_to_represent 14840 : Diagnostics.Expression_produces_a_tuple_type_that_is_too_large_to_represent); 14841 return errorType; 14842 } 14843 // Spread variadic elements with tuple types into the resulting tuple. 14844 forEach(elements, (t, n) => addElement(t, type.target.elementFlags[n], type.target.labeledElementDeclarations?.[n])); 14845 } 14846 else { 14847 // Treat everything else as an array type and create a rest element. 14848 addElement(isArrayLikeType(type) && getIndexTypeOfType(type, numberType) || errorType, ElementFlags.Rest, target.labeledElementDeclarations?.[i]); 14849 } 14850 } 14851 else { 14852 // Copy other element kinds with no change. 14853 addElement(type, flags, target.labeledElementDeclarations?.[i]); 14854 } 14855 } 14856 // Turn optional elements preceding the last required element into required elements 14857 for (let i = 0; i < lastRequiredIndex; i++) { 14858 if (expandedFlags[i] & ElementFlags.Optional) expandedFlags[i] = ElementFlags.Required; 14859 } 14860 if (firstRestIndex >= 0 && firstRestIndex < lastOptionalOrRestIndex) { 14861 // Turn elements between first rest and last optional/rest into a single rest element 14862 expandedTypes[firstRestIndex] = getUnionType(sameMap(expandedTypes.slice(firstRestIndex, lastOptionalOrRestIndex + 1), 14863 (t, i) => expandedFlags[firstRestIndex + i] & ElementFlags.Variadic ? getIndexedAccessType(t, numberType) : t)); 14864 expandedTypes.splice(firstRestIndex + 1, lastOptionalOrRestIndex - firstRestIndex); 14865 expandedFlags.splice(firstRestIndex + 1, lastOptionalOrRestIndex - firstRestIndex); 14866 expandedDeclarations?.splice(firstRestIndex + 1, lastOptionalOrRestIndex - firstRestIndex); 14867 } 14868 const tupleTarget = getTupleTargetType(expandedFlags, target.readonly, expandedDeclarations); 14869 return tupleTarget === emptyGenericType ? emptyObjectType : 14870 expandedFlags.length ? createTypeReference(tupleTarget, expandedTypes) : 14871 tupleTarget; 14872 14873 function addElement(type: Type, flags: ElementFlags, declaration: NamedTupleMember | ParameterDeclaration | undefined) { 14874 if (flags & ElementFlags.Required) { 14875 lastRequiredIndex = expandedFlags.length; 14876 } 14877 if (flags & ElementFlags.Rest && firstRestIndex < 0) { 14878 firstRestIndex = expandedFlags.length; 14879 } 14880 if (flags & (ElementFlags.Optional | ElementFlags.Rest)) { 14881 lastOptionalOrRestIndex = expandedFlags.length; 14882 } 14883 expandedTypes.push(flags & ElementFlags.Optional ? addOptionality(type, /*isProperty*/ true) : type); 14884 expandedFlags.push(flags); 14885 if (expandedDeclarations && declaration) { 14886 expandedDeclarations.push(declaration); 14887 } 14888 else { 14889 expandedDeclarations = undefined; 14890 } 14891 } 14892 } 14893 14894 function sliceTupleType(type: TupleTypeReference, index: number, endSkipCount = 0) { 14895 const target = type.target; 14896 const endIndex = getTypeReferenceArity(type) - endSkipCount; 14897 return index > target.fixedLength ? getRestArrayTypeOfTupleType(type) || createTupleType(emptyArray) : 14898 createTupleType(getTypeArguments(type).slice(index, endIndex), target.elementFlags.slice(index, endIndex), 14899 /*readonly*/ false, target.labeledElementDeclarations && target.labeledElementDeclarations.slice(index, endIndex)); 14900 } 14901 14902 function getKnownKeysOfTupleType(type: TupleTypeReference) { 14903 return getUnionType(append(arrayOf(type.target.fixedLength, i => getStringLiteralType("" + i)), 14904 getIndexType(type.target.readonly ? globalReadonlyArrayType : globalArrayType))); 14905 } 14906 14907 // Return count of starting consecutive tuple elements of the given kind(s) 14908 function getStartElementCount(type: TupleType, flags: ElementFlags) { 14909 const index = findIndex(type.elementFlags, f => !(f & flags)); 14910 return index >= 0 ? index : type.elementFlags.length; 14911 } 14912 14913 // Return count of ending consecutive tuple elements of the given kind(s) 14914 function getEndElementCount(type: TupleType, flags: ElementFlags) { 14915 return type.elementFlags.length - findLastIndex(type.elementFlags, f => !(f & flags)) - 1; 14916 } 14917 14918 function getTypeFromOptionalTypeNode(node: OptionalTypeNode): Type { 14919 return addOptionality(getTypeFromTypeNode(node.type), /*isProperty*/ true); 14920 } 14921 14922 function getTypeId(type: Type): TypeId { 14923 return type.id; 14924 } 14925 14926 function containsType(types: readonly Type[], type: Type): boolean { 14927 return binarySearch(types, type, getTypeId, compareValues) >= 0; 14928 } 14929 14930 function insertType(types: Type[], type: Type): boolean { 14931 const index = binarySearch(types, type, getTypeId, compareValues); 14932 if (index < 0) { 14933 types.splice(~index, 0, type); 14934 return true; 14935 } 14936 return false; 14937 } 14938 14939 function addTypeToUnion(typeSet: Type[], includes: TypeFlags, type: Type) { 14940 const flags = type.flags; 14941 if (flags & TypeFlags.Union) { 14942 return addTypesToUnion(typeSet, includes | (isNamedUnionType(type) ? TypeFlags.Union : 0), (type as UnionType).types); 14943 } 14944 // We ignore 'never' types in unions 14945 if (!(flags & TypeFlags.Never)) { 14946 includes |= flags & TypeFlags.IncludesMask; 14947 if (flags & TypeFlags.Instantiable) includes |= TypeFlags.IncludesInstantiable; 14948 if (type === wildcardType) includes |= TypeFlags.IncludesWildcard; 14949 if (!strictNullChecks && flags & TypeFlags.Nullable) { 14950 if (!(getObjectFlags(type) & ObjectFlags.ContainsWideningType)) includes |= TypeFlags.IncludesNonWideningType; 14951 } 14952 else { 14953 const len = typeSet.length; 14954 const index = len && type.id > typeSet[len - 1].id ? ~len : binarySearch(typeSet, type, getTypeId, compareValues); 14955 if (index < 0) { 14956 typeSet.splice(~index, 0, type); 14957 } 14958 } 14959 } 14960 return includes; 14961 } 14962 14963 // Add the given types to the given type set. Order is preserved, duplicates are removed, 14964 // and nested types of the given kind are flattened into the set. 14965 function addTypesToUnion(typeSet: Type[], includes: TypeFlags, types: readonly Type[]): TypeFlags { 14966 for (const type of types) { 14967 includes = addTypeToUnion(typeSet, includes, type); 14968 } 14969 return includes; 14970 } 14971 14972 function removeSubtypes(types: Type[], hasObjectTypes: boolean): Type[] | undefined { 14973 // [] and [T] immediately reduce to [] and [T] respectively 14974 if (types.length < 2) { 14975 return types; 14976 } 14977 14978 const id = getTypeListId(types); 14979 const match = subtypeReductionCache.get(id); 14980 if (match) { 14981 return match; 14982 } 14983 14984 // We assume that redundant primitive types have already been removed from the types array and that there 14985 // are no any and unknown types in the array. Thus, the only possible supertypes for primitive types are empty 14986 // object types, and if none of those are present we can exclude primitive types from the subtype check. 14987 const hasEmptyObject = hasObjectTypes && some(types, t => !!(t.flags & TypeFlags.Object) && !isGenericMappedType(t) && isEmptyResolvedType(resolveStructuredTypeMembers(t as ObjectType))); 14988 const len = types.length; 14989 let i = len; 14990 let count = 0; 14991 while (i > 0) { 14992 i--; 14993 const source = types[i]; 14994 if (hasEmptyObject || source.flags & TypeFlags.StructuredOrInstantiable) { 14995 // Find the first property with a unit type, if any. When constituents have a property by the same name 14996 // but of a different unit type, we can quickly disqualify them from subtype checks. This helps subtype 14997 // reduction of large discriminated union types. 14998 const keyProperty = source.flags & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.InstantiableNonPrimitive) ? 14999 find(getPropertiesOfType(source), p => isUnitType(getTypeOfSymbol(p))) : 15000 undefined; 15001 const keyPropertyType = keyProperty && getRegularTypeOfLiteralType(getTypeOfSymbol(keyProperty)); 15002 for (const target of types) { 15003 if (source !== target) { 15004 if (count === 100000) { 15005 // After 100000 subtype checks we estimate the remaining amount of work by assuming the 15006 // same ratio of checks per element. If the estimated number of remaining type checks is 15007 // greater than 1M we deem the union type too complex to represent. This for example 15008 // caps union types at 1000 unique object types. 15009 const estimatedCount = (count / (len - i)) * len; 15010 if (estimatedCount > 1000000) { 15011 tracing?.instant(tracing.Phase.CheckTypes, "removeSubtypes_DepthLimit", { typeIds: types.map(t => t.id) }); 15012 error(currentNode, Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent); 15013 return undefined; 15014 } 15015 } 15016 count++; 15017 if (keyProperty && target.flags & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.InstantiableNonPrimitive)) { 15018 const t = getTypeOfPropertyOfType(target, keyProperty.escapedName); 15019 if (t && isUnitType(t) && getRegularTypeOfLiteralType(t) !== keyPropertyType) { 15020 continue; 15021 } 15022 } 15023 if (isTypeRelatedTo(source, target, strictSubtypeRelation) && ( 15024 !(getObjectFlags(getTargetType(source)) & ObjectFlags.Class) || 15025 !(getObjectFlags(getTargetType(target)) & ObjectFlags.Class) || 15026 isTypeDerivedFrom(source, target))) { 15027 orderedRemoveItemAt(types, i); 15028 break; 15029 } 15030 } 15031 } 15032 } 15033 } 15034 subtypeReductionCache.set(id, types); 15035 return types; 15036 } 15037 15038 function removeRedundantLiteralTypes(types: Type[], includes: TypeFlags, reduceVoidUndefined: boolean) { 15039 let i = types.length; 15040 while (i > 0) { 15041 i--; 15042 const t = types[i]; 15043 const flags = t.flags; 15044 const remove = 15045 flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) && includes & TypeFlags.String || 15046 flags & TypeFlags.NumberLiteral && includes & TypeFlags.Number || 15047 flags & TypeFlags.BigIntLiteral && includes & TypeFlags.BigInt || 15048 flags & TypeFlags.UniqueESSymbol && includes & TypeFlags.ESSymbol || 15049 reduceVoidUndefined && flags & TypeFlags.Undefined && includes & TypeFlags.Void || 15050 isFreshLiteralType(t) && containsType(types, (t as LiteralType).regularType); 15051 if (remove) { 15052 orderedRemoveItemAt(types, i); 15053 } 15054 } 15055 } 15056 15057 function removeStringLiteralsMatchedByTemplateLiterals(types: Type[]) { 15058 const templates = filter(types, isPatternLiteralType) as TemplateLiteralType[]; 15059 if (templates.length) { 15060 let i = types.length; 15061 while (i > 0) { 15062 i--; 15063 const t = types[i]; 15064 if (t.flags & TypeFlags.StringLiteral && some(templates, template => isTypeMatchedByTemplateLiteralType(t, template))) { 15065 orderedRemoveItemAt(types, i); 15066 } 15067 } 15068 } 15069 } 15070 15071 function isNamedUnionType(type: Type) { 15072 return !!(type.flags & TypeFlags.Union && (type.aliasSymbol || (type as UnionType).origin)); 15073 } 15074 15075 function addNamedUnions(namedUnions: Type[], types: readonly Type[]) { 15076 for (const t of types) { 15077 if (t.flags & TypeFlags.Union) { 15078 const origin = (t as UnionType).origin; 15079 if (t.aliasSymbol || origin && !(origin.flags & TypeFlags.Union)) { 15080 pushIfUnique(namedUnions, t); 15081 } 15082 else if (origin && origin.flags & TypeFlags.Union) { 15083 addNamedUnions(namedUnions, (origin as UnionType).types); 15084 } 15085 } 15086 } 15087 } 15088 15089 function createOriginUnionOrIntersectionType(flags: TypeFlags, types: Type[]) { 15090 const result = createOriginType(flags) as UnionOrIntersectionType; 15091 result.types = types; 15092 return result; 15093 } 15094 15095 // We sort and deduplicate the constituent types based on object identity. If the subtypeReduction 15096 // flag is specified we also reduce the constituent type set to only include types that aren't subtypes 15097 // of other types. Subtype reduction is expensive for large union types and is possible only when union 15098 // types are known not to circularly reference themselves (as is the case with union types created by 15099 // expression constructs such as array literals and the || and ?: operators). Named types can 15100 // circularly reference themselves and therefore cannot be subtype reduced during their declaration. 15101 // For example, "type Item = string | (() => Item" is a named type that circularly references itself. 15102 function getUnionType(types: readonly Type[], unionReduction: UnionReduction = UnionReduction.Literal, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[], origin?: Type): Type { 15103 if (types.length === 0) { 15104 return neverType; 15105 } 15106 if (types.length === 1) { 15107 return types[0]; 15108 } 15109 let typeSet: Type[] | undefined = []; 15110 const includes = addTypesToUnion(typeSet, 0, types); 15111 if (unionReduction !== UnionReduction.None) { 15112 if (includes & TypeFlags.AnyOrUnknown) { 15113 return includes & TypeFlags.Any ? 15114 includes & TypeFlags.IncludesWildcard ? wildcardType : anyType : 15115 includes & TypeFlags.Null || containsType(typeSet, unknownType) ? unknownType : nonNullUnknownType; 15116 } 15117 if (exactOptionalPropertyTypes && includes & TypeFlags.Undefined) { 15118 const missingIndex = binarySearch(typeSet, missingType, getTypeId, compareValues); 15119 if (missingIndex >= 0 && containsType(typeSet, undefinedType)) { 15120 orderedRemoveItemAt(typeSet, missingIndex); 15121 } 15122 } 15123 if (includes & (TypeFlags.Literal | TypeFlags.UniqueESSymbol | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) || includes & TypeFlags.Void && includes & TypeFlags.Undefined) { 15124 removeRedundantLiteralTypes(typeSet, includes, !!(unionReduction & UnionReduction.Subtype)); 15125 } 15126 if (includes & TypeFlags.StringLiteral && includes & TypeFlags.TemplateLiteral) { 15127 removeStringLiteralsMatchedByTemplateLiterals(typeSet); 15128 } 15129 if (unionReduction === UnionReduction.Subtype) { 15130 typeSet = removeSubtypes(typeSet, !!(includes & TypeFlags.Object)); 15131 if (!typeSet) { 15132 return errorType; 15133 } 15134 } 15135 if (typeSet.length === 0) { 15136 return includes & TypeFlags.Null ? includes & TypeFlags.IncludesNonWideningType ? nullType : nullWideningType : 15137 includes & TypeFlags.Undefined ? includes & TypeFlags.IncludesNonWideningType ? undefinedType : undefinedWideningType : 15138 neverType; 15139 } 15140 } 15141 if (!origin && includes & TypeFlags.Union) { 15142 const namedUnions: Type[] = []; 15143 addNamedUnions(namedUnions, types); 15144 const reducedTypes: Type[] = []; 15145 for (const t of typeSet) { 15146 if (!some(namedUnions, union => containsType((union as UnionType).types, t))) { 15147 reducedTypes.push(t); 15148 } 15149 } 15150 if (!aliasSymbol && namedUnions.length === 1 && reducedTypes.length === 0) { 15151 return namedUnions[0]; 15152 } 15153 // We create a denormalized origin type only when the union was created from one or more named unions 15154 // (unions with alias symbols or origins) and when there is no overlap between those named unions. 15155 const namedTypesCount = reduceLeft(namedUnions, (sum, union) => sum + (union as UnionType).types.length, 0); 15156 if (namedTypesCount + reducedTypes.length === typeSet.length) { 15157 for (const t of namedUnions) { 15158 insertType(reducedTypes, t); 15159 } 15160 origin = createOriginUnionOrIntersectionType(TypeFlags.Union, reducedTypes); 15161 } 15162 } 15163 const objectFlags = (includes & TypeFlags.NotPrimitiveUnion ? 0 : ObjectFlags.PrimitiveUnion) | 15164 (includes & TypeFlags.Intersection ? ObjectFlags.ContainsIntersections : 0); 15165 return getUnionTypeFromSortedList(typeSet, objectFlags, aliasSymbol, aliasTypeArguments, origin); 15166 } 15167 15168 function getUnionOrIntersectionTypePredicate(signatures: readonly Signature[], kind: TypeFlags | undefined): TypePredicate | undefined { 15169 let first: TypePredicate | undefined; 15170 const types: Type[] = []; 15171 for (const sig of signatures) { 15172 const pred = getTypePredicateOfSignature(sig); 15173 if (!pred || pred.kind === TypePredicateKind.AssertsThis || pred.kind === TypePredicateKind.AssertsIdentifier) { 15174 if (kind !== TypeFlags.Intersection) { 15175 continue; 15176 } 15177 else { 15178 return; // intersections demand all members be type predicates for the result to have a predicate 15179 } 15180 } 15181 15182 if (first) { 15183 if (!typePredicateKindsMatch(first, pred)) { 15184 // No common type predicate. 15185 return undefined; 15186 } 15187 } 15188 else { 15189 first = pred; 15190 } 15191 types.push(pred.type); 15192 } 15193 if (!first) { 15194 // No signatures had a type predicate. 15195 return undefined; 15196 } 15197 const compositeType = getUnionOrIntersectionType(types, kind); 15198 return createTypePredicate(first.kind, first.parameterName, first.parameterIndex, compositeType); 15199 } 15200 15201 function typePredicateKindsMatch(a: TypePredicate, b: TypePredicate): boolean { 15202 return a.kind === b.kind && a.parameterIndex === b.parameterIndex; 15203 } 15204 15205 // This function assumes the constituent type list is sorted and deduplicated. 15206 function getUnionTypeFromSortedList(types: Type[], objectFlags: ObjectFlags, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[], origin?: Type): Type { 15207 if (types.length === 0) { 15208 return neverType; 15209 } 15210 if (types.length === 1) { 15211 return types[0]; 15212 } 15213 const typeKey = !origin ? getTypeListId(types) : 15214 origin.flags & TypeFlags.Union ? `|${getTypeListId((origin as UnionType).types)}` : 15215 origin.flags & TypeFlags.Intersection ? `&${getTypeListId((origin as IntersectionType).types)}` : 15216 `#${(origin as IndexType).type.id}|${getTypeListId(types)}`; // origin type id alone is insufficient, as `keyof x` may resolve to multiple WIP values while `x` is still resolving 15217 const id = typeKey + getAliasId(aliasSymbol, aliasTypeArguments); 15218 let type = unionTypes.get(id); 15219 if (!type) { 15220 type = createType(TypeFlags.Union) as UnionType; 15221 type.objectFlags = objectFlags | getPropagatingFlagsOfTypes(types, /*excludeKinds*/ TypeFlags.Nullable); 15222 type.types = types; 15223 type.origin = origin; 15224 type.aliasSymbol = aliasSymbol; 15225 type.aliasTypeArguments = aliasTypeArguments; 15226 if (types.length === 2 && types[0].flags & TypeFlags.BooleanLiteral && types[1].flags & TypeFlags.BooleanLiteral) { 15227 type.flags |= TypeFlags.Boolean; 15228 (type as UnionType & IntrinsicType).intrinsicName = "boolean"; 15229 } 15230 unionTypes.set(id, type); 15231 } 15232 return type; 15233 } 15234 15235 function getTypeFromUnionTypeNode(node: UnionTypeNode): Type { 15236 const links = getNodeLinks(node); 15237 if (!links.resolvedType) { 15238 const aliasSymbol = getAliasSymbolForTypeNode(node); 15239 links.resolvedType = getUnionType(map(node.types, getTypeFromTypeNode), UnionReduction.Literal, 15240 aliasSymbol, getTypeArgumentsForAliasSymbol(aliasSymbol)); 15241 } 15242 return links.resolvedType; 15243 } 15244 15245 function addTypeToIntersection(typeSet: ESMap<string, Type>, includes: TypeFlags, type: Type) { 15246 const flags = type.flags; 15247 if (flags & TypeFlags.Intersection) { 15248 return addTypesToIntersection(typeSet, includes, (type as IntersectionType).types); 15249 } 15250 if (isEmptyAnonymousObjectType(type)) { 15251 if (!(includes & TypeFlags.IncludesEmptyObject)) { 15252 includes |= TypeFlags.IncludesEmptyObject; 15253 typeSet.set(type.id.toString(), type); 15254 } 15255 } 15256 else { 15257 if (flags & TypeFlags.AnyOrUnknown) { 15258 if (type === wildcardType) includes |= TypeFlags.IncludesWildcard; 15259 } 15260 else if (strictNullChecks || !(flags & TypeFlags.Nullable)) { 15261 if (exactOptionalPropertyTypes && type === missingType) { 15262 includes |= TypeFlags.IncludesMissingType; 15263 type = undefinedType; 15264 } 15265 if (!typeSet.has(type.id.toString())) { 15266 if (type.flags & TypeFlags.Unit && includes & TypeFlags.Unit) { 15267 // We have seen two distinct unit types which means we should reduce to an 15268 // empty intersection. Adding TypeFlags.NonPrimitive causes that to happen. 15269 includes |= TypeFlags.NonPrimitive; 15270 } 15271 typeSet.set(type.id.toString(), type); 15272 } 15273 } 15274 includes |= flags & TypeFlags.IncludesMask; 15275 } 15276 return includes; 15277 } 15278 15279 // Add the given types to the given type set. Order is preserved, freshness is removed from literal 15280 // types, duplicates are removed, and nested types of the given kind are flattened into the set. 15281 function addTypesToIntersection(typeSet: ESMap<string, Type>, includes: TypeFlags, types: readonly Type[]) { 15282 for (const type of types) { 15283 includes = addTypeToIntersection(typeSet, includes, getRegularTypeOfLiteralType(type)); 15284 } 15285 return includes; 15286 } 15287 15288 function removeRedundantSupertypes(types: Type[], includes: TypeFlags) { 15289 let i = types.length; 15290 while (i > 0) { 15291 i--; 15292 const t = types[i]; 15293 const remove = 15294 t.flags & TypeFlags.String && includes & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) || 15295 t.flags & TypeFlags.Number && includes & TypeFlags.NumberLiteral || 15296 t.flags & TypeFlags.BigInt && includes & TypeFlags.BigIntLiteral || 15297 t.flags & TypeFlags.ESSymbol && includes & TypeFlags.UniqueESSymbol || 15298 t.flags & TypeFlags.Void && includes & TypeFlags.Undefined || 15299 isEmptyAnonymousObjectType(t) && includes & TypeFlags.DefinitelyNonNullable; 15300 if (remove) { 15301 orderedRemoveItemAt(types, i); 15302 } 15303 } 15304 } 15305 15306 // Check that the given type has a match in every union. A given type is matched by 15307 // an identical type, and a literal type is additionally matched by its corresponding 15308 // primitive type. 15309 function eachUnionContains(unionTypes: UnionType[], type: Type) { 15310 for (const u of unionTypes) { 15311 if (!containsType(u.types, type)) { 15312 const primitive = type.flags & TypeFlags.StringLiteral ? stringType : 15313 type.flags & TypeFlags.NumberLiteral ? numberType : 15314 type.flags & TypeFlags.BigIntLiteral ? bigintType : 15315 type.flags & TypeFlags.UniqueESSymbol ? esSymbolType : 15316 undefined; 15317 if (!primitive || !containsType(u.types, primitive)) { 15318 return false; 15319 } 15320 } 15321 } 15322 return true; 15323 } 15324 15325 /** 15326 * Returns `true` if the intersection of the template literals and string literals is the empty set, eg `get${string}` & "setX", and should reduce to `never` 15327 */ 15328 function extractRedundantTemplateLiterals(types: Type[]): boolean { 15329 let i = types.length; 15330 const literals = filter(types, t => !!(t.flags & TypeFlags.StringLiteral)); 15331 while (i > 0) { 15332 i--; 15333 const t = types[i]; 15334 if (!(t.flags & TypeFlags.TemplateLiteral)) continue; 15335 for (const t2 of literals) { 15336 if (isTypeSubtypeOf(t2, t)) { 15337 // eg, ``get${T}` & "getX"` is just `"getX"` 15338 orderedRemoveItemAt(types, i); 15339 break; 15340 } 15341 else if (isPatternLiteralType(t)) { 15342 return true; 15343 } 15344 } 15345 } 15346 return false; 15347 } 15348 15349 function eachIsUnionContaining(types: Type[], flag: TypeFlags) { 15350 return every(types, t => !!(t.flags & TypeFlags.Union) && some((t as UnionType).types, tt => !!(tt.flags & flag))); 15351 } 15352 15353 function removeFromEach(types: Type[], flag: TypeFlags) { 15354 for (let i = 0; i < types.length; i++) { 15355 types[i] = filterType(types[i], t => !(t.flags & flag)); 15356 } 15357 } 15358 15359 // If the given list of types contains more than one union of primitive types, replace the 15360 // first with a union containing an intersection of those primitive types, then remove the 15361 // other unions and return true. Otherwise, do nothing and return false. 15362 function intersectUnionsOfPrimitiveTypes(types: Type[]) { 15363 let unionTypes: UnionType[] | undefined; 15364 const index = findIndex(types, t => !!(getObjectFlags(t) & ObjectFlags.PrimitiveUnion)); 15365 if (index < 0) { 15366 return false; 15367 } 15368 let i = index + 1; 15369 // Remove all but the first union of primitive types and collect them in 15370 // the unionTypes array. 15371 while (i < types.length) { 15372 const t = types[i]; 15373 if (getObjectFlags(t) & ObjectFlags.PrimitiveUnion) { 15374 (unionTypes || (unionTypes = [types[index] as UnionType])).push(t as UnionType); 15375 orderedRemoveItemAt(types, i); 15376 } 15377 else { 15378 i++; 15379 } 15380 } 15381 // Return false if there was only one union of primitive types 15382 if (!unionTypes) { 15383 return false; 15384 } 15385 // We have more than one union of primitive types, now intersect them. For each 15386 // type in each union we check if the type is matched in every union and if so 15387 // we include it in the result. 15388 const checked: Type[] = []; 15389 const result: Type[] = []; 15390 for (const u of unionTypes) { 15391 for (const t of u.types) { 15392 if (insertType(checked, t)) { 15393 if (eachUnionContains(unionTypes, t)) { 15394 insertType(result, t); 15395 } 15396 } 15397 } 15398 } 15399 // Finally replace the first union with the result 15400 types[index] = getUnionTypeFromSortedList(result, ObjectFlags.PrimitiveUnion); 15401 return true; 15402 } 15403 15404 function createIntersectionType(types: Type[], aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]) { 15405 const result = createType(TypeFlags.Intersection) as IntersectionType; 15406 result.objectFlags = getPropagatingFlagsOfTypes(types, /*excludeKinds*/ TypeFlags.Nullable); 15407 result.types = types; 15408 result.aliasSymbol = aliasSymbol; 15409 result.aliasTypeArguments = aliasTypeArguments; 15410 return result; 15411 } 15412 15413 // We normalize combinations of intersection and union types based on the distributive property of the '&' 15414 // operator. Specifically, because X & (A | B) is equivalent to X & A | X & B, we can transform intersection 15415 // types with union type constituents into equivalent union types with intersection type constituents and 15416 // effectively ensure that union types are always at the top level in type representations. 15417 // 15418 // We do not perform structural deduplication on intersection types. Intersection types are created only by the & 15419 // type operator and we can't reduce those because we want to support recursive intersection types. For example, 15420 // a type alias of the form "type List<T> = T & { next: List<T> }" cannot be reduced during its declaration. 15421 // Also, unlike union types, the order of the constituent types is preserved in order that overload resolution 15422 // for intersections of types with signatures can be deterministic. 15423 function getIntersectionType(types: readonly Type[], aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[], noSupertypeReduction?: boolean): Type { 15424 const typeMembershipMap: ESMap<string, Type> = new Map(); 15425 const includes = addTypesToIntersection(typeMembershipMap, 0, types); 15426 const typeSet: Type[] = arrayFrom(typeMembershipMap.values()); 15427 // An intersection type is considered empty if it contains 15428 // the type never, or 15429 // more than one unit type or, 15430 // an object type and a nullable type (null or undefined), or 15431 // a string-like type and a type known to be non-string-like, or 15432 // a number-like type and a type known to be non-number-like, or 15433 // a symbol-like type and a type known to be non-symbol-like, or 15434 // a void-like type and a type known to be non-void-like, or 15435 // a non-primitive type and a type known to be primitive. 15436 if (includes & TypeFlags.Never) { 15437 return contains(typeSet, silentNeverType) ? silentNeverType : neverType; 15438 } 15439 if (strictNullChecks && includes & TypeFlags.Nullable && includes & (TypeFlags.Object | TypeFlags.NonPrimitive | TypeFlags.IncludesEmptyObject) || 15440 includes & TypeFlags.NonPrimitive && includes & (TypeFlags.DisjointDomains & ~TypeFlags.NonPrimitive) || 15441 includes & TypeFlags.StringLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.StringLike) || 15442 includes & TypeFlags.NumberLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.NumberLike) || 15443 includes & TypeFlags.BigIntLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.BigIntLike) || 15444 includes & TypeFlags.ESSymbolLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.ESSymbolLike) || 15445 includes & TypeFlags.VoidLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.VoidLike)) { 15446 return neverType; 15447 } 15448 if (includes & TypeFlags.TemplateLiteral && includes & TypeFlags.StringLiteral && extractRedundantTemplateLiterals(typeSet)) { 15449 return neverType; 15450 } 15451 if (includes & TypeFlags.Any) { 15452 return includes & TypeFlags.IncludesWildcard ? wildcardType : anyType; 15453 } 15454 if (!strictNullChecks && includes & TypeFlags.Nullable) { 15455 return includes & TypeFlags.IncludesEmptyObject ? neverType : includes & TypeFlags.Undefined ? undefinedType : nullType; 15456 } 15457 if (includes & TypeFlags.String && includes & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) || 15458 includes & TypeFlags.Number && includes & TypeFlags.NumberLiteral || 15459 includes & TypeFlags.BigInt && includes & TypeFlags.BigIntLiteral || 15460 includes & TypeFlags.ESSymbol && includes & TypeFlags.UniqueESSymbol || 15461 includes & TypeFlags.Void && includes & TypeFlags.Undefined || 15462 includes & TypeFlags.IncludesEmptyObject && includes & TypeFlags.DefinitelyNonNullable) { 15463 if (!noSupertypeReduction) removeRedundantSupertypes(typeSet, includes); 15464 } 15465 if (includes & TypeFlags.IncludesMissingType) { 15466 typeSet[typeSet.indexOf(undefinedType)] = missingType; 15467 } 15468 if (typeSet.length === 0) { 15469 return unknownType; 15470 } 15471 if (typeSet.length === 1) { 15472 return typeSet[0]; 15473 } 15474 const id = getTypeListId(typeSet) + getAliasId(aliasSymbol, aliasTypeArguments); 15475 let result = intersectionTypes.get(id); 15476 if (!result) { 15477 if (includes & TypeFlags.Union) { 15478 if (intersectUnionsOfPrimitiveTypes(typeSet)) { 15479 // When the intersection creates a reduced set (which might mean that *all* union types have 15480 // disappeared), we restart the operation to get a new set of combined flags. Once we have 15481 // reduced we'll never reduce again, so this occurs at most once. 15482 result = getIntersectionType(typeSet, aliasSymbol, aliasTypeArguments); 15483 } 15484 else if (eachIsUnionContaining(typeSet, TypeFlags.Undefined)) { 15485 const undefinedOrMissingType = exactOptionalPropertyTypes && some(typeSet, t => containsType((t as UnionType).types, missingType)) ? missingType : undefinedType; 15486 removeFromEach(typeSet, TypeFlags.Undefined); 15487 result = getUnionType([getIntersectionType(typeSet), undefinedOrMissingType], UnionReduction.Literal, aliasSymbol, aliasTypeArguments); 15488 } 15489 else if (eachIsUnionContaining(typeSet, TypeFlags.Null)) { 15490 removeFromEach(typeSet, TypeFlags.Null); 15491 result = getUnionType([getIntersectionType(typeSet), nullType], UnionReduction.Literal, aliasSymbol, aliasTypeArguments); 15492 } 15493 else { 15494 // We are attempting to construct a type of the form X & (A | B) & (C | D). Transform this into a type of 15495 // the form X & A & C | X & A & D | X & B & C | X & B & D. If the estimated size of the resulting union type 15496 // exceeds 100000 constituents, report an error. 15497 if (!checkCrossProductUnion(typeSet)) { 15498 return errorType; 15499 } 15500 const constituents = getCrossProductIntersections(typeSet); 15501 // We attach a denormalized origin type when at least one constituent of the cross-product union is an 15502 // intersection (i.e. when the intersection didn't just reduce one or more unions to smaller unions) and 15503 // the denormalized origin has fewer constituents than the union itself. 15504 const origin = some(constituents, t => !!(t.flags & TypeFlags.Intersection)) && getConstituentCountOfTypes(constituents) > getConstituentCountOfTypes(typeSet) ? createOriginUnionOrIntersectionType(TypeFlags.Intersection, typeSet) : undefined; 15505 result = getUnionType(constituents, UnionReduction.Literal, aliasSymbol, aliasTypeArguments, origin); 15506 } 15507 } 15508 else { 15509 result = createIntersectionType(typeSet, aliasSymbol, aliasTypeArguments); 15510 } 15511 intersectionTypes.set(id, result); 15512 } 15513 return result; 15514 } 15515 15516 function getCrossProductUnionSize(types: readonly Type[]) { 15517 return reduceLeft(types, (n, t) => t.flags & TypeFlags.Union ? n * (t as UnionType).types.length : t.flags & TypeFlags.Never ? 0 : n, 1); 15518 } 15519 15520 function checkCrossProductUnion(types: readonly Type[]) { 15521 const size = getCrossProductUnionSize(types); 15522 if (size >= 100000) { 15523 tracing?.instant(tracing.Phase.CheckTypes, "checkCrossProductUnion_DepthLimit", { typeIds: types.map(t => t.id), size }); 15524 error(currentNode, Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent); 15525 return false; 15526 } 15527 return true; 15528 } 15529 15530 function getCrossProductIntersections(types: readonly Type[]) { 15531 const count = getCrossProductUnionSize(types); 15532 const intersections: Type[] = []; 15533 for (let i = 0; i < count; i++) { 15534 const constituents = types.slice(); 15535 let n = i; 15536 for (let j = types.length - 1; j >= 0; j--) { 15537 if (types[j].flags & TypeFlags.Union) { 15538 const sourceTypes = (types[j] as UnionType).types; 15539 const length = sourceTypes.length; 15540 constituents[j] = sourceTypes[n % length]; 15541 n = Math.floor(n / length); 15542 } 15543 } 15544 const t = getIntersectionType(constituents); 15545 if (!(t.flags & TypeFlags.Never)) intersections.push(t); 15546 } 15547 return intersections; 15548 } 15549 15550 function getConstituentCount(type: Type): number { 15551 return !(type.flags & TypeFlags.UnionOrIntersection) || type.aliasSymbol ? 1 : 15552 type.flags & TypeFlags.Union && (type as UnionType).origin ? getConstituentCount((type as UnionType).origin!) : 15553 getConstituentCountOfTypes((type as UnionOrIntersectionType).types); 15554 } 15555 15556 function getConstituentCountOfTypes(types: Type[]): number { 15557 return reduceLeft(types, (n, t) => n + getConstituentCount(t), 0); 15558 } 15559 15560 function getTypeFromIntersectionTypeNode(node: IntersectionTypeNode): Type { 15561 const links = getNodeLinks(node); 15562 if (!links.resolvedType) { 15563 const aliasSymbol = getAliasSymbolForTypeNode(node); 15564 const types = map(node.types, getTypeFromTypeNode); 15565 const noSupertypeReduction = types.length === 2 && !!(types[0].flags & (TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt)) && types[1] === emptyTypeLiteralType; 15566 links.resolvedType = getIntersectionType(types, aliasSymbol, getTypeArgumentsForAliasSymbol(aliasSymbol), noSupertypeReduction); 15567 } 15568 return links.resolvedType; 15569 } 15570 15571 function createIndexType(type: InstantiableType | UnionOrIntersectionType, stringsOnly: boolean) { 15572 const result = createType(TypeFlags.Index) as IndexType; 15573 result.type = type; 15574 result.stringsOnly = stringsOnly; 15575 return result; 15576 } 15577 15578 function createOriginIndexType(type: InstantiableType | UnionOrIntersectionType) { 15579 const result = createOriginType(TypeFlags.Index) as IndexType; 15580 result.type = type; 15581 return result; 15582 } 15583 15584 function getIndexTypeForGenericType(type: InstantiableType | UnionOrIntersectionType, stringsOnly: boolean) { 15585 return stringsOnly ? 15586 type.resolvedStringIndexType || (type.resolvedStringIndexType = createIndexType(type, /*stringsOnly*/ true)) : 15587 type.resolvedIndexType || (type.resolvedIndexType = createIndexType(type, /*stringsOnly*/ false)); 15588 } 15589 15590 /** 15591 * This roughly mirrors `resolveMappedTypeMembers` in the nongeneric case, except only reports a union of the keys calculated, 15592 * rather than manufacturing the properties. We can't just fetch the `constraintType` since that would ignore mappings 15593 * and mapping the `constraintType` directly ignores how mapped types map _properties_ and not keys (thus ignoring subtype 15594 * reduction in the constraintType) when possible. 15595 * @param noIndexSignatures Indicates if _string_ index signatures should be elided. (other index signatures are always reported) 15596 */ 15597 function getIndexTypeForMappedType(type: MappedType, stringsOnly: boolean, noIndexSignatures: boolean | undefined) { 15598 const typeParameter = getTypeParameterFromMappedType(type); 15599 const constraintType = getConstraintTypeFromMappedType(type); 15600 const nameType = getNameTypeFromMappedType(type.target as MappedType || type); 15601 if (!nameType && !noIndexSignatures) { 15602 // no mapping and no filtering required, just quickly bail to returning the constraint in the common case 15603 return constraintType; 15604 } 15605 const keyTypes: Type[] = []; 15606 if (isMappedTypeWithKeyofConstraintDeclaration(type)) { 15607 // We have a { [P in keyof T]: X } 15608 15609 // `getApparentType` on the T in a generic mapped type can trigger a circularity 15610 // (conditionals and `infer` types create a circular dependency in the constraint resolution) 15611 // so we only eagerly manifest the keys if the constraint is nongeneric 15612 if (!isGenericIndexType(constraintType)) { 15613 const modifiersType = getApparentType(getModifiersTypeFromMappedType(type)); // The 'T' in 'keyof T' 15614 forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType(modifiersType, TypeFlags.StringOrNumberLiteralOrUnique, stringsOnly, addMemberForKeyType); 15615 } 15616 else { 15617 // we have a generic index and a homomorphic mapping (but a distributive key remapping) - we need to defer the whole `keyof whatever` for later 15618 // since it's not safe to resolve the shape of modifier type 15619 return getIndexTypeForGenericType(type, stringsOnly); 15620 } 15621 } 15622 else { 15623 forEachType(getLowerBoundOfKeyType(constraintType), addMemberForKeyType); 15624 } 15625 if (isGenericIndexType(constraintType)) { // include the generic component in the resulting type 15626 forEachType(constraintType, addMemberForKeyType); 15627 } 15628 // we had to pick apart the constraintType to potentially map/filter it - compare the final resulting list with the original constraintType, 15629 // so we can return the union that preserves aliases/origin data if possible 15630 const result = noIndexSignatures ? filterType(getUnionType(keyTypes), t => !(t.flags & (TypeFlags.Any | TypeFlags.String))) : getUnionType(keyTypes); 15631 if (result.flags & TypeFlags.Union && constraintType.flags & TypeFlags.Union && getTypeListId((result as UnionType).types) === getTypeListId((constraintType as UnionType).types)){ 15632 return constraintType; 15633 } 15634 return result; 15635 15636 function addMemberForKeyType(keyType: Type) { 15637 const propNameType = nameType ? instantiateType(nameType, appendTypeMapping(type.mapper, typeParameter, keyType)) : keyType; 15638 // `keyof` currently always returns `string | number` for concrete `string` index signatures - the below ternary keeps that behavior for mapped types 15639 // See `getLiteralTypeFromProperties` where there's a similar ternary to cause the same behavior. 15640 keyTypes.push(propNameType === stringType ? stringOrNumberType : propNameType); 15641 } 15642 } 15643 15644 // Ordinarily we reduce a keyof M, where M is a mapped type { [P in K as N<P>]: X }, to simply N<K>. This however presumes 15645 // that N distributes over union types, i.e. that N<A | B | C> is equivalent to N<A> | N<B> | N<C>. Specifically, we only 15646 // want to perform the reduction when the name type of a mapped type is distributive with respect to the type variable 15647 // introduced by the 'in' clause of the mapped type. Note that non-generic types are considered to be distributive because 15648 // they're the same type regardless of what's being distributed over. 15649 function hasDistributiveNameType(mappedType: MappedType) { 15650 const typeVariable = getTypeParameterFromMappedType(mappedType); 15651 return isDistributive(getNameTypeFromMappedType(mappedType) || typeVariable); 15652 function isDistributive(type: Type): boolean { 15653 return type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Primitive | TypeFlags.Never | TypeFlags.TypeParameter | TypeFlags.Object | TypeFlags.NonPrimitive) ? true : 15654 type.flags & TypeFlags.Conditional ? (type as ConditionalType).root.isDistributive && (type as ConditionalType).checkType === typeVariable : 15655 type.flags & (TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral) ? every((type as UnionOrIntersectionType | TemplateLiteralType).types, isDistributive) : 15656 type.flags & TypeFlags.IndexedAccess ? isDistributive((type as IndexedAccessType).objectType) && isDistributive((type as IndexedAccessType).indexType) : 15657 type.flags & TypeFlags.Substitution ? isDistributive((type as SubstitutionType).baseType) && isDistributive((type as SubstitutionType).constraint): 15658 type.flags & TypeFlags.StringMapping ? isDistributive((type as StringMappingType).type) : 15659 false; 15660 } 15661 } 15662 15663 function getLiteralTypeFromPropertyName(name: PropertyName) { 15664 if (isPrivateIdentifier(name)) { 15665 return neverType; 15666 } 15667 return isIdentifier(name) ? getStringLiteralType(unescapeLeadingUnderscores(name.escapedText)) : 15668 getRegularTypeOfLiteralType(isComputedPropertyName(name) ? checkComputedPropertyName(name) : checkExpression(name)); 15669 } 15670 15671 function getLiteralTypeFromProperty(prop: Symbol, include: TypeFlags, includeNonPublic?: boolean) { 15672 if (includeNonPublic || !(getDeclarationModifierFlagsFromSymbol(prop) & ModifierFlags.NonPublicAccessibilityModifier)) { 15673 let type = getSymbolLinks(getLateBoundSymbol(prop)).nameType; 15674 if (!type) { 15675 const name = getNameOfDeclaration(prop.valueDeclaration) as PropertyName; 15676 type = prop.escapedName === InternalSymbolName.Default ? getStringLiteralType("default") : 15677 name && getLiteralTypeFromPropertyName(name) || (!isKnownSymbol(prop) ? getStringLiteralType(symbolName(prop)) : undefined); 15678 } 15679 if (type && type.flags & include) { 15680 return type; 15681 } 15682 } 15683 return neverType; 15684 } 15685 15686 function isKeyTypeIncluded(keyType: Type, include: TypeFlags): boolean { 15687 return !!(keyType.flags & include || keyType.flags & TypeFlags.Intersection && some((keyType as IntersectionType).types, t => isKeyTypeIncluded(t, include))); 15688 } 15689 15690 function getLiteralTypeFromProperties(type: Type, include: TypeFlags, includeOrigin: boolean) { 15691 const origin = includeOrigin && (getObjectFlags(type) & (ObjectFlags.ClassOrInterface | ObjectFlags.Reference) || type.aliasSymbol) ? createOriginIndexType(type) : undefined; 15692 const propertyTypes = map(getPropertiesOfType(type), prop => getLiteralTypeFromProperty(prop, include)); 15693 const indexKeyTypes = map(getIndexInfosOfType(type), info => info !== enumNumberIndexInfo && isKeyTypeIncluded(info.keyType, include) ? 15694 info.keyType === stringType && include & TypeFlags.Number ? stringOrNumberType : info.keyType : neverType); 15695 return getUnionType(concatenate(propertyTypes, indexKeyTypes), UnionReduction.Literal, 15696 /*aliasSymbol*/ undefined, /*aliasTypeArguments*/ undefined, origin); 15697 } 15698 15699 /** 15700 * A union type which is reducible upon instantiation (meaning some members are removed under certain instantiations) 15701 * must be kept generic, as that instantiation information needs to flow through the type system. By replacing all 15702 * type parameters in the union with a special never type that is treated as a literal in `getReducedType`, we can cause the `getReducedType` logic 15703 * to reduce the resulting type if possible (since only intersections with conflicting literal-typed properties are reducible). 15704 */ 15705 function isPossiblyReducibleByInstantiation(type: Type): boolean { 15706 const uniqueFilled = getUniqueLiteralFilledInstantiation(type); 15707 return getReducedType(uniqueFilled) !== uniqueFilled; 15708 } 15709 15710 function shouldDeferIndexType(type: Type) { 15711 return !!(type.flags & TypeFlags.InstantiableNonPrimitive || 15712 isGenericTupleType(type) || 15713 isGenericMappedType(type) && !hasDistributiveNameType(type) || 15714 type.flags & TypeFlags.Union && some((type as UnionType).types, isPossiblyReducibleByInstantiation) || 15715 type.flags & TypeFlags.Intersection && maybeTypeOfKind(type, TypeFlags.Instantiable) && some((type as IntersectionType).types, isEmptyAnonymousObjectType)); 15716 } 15717 15718 function getIndexType(type: Type, stringsOnly = keyofStringsOnly, noIndexSignatures?: boolean): Type { 15719 type = getReducedType(type); 15720 return shouldDeferIndexType(type) ? getIndexTypeForGenericType(type as InstantiableType | UnionOrIntersectionType, stringsOnly) : 15721 type.flags & TypeFlags.Union ? getIntersectionType(map((type as UnionType).types, t => getIndexType(t, stringsOnly, noIndexSignatures))) : 15722 type.flags & TypeFlags.Intersection ? getUnionType(map((type as IntersectionType).types, t => getIndexType(t, stringsOnly, noIndexSignatures))) : 15723 getObjectFlags(type) & ObjectFlags.Mapped ? getIndexTypeForMappedType(type as MappedType, stringsOnly, noIndexSignatures) : 15724 type === wildcardType ? wildcardType : 15725 type.flags & TypeFlags.Unknown ? neverType : 15726 type.flags & (TypeFlags.Any | TypeFlags.Never) ? keyofConstraintType : 15727 getLiteralTypeFromProperties(type, (noIndexSignatures ? TypeFlags.StringLiteral : TypeFlags.StringLike) | (stringsOnly ? 0 : TypeFlags.NumberLike | TypeFlags.ESSymbolLike), 15728 stringsOnly === keyofStringsOnly && !noIndexSignatures); 15729 } 15730 15731 function getExtractStringType(type: Type) { 15732 if (keyofStringsOnly) { 15733 return type; 15734 } 15735 const extractTypeAlias = getGlobalExtractSymbol(); 15736 return extractTypeAlias ? getTypeAliasInstantiation(extractTypeAlias, [type, stringType]) : stringType; 15737 } 15738 15739 function getIndexTypeOrString(type: Type): Type { 15740 const indexType = getExtractStringType(getIndexType(type)); 15741 return indexType.flags & TypeFlags.Never ? stringType : indexType; 15742 } 15743 15744 function getTypeFromTypeOperatorNode(node: TypeOperatorNode): Type { 15745 const links = getNodeLinks(node); 15746 if (!links.resolvedType) { 15747 switch (node.operator) { 15748 case SyntaxKind.KeyOfKeyword: 15749 links.resolvedType = getIndexType(getTypeFromTypeNode(node.type)); 15750 break; 15751 case SyntaxKind.UniqueKeyword: 15752 links.resolvedType = node.type.kind === SyntaxKind.SymbolKeyword 15753 ? getESSymbolLikeTypeForNode(walkUpParenthesizedTypes(node.parent)) 15754 : errorType; 15755 break; 15756 case SyntaxKind.ReadonlyKeyword: 15757 links.resolvedType = getTypeFromTypeNode(node.type); 15758 break; 15759 default: 15760 throw Debug.assertNever(node.operator); 15761 } 15762 } 15763 return links.resolvedType; 15764 } 15765 15766 function getTypeFromTemplateTypeNode(node: TemplateLiteralTypeNode) { 15767 const links = getNodeLinks(node); 15768 if (!links.resolvedType) { 15769 links.resolvedType = getTemplateLiteralType( 15770 [node.head.text, ...map(node.templateSpans, span => span.literal.text)], 15771 map(node.templateSpans, span => getTypeFromTypeNode(span.type))); 15772 } 15773 return links.resolvedType; 15774 } 15775 15776 function getTemplateLiteralType(texts: readonly string[], types: readonly Type[]): Type { 15777 const unionIndex = findIndex(types, t => !!(t.flags & (TypeFlags.Never | TypeFlags.Union))); 15778 if (unionIndex >= 0) { 15779 return checkCrossProductUnion(types) ? 15780 mapType(types[unionIndex], t => getTemplateLiteralType(texts, replaceElement(types, unionIndex, t))) : 15781 errorType; 15782 } 15783 if (contains(types, wildcardType)) { 15784 return wildcardType; 15785 } 15786 const newTypes: Type[] = []; 15787 const newTexts: string[] = []; 15788 let text = texts[0]; 15789 if (!addSpans(texts, types)) { 15790 return stringType; 15791 } 15792 if (newTypes.length === 0) { 15793 return getStringLiteralType(text); 15794 } 15795 newTexts.push(text); 15796 if (every(newTexts, t => t === "")) { 15797 if (every(newTypes, t => !!(t.flags & TypeFlags.String))) { 15798 return stringType; 15799 } 15800 // Normalize `${Mapping<xxx>}` into Mapping<xxx> 15801 if (newTypes.length === 1 && isPatternLiteralType(newTypes[0])) { 15802 return newTypes[0]; 15803 } 15804 } 15805 const id = `${getTypeListId(newTypes)}|${map(newTexts, t => t.length).join(",")}|${newTexts.join("")}`; 15806 let type = templateLiteralTypes.get(id); 15807 if (!type) { 15808 templateLiteralTypes.set(id, type = createTemplateLiteralType(newTexts, newTypes)); 15809 } 15810 return type; 15811 15812 function addSpans(texts: readonly string[] | string, types: readonly Type[]): boolean { 15813 const isTextsArray = isArray(texts); 15814 for (let i = 0; i < types.length; i++) { 15815 const t = types[i]; 15816 const addText = isTextsArray ? texts[i + 1] : texts; 15817 if (t.flags & (TypeFlags.Literal | TypeFlags.Null | TypeFlags.Undefined)) { 15818 text += getTemplateStringForType(t) || ""; 15819 text += addText; 15820 if (!isTextsArray) return true; 15821 } 15822 else if (t.flags & TypeFlags.TemplateLiteral) { 15823 text += (t as TemplateLiteralType).texts[0]; 15824 if (!addSpans((t as TemplateLiteralType).texts, (t as TemplateLiteralType).types)) return false; 15825 text += addText; 15826 if (!isTextsArray) return true; 15827 } 15828 else if (isGenericIndexType(t) || isPatternLiteralPlaceholderType(t)) { 15829 newTypes.push(t); 15830 newTexts.push(text); 15831 text = addText; 15832 } 15833 else if (t.flags & TypeFlags.Intersection) { 15834 const added = addSpans(texts[i + 1], (t as IntersectionType).types); 15835 if (!added) return false; 15836 } 15837 else if (isTextsArray) { 15838 return false; 15839 } 15840 } 15841 return true; 15842 } 15843 } 15844 15845 function getTemplateStringForType(type: Type) { 15846 return type.flags & TypeFlags.StringLiteral ? (type as StringLiteralType).value : 15847 type.flags & TypeFlags.NumberLiteral ? "" + (type as NumberLiteralType).value : 15848 type.flags & TypeFlags.BigIntLiteral ? pseudoBigIntToString((type as BigIntLiteralType).value) : 15849 type.flags & (TypeFlags.BooleanLiteral | TypeFlags.Nullable) ? (type as IntrinsicType).intrinsicName : 15850 undefined; 15851 } 15852 15853 function createTemplateLiteralType(texts: readonly string[], types: readonly Type[]) { 15854 const type = createType(TypeFlags.TemplateLiteral) as TemplateLiteralType; 15855 type.texts = texts; 15856 type.types = types; 15857 return type; 15858 } 15859 15860 function getStringMappingType(symbol: Symbol, type: Type): Type { 15861 return type.flags & (TypeFlags.Union | TypeFlags.Never) ? mapType(type, t => getStringMappingType(symbol, t)) : 15862 type.flags & TypeFlags.StringLiteral ? getStringLiteralType(applyStringMapping(symbol, (type as StringLiteralType).value)) : 15863 type.flags & TypeFlags.TemplateLiteral ? getTemplateLiteralType(...applyTemplateStringMapping(symbol, (type as TemplateLiteralType).texts, (type as TemplateLiteralType).types)) : 15864 // Mapping<Mapping<T>> === Mapping<T> 15865 type.flags & TypeFlags.StringMapping && symbol === type.symbol ? type : 15866 type.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.StringMapping) || isGenericIndexType(type) ? getStringMappingTypeForGenericType(symbol, type) : 15867 // This handles Mapping<`${number}`> and Mapping<`${bigint}`> 15868 isPatternLiteralPlaceholderType(type) ? getStringMappingTypeForGenericType(symbol, getTemplateLiteralType(["", ""], [type])) : 15869 type; 15870 } 15871 15872 function applyStringMapping(symbol: Symbol, str: string) { 15873 switch (intrinsicTypeKinds.get(symbol.escapedName as string)) { 15874 case IntrinsicTypeKind.Uppercase: return str.toUpperCase(); 15875 case IntrinsicTypeKind.Lowercase: return str.toLowerCase(); 15876 case IntrinsicTypeKind.Capitalize: return str.charAt(0).toUpperCase() + str.slice(1); 15877 case IntrinsicTypeKind.Uncapitalize: return str.charAt(0).toLowerCase() + str.slice(1); 15878 } 15879 return str; 15880 } 15881 15882 function applyTemplateStringMapping(symbol: Symbol, texts: readonly string[], types: readonly Type[]): [texts: readonly string[], types: readonly Type[]] { 15883 switch (intrinsicTypeKinds.get(symbol.escapedName as string)) { 15884 case IntrinsicTypeKind.Uppercase: return [texts.map(t => t.toUpperCase()), types.map(t => getStringMappingType(symbol, t))]; 15885 case IntrinsicTypeKind.Lowercase: return [texts.map(t => t.toLowerCase()), types.map(t => getStringMappingType(symbol, t))]; 15886 case IntrinsicTypeKind.Capitalize: return [texts[0] === "" ? texts : [texts[0].charAt(0).toUpperCase() + texts[0].slice(1), ...texts.slice(1)], texts[0] === "" ? [getStringMappingType(symbol, types[0]), ...types.slice(1)] : types]; 15887 case IntrinsicTypeKind.Uncapitalize: return [texts[0] === "" ? texts : [texts[0].charAt(0).toLowerCase() + texts[0].slice(1), ...texts.slice(1)], texts[0] === "" ? [getStringMappingType(symbol, types[0]), ...types.slice(1)] : types]; 15888 } 15889 return [texts, types]; 15890 } 15891 15892 function getStringMappingTypeForGenericType(symbol: Symbol, type: Type): Type { 15893 const id = `${getSymbolId(symbol)},${getTypeId(type)}`; 15894 let result = stringMappingTypes.get(id); 15895 if (!result) { 15896 stringMappingTypes.set(id, result = createStringMappingType(symbol, type)); 15897 } 15898 return result; 15899 } 15900 15901 function createStringMappingType(symbol: Symbol, type: Type) { 15902 const result = createType(TypeFlags.StringMapping) as StringMappingType; 15903 result.symbol = symbol; 15904 result.type = type; 15905 return result; 15906 } 15907 15908 function createIndexedAccessType(objectType: Type, indexType: Type, accessFlags: AccessFlags, aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined) { 15909 const type = createType(TypeFlags.IndexedAccess) as IndexedAccessType; 15910 type.objectType = objectType; 15911 type.indexType = indexType; 15912 type.accessFlags = accessFlags; 15913 type.aliasSymbol = aliasSymbol; 15914 type.aliasTypeArguments = aliasTypeArguments; 15915 return type; 15916 } 15917 15918 /** 15919 * Returns if a type is or consists of a JSLiteral object type 15920 * In addition to objects which are directly literals, 15921 * * unions where every element is a jsliteral 15922 * * intersections where at least one element is a jsliteral 15923 * * and instantiable types constrained to a jsliteral 15924 * Should all count as literals and not print errors on access or assignment of possibly existing properties. 15925 * This mirrors the behavior of the index signature propagation, to which this behaves similarly (but doesn't affect assignability or inference). 15926 */ 15927 function isJSLiteralType(type: Type): boolean { 15928 if (noImplicitAny) { 15929 return false; // Flag is meaningless under `noImplicitAny` mode 15930 } 15931 if (getObjectFlags(type) & ObjectFlags.JSLiteral) { 15932 return true; 15933 } 15934 if (type.flags & TypeFlags.Union) { 15935 return every((type as UnionType).types, isJSLiteralType); 15936 } 15937 if (type.flags & TypeFlags.Intersection) { 15938 return some((type as IntersectionType).types, isJSLiteralType); 15939 } 15940 if (type.flags & TypeFlags.Instantiable) { 15941 const constraint = getResolvedBaseConstraint(type); 15942 return constraint !== type && isJSLiteralType(constraint); 15943 } 15944 return false; 15945 } 15946 15947 function getPropertyNameFromIndex(indexType: Type, accessNode: StringLiteral | Identifier | PrivateIdentifier | ObjectBindingPattern | ArrayBindingPattern | ComputedPropertyName | NumericLiteral | IndexedAccessTypeNode | ElementAccessExpression | SyntheticExpression | undefined) { 15948 return isTypeUsableAsPropertyName(indexType) ? 15949 getPropertyNameFromType(indexType) : 15950 accessNode && isPropertyName(accessNode) ? 15951 // late bound names are handled in the first branch, so here we only need to handle normal names 15952 getPropertyNameForPropertyNameNode(accessNode) : 15953 undefined; 15954 } 15955 15956 function isUncalledFunctionReference(node: Node, symbol: Symbol) { 15957 if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method)) { 15958 const parent = findAncestor(node.parent, n => !isAccessExpression(n)) || node.parent; 15959 if (isCallLikeExpression(parent)) { 15960 return isCallOrNewExpression(parent) && isIdentifier(node) && hasMatchingArgument(parent, node); 15961 } 15962 return every(symbol.declarations, d => !isFunctionLike(d) || !!(getCombinedNodeFlags(d) & NodeFlags.Deprecated)); 15963 } 15964 return true; 15965 } 15966 15967 function getPropertyTypeForIndexType(originalObjectType: Type, objectType: Type, indexType: Type, fullIndexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression | undefined, accessFlags: AccessFlags) { 15968 const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode : undefined; 15969 const propName = accessNode && isPrivateIdentifier(accessNode) ? undefined : getPropertyNameFromIndex(indexType, accessNode); 15970 15971 if (propName !== undefined) { 15972 if (accessFlags & AccessFlags.Contextual) { 15973 return getTypeOfPropertyOfContextualType(objectType, propName) || anyType; 15974 } 15975 const prop = getPropertyOfType(objectType, propName); 15976 if (prop) { 15977 if (accessFlags & AccessFlags.ReportDeprecated && accessNode && prop.declarations && isDeprecatedSymbol(prop) && isUncalledFunctionReference(accessNode, prop)) { 15978 const deprecatedNode = accessExpression?.argumentExpression ?? (isIndexedAccessTypeNode(accessNode) ? accessNode.indexType : accessNode); 15979 addDeprecatedSuggestion(deprecatedNode, prop.declarations, propName as string); 15980 } 15981 if (accessExpression) { 15982 markPropertyAsReferenced(prop, accessExpression, isSelfTypeAccess(accessExpression.expression, objectType.symbol)); 15983 if (isAssignmentToReadonlyEntity(accessExpression, prop, getAssignmentTargetKind(accessExpression))) { 15984 error(accessExpression.argumentExpression, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, symbolToString(prop)); 15985 return undefined; 15986 } 15987 if (accessFlags & AccessFlags.CacheSymbol) { 15988 getNodeLinks(accessNode!).resolvedSymbol = prop; 15989 } 15990 if (isThisPropertyAccessInConstructor(accessExpression, prop)) { 15991 return autoType; 15992 } 15993 } 15994 const propType = getTypeOfSymbol(prop); 15995 return accessExpression && getAssignmentTargetKind(accessExpression) !== AssignmentKind.Definite ? 15996 getFlowTypeOfReference(accessExpression, propType) : 15997 propType; 15998 } 15999 if (everyType(objectType, isTupleType) && isNumericLiteralName(propName)) { 16000 const index = +propName; 16001 if (accessNode && everyType(objectType, t => !(t as TupleTypeReference).target.hasRestElement) && !(accessFlags & AccessFlags.NoTupleBoundsCheck)) { 16002 const indexNode = getIndexNodeForAccessExpression(accessNode); 16003 if (isTupleType(objectType)) { 16004 if (index < 0) { 16005 error(indexNode, Diagnostics.A_tuple_type_cannot_be_indexed_with_a_negative_value); 16006 return undefinedType; 16007 } 16008 error(indexNode, Diagnostics.Tuple_type_0_of_length_1_has_no_element_at_index_2, 16009 typeToString(objectType), getTypeReferenceArity(objectType), unescapeLeadingUnderscores(propName)); 16010 } 16011 else { 16012 error(indexNode, Diagnostics.Property_0_does_not_exist_on_type_1, unescapeLeadingUnderscores(propName), typeToString(objectType)); 16013 } 16014 } 16015 if (index >= 0) { 16016 errorIfWritingToReadonlyIndex(getIndexInfoOfType(objectType, numberType)); 16017 return mapType(objectType, t => { 16018 const restType = getRestTypeOfTupleType(t as TupleTypeReference) || undefinedType; 16019 return accessFlags & AccessFlags.IncludeUndefined ? getUnionType([restType, undefinedType]) : restType; 16020 }); 16021 } 16022 } 16023 } 16024 if (!(indexType.flags & TypeFlags.Nullable) && isTypeAssignableToKind(indexType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbolLike)) { 16025 if (objectType.flags & (TypeFlags.Any | TypeFlags.Never)) { 16026 return objectType; 16027 } 16028 // If no index signature is applicable, we default to the string index signature. In effect, this means the string 16029 // index signature applies even when accessing with a symbol-like type. 16030 const indexInfo = getApplicableIndexInfo(objectType, indexType) || getIndexInfoOfType(objectType, stringType); 16031 if (indexInfo) { 16032 if (accessFlags & AccessFlags.NoIndexSignatures && indexInfo.keyType !== numberType) { 16033 if (accessExpression) { 16034 error(accessExpression, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(originalObjectType)); 16035 } 16036 return undefined; 16037 } 16038 if (accessNode && indexInfo.keyType === stringType && !isTypeAssignableToKind(indexType, TypeFlags.String | TypeFlags.Number)) { 16039 const indexNode = getIndexNodeForAccessExpression(accessNode); 16040 error(indexNode, Diagnostics.Type_0_cannot_be_used_as_an_index_type, typeToString(indexType)); 16041 return accessFlags & AccessFlags.IncludeUndefined ? getUnionType([indexInfo.type, undefinedType]) : indexInfo.type; 16042 } 16043 errorIfWritingToReadonlyIndex(indexInfo); 16044 // When accessing an enum object with its own type, 16045 // e.g. E[E.A] for enum E { A }, undefined shouldn't 16046 // be included in the result type 16047 if ((accessFlags & AccessFlags.IncludeUndefined) && 16048 !(objectType.symbol && 16049 objectType.symbol.flags & (SymbolFlags.RegularEnum | SymbolFlags.ConstEnum) && 16050 (indexType.symbol && 16051 indexType.flags & TypeFlags.EnumLiteral && 16052 getParentOfSymbol(indexType.symbol) === objectType.symbol))) { 16053 return getUnionType([indexInfo.type, undefinedType]); 16054 } 16055 return indexInfo.type; 16056 } 16057 if (indexType.flags & TypeFlags.Never) { 16058 return neverType; 16059 } 16060 if (isJSLiteralType(objectType)) { 16061 return anyType; 16062 } 16063 if (accessExpression && !isConstEnumObjectType(objectType)) { 16064 if (isObjectLiteralType(objectType)) { 16065 if (noImplicitAny && indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) { 16066 diagnostics.add(createDiagnosticForNode(accessExpression, Diagnostics.Property_0_does_not_exist_on_type_1, (indexType as StringLiteralType).value, typeToString(objectType))); 16067 return undefinedType; 16068 } 16069 else if (indexType.flags & (TypeFlags.Number | TypeFlags.String)) { 16070 const types = map((objectType as ResolvedType).properties, property => { 16071 return getTypeOfSymbol(property); 16072 }); 16073 return getUnionType(append(types, undefinedType)); 16074 } 16075 } 16076 16077 if (objectType.symbol === globalThisSymbol && propName !== undefined && globalThisSymbol.exports!.has(propName) && (globalThisSymbol.exports!.get(propName)!.flags & SymbolFlags.BlockScoped)) { 16078 error(accessExpression, Diagnostics.Property_0_does_not_exist_on_type_1, unescapeLeadingUnderscores(propName), typeToString(objectType)); 16079 } 16080 else if (noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors && !(accessFlags & AccessFlags.SuppressNoImplicitAnyError)) { 16081 if (propName !== undefined && typeHasStaticProperty(propName, objectType)) { 16082 const typeName = typeToString(objectType); 16083 error(accessExpression, Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_to_access_the_static_member_2_instead, propName as string, typeName, typeName + "[" + getTextOfNode(accessExpression.argumentExpression) + "]"); 16084 } 16085 else if (getIndexTypeOfType(objectType, numberType)) { 16086 error(accessExpression.argumentExpression, Diagnostics.Element_implicitly_has_an_any_type_because_index_expression_is_not_of_type_number); 16087 } 16088 else { 16089 let suggestion: string | undefined; 16090 if (propName !== undefined && (suggestion = getSuggestionForNonexistentProperty(propName as string, objectType))) { 16091 if (suggestion !== undefined) { 16092 error(accessExpression.argumentExpression, Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2, propName as string, typeToString(objectType), suggestion); 16093 } 16094 } 16095 else { 16096 const suggestion = getSuggestionForNonexistentIndexSignature(objectType, accessExpression, indexType); 16097 if (suggestion !== undefined) { 16098 error(accessExpression, Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature_Did_you_mean_to_call_1, typeToString(objectType), suggestion); 16099 } 16100 else { 16101 let errorInfo: DiagnosticMessageChain | undefined; 16102 if (indexType.flags & TypeFlags.EnumLiteral) { 16103 errorInfo = chainDiagnosticMessages(/* details */ undefined, Diagnostics.Property_0_does_not_exist_on_type_1, "[" + typeToString(indexType) + "]", typeToString(objectType)); 16104 } 16105 else if (indexType.flags & TypeFlags.UniqueESSymbol) { 16106 const symbolName = getFullyQualifiedName((indexType as UniqueESSymbolType).symbol, accessExpression); 16107 errorInfo = chainDiagnosticMessages(/* details */ undefined, Diagnostics.Property_0_does_not_exist_on_type_1, "[" + symbolName + "]", typeToString(objectType)); 16108 } 16109 else if (indexType.flags & TypeFlags.StringLiteral) { 16110 errorInfo = chainDiagnosticMessages(/* details */ undefined, Diagnostics.Property_0_does_not_exist_on_type_1, (indexType as StringLiteralType).value, typeToString(objectType)); 16111 } 16112 else if (indexType.flags & TypeFlags.NumberLiteral) { 16113 errorInfo = chainDiagnosticMessages(/* details */ undefined, Diagnostics.Property_0_does_not_exist_on_type_1, (indexType as NumberLiteralType).value, typeToString(objectType)); 16114 } 16115 else if (indexType.flags & (TypeFlags.Number | TypeFlags.String)) { 16116 errorInfo = chainDiagnosticMessages(/* details */ undefined, Diagnostics.No_index_signature_with_a_parameter_of_type_0_was_found_on_type_1, typeToString(indexType), typeToString(objectType)); 16117 } 16118 16119 errorInfo = chainDiagnosticMessages( 16120 errorInfo, 16121 Diagnostics.Element_implicitly_has_an_any_type_because_expression_of_type_0_can_t_be_used_to_index_type_1, typeToString(fullIndexType), typeToString(objectType) 16122 ); 16123 diagnostics.add(createDiagnosticForNodeFromMessageChain(accessExpression, errorInfo)); 16124 } 16125 } 16126 } 16127 } 16128 return undefined; 16129 } 16130 } 16131 if (isJSLiteralType(objectType)) { 16132 return anyType; 16133 } 16134 if (accessNode) { 16135 const indexNode = getIndexNodeForAccessExpression(accessNode); 16136 if (indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) { 16137 error(indexNode, Diagnostics.Property_0_does_not_exist_on_type_1, "" + (indexType as StringLiteralType | NumberLiteralType).value, typeToString(objectType)); 16138 } 16139 else if (indexType.flags & (TypeFlags.String | TypeFlags.Number)) { 16140 error(indexNode, Diagnostics.Type_0_has_no_matching_index_signature_for_type_1, typeToString(objectType), typeToString(indexType)); 16141 } 16142 else { 16143 error(indexNode, Diagnostics.Type_0_cannot_be_used_as_an_index_type, typeToString(indexType)); 16144 } 16145 } 16146 if (isTypeAny(indexType)) { 16147 return indexType; 16148 } 16149 return undefined; 16150 16151 function errorIfWritingToReadonlyIndex(indexInfo: IndexInfo | undefined): void { 16152 if (indexInfo && indexInfo.isReadonly && accessExpression && (isAssignmentTarget(accessExpression) || isDeleteTarget(accessExpression))) { 16153 error(accessExpression, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(objectType)); 16154 } 16155 } 16156 } 16157 16158 function getIndexNodeForAccessExpression(accessNode: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression) { 16159 return accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode.argumentExpression : 16160 accessNode.kind === SyntaxKind.IndexedAccessType ? accessNode.indexType : 16161 accessNode.kind === SyntaxKind.ComputedPropertyName ? accessNode.expression : 16162 accessNode; 16163 } 16164 16165 function isPatternLiteralPlaceholderType(type: Type): boolean { 16166 return !!(type.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt)) || isPatternLiteralType(type); 16167 } 16168 16169 function isPatternLiteralType(type: Type) { 16170 return !!(type.flags & TypeFlags.TemplateLiteral) && every((type as TemplateLiteralType).types, isPatternLiteralPlaceholderType) || 16171 !!(type.flags & TypeFlags.StringMapping) && isPatternLiteralPlaceholderType((type as StringMappingType).type); 16172 } 16173 16174 function isGenericType(type: Type): boolean { 16175 return !!getGenericObjectFlags(type); 16176 } 16177 16178 function isGenericObjectType(type: Type): boolean { 16179 return !!(getGenericObjectFlags(type) & ObjectFlags.IsGenericObjectType); 16180 } 16181 16182 function isGenericIndexType(type: Type): boolean { 16183 return !!(getGenericObjectFlags(type) & ObjectFlags.IsGenericIndexType); 16184 } 16185 16186 function getGenericObjectFlags(type: Type): ObjectFlags { 16187 if (type.flags & TypeFlags.UnionOrIntersection) { 16188 if (!((type as UnionOrIntersectionType).objectFlags & ObjectFlags.IsGenericTypeComputed)) { 16189 (type as UnionOrIntersectionType).objectFlags |= ObjectFlags.IsGenericTypeComputed | 16190 reduceLeft((type as UnionOrIntersectionType).types, (flags, t) => flags | getGenericObjectFlags(t), 0); 16191 } 16192 return (type as UnionOrIntersectionType).objectFlags & ObjectFlags.IsGenericType; 16193 } 16194 if (type.flags & TypeFlags.Substitution) { 16195 if (!((type as SubstitutionType).objectFlags & ObjectFlags.IsGenericTypeComputed)) { 16196 (type as SubstitutionType).objectFlags |= ObjectFlags.IsGenericTypeComputed | 16197 getGenericObjectFlags((type as SubstitutionType).baseType) | getGenericObjectFlags((type as SubstitutionType).constraint); 16198 } 16199 return (type as SubstitutionType).objectFlags & ObjectFlags.IsGenericType; 16200 } 16201 return (type.flags & TypeFlags.InstantiableNonPrimitive || isGenericMappedType(type) || isGenericTupleType(type) ? ObjectFlags.IsGenericObjectType : 0) | 16202 (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) && !isPatternLiteralType(type) ? ObjectFlags.IsGenericIndexType : 0); 16203 } 16204 16205 function getSimplifiedType(type: Type, writing: boolean): Type { 16206 return type.flags & TypeFlags.IndexedAccess ? getSimplifiedIndexedAccessType(type as IndexedAccessType, writing) : 16207 type.flags & TypeFlags.Conditional ? getSimplifiedConditionalType(type as ConditionalType, writing) : 16208 type; 16209 } 16210 16211 function distributeIndexOverObjectType(objectType: Type, indexType: Type, writing: boolean) { 16212 // (T | U)[K] -> T[K] | U[K] (reading) 16213 // (T | U)[K] -> T[K] & U[K] (writing) 16214 // (T & U)[K] -> T[K] & U[K] 16215 if (objectType.flags & TypeFlags.Union || objectType.flags & TypeFlags.Intersection && !shouldDeferIndexType(objectType)) { 16216 const types = map((objectType as UnionOrIntersectionType).types, t => getSimplifiedType(getIndexedAccessType(t, indexType), writing)); 16217 return objectType.flags & TypeFlags.Intersection || writing ? getIntersectionType(types) : getUnionType(types); 16218 } 16219 } 16220 16221 function distributeObjectOverIndexType(objectType: Type, indexType: Type, writing: boolean) { 16222 // T[A | B] -> T[A] | T[B] (reading) 16223 // T[A | B] -> T[A] & T[B] (writing) 16224 if (indexType.flags & TypeFlags.Union) { 16225 const types = map((indexType as UnionType).types, t => getSimplifiedType(getIndexedAccessType(objectType, t), writing)); 16226 return writing ? getIntersectionType(types) : getUnionType(types); 16227 } 16228 } 16229 16230 // Transform an indexed access to a simpler form, if possible. Return the simpler form, or return 16231 // the type itself if no transformation is possible. The writing flag indicates that the type is 16232 // the target of an assignment. 16233 function getSimplifiedIndexedAccessType(type: IndexedAccessType, writing: boolean): Type { 16234 const cache = writing ? "simplifiedForWriting" : "simplifiedForReading"; 16235 if (type[cache]) { 16236 return type[cache] === circularConstraintType ? type : type[cache]!; 16237 } 16238 type[cache] = circularConstraintType; 16239 // We recursively simplify the object type as it may in turn be an indexed access type. For example, with 16240 // '{ [P in T]: { [Q in U]: number } }[T][U]' we want to first simplify the inner indexed access type. 16241 const objectType = getSimplifiedType(type.objectType, writing); 16242 const indexType = getSimplifiedType(type.indexType, writing); 16243 // T[A | B] -> T[A] | T[B] (reading) 16244 // T[A | B] -> T[A] & T[B] (writing) 16245 const distributedOverIndex = distributeObjectOverIndexType(objectType, indexType, writing); 16246 if (distributedOverIndex) { 16247 return type[cache] = distributedOverIndex; 16248 } 16249 // Only do the inner distributions if the index can no longer be instantiated to cause index distribution again 16250 if (!(indexType.flags & TypeFlags.Instantiable)) { 16251 // (T | U)[K] -> T[K] | U[K] (reading) 16252 // (T | U)[K] -> T[K] & U[K] (writing) 16253 // (T & U)[K] -> T[K] & U[K] 16254 const distributedOverObject = distributeIndexOverObjectType(objectType, indexType, writing); 16255 if (distributedOverObject) { 16256 return type[cache] = distributedOverObject; 16257 } 16258 } 16259 // So ultimately (reading): 16260 // ((A & B) | C)[K1 | K2] -> ((A & B) | C)[K1] | ((A & B) | C)[K2] -> (A & B)[K1] | C[K1] | (A & B)[K2] | C[K2] -> (A[K1] & B[K1]) | C[K1] | (A[K2] & B[K2]) | C[K2] 16261 16262 // A generic tuple type indexed by a number exists only when the index type doesn't select a 16263 // fixed element. We simplify to either the combined type of all elements (when the index type 16264 // the actual number type) or to the combined type of all non-fixed elements. 16265 if (isGenericTupleType(objectType) && indexType.flags & TypeFlags.NumberLike) { 16266 const elementType = getElementTypeOfSliceOfTupleType(objectType, indexType.flags & TypeFlags.Number ? 0 : objectType.target.fixedLength, /*endSkipCount*/ 0, writing); 16267 if (elementType) { 16268 return type[cache] = elementType; 16269 } 16270 } 16271 // If the object type is a mapped type { [P in K]: E }, where K is generic, or { [P in K as N]: E }, where 16272 // K is generic and N is assignable to P, instantiate E using a mapper that substitutes the index type for P. 16273 // For example, for an index access { [P in K]: Box<T[P]> }[X], we construct the type Box<T[X]>. 16274 if (isGenericMappedType(objectType)) { 16275 const nameType = getNameTypeFromMappedType(objectType); 16276 if (!nameType || isTypeAssignableTo(nameType, getTypeParameterFromMappedType(objectType))) { 16277 return type[cache] = mapType(substituteIndexedMappedType(objectType, type.indexType), t => getSimplifiedType(t, writing)); 16278 } 16279 } 16280 return type[cache] = type; 16281 } 16282 16283 function getSimplifiedConditionalType(type: ConditionalType, writing: boolean) { 16284 const checkType = type.checkType; 16285 const extendsType = type.extendsType; 16286 const trueType = getTrueTypeFromConditionalType(type); 16287 const falseType = getFalseTypeFromConditionalType(type); 16288 // Simplifications for types of the form `T extends U ? T : never` and `T extends U ? never : T`. 16289 if (falseType.flags & TypeFlags.Never && getActualTypeVariable(trueType) === getActualTypeVariable(checkType)) { 16290 if (checkType.flags & TypeFlags.Any || isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(extendsType))) { // Always true 16291 return getSimplifiedType(trueType, writing); 16292 } 16293 else if (isIntersectionEmpty(checkType, extendsType)) { // Always false 16294 return neverType; 16295 } 16296 } 16297 else if (trueType.flags & TypeFlags.Never && getActualTypeVariable(falseType) === getActualTypeVariable(checkType)) { 16298 if (!(checkType.flags & TypeFlags.Any) && isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(extendsType))) { // Always true 16299 return neverType; 16300 } 16301 else if (checkType.flags & TypeFlags.Any || isIntersectionEmpty(checkType, extendsType)) { // Always false 16302 return getSimplifiedType(falseType, writing); 16303 } 16304 } 16305 return type; 16306 } 16307 16308 /** 16309 * Invokes union simplification logic to determine if an intersection is considered empty as a union constituent 16310 */ 16311 function isIntersectionEmpty(type1: Type, type2: Type) { 16312 return !!(getUnionType([intersectTypes(type1, type2), neverType]).flags & TypeFlags.Never); 16313 } 16314 16315 function substituteIndexedMappedType(objectType: MappedType, index: Type) { 16316 const mapper = createTypeMapper([getTypeParameterFromMappedType(objectType)], [index]); 16317 const templateMapper = combineTypeMappers(objectType.mapper, mapper); 16318 return instantiateType(getTemplateTypeFromMappedType(objectType.target as MappedType || objectType), templateMapper); 16319 } 16320 16321 function getIndexedAccessType(objectType: Type, indexType: Type, accessFlags = AccessFlags.None, accessNode?: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type { 16322 return getIndexedAccessTypeOrUndefined(objectType, indexType, accessFlags, accessNode, aliasSymbol, aliasTypeArguments) || (accessNode ? errorType : unknownType); 16323 } 16324 16325 function indexTypeLessThan(indexType: Type, limit: number) { 16326 return everyType(indexType, t => { 16327 if (t.flags & TypeFlags.StringOrNumberLiteral) { 16328 const propName = getPropertyNameFromType(t as StringLiteralType | NumberLiteralType); 16329 if (isNumericLiteralName(propName)) { 16330 const index = +propName; 16331 return index >= 0 && index < limit; 16332 } 16333 } 16334 return false; 16335 }); 16336 } 16337 16338 function getIndexedAccessTypeOrUndefined(objectType: Type, indexType: Type, accessFlags = AccessFlags.None, accessNode?: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type | undefined { 16339 if (objectType === wildcardType || indexType === wildcardType) { 16340 return wildcardType; 16341 } 16342 // If the object type has a string index signature and no other members we know that the result will 16343 // always be the type of that index signature and we can simplify accordingly. 16344 if (isStringIndexSignatureOnlyType(objectType) && !(indexType.flags & TypeFlags.Nullable) && isTypeAssignableToKind(indexType, TypeFlags.String | TypeFlags.Number)) { 16345 indexType = stringType; 16346 } 16347 // In noUncheckedIndexedAccess mode, indexed access operations that occur in an expression in a read position and resolve to 16348 // an index signature have 'undefined' included in their type. 16349 if (compilerOptions.noUncheckedIndexedAccess && accessFlags & AccessFlags.ExpressionPosition) accessFlags |= AccessFlags.IncludeUndefined; 16350 // If the index type is generic, or if the object type is generic and doesn't originate in an expression and 16351 // the operation isn't exclusively indexing the fixed (non-variadic) portion of a tuple type, we are performing 16352 // a higher-order index access where we cannot meaningfully access the properties of the object type. Note that 16353 // for a generic T and a non-generic K, we eagerly resolve T[K] if it originates in an expression. This is to 16354 // preserve backwards compatibility. For example, an element access 'this["foo"]' has always been resolved 16355 // eagerly using the constraint type of 'this' at the given location. 16356 if (isGenericIndexType(indexType) || (accessNode && accessNode.kind !== SyntaxKind.IndexedAccessType ? 16357 isGenericTupleType(objectType) && !indexTypeLessThan(indexType, objectType.target.fixedLength) : 16358 isGenericObjectType(objectType) && !(isTupleType(objectType) && indexTypeLessThan(indexType, objectType.target.fixedLength)))) { 16359 if (objectType.flags & TypeFlags.AnyOrUnknown) { 16360 return objectType; 16361 } 16362 // Defer the operation by creating an indexed access type. 16363 const persistentAccessFlags = accessFlags & AccessFlags.Persistent; 16364 const id = objectType.id + "," + indexType.id + "," + persistentAccessFlags + getAliasId(aliasSymbol, aliasTypeArguments); 16365 let type = indexedAccessTypes.get(id); 16366 if (!type) { 16367 indexedAccessTypes.set(id, type = createIndexedAccessType(objectType, indexType, persistentAccessFlags, aliasSymbol, aliasTypeArguments)); 16368 } 16369 16370 return type; 16371 } 16372 // In the following we resolve T[K] to the type of the property in T selected by K. 16373 // We treat boolean as different from other unions to improve errors; 16374 // skipping straight to getPropertyTypeForIndexType gives errors with 'boolean' instead of 'true'. 16375 const apparentObjectType = getReducedApparentType(objectType); 16376 if (indexType.flags & TypeFlags.Union && !(indexType.flags & TypeFlags.Boolean)) { 16377 const propTypes: Type[] = []; 16378 let wasMissingProp = false; 16379 for (const t of (indexType as UnionType).types) { 16380 const propType = getPropertyTypeForIndexType(objectType, apparentObjectType, t, indexType, accessNode, accessFlags | (wasMissingProp ? AccessFlags.SuppressNoImplicitAnyError : 0)); 16381 if (propType) { 16382 propTypes.push(propType); 16383 } 16384 else if (!accessNode) { 16385 // If there's no error node, we can immeditely stop, since error reporting is off 16386 return undefined; 16387 } 16388 else { 16389 // Otherwise we set a flag and return at the end of the loop so we still mark all errors 16390 wasMissingProp = true; 16391 } 16392 } 16393 if (wasMissingProp) { 16394 return undefined; 16395 } 16396 return accessFlags & AccessFlags.Writing 16397 ? getIntersectionType(propTypes, aliasSymbol, aliasTypeArguments) 16398 : getUnionType(propTypes, UnionReduction.Literal, aliasSymbol, aliasTypeArguments); 16399 } 16400 return getPropertyTypeForIndexType(objectType, apparentObjectType, indexType, indexType, accessNode, accessFlags | AccessFlags.CacheSymbol | AccessFlags.ReportDeprecated); 16401 } 16402 16403 function getTypeFromIndexedAccessTypeNode(node: IndexedAccessTypeNode) { 16404 const links = getNodeLinks(node); 16405 if (!links.resolvedType) { 16406 const objectType = getTypeFromTypeNode(node.objectType); 16407 const indexType = getTypeFromTypeNode(node.indexType); 16408 const potentialAlias = getAliasSymbolForTypeNode(node); 16409 links.resolvedType = getIndexedAccessType(objectType, indexType, AccessFlags.None, node, potentialAlias, getTypeArgumentsForAliasSymbol(potentialAlias)); 16410 } 16411 return links.resolvedType; 16412 } 16413 16414 function getTypeFromMappedTypeNode(node: MappedTypeNode): Type { 16415 const links = getNodeLinks(node); 16416 if (!links.resolvedType) { 16417 const type = createObjectType(ObjectFlags.Mapped, node.symbol) as MappedType; 16418 type.declaration = node; 16419 type.aliasSymbol = getAliasSymbolForTypeNode(node); 16420 type.aliasTypeArguments = getTypeArgumentsForAliasSymbol(type.aliasSymbol); 16421 links.resolvedType = type; 16422 // Eagerly resolve the constraint type which forces an error if the constraint type circularly 16423 // references itself through one or more type aliases. 16424 getConstraintTypeFromMappedType(type); 16425 } 16426 return links.resolvedType; 16427 } 16428 16429 function getActualTypeVariable(type: Type): Type { 16430 if (type.flags & TypeFlags.Substitution) { 16431 return (type as SubstitutionType).baseType; 16432 } 16433 if (type.flags & TypeFlags.IndexedAccess && ( 16434 (type as IndexedAccessType).objectType.flags & TypeFlags.Substitution || 16435 (type as IndexedAccessType).indexType.flags & TypeFlags.Substitution)) { 16436 return getIndexedAccessType(getActualTypeVariable((type as IndexedAccessType).objectType), getActualTypeVariable((type as IndexedAccessType).indexType)); 16437 } 16438 return type; 16439 } 16440 16441 function maybeCloneTypeParameter(p: TypeParameter) { 16442 const constraint = getConstraintOfTypeParameter(p); 16443 return constraint && (isGenericObjectType(constraint) || isGenericIndexType(constraint)) ? cloneTypeParameter(p) : p; 16444 } 16445 16446 function isTypicalNondistributiveConditional(root: ConditionalRoot) { 16447 return !root.isDistributive && isSingletonTupleType(root.node.checkType) && isSingletonTupleType(root.node.extendsType); 16448 } 16449 16450 function isSingletonTupleType(node: TypeNode) { 16451 return isTupleTypeNode(node) && 16452 length(node.elements) === 1 && 16453 !isOptionalTypeNode(node.elements[0]) && 16454 !isRestTypeNode(node.elements[0]) && 16455 !(isNamedTupleMember(node.elements[0]) && (node.elements[0].questionToken || node.elements[0].dotDotDotToken)); 16456 } 16457 16458 /** 16459 * We syntactually check for common nondistributive conditional shapes and unwrap them into 16460 * the intended comparison - we do this so we can check if the unwrapped types are generic or 16461 * not and appropriately defer condition calculation 16462 */ 16463 function unwrapNondistributiveConditionalTuple(root: ConditionalRoot, type: Type) { 16464 return isTypicalNondistributiveConditional(root) && isTupleType(type) ? getTypeArguments(type)[0] : type; 16465 } 16466 16467 function getConditionalType(root: ConditionalRoot, mapper: TypeMapper | undefined, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type { 16468 let result; 16469 let extraTypes: Type[] | undefined; 16470 let tailCount = 0; 16471 // We loop here for an immediately nested conditional type in the false position, effectively treating 16472 // types of the form 'A extends B ? X : C extends D ? Y : E extends F ? Z : ...' as a single construct for 16473 // purposes of resolution. We also loop here when resolution of a conditional type ends in resolution of 16474 // another (or, through recursion, possibly the same) conditional type. In the potentially tail-recursive 16475 // cases we increment the tail recursion counter and stop after 1000 iterations. 16476 while (true) { 16477 if (tailCount === 1000) { 16478 error(currentNode, Diagnostics.Type_instantiation_is_excessively_deep_and_possibly_infinite); 16479 result = errorType; 16480 break; 16481 } 16482 const isUnwrapped = isTypicalNondistributiveConditional(root); 16483 const checkType = instantiateType(unwrapNondistributiveConditionalTuple(root, getActualTypeVariable(root.checkType)), mapper); 16484 const checkTypeInstantiable = isGenericType(checkType); 16485 const extendsType = instantiateType(unwrapNondistributiveConditionalTuple(root, root.extendsType), mapper); 16486 if (checkType === wildcardType || extendsType === wildcardType) { 16487 return wildcardType; 16488 } 16489 let combinedMapper: TypeMapper | undefined; 16490 if (root.inferTypeParameters) { 16491 // When we're looking at making an inference for an infer type, when we get its constraint, it'll automagically be 16492 // instantiated with the context, so it doesn't need the mapper for the inference contex - however the constraint 16493 // may refer to another _root_, _uncloned_ `infer` type parameter [1], or to something mapped by `mapper` [2]. 16494 // [1] Eg, if we have `Foo<T, U extends T>` and `Foo<number, infer B>` - `B` is constrained to `T`, which, in turn, has been instantiated 16495 // as `number` 16496 // Conversely, if we have `Foo<infer A, infer B>`, `B` is still constrained to `T` and `T` is instantiated as `A` 16497 // [2] Eg, if we have `Foo<T, U extends T>` and `Foo<Q, infer B>` where `Q` is mapped by `mapper` into `number` - `B` is constrained to `T` 16498 // which is in turn instantiated as `Q`, which is in turn instantiated as `number`. 16499 // So we need to: 16500 // * Clone the type parameters so their constraints can be instantiated in the context of `mapper` (otherwise theyd only get inference context information) 16501 // * Set the clones to both map the conditional's enclosing `mapper` and the original params 16502 // * instantiate the extends type with the clones 16503 // * incorporate all of the component mappers into the combined mapper for the true and false members 16504 // This means we have three mappers that need applying: 16505 // * The original `mapper` used to create this conditional 16506 // * The mapper that maps the old root type parameter to the clone (`freshMapper`) 16507 // * The mapper that maps the clone to its inference result (`context.mapper`) 16508 const freshParams = sameMap(root.inferTypeParameters, maybeCloneTypeParameter); 16509 const freshMapper = freshParams !== root.inferTypeParameters ? createTypeMapper(root.inferTypeParameters, freshParams) : undefined; 16510 const context = createInferenceContext(freshParams, /*signature*/ undefined, InferenceFlags.None); 16511 if (freshMapper) { 16512 const freshCombinedMapper = combineTypeMappers(mapper, freshMapper); 16513 for (const p of freshParams) { 16514 if (root.inferTypeParameters.indexOf(p) === -1) { 16515 p.mapper = freshCombinedMapper; 16516 } 16517 } 16518 } 16519 if (!checkTypeInstantiable) { 16520 // We don't want inferences from constraints as they may cause us to eagerly resolve the 16521 // conditional type instead of deferring resolution. Also, we always want strict function 16522 // types rules (i.e. proper contravariance) for inferences. 16523 inferTypes(context.inferences, checkType, instantiateType(extendsType, freshMapper), InferencePriority.NoConstraints | InferencePriority.AlwaysStrict); 16524 } 16525 const innerMapper = combineTypeMappers(freshMapper, context.mapper); 16526 // It's possible for 'infer T' type paramteters to be given uninstantiated constraints when the 16527 // those type parameters are used in type references (see getInferredTypeParameterConstraint). For 16528 // that reason we need context.mapper to be first in the combined mapper. See #42636 for examples. 16529 combinedMapper = mapper ? combineTypeMappers(innerMapper, mapper) : innerMapper; 16530 } 16531 // Instantiate the extends type including inferences for 'infer T' type parameters 16532 const inferredExtendsType = combinedMapper ? instantiateType(unwrapNondistributiveConditionalTuple(root, root.extendsType), combinedMapper) : extendsType; 16533 // We attempt to resolve the conditional type only when the check and extends types are non-generic 16534 if (!checkTypeInstantiable && !isGenericType(inferredExtendsType)) { 16535 // Return falseType for a definitely false extends check. We check an instantiations of the two 16536 // types with type parameters mapped to the wildcard type, the most permissive instantiations 16537 // possible (the wildcard type is assignable to and from all types). If those are not related, 16538 // then no instantiations will be and we can just return the false branch type. 16539 if (!(inferredExtendsType.flags & TypeFlags.AnyOrUnknown) && ((checkType.flags & TypeFlags.Any && !isUnwrapped) || !isTypeAssignableTo(getPermissiveInstantiation(checkType), getPermissiveInstantiation(inferredExtendsType)))) { 16540 // Return union of trueType and falseType for 'any' since it matches anything 16541 if (checkType.flags & TypeFlags.Any && !isUnwrapped) { 16542 (extraTypes || (extraTypes = [])).push(instantiateType(getTypeFromTypeNode(root.node.trueType), combinedMapper || mapper)); 16543 } 16544 // If falseType is an immediately nested conditional type that isn't distributive or has an 16545 // identical checkType, switch to that type and loop. 16546 const falseType = getTypeFromTypeNode(root.node.falseType); 16547 if (falseType.flags & TypeFlags.Conditional) { 16548 const newRoot = (falseType as ConditionalType).root; 16549 if (newRoot.node.parent === root.node && (!newRoot.isDistributive || newRoot.checkType === root.checkType)) { 16550 root = newRoot; 16551 continue; 16552 } 16553 if (canTailRecurse(falseType, mapper)) { 16554 continue; 16555 } 16556 } 16557 result = instantiateType(falseType, mapper); 16558 break; 16559 } 16560 // Return trueType for a definitely true extends check. We check instantiations of the two 16561 // types with type parameters mapped to their restrictive form, i.e. a form of the type parameter 16562 // that has no constraint. This ensures that, for example, the type 16563 // type Foo<T extends { x: any }> = T extends { x: string } ? string : number 16564 // doesn't immediately resolve to 'string' instead of being deferred. 16565 if (inferredExtendsType.flags & TypeFlags.AnyOrUnknown || isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(inferredExtendsType))) { 16566 const trueType = getTypeFromTypeNode(root.node.trueType); 16567 const trueMapper = combinedMapper || mapper; 16568 if (canTailRecurse(trueType, trueMapper)) { 16569 continue; 16570 } 16571 result = instantiateType(trueType, trueMapper); 16572 break; 16573 } 16574 } 16575 // Return a deferred type for a check that is neither definitely true nor definitely false 16576 result = createType(TypeFlags.Conditional) as ConditionalType; 16577 result.root = root; 16578 result.checkType = instantiateType(root.checkType, mapper); 16579 result.extendsType = instantiateType(root.extendsType, mapper); 16580 result.mapper = mapper; 16581 result.combinedMapper = combinedMapper; 16582 result.aliasSymbol = aliasSymbol || root.aliasSymbol; 16583 result.aliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(root.aliasTypeArguments, mapper!); // TODO: GH#18217 16584 break; 16585 } 16586 return extraTypes ? getUnionType(append(extraTypes, result)) : result; 16587 // We tail-recurse for generic conditional types that (a) have not already been evaluated and cached, and 16588 // (b) are non distributive, have a check type that is unaffected by instantiation, or have a non-union check 16589 // type. Note that recursion is possible only through aliased conditional types, so we only increment the tail 16590 // recursion counter for those. 16591 function canTailRecurse(newType: Type, newMapper: TypeMapper | undefined) { 16592 if (newType.flags & TypeFlags.Conditional && newMapper) { 16593 const newRoot = (newType as ConditionalType).root; 16594 if (newRoot.outerTypeParameters) { 16595 const typeParamMapper = combineTypeMappers((newType as ConditionalType).mapper, newMapper); 16596 const typeArguments = map(newRoot.outerTypeParameters, t => getMappedType(t, typeParamMapper)); 16597 const newRootMapper = createTypeMapper(newRoot.outerTypeParameters, typeArguments); 16598 const newCheckType = newRoot.isDistributive ? getMappedType(newRoot.checkType, newRootMapper) : undefined; 16599 if (!newCheckType || newCheckType === newRoot.checkType || !(newCheckType.flags & (TypeFlags.Union | TypeFlags.Never))) { 16600 root = newRoot; 16601 mapper = newRootMapper; 16602 aliasSymbol = undefined; 16603 aliasTypeArguments = undefined; 16604 if (newRoot.aliasSymbol) { 16605 tailCount++; 16606 } 16607 return true; 16608 } 16609 } 16610 } 16611 return false; 16612 } 16613 } 16614 16615 function getTrueTypeFromConditionalType(type: ConditionalType) { 16616 return type.resolvedTrueType || (type.resolvedTrueType = instantiateType(getTypeFromTypeNode(type.root.node.trueType), type.mapper)); 16617 } 16618 16619 function getFalseTypeFromConditionalType(type: ConditionalType) { 16620 return type.resolvedFalseType || (type.resolvedFalseType = instantiateType(getTypeFromTypeNode(type.root.node.falseType), type.mapper)); 16621 } 16622 16623 function getInferredTrueTypeFromConditionalType(type: ConditionalType) { 16624 return type.resolvedInferredTrueType || (type.resolvedInferredTrueType = type.combinedMapper ? instantiateType(getTypeFromTypeNode(type.root.node.trueType), type.combinedMapper) : getTrueTypeFromConditionalType(type)); 16625 } 16626 16627 function getInferTypeParameters(node: ConditionalTypeNode): TypeParameter[] | undefined { 16628 let result: TypeParameter[] | undefined; 16629 if (node.locals) { 16630 node.locals.forEach(symbol => { 16631 if (symbol.flags & SymbolFlags.TypeParameter) { 16632 result = append(result, getDeclaredTypeOfSymbol(symbol)); 16633 } 16634 }); 16635 } 16636 return result; 16637 } 16638 16639 function isDistributionDependent(root: ConditionalRoot) { 16640 return root.isDistributive && ( 16641 isTypeParameterPossiblyReferenced(root.checkType as TypeParameter, root.node.trueType) || 16642 isTypeParameterPossiblyReferenced(root.checkType as TypeParameter, root.node.falseType)); 16643 } 16644 16645 function getTypeFromConditionalTypeNode(node: ConditionalTypeNode): Type { 16646 const links = getNodeLinks(node); 16647 if (!links.resolvedType) { 16648 const checkType = getTypeFromTypeNode(node.checkType); 16649 const aliasSymbol = getAliasSymbolForTypeNode(node); 16650 const aliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol); 16651 const allOuterTypeParameters = getOuterTypeParameters(node, /*includeThisTypes*/ true); 16652 const outerTypeParameters = aliasTypeArguments ? allOuterTypeParameters : filter(allOuterTypeParameters, tp => isTypeParameterPossiblyReferenced(tp, node)); 16653 const root: ConditionalRoot = { 16654 node, 16655 checkType, 16656 extendsType: getTypeFromTypeNode(node.extendsType), 16657 isDistributive: !!(checkType.flags & TypeFlags.TypeParameter), 16658 inferTypeParameters: getInferTypeParameters(node), 16659 outerTypeParameters, 16660 instantiations: undefined, 16661 aliasSymbol, 16662 aliasTypeArguments 16663 }; 16664 links.resolvedType = getConditionalType(root, /*mapper*/ undefined); 16665 if (outerTypeParameters) { 16666 root.instantiations = new Map<string, Type>(); 16667 root.instantiations.set(getTypeListId(outerTypeParameters), links.resolvedType); 16668 } 16669 } 16670 return links.resolvedType; 16671 } 16672 16673 function getTypeFromInferTypeNode(node: InferTypeNode): Type { 16674 const links = getNodeLinks(node); 16675 if (!links.resolvedType) { 16676 links.resolvedType = getDeclaredTypeOfTypeParameter(getSymbolOfNode(node.typeParameter)); 16677 } 16678 return links.resolvedType; 16679 } 16680 16681 function getIdentifierChain(node: EntityName): Identifier[] { 16682 if (isIdentifier(node)) { 16683 return [node]; 16684 } 16685 else { 16686 return append(getIdentifierChain(node.left), node.right); 16687 } 16688 } 16689 16690 function getTypeFromImportTypeNode(node: ImportTypeNode): Type { 16691 const links = getNodeLinks(node); 16692 if (!links.resolvedType) { 16693 if (node.isTypeOf && node.typeArguments) { // Only the non-typeof form can make use of type arguments 16694 error(node, Diagnostics.Type_arguments_cannot_be_used_here); 16695 links.resolvedSymbol = unknownSymbol; 16696 return links.resolvedType = errorType; 16697 } 16698 if (!isLiteralImportTypeNode(node)) { 16699 error(node.argument, Diagnostics.String_literal_expected); 16700 links.resolvedSymbol = unknownSymbol; 16701 return links.resolvedType = errorType; 16702 } 16703 const targetMeaning = node.isTypeOf ? SymbolFlags.Value : node.flags & NodeFlags.JSDoc ? SymbolFlags.Value | SymbolFlags.Type : SymbolFlags.Type; 16704 // TODO: Future work: support unions/generics/whatever via a deferred import-type 16705 const innerModuleSymbol = resolveExternalModuleName(node, node.argument.literal); 16706 if (!innerModuleSymbol) { 16707 links.resolvedSymbol = unknownSymbol; 16708 return links.resolvedType = errorType; 16709 } 16710 const isExportEquals = !!innerModuleSymbol.exports?.get(InternalSymbolName.ExportEquals); 16711 const moduleSymbol = resolveExternalModuleSymbol(innerModuleSymbol, /*dontResolveAlias*/ false); 16712 if (!nodeIsMissing(node.qualifier)) { 16713 const nameStack: Identifier[] = getIdentifierChain(node.qualifier!); 16714 let currentNamespace = moduleSymbol; 16715 let current: Identifier | undefined; 16716 while (current = nameStack.shift()) { 16717 const meaning = nameStack.length ? SymbolFlags.Namespace : targetMeaning; 16718 // typeof a.b.c is normally resolved using `checkExpression` which in turn defers to `checkQualifiedName` 16719 // That, in turn, ultimately uses `getPropertyOfType` on the type of the symbol, which differs slightly from 16720 // the `exports` lookup process that only looks up namespace members which is used for most type references 16721 const mergedResolvedSymbol = getMergedSymbol(resolveSymbol(currentNamespace)); 16722 const symbolFromVariable = node.isTypeOf || isInJSFile(node) && isExportEquals 16723 ? getPropertyOfType(getTypeOfSymbol(mergedResolvedSymbol), current.escapedText, /*skipObjectFunctionPropertyAugment*/ false, /*includeTypeOnlyMembers*/ true) 16724 : undefined; 16725 const symbolFromModule = node.isTypeOf ? undefined : getSymbol(getExportsOfSymbol(mergedResolvedSymbol), current.escapedText, meaning); 16726 const next = symbolFromModule ?? symbolFromVariable; 16727 if (!next) { 16728 error(current, Diagnostics.Namespace_0_has_no_exported_member_1, getFullyQualifiedName(currentNamespace), declarationNameToString(current)); 16729 return links.resolvedType = errorType; 16730 } 16731 getNodeLinks(current).resolvedSymbol = next; 16732 getNodeLinks(current.parent).resolvedSymbol = next; 16733 currentNamespace = next; 16734 } 16735 links.resolvedType = resolveImportSymbolType(node, links, currentNamespace, targetMeaning); 16736 } 16737 else { 16738 if (moduleSymbol.flags & targetMeaning) { 16739 links.resolvedType = resolveImportSymbolType(node, links, moduleSymbol, targetMeaning); 16740 } 16741 else { 16742 const errorMessage = targetMeaning === SymbolFlags.Value 16743 ? Diagnostics.Module_0_does_not_refer_to_a_value_but_is_used_as_a_value_here 16744 : Diagnostics.Module_0_does_not_refer_to_a_type_but_is_used_as_a_type_here_Did_you_mean_typeof_import_0; 16745 16746 error(node, errorMessage, node.argument.literal.text); 16747 16748 links.resolvedSymbol = unknownSymbol; 16749 links.resolvedType = errorType; 16750 } 16751 } 16752 } 16753 return links.resolvedType; 16754 } 16755 16756 function resolveImportSymbolType(node: ImportTypeNode, links: NodeLinks, symbol: Symbol, meaning: SymbolFlags) { 16757 const resolvedSymbol = resolveSymbol(symbol); 16758 links.resolvedSymbol = resolvedSymbol; 16759 if (meaning === SymbolFlags.Value) { 16760 return getTypeOfSymbol(symbol); // intentionally doesn't use resolved symbol so type is cached as expected on the alias 16761 } 16762 else { 16763 return getTypeReferenceType(node, resolvedSymbol); // getTypeReferenceType doesn't handle aliases - it must get the resolved symbol 16764 } 16765 } 16766 16767 function getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node: TypeNode): Type { 16768 const links = getNodeLinks(node); 16769 if (!links.resolvedType) { 16770 // Deferred resolution of members is handled by resolveObjectTypeMembers 16771 const aliasSymbol = getAliasSymbolForTypeNode(node); 16772 if (getMembersOfSymbol(node.symbol).size === 0 && !aliasSymbol) { 16773 links.resolvedType = emptyTypeLiteralType; 16774 } 16775 else { 16776 let type = createObjectType(ObjectFlags.Anonymous, node.symbol); 16777 type.aliasSymbol = aliasSymbol; 16778 type.aliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol); 16779 if (isJSDocTypeLiteral(node) && node.isArrayType) { 16780 type = createArrayType(type); 16781 } 16782 links.resolvedType = type; 16783 } 16784 } 16785 return links.resolvedType; 16786 } 16787 16788 function getAliasSymbolForTypeNode(node: Node) { 16789 let host = node.parent; 16790 while (isParenthesizedTypeNode(host) || isJSDocTypeExpression(host) || isTypeOperatorNode(host) && host.operator === SyntaxKind.ReadonlyKeyword) { 16791 host = host.parent; 16792 } 16793 return isTypeAlias(host) ? getSymbolOfNode(host) : undefined; 16794 } 16795 16796 function getTypeArgumentsForAliasSymbol(symbol: Symbol | undefined) { 16797 return symbol ? getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol) : undefined; 16798 } 16799 16800 function isNonGenericObjectType(type: Type) { 16801 return !!(type.flags & TypeFlags.Object) && !isGenericMappedType(type); 16802 } 16803 16804 function isEmptyObjectTypeOrSpreadsIntoEmptyObject(type: Type) { 16805 return isEmptyObjectType(type) || !!(type.flags & (TypeFlags.Null | TypeFlags.Undefined | TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.EnumLike | TypeFlags.NonPrimitive | TypeFlags.Index)); 16806 } 16807 16808 function tryMergeUnionOfObjectTypeAndEmptyObject(type: Type, readonly: boolean): Type { 16809 if (!(type.flags & TypeFlags.Union)) { 16810 return type; 16811 } 16812 if (every((type as UnionType).types, isEmptyObjectTypeOrSpreadsIntoEmptyObject)) { 16813 return find((type as UnionType).types, isEmptyObjectType) || emptyObjectType; 16814 } 16815 const firstType = find((type as UnionType).types, t => !isEmptyObjectTypeOrSpreadsIntoEmptyObject(t)); 16816 if (!firstType) { 16817 return type; 16818 } 16819 const secondType = find((type as UnionType).types, t => t !== firstType && !isEmptyObjectTypeOrSpreadsIntoEmptyObject(t)); 16820 if (secondType) { 16821 return type; 16822 } 16823 return getAnonymousPartialType(firstType); 16824 16825 function getAnonymousPartialType(type: Type) { 16826 // gets the type as if it had been spread, but where everything in the spread is made optional 16827 const members = createSymbolTable(); 16828 for (const prop of getPropertiesOfType(type)) { 16829 if (getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected)) { 16830 // do nothing, skip privates 16831 } 16832 else if (isSpreadableProperty(prop)) { 16833 const isSetonlyAccessor = prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor); 16834 const flags = SymbolFlags.Property | SymbolFlags.Optional; 16835 const result = createSymbol(flags, prop.escapedName, getIsLateCheckFlag(prop) | (readonly ? CheckFlags.Readonly : 0)); 16836 result.type = isSetonlyAccessor ? undefinedType : addOptionality(getTypeOfSymbol(prop), /*isProperty*/ true); 16837 result.declarations = prop.declarations; 16838 result.nameType = getSymbolLinks(prop).nameType; 16839 result.syntheticOrigin = prop; 16840 members.set(prop.escapedName, result); 16841 } 16842 } 16843 const spread = createAnonymousType(type.symbol, members, emptyArray, emptyArray, getIndexInfosOfType(type)); 16844 spread.objectFlags |= ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral; 16845 return spread; 16846 } 16847 } 16848 16849 /** 16850 * Since the source of spread types are object literals, which are not binary, 16851 * this function should be called in a left folding style, with left = previous result of getSpreadType 16852 * and right = the new element to be spread. 16853 */ 16854 function getSpreadType(left: Type, right: Type, symbol: Symbol | undefined, objectFlags: ObjectFlags, readonly: boolean): Type { 16855 if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) { 16856 return anyType; 16857 } 16858 if (left.flags & TypeFlags.Unknown || right.flags & TypeFlags.Unknown) { 16859 return unknownType; 16860 } 16861 if (left.flags & TypeFlags.Never) { 16862 return right; 16863 } 16864 if (right.flags & TypeFlags.Never) { 16865 return left; 16866 } 16867 left = tryMergeUnionOfObjectTypeAndEmptyObject(left, readonly); 16868 if (left.flags & TypeFlags.Union) { 16869 return checkCrossProductUnion([left, right]) 16870 ? mapType(left, t => getSpreadType(t, right, symbol, objectFlags, readonly)) 16871 : errorType; 16872 } 16873 right = tryMergeUnionOfObjectTypeAndEmptyObject(right, readonly); 16874 if (right.flags & TypeFlags.Union) { 16875 return checkCrossProductUnion([left, right]) 16876 ? mapType(right, t => getSpreadType(left, t, symbol, objectFlags, readonly)) 16877 : errorType; 16878 } 16879 if (right.flags & (TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.EnumLike | TypeFlags.NonPrimitive | TypeFlags.Index)) { 16880 return left; 16881 } 16882 16883 if (isGenericObjectType(left) || isGenericObjectType(right)) { 16884 if (isEmptyObjectType(left)) { 16885 return right; 16886 } 16887 // When the left type is an intersection, we may need to merge the last constituent of the 16888 // intersection with the right type. For example when the left type is 'T & { a: string }' 16889 // and the right type is '{ b: string }' we produce 'T & { a: string, b: string }'. 16890 if (left.flags & TypeFlags.Intersection) { 16891 const types = (left as IntersectionType).types; 16892 const lastLeft = types[types.length - 1]; 16893 if (isNonGenericObjectType(lastLeft) && isNonGenericObjectType(right)) { 16894 return getIntersectionType(concatenate(types.slice(0, types.length - 1), [getSpreadType(lastLeft, right, symbol, objectFlags, readonly)])); 16895 } 16896 } 16897 return getIntersectionType([left, right]); 16898 } 16899 16900 const members = createSymbolTable(); 16901 const skippedPrivateMembers = new Set<__String>(); 16902 const indexInfos = left === emptyObjectType ? getIndexInfosOfType(right) : getUnionIndexInfos([left, right]); 16903 16904 for (const rightProp of getPropertiesOfType(right)) { 16905 if (getDeclarationModifierFlagsFromSymbol(rightProp) & (ModifierFlags.Private | ModifierFlags.Protected)) { 16906 skippedPrivateMembers.add(rightProp.escapedName); 16907 } 16908 else if (isSpreadableProperty(rightProp)) { 16909 members.set(rightProp.escapedName, getSpreadSymbol(rightProp, readonly)); 16910 } 16911 } 16912 16913 for (const leftProp of getPropertiesOfType(left)) { 16914 if (skippedPrivateMembers.has(leftProp.escapedName) || !isSpreadableProperty(leftProp)) { 16915 continue; 16916 } 16917 if (members.has(leftProp.escapedName)) { 16918 const rightProp = members.get(leftProp.escapedName)!; 16919 const rightType = getTypeOfSymbol(rightProp); 16920 if (rightProp.flags & SymbolFlags.Optional) { 16921 const declarations = concatenate(leftProp.declarations, rightProp.declarations); 16922 const flags = SymbolFlags.Property | (leftProp.flags & SymbolFlags.Optional); 16923 const result = createSymbol(flags, leftProp.escapedName); 16924 result.type = getUnionType([getTypeOfSymbol(leftProp), removeMissingOrUndefinedType(rightType)], UnionReduction.Subtype); 16925 result.leftSpread = leftProp; 16926 result.rightSpread = rightProp; 16927 result.declarations = declarations; 16928 result.nameType = getSymbolLinks(leftProp).nameType; 16929 members.set(leftProp.escapedName, result); 16930 } 16931 } 16932 else { 16933 members.set(leftProp.escapedName, getSpreadSymbol(leftProp, readonly)); 16934 } 16935 } 16936 16937 const spread = createAnonymousType(symbol, members, emptyArray, emptyArray, sameMap(indexInfos, info => getIndexInfoWithReadonly(info, readonly))); 16938 spread.objectFlags |= ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral | ObjectFlags.ContainsSpread | objectFlags; 16939 return spread; 16940 } 16941 16942 /** We approximate own properties as non-methods plus methods that are inside the object literal */ 16943 function isSpreadableProperty(prop: Symbol): boolean { 16944 return !some(prop.declarations, isPrivateIdentifierClassElementDeclaration) && 16945 (!(prop.flags & (SymbolFlags.Method | SymbolFlags.GetAccessor | SymbolFlags.SetAccessor)) || 16946 !prop.declarations?.some(decl => isClassLike(decl.parent))); 16947 } 16948 16949 function getSpreadSymbol(prop: Symbol, readonly: boolean) { 16950 const isSetonlyAccessor = prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor); 16951 if (!isSetonlyAccessor && readonly === isReadonlySymbol(prop)) { 16952 return prop; 16953 } 16954 const flags = SymbolFlags.Property | (prop.flags & SymbolFlags.Optional); 16955 const result = createSymbol(flags, prop.escapedName, getIsLateCheckFlag(prop) | (readonly ? CheckFlags.Readonly : 0)); 16956 result.type = isSetonlyAccessor ? undefinedType : getTypeOfSymbol(prop); 16957 result.declarations = prop.declarations; 16958 result.nameType = getSymbolLinks(prop).nameType; 16959 result.syntheticOrigin = prop; 16960 return result; 16961 } 16962 16963 function getIndexInfoWithReadonly(info: IndexInfo, readonly: boolean) { 16964 return info.isReadonly !== readonly ? createIndexInfo(info.keyType, info.type, readonly, info.declaration) : info; 16965 } 16966 16967 function createLiteralType(flags: TypeFlags, value: string | number | PseudoBigInt, symbol?: Symbol, regularType?: LiteralType) { 16968 const type = createType(flags) as LiteralType; 16969 type.symbol = symbol!; 16970 type.value = value; 16971 type.regularType = regularType || type; 16972 return type; 16973 } 16974 16975 function getFreshTypeOfLiteralType(type: Type): Type { 16976 if (type.flags & TypeFlags.Literal) { 16977 if (!(type as LiteralType).freshType) { 16978 const freshType = createLiteralType(type.flags, (type as LiteralType).value, (type as LiteralType).symbol, type as LiteralType); 16979 freshType.freshType = freshType; 16980 (type as LiteralType).freshType = freshType; 16981 } 16982 return (type as LiteralType).freshType; 16983 } 16984 return type; 16985 } 16986 16987 function getRegularTypeOfLiteralType(type: Type): Type { 16988 return type.flags & TypeFlags.Literal ? (type as LiteralType).regularType : 16989 type.flags & TypeFlags.Union ? ((type as UnionType).regularType || ((type as UnionType).regularType = mapType(type, getRegularTypeOfLiteralType) as UnionType)) : 16990 type; 16991 } 16992 16993 function isFreshLiteralType(type: Type) { 16994 return !!(type.flags & TypeFlags.Literal) && (type as LiteralType).freshType === type; 16995 } 16996 16997 function getStringLiteralType(value: string): StringLiteralType { 16998 let type; 16999 return stringLiteralTypes.get(value) || 17000 (stringLiteralTypes.set(value, type = createLiteralType(TypeFlags.StringLiteral, value) as StringLiteralType), type); 17001 } 17002 17003 function getNumberLiteralType(value: number): NumberLiteralType { 17004 let type; 17005 return numberLiteralTypes.get(value) || 17006 (numberLiteralTypes.set(value, type = createLiteralType(TypeFlags.NumberLiteral, value) as NumberLiteralType), type); 17007 } 17008 17009 function getBigIntLiteralType(value: PseudoBigInt): BigIntLiteralType { 17010 let type; 17011 const key = pseudoBigIntToString(value); 17012 return bigIntLiteralTypes.get(key) || 17013 (bigIntLiteralTypes.set(key, type = createLiteralType(TypeFlags.BigIntLiteral, value) as BigIntLiteralType), type); 17014 } 17015 17016 function getEnumLiteralType(value: string | number, enumId: number, symbol: Symbol): LiteralType { 17017 let type; 17018 const qualifier = typeof value === "string" ? "@" : "#"; 17019 const key = enumId + qualifier + value; 17020 const flags = TypeFlags.EnumLiteral | (typeof value === "string" ? TypeFlags.StringLiteral : TypeFlags.NumberLiteral); 17021 return enumLiteralTypes.get(key) || 17022 (enumLiteralTypes.set(key, type = createLiteralType(flags, value, symbol)), type); 17023 } 17024 17025 function getTypeFromLiteralTypeNode(node: LiteralTypeNode): Type { 17026 if (node.literal.kind === SyntaxKind.NullKeyword) { 17027 return nullType; 17028 } 17029 const links = getNodeLinks(node); 17030 if (!links.resolvedType) { 17031 links.resolvedType = getRegularTypeOfLiteralType(checkExpression(node.literal)); 17032 } 17033 return links.resolvedType; 17034 } 17035 17036 function createUniqueESSymbolType(symbol: Symbol) { 17037 const type = createType(TypeFlags.UniqueESSymbol) as UniqueESSymbolType; 17038 type.symbol = symbol; 17039 type.escapedName = `__@${type.symbol.escapedName}@${getSymbolId(type.symbol)}` as __String; 17040 return type; 17041 } 17042 17043 function getESSymbolLikeTypeForNode(node: Node) { 17044 if (isValidESSymbolDeclaration(node)) { 17045 const symbol = isCommonJsExportPropertyAssignment(node) ? getSymbolOfNode((node as BinaryExpression).left) : getSymbolOfNode(node); 17046 if (symbol) { 17047 const links = getSymbolLinks(symbol); 17048 return links.uniqueESSymbolType || (links.uniqueESSymbolType = createUniqueESSymbolType(symbol)); 17049 } 17050 } 17051 return esSymbolType; 17052 } 17053 17054 function getThisType(node: Node): Type { 17055 const container = getThisContainer(node, /*includeArrowFunctions*/ false); 17056 const parent = container && container.parent; 17057 if (parent && (isClassLike(parent) || parent.kind === SyntaxKind.InterfaceDeclaration)) { 17058 if (!isStatic(container) && 17059 (!isConstructorDeclaration(container) || isNodeDescendantOf(node, container.body))) { 17060 return getDeclaredTypeOfClassOrInterface(getSymbolOfNode(parent as ClassLikeDeclaration | InterfaceDeclaration)).thisType!; 17061 } 17062 } 17063 17064 // inside x.prototype = { ... } 17065 if (parent && isObjectLiteralExpression(parent) && isBinaryExpression(parent.parent) && getAssignmentDeclarationKind(parent.parent) === AssignmentDeclarationKind.Prototype) { 17066 return getDeclaredTypeOfClassOrInterface(getSymbolOfNode(parent.parent.left)!.parent!).thisType!; 17067 } 17068 // /** @return {this} */ 17069 // x.prototype.m = function() { ... } 17070 const host = node.flags & NodeFlags.JSDoc ? getHostSignatureFromJSDoc(node) : undefined; 17071 if (host && isFunctionExpression(host) && isBinaryExpression(host.parent) && getAssignmentDeclarationKind(host.parent) === AssignmentDeclarationKind.PrototypeProperty) { 17072 return getDeclaredTypeOfClassOrInterface(getSymbolOfNode(host.parent.left)!.parent!).thisType!; 17073 } 17074 // inside constructor function C() { ... } 17075 if (isJSConstructor(container) && isNodeDescendantOf(node, container.body)) { 17076 return getDeclaredTypeOfClassOrInterface(getSymbolOfNode(container)).thisType!; 17077 } 17078 error(node, Diagnostics.A_this_type_is_available_only_in_a_non_static_member_of_a_class_or_interface); 17079 return errorType; 17080 } 17081 17082 function getTypeFromThisTypeNode(node: ThisExpression | ThisTypeNode): Type { 17083 const links = getNodeLinks(node); 17084 if (!links.resolvedType) { 17085 links.resolvedType = getThisType(node); 17086 } 17087 return links.resolvedType; 17088 } 17089 17090 function getTypeFromRestTypeNode(node: RestTypeNode | NamedTupleMember) { 17091 return getTypeFromTypeNode(getArrayElementTypeNode(node.type) || node.type); 17092 } 17093 17094 function getArrayElementTypeNode(node: TypeNode): TypeNode | undefined { 17095 switch (node.kind) { 17096 case SyntaxKind.ParenthesizedType: 17097 return getArrayElementTypeNode((node as ParenthesizedTypeNode).type); 17098 case SyntaxKind.TupleType: 17099 if ((node as TupleTypeNode).elements.length === 1) { 17100 node = (node as TupleTypeNode).elements[0]; 17101 if (node.kind === SyntaxKind.RestType || node.kind === SyntaxKind.NamedTupleMember && (node as NamedTupleMember).dotDotDotToken) { 17102 return getArrayElementTypeNode((node as RestTypeNode | NamedTupleMember).type); 17103 } 17104 } 17105 break; 17106 case SyntaxKind.ArrayType: 17107 return (node as ArrayTypeNode).elementType; 17108 } 17109 return undefined; 17110 } 17111 17112 function getTypeFromNamedTupleTypeNode(node: NamedTupleMember): Type { 17113 const links = getNodeLinks(node); 17114 return links.resolvedType || (links.resolvedType = 17115 node.dotDotDotToken ? getTypeFromRestTypeNode(node) : 17116 addOptionality(getTypeFromTypeNode(node.type), /*isProperty*/ true, !!node.questionToken)); 17117 } 17118 17119 function getTypeFromTypeNode(node: TypeNode): Type { 17120 return getConditionalFlowTypeOfType(getTypeFromTypeNodeWorker(node), node); 17121 } 17122 17123 function getTypeFromTypeNodeWorker(node: TypeNode): Type { 17124 switch (node.kind) { 17125 case SyntaxKind.AnyKeyword: 17126 case SyntaxKind.JSDocAllType: 17127 case SyntaxKind.JSDocUnknownType: 17128 return anyType; 17129 case SyntaxKind.UnknownKeyword: 17130 return unknownType; 17131 case SyntaxKind.StringKeyword: 17132 return stringType; 17133 case SyntaxKind.NumberKeyword: 17134 return numberType; 17135 case SyntaxKind.BigIntKeyword: 17136 return bigintType; 17137 case SyntaxKind.BooleanKeyword: 17138 return booleanType; 17139 case SyntaxKind.SymbolKeyword: 17140 return esSymbolType; 17141 case SyntaxKind.VoidKeyword: 17142 return voidType; 17143 case SyntaxKind.UndefinedKeyword: 17144 return undefinedType; 17145 case SyntaxKind.NullKeyword as TypeNodeSyntaxKind: 17146 // TODO(rbuckton): `NullKeyword` is no longer a `TypeNode`, but we defensively allow it here because of incorrect casts in the Language Service. 17147 return nullType; 17148 case SyntaxKind.NeverKeyword: 17149 return neverType; 17150 case SyntaxKind.ObjectKeyword: 17151 return node.flags & NodeFlags.JavaScriptFile && !noImplicitAny ? anyType : nonPrimitiveType; 17152 case SyntaxKind.IntrinsicKeyword: 17153 return intrinsicMarkerType; 17154 case SyntaxKind.ThisType: 17155 case SyntaxKind.ThisKeyword as TypeNodeSyntaxKind: 17156 // TODO(rbuckton): `ThisKeyword` is no longer a `TypeNode`, but we defensively allow it here because of incorrect casts in the Language Service and because of `isPartOfTypeNode`. 17157 return getTypeFromThisTypeNode(node as ThisExpression | ThisTypeNode); 17158 case SyntaxKind.LiteralType: 17159 return getTypeFromLiteralTypeNode(node as LiteralTypeNode); 17160 case SyntaxKind.TypeReference: 17161 return getTypeFromTypeReference(node as TypeReferenceNode); 17162 case SyntaxKind.TypePredicate: 17163 return (node as TypePredicateNode).assertsModifier ? voidType : booleanType; 17164 case SyntaxKind.ExpressionWithTypeArguments: 17165 return getTypeFromTypeReference(node as ExpressionWithTypeArguments); 17166 case SyntaxKind.TypeQuery: 17167 return getTypeFromTypeQueryNode(node as TypeQueryNode); 17168 case SyntaxKind.ArrayType: 17169 case SyntaxKind.TupleType: 17170 return getTypeFromArrayOrTupleTypeNode(node as ArrayTypeNode | TupleTypeNode); 17171 case SyntaxKind.OptionalType: 17172 return getTypeFromOptionalTypeNode(node as OptionalTypeNode); 17173 case SyntaxKind.UnionType: 17174 return getTypeFromUnionTypeNode(node as UnionTypeNode); 17175 case SyntaxKind.IntersectionType: 17176 return getTypeFromIntersectionTypeNode(node as IntersectionTypeNode); 17177 case SyntaxKind.JSDocNullableType: 17178 return getTypeFromJSDocNullableTypeNode(node as JSDocNullableType); 17179 case SyntaxKind.JSDocOptionalType: 17180 return addOptionality(getTypeFromTypeNode((node as JSDocOptionalType).type)); 17181 case SyntaxKind.NamedTupleMember: 17182 return getTypeFromNamedTupleTypeNode(node as NamedTupleMember); 17183 case SyntaxKind.ParenthesizedType: 17184 case SyntaxKind.JSDocNonNullableType: 17185 case SyntaxKind.JSDocTypeExpression: 17186 return getTypeFromTypeNode((node as ParenthesizedTypeNode | JSDocTypeReferencingNode | JSDocTypeExpression | NamedTupleMember).type); 17187 case SyntaxKind.RestType: 17188 return getTypeFromRestTypeNode(node as RestTypeNode); 17189 case SyntaxKind.JSDocVariadicType: 17190 return getTypeFromJSDocVariadicType(node as JSDocVariadicType); 17191 case SyntaxKind.FunctionType: 17192 case SyntaxKind.ConstructorType: 17193 case SyntaxKind.TypeLiteral: 17194 case SyntaxKind.JSDocTypeLiteral: 17195 case SyntaxKind.JSDocFunctionType: 17196 case SyntaxKind.JSDocSignature: 17197 return getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node); 17198 case SyntaxKind.TypeOperator: 17199 return getTypeFromTypeOperatorNode(node as TypeOperatorNode); 17200 case SyntaxKind.IndexedAccessType: 17201 return getTypeFromIndexedAccessTypeNode(node as IndexedAccessTypeNode); 17202 case SyntaxKind.MappedType: 17203 return getTypeFromMappedTypeNode(node as MappedTypeNode); 17204 case SyntaxKind.ConditionalType: 17205 return getTypeFromConditionalTypeNode(node as ConditionalTypeNode); 17206 case SyntaxKind.InferType: 17207 return getTypeFromInferTypeNode(node as InferTypeNode); 17208 case SyntaxKind.TemplateLiteralType: 17209 return getTypeFromTemplateTypeNode(node as TemplateLiteralTypeNode); 17210 case SyntaxKind.ImportType: 17211 return getTypeFromImportTypeNode(node as ImportTypeNode); 17212 // This function assumes that an identifier, qualified name, or property access expression is a type expression 17213 // Callers should first ensure this by calling `isPartOfTypeNode` 17214 // TODO(rbuckton): These aren't valid TypeNodes, but we treat them as such because of `isPartOfTypeNode`, which returns `true` for things that aren't `TypeNode`s. 17215 case SyntaxKind.Identifier as TypeNodeSyntaxKind: 17216 case SyntaxKind.QualifiedName as TypeNodeSyntaxKind: 17217 case SyntaxKind.PropertyAccessExpression as TypeNodeSyntaxKind: 17218 const symbol = getSymbolAtLocation(node); 17219 return symbol ? getDeclaredTypeOfSymbol(symbol) : errorType; 17220 default: 17221 return errorType; 17222 } 17223 } 17224 17225 function instantiateList<T>(items: readonly T[], mapper: TypeMapper, instantiator: (item: T, mapper: TypeMapper) => T): readonly T[]; 17226 function instantiateList<T>(items: readonly T[] | undefined, mapper: TypeMapper, instantiator: (item: T, mapper: TypeMapper) => T): readonly T[] | undefined; 17227 function instantiateList<T>(items: readonly T[] | undefined, mapper: TypeMapper, instantiator: (item: T, mapper: TypeMapper) => T): readonly T[] | undefined { 17228 if (items && items.length) { 17229 for (let i = 0; i < items.length; i++) { 17230 const item = items[i]; 17231 const mapped = instantiator(item, mapper); 17232 if (item !== mapped) { 17233 const result = i === 0 ? [] : items.slice(0, i); 17234 result.push(mapped); 17235 for (i++; i < items.length; i++) { 17236 result.push(instantiator(items[i], mapper)); 17237 } 17238 return result; 17239 } 17240 } 17241 } 17242 return items; 17243 } 17244 17245 function instantiateTypes(types: readonly Type[], mapper: TypeMapper): readonly Type[]; 17246 function instantiateTypes(types: readonly Type[] | undefined, mapper: TypeMapper): readonly Type[] | undefined; 17247 function instantiateTypes(types: readonly Type[] | undefined, mapper: TypeMapper): readonly Type[] | undefined { 17248 return instantiateList<Type>(types, mapper, instantiateType); 17249 } 17250 17251 function instantiateSignatures(signatures: readonly Signature[], mapper: TypeMapper): readonly Signature[] { 17252 return instantiateList<Signature>(signatures, mapper, instantiateSignature); 17253 } 17254 17255 function instantiateIndexInfos(indexInfos: readonly IndexInfo[], mapper: TypeMapper): readonly IndexInfo[] { 17256 return instantiateList<IndexInfo>(indexInfos, mapper, instantiateIndexInfo); 17257 } 17258 17259 function createTypeMapper(sources: readonly TypeParameter[], targets: readonly Type[] | undefined): TypeMapper { 17260 return sources.length === 1 ? makeUnaryTypeMapper(sources[0], targets ? targets[0] : anyType) : makeArrayTypeMapper(sources, targets); 17261 } 17262 17263 function getMappedType(type: Type, mapper: TypeMapper): Type { 17264 switch (mapper.kind) { 17265 case TypeMapKind.Simple: 17266 return type === mapper.source ? mapper.target : type; 17267 case TypeMapKind.Array: { 17268 const sources = mapper.sources; 17269 const targets = mapper.targets; 17270 for (let i = 0; i < sources.length; i++) { 17271 if (type === sources[i]) { 17272 return targets ? targets[i] : anyType; 17273 } 17274 } 17275 return type; 17276 } 17277 case TypeMapKind.Deferred: { 17278 const sources = mapper.sources; 17279 const targets = mapper.targets; 17280 for (let i = 0; i < sources.length; i++) { 17281 if (type === sources[i]) { 17282 return targets[i](); 17283 } 17284 } 17285 return type; 17286 } 17287 case TypeMapKind.Function: 17288 return mapper.func(type); 17289 case TypeMapKind.Composite: 17290 case TypeMapKind.Merged: 17291 const t1 = getMappedType(type, mapper.mapper1); 17292 return t1 !== type && mapper.kind === TypeMapKind.Composite ? instantiateType(t1, mapper.mapper2) : getMappedType(t1, mapper.mapper2); 17293 } 17294 } 17295 17296 function makeUnaryTypeMapper(source: Type, target: Type): TypeMapper { 17297 return Debug.attachDebugPrototypeIfDebug({ kind: TypeMapKind.Simple, source, target }); 17298 } 17299 17300 function makeArrayTypeMapper(sources: readonly TypeParameter[], targets: readonly Type[] | undefined): TypeMapper { 17301 return Debug.attachDebugPrototypeIfDebug({ kind: TypeMapKind.Array, sources, targets }); 17302 } 17303 17304 function makeFunctionTypeMapper(func: (t: Type) => Type, debugInfo: () => string): TypeMapper { 17305 return Debug.attachDebugPrototypeIfDebug({ kind: TypeMapKind.Function, func, debugInfo: Debug.isDebugging ? debugInfo : undefined }); 17306 } 17307 17308 function makeDeferredTypeMapper(sources: readonly TypeParameter[], targets: (() => Type)[]) { 17309 return Debug.attachDebugPrototypeIfDebug({ kind: TypeMapKind.Deferred, sources, targets }); 17310 } 17311 17312 function makeCompositeTypeMapper(kind: TypeMapKind.Composite | TypeMapKind.Merged, mapper1: TypeMapper, mapper2: TypeMapper): TypeMapper { 17313 return Debug.attachDebugPrototypeIfDebug({ kind, mapper1, mapper2 }); 17314 } 17315 17316 function createTypeEraser(sources: readonly TypeParameter[]): TypeMapper { 17317 return createTypeMapper(sources, /*targets*/ undefined); 17318 } 17319 17320 /** 17321 * Maps forward-references to later types parameters to the empty object type. 17322 * This is used during inference when instantiating type parameter defaults. 17323 */ 17324 function createBackreferenceMapper(context: InferenceContext, index: number): TypeMapper { 17325 const forwardInferences = context.inferences.slice(index); 17326 return createTypeMapper(map(forwardInferences, i => i.typeParameter), map(forwardInferences, () => unknownType)); 17327 } 17328 17329 function combineTypeMappers(mapper1: TypeMapper | undefined, mapper2: TypeMapper): TypeMapper { 17330 return mapper1 ? makeCompositeTypeMapper(TypeMapKind.Composite, mapper1, mapper2) : mapper2; 17331 } 17332 17333 function mergeTypeMappers(mapper1: TypeMapper | undefined, mapper2: TypeMapper): TypeMapper { 17334 return mapper1 ? makeCompositeTypeMapper(TypeMapKind.Merged, mapper1, mapper2) : mapper2; 17335 } 17336 17337 function prependTypeMapping(source: Type, target: Type, mapper: TypeMapper | undefined) { 17338 return !mapper ? makeUnaryTypeMapper(source, target) : makeCompositeTypeMapper(TypeMapKind.Merged, makeUnaryTypeMapper(source, target), mapper); 17339 } 17340 17341 function appendTypeMapping(mapper: TypeMapper | undefined, source: Type, target: Type) { 17342 return !mapper ? makeUnaryTypeMapper(source, target) : makeCompositeTypeMapper(TypeMapKind.Merged, mapper, makeUnaryTypeMapper(source, target)); 17343 } 17344 17345 function getRestrictiveTypeParameter(tp: TypeParameter) { 17346 return !tp.constraint && !getConstraintDeclaration(tp) || tp.constraint === noConstraintType ? tp : tp.restrictiveInstantiation || ( 17347 tp.restrictiveInstantiation = createTypeParameter(tp.symbol), 17348 (tp.restrictiveInstantiation as TypeParameter).constraint = noConstraintType, 17349 tp.restrictiveInstantiation 17350 ); 17351 } 17352 17353 function cloneTypeParameter(typeParameter: TypeParameter): TypeParameter { 17354 const result = createTypeParameter(typeParameter.symbol); 17355 result.target = typeParameter; 17356 return result; 17357 } 17358 17359 function instantiateTypePredicate(predicate: TypePredicate, mapper: TypeMapper): TypePredicate { 17360 return createTypePredicate(predicate.kind, predicate.parameterName, predicate.parameterIndex, instantiateType(predicate.type, mapper)); 17361 } 17362 17363 function instantiateSignature(signature: Signature, mapper: TypeMapper, eraseTypeParameters?: boolean): Signature { 17364 let freshTypeParameters: TypeParameter[] | undefined; 17365 if (signature.typeParameters && !eraseTypeParameters) { 17366 // First create a fresh set of type parameters, then include a mapping from the old to the 17367 // new type parameters in the mapper function. Finally store this mapper in the new type 17368 // parameters such that we can use it when instantiating constraints. 17369 freshTypeParameters = map(signature.typeParameters, cloneTypeParameter); 17370 mapper = combineTypeMappers(createTypeMapper(signature.typeParameters, freshTypeParameters), mapper); 17371 for (const tp of freshTypeParameters) { 17372 tp.mapper = mapper; 17373 } 17374 } 17375 // Don't compute resolvedReturnType and resolvedTypePredicate now, 17376 // because using `mapper` now could trigger inferences to become fixed. (See `createInferenceContext`.) 17377 // See GH#17600. 17378 const result = createSignature(signature.declaration, freshTypeParameters, 17379 signature.thisParameter && instantiateSymbol(signature.thisParameter, mapper), 17380 instantiateList(signature.parameters, mapper, instantiateSymbol), 17381 /*resolvedReturnType*/ undefined, 17382 /*resolvedTypePredicate*/ undefined, 17383 signature.minArgumentCount, 17384 signature.flags & SignatureFlags.PropagatingFlags); 17385 result.target = signature; 17386 result.mapper = mapper; 17387 return result; 17388 } 17389 17390 function instantiateSymbol(symbol: Symbol, mapper: TypeMapper): Symbol { 17391 const links = getSymbolLinks(symbol); 17392 if (links.type && !couldContainTypeVariables(links.type)) { 17393 // If the type of the symbol is already resolved, and if that type could not possibly 17394 // be affected by instantiation, simply return the symbol itself. 17395 return symbol; 17396 } 17397 if (getCheckFlags(symbol) & CheckFlags.Instantiated) { 17398 // If symbol being instantiated is itself a instantiation, fetch the original target and combine the 17399 // type mappers. This ensures that original type identities are properly preserved and that aliases 17400 // always reference a non-aliases. 17401 symbol = links.target!; 17402 mapper = combineTypeMappers(links.mapper, mapper); 17403 } 17404 // Keep the flags from the symbol we're instantiating. Mark that is instantiated, and 17405 // also transient so that we can just store data on it directly. 17406 const result = createSymbol(symbol.flags, symbol.escapedName, CheckFlags.Instantiated | getCheckFlags(symbol) & (CheckFlags.Readonly | CheckFlags.Late | CheckFlags.OptionalParameter | CheckFlags.RestParameter)); 17407 result.declarations = symbol.declarations; 17408 result.parent = symbol.parent; 17409 result.target = symbol; 17410 result.mapper = mapper; 17411 if (symbol.valueDeclaration) { 17412 result.valueDeclaration = symbol.valueDeclaration; 17413 } 17414 if (links.nameType) { 17415 result.nameType = links.nameType; 17416 } 17417 return result; 17418 } 17419 17420 function getObjectTypeInstantiation(type: AnonymousType | DeferredTypeReference, mapper: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]) { 17421 const declaration = type.objectFlags & ObjectFlags.Reference ? (type as TypeReference).node! : 17422 type.objectFlags & ObjectFlags.InstantiationExpressionType ? (type as InstantiationExpressionType).node : 17423 type.symbol.declarations![0]; 17424 const links = getNodeLinks(declaration); 17425 const target = type.objectFlags & ObjectFlags.Reference ? links.resolvedType! as DeferredTypeReference : 17426 type.objectFlags & ObjectFlags.Instantiated ? type.target! : type; 17427 let typeParameters = links.outerTypeParameters; 17428 if (!typeParameters) { 17429 // The first time an anonymous type is instantiated we compute and store a list of the type 17430 // parameters that are in scope (and therefore potentially referenced). For type literals that 17431 // aren't the right hand side of a generic type alias declaration we optimize by reducing the 17432 // set of type parameters to those that are possibly referenced in the literal. 17433 let outerTypeParameters = getOuterTypeParameters(declaration, /*includeThisTypes*/ true); 17434 if (isJSConstructor(declaration)) { 17435 const templateTagParameters = getTypeParametersFromDeclaration(declaration as DeclarationWithTypeParameters); 17436 outerTypeParameters = addRange(outerTypeParameters, templateTagParameters); 17437 } 17438 typeParameters = outerTypeParameters || emptyArray; 17439 const allDeclarations = type.objectFlags & (ObjectFlags.Reference | ObjectFlags.InstantiationExpressionType) ? [declaration] : type.symbol.declarations!; 17440 typeParameters = (target.objectFlags & (ObjectFlags.Reference | ObjectFlags.InstantiationExpressionType) || target.symbol.flags & SymbolFlags.Method || target.symbol.flags & SymbolFlags.TypeLiteral) && !target.aliasTypeArguments ? 17441 filter(typeParameters, tp => some(allDeclarations, d => isTypeParameterPossiblyReferenced(tp, d))) : 17442 typeParameters; 17443 links.outerTypeParameters = typeParameters; 17444 } 17445 if (typeParameters.length) { 17446 // We are instantiating an anonymous type that has one or more type parameters in scope. Apply the 17447 // mapper to the type parameters to produce the effective list of type arguments, and compute the 17448 // instantiation cache key from the type IDs of the type arguments. 17449 const combinedMapper = combineTypeMappers(type.mapper, mapper); 17450 const typeArguments = map(typeParameters, t => getMappedType(t, combinedMapper)); 17451 const newAliasSymbol = aliasSymbol || type.aliasSymbol; 17452 const newAliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(type.aliasTypeArguments, mapper); 17453 const id = getTypeListId(typeArguments) + getAliasId(newAliasSymbol, newAliasTypeArguments); 17454 if (!target.instantiations) { 17455 target.instantiations = new Map<string, Type>(); 17456 target.instantiations.set(getTypeListId(typeParameters) + getAliasId(target.aliasSymbol, target.aliasTypeArguments), target); 17457 } 17458 let result = target.instantiations.get(id); 17459 if (!result) { 17460 const newMapper = createTypeMapper(typeParameters, typeArguments); 17461 result = target.objectFlags & ObjectFlags.Reference ? createDeferredTypeReference((type as DeferredTypeReference).target, (type as DeferredTypeReference).node, newMapper, newAliasSymbol, newAliasTypeArguments) : 17462 target.objectFlags & ObjectFlags.Mapped ? instantiateMappedType(target as MappedType, newMapper, newAliasSymbol, newAliasTypeArguments) : 17463 instantiateAnonymousType(target, newMapper, newAliasSymbol, newAliasTypeArguments); 17464 target.instantiations.set(id, result); 17465 } 17466 return result; 17467 } 17468 return type; 17469 } 17470 17471 function maybeTypeParameterReference(node: Node) { 17472 return !(node.parent.kind === SyntaxKind.TypeReference && (node.parent as TypeReferenceNode).typeArguments && node === (node.parent as TypeReferenceNode).typeName || 17473 node.parent.kind === SyntaxKind.ImportType && (node.parent as ImportTypeNode).typeArguments && node === (node.parent as ImportTypeNode).qualifier); 17474 } 17475 17476 function isTypeParameterPossiblyReferenced(tp: TypeParameter, node: Node) { 17477 // If the type parameter doesn't have exactly one declaration, if there are intervening statement blocks 17478 // between the node and the type parameter declaration, if the node contains actual references to the 17479 // type parameter, or if the node contains type queries that we can't prove couldn't contain references to the type parameter, 17480 // we consider the type parameter possibly referenced. 17481 if (tp.symbol && tp.symbol.declarations && tp.symbol.declarations.length === 1) { 17482 const container = tp.symbol.declarations[0].parent; 17483 for (let n = node; n !== container; n = n.parent) { 17484 if (!n || n.kind === SyntaxKind.Block || n.kind === SyntaxKind.ConditionalType && forEachChild((n as ConditionalTypeNode).extendsType, containsReference)) { 17485 return true; 17486 } 17487 } 17488 return containsReference(node); 17489 } 17490 return true; 17491 function containsReference(node: Node): boolean { 17492 switch (node.kind) { 17493 case SyntaxKind.ThisType: 17494 return !!tp.isThisType; 17495 case SyntaxKind.Identifier: 17496 return !tp.isThisType && isPartOfTypeNode(node) && maybeTypeParameterReference(node) && 17497 getTypeFromTypeNodeWorker(node as TypeNode) === tp; // use worker because we're looking for === equality 17498 case SyntaxKind.TypeQuery: 17499 const entityName = (node as TypeQueryNode).exprName; 17500 const firstIdentifier = getFirstIdentifier(entityName); 17501 const firstIdentifierSymbol = getResolvedSymbol(firstIdentifier); 17502 const tpDeclaration = tp.symbol.declarations![0]; // There is exactly one declaration, otherwise `containsReference` is not called 17503 let tpScope: Node; 17504 if (tpDeclaration.kind === SyntaxKind.TypeParameter) { // Type parameter is a regular type parameter, e.g. foo<T> 17505 tpScope = tpDeclaration.parent; 17506 } 17507 else if (tp.isThisType) { 17508 // Type parameter is the this type, and its declaration is the class declaration. 17509 tpScope = tpDeclaration; 17510 } 17511 else { 17512 // Type parameter's declaration was unrecognized. 17513 // This could happen if the type parameter comes from e.g. a JSDoc annotation, so we default to returning true. 17514 return true; 17515 } 17516 17517 if (firstIdentifierSymbol.declarations) { 17518 return some(firstIdentifierSymbol.declarations, idDecl => isNodeDescendantOf(idDecl, tpScope)) || 17519 some((node as TypeQueryNode).typeArguments, containsReference); 17520 } 17521 return true; 17522 case SyntaxKind.MethodDeclaration: 17523 case SyntaxKind.MethodSignature: 17524 return !(node as FunctionLikeDeclaration).type && !!(node as FunctionLikeDeclaration).body || 17525 some((node as FunctionLikeDeclaration).typeParameters, containsReference) || 17526 some((node as FunctionLikeDeclaration).parameters, containsReference) || 17527 !!(node as FunctionLikeDeclaration).type && containsReference((node as FunctionLikeDeclaration).type!); 17528 } 17529 return !!forEachChild(node, containsReference); 17530 } 17531 } 17532 17533 function getHomomorphicTypeVariable(type: MappedType) { 17534 const constraintType = getConstraintTypeFromMappedType(type); 17535 if (constraintType.flags & TypeFlags.Index) { 17536 const typeVariable = getActualTypeVariable((constraintType as IndexType).type); 17537 if (typeVariable.flags & TypeFlags.TypeParameter) { 17538 return typeVariable as TypeParameter; 17539 } 17540 } 17541 return undefined; 17542 } 17543 17544 function instantiateMappedType(type: MappedType, mapper: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type { 17545 // For a homomorphic mapped type { [P in keyof T]: X }, where T is some type variable, the mapping 17546 // operation depends on T as follows: 17547 // * If T is a primitive type no mapping is performed and the result is simply T. 17548 // * If T is a union type we distribute the mapped type over the union. 17549 // * If T is an array we map to an array where the element type has been transformed. 17550 // * If T is a tuple we map to a tuple where the element types have been transformed. 17551 // * Otherwise we map to an object type where the type of each property has been transformed. 17552 // For example, when T is instantiated to a union type A | B, we produce { [P in keyof A]: X } | 17553 // { [P in keyof B]: X }, and when when T is instantiated to a union type A | undefined, we produce 17554 // { [P in keyof A]: X } | undefined. 17555 const typeVariable = getHomomorphicTypeVariable(type); 17556 if (typeVariable) { 17557 const mappedTypeVariable = instantiateType(typeVariable, mapper); 17558 if (typeVariable !== mappedTypeVariable) { 17559 return mapTypeWithAlias(getReducedType(mappedTypeVariable), t => { 17560 if (t.flags & (TypeFlags.AnyOrUnknown | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object | TypeFlags.Intersection) && t !== wildcardType && !isErrorType(t)) { 17561 if (!type.declaration.nameType) { 17562 let constraint; 17563 if (isArrayType(t) || t.flags & TypeFlags.Any && findResolutionCycleStartIndex(typeVariable, TypeSystemPropertyName.ImmediateBaseConstraint) < 0 && 17564 (constraint = getConstraintOfTypeParameter(typeVariable)) && everyType(constraint, isArrayOrTupleType)) { 17565 return instantiateMappedArrayType(t, type, prependTypeMapping(typeVariable, t, mapper)); 17566 } 17567 if (isGenericTupleType(t)) { 17568 return instantiateMappedGenericTupleType(t, type, typeVariable, mapper); 17569 } 17570 if (isTupleType(t)) { 17571 return instantiateMappedTupleType(t, type, prependTypeMapping(typeVariable, t, mapper)); 17572 } 17573 } 17574 return instantiateAnonymousType(type, prependTypeMapping(typeVariable, t, mapper)); 17575 } 17576 return t; 17577 }, aliasSymbol, aliasTypeArguments); 17578 } 17579 } 17580 // If the constraint type of the instantiation is the wildcard type, return the wildcard type. 17581 return instantiateType(getConstraintTypeFromMappedType(type), mapper) === wildcardType ? wildcardType : instantiateAnonymousType(type, mapper, aliasSymbol, aliasTypeArguments); 17582 } 17583 17584 function getModifiedReadonlyState(state: boolean, modifiers: MappedTypeModifiers) { 17585 return modifiers & MappedTypeModifiers.IncludeReadonly ? true : modifiers & MappedTypeModifiers.ExcludeReadonly ? false : state; 17586 } 17587 17588 function instantiateMappedGenericTupleType(tupleType: TupleTypeReference, mappedType: MappedType, typeVariable: TypeVariable, mapper: TypeMapper) { 17589 // When a tuple type is generic (i.e. when it contains variadic elements), we want to eagerly map the 17590 // non-generic elements and defer mapping the generic elements. In order to facilitate this, we transform 17591 // M<[A, B?, ...T, ...C[]] into [...M<[A]>, ...M<[B?]>, ...M<T>, ...M<C[]>] and then rely on tuple type 17592 // normalization to resolve the non-generic parts of the resulting tuple. 17593 const elementFlags = tupleType.target.elementFlags; 17594 const elementTypes = map(getTypeArguments(tupleType), (t, i) => { 17595 const singleton = elementFlags[i] & ElementFlags.Variadic ? t : 17596 elementFlags[i] & ElementFlags.Rest ? createArrayType(t) : 17597 createTupleType([t], [elementFlags[i]]); 17598 // The singleton is never a generic tuple type, so it is safe to recurse here. 17599 return instantiateMappedType(mappedType, prependTypeMapping(typeVariable, singleton, mapper)); 17600 }); 17601 const newReadonly = getModifiedReadonlyState(tupleType.target.readonly, getMappedTypeModifiers(mappedType)); 17602 return createTupleType(elementTypes, map(elementTypes, _ => ElementFlags.Variadic), newReadonly); 17603 } 17604 17605 function instantiateMappedArrayType(arrayType: Type, mappedType: MappedType, mapper: TypeMapper) { 17606 const elementType = instantiateMappedTypeTemplate(mappedType, numberType, /*isOptional*/ true, mapper); 17607 return isErrorType(elementType) ? errorType : 17608 createArrayType(elementType, getModifiedReadonlyState(isReadonlyArrayType(arrayType), getMappedTypeModifiers(mappedType))); 17609 } 17610 17611 function instantiateMappedTupleType(tupleType: TupleTypeReference, mappedType: MappedType, mapper: TypeMapper) { 17612 const elementFlags = tupleType.target.elementFlags; 17613 const elementTypes = map(getTypeArguments(tupleType), (_, i) => 17614 instantiateMappedTypeTemplate(mappedType, getStringLiteralType("" + i), !!(elementFlags[i] & ElementFlags.Optional), mapper)); 17615 const modifiers = getMappedTypeModifiers(mappedType); 17616 const newTupleModifiers = modifiers & MappedTypeModifiers.IncludeOptional ? map(elementFlags, f => f & ElementFlags.Required ? ElementFlags.Optional : f) : 17617 modifiers & MappedTypeModifiers.ExcludeOptional ? map(elementFlags, f => f & ElementFlags.Optional ? ElementFlags.Required : f) : 17618 elementFlags; 17619 const newReadonly = getModifiedReadonlyState(tupleType.target.readonly, modifiers); 17620 return contains(elementTypes, errorType) ? errorType : 17621 createTupleType(elementTypes, newTupleModifiers, newReadonly, tupleType.target.labeledElementDeclarations); 17622 } 17623 17624 function instantiateMappedTypeTemplate(type: MappedType, key: Type, isOptional: boolean, mapper: TypeMapper) { 17625 const templateMapper = appendTypeMapping(mapper, getTypeParameterFromMappedType(type), key); 17626 const propType = instantiateType(getTemplateTypeFromMappedType(type.target as MappedType || type), templateMapper); 17627 const modifiers = getMappedTypeModifiers(type); 17628 return strictNullChecks && modifiers & MappedTypeModifiers.IncludeOptional && !maybeTypeOfKind(propType, TypeFlags.Undefined | TypeFlags.Void) ? getOptionalType(propType, /*isProperty*/ true) : 17629 strictNullChecks && modifiers & MappedTypeModifiers.ExcludeOptional && isOptional ? getTypeWithFacts(propType, TypeFacts.NEUndefined) : 17630 propType; 17631 } 17632 17633 function instantiateAnonymousType(type: AnonymousType, mapper: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): AnonymousType { 17634 const result = createObjectType(type.objectFlags | ObjectFlags.Instantiated, type.symbol) as AnonymousType; 17635 if (type.objectFlags & ObjectFlags.Mapped) { 17636 (result as MappedType).declaration = (type as MappedType).declaration; 17637 // C.f. instantiateSignature 17638 const origTypeParameter = getTypeParameterFromMappedType(type as MappedType); 17639 const freshTypeParameter = cloneTypeParameter(origTypeParameter); 17640 (result as MappedType).typeParameter = freshTypeParameter; 17641 mapper = combineTypeMappers(makeUnaryTypeMapper(origTypeParameter, freshTypeParameter), mapper); 17642 freshTypeParameter.mapper = mapper; 17643 } 17644 if (type.objectFlags & ObjectFlags.InstantiationExpressionType) { 17645 (result as InstantiationExpressionType).node = (type as InstantiationExpressionType).node; 17646 } 17647 result.target = type; 17648 result.mapper = mapper; 17649 result.aliasSymbol = aliasSymbol || type.aliasSymbol; 17650 result.aliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(type.aliasTypeArguments, mapper); 17651 result.objectFlags |= result.aliasTypeArguments ? getPropagatingFlagsOfTypes(result.aliasTypeArguments) : 0; 17652 return result; 17653 } 17654 17655 function getConditionalTypeInstantiation(type: ConditionalType, mapper: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type { 17656 const root = type.root; 17657 if (root.outerTypeParameters) { 17658 // We are instantiating a conditional type that has one or more type parameters in scope. Apply the 17659 // mapper to the type parameters to produce the effective list of type arguments, and compute the 17660 // instantiation cache key from the type IDs of the type arguments. 17661 const typeArguments = map(root.outerTypeParameters, t => getMappedType(t, mapper)); 17662 const id = getTypeListId(typeArguments) + getAliasId(aliasSymbol, aliasTypeArguments); 17663 let result = root.instantiations!.get(id); 17664 if (!result) { 17665 const newMapper = createTypeMapper(root.outerTypeParameters, typeArguments); 17666 const checkType = root.checkType; 17667 const distributionType = root.isDistributive ? getMappedType(checkType, newMapper) : undefined; 17668 // Distributive conditional types are distributed over union types. For example, when the 17669 // distributive conditional type T extends U ? X : Y is instantiated with A | B for T, the 17670 // result is (A extends U ? X : Y) | (B extends U ? X : Y). 17671 result = distributionType && checkType !== distributionType && distributionType.flags & (TypeFlags.Union | TypeFlags.Never) ? 17672 mapTypeWithAlias(getReducedType(distributionType), t => getConditionalType(root, prependTypeMapping(checkType, t, newMapper)), aliasSymbol, aliasTypeArguments) : 17673 getConditionalType(root, newMapper, aliasSymbol, aliasTypeArguments); 17674 root.instantiations!.set(id, result); 17675 } 17676 return result; 17677 } 17678 return type; 17679 } 17680 17681 function instantiateType(type: Type, mapper: TypeMapper | undefined): Type; 17682 function instantiateType(type: Type | undefined, mapper: TypeMapper | undefined): Type | undefined; 17683 function instantiateType(type: Type | undefined, mapper: TypeMapper | undefined): Type | undefined { 17684 return type && mapper ? instantiateTypeWithAlias(type, mapper, /*aliasSymbol*/ undefined, /*aliasTypeArguments*/ undefined) : type; 17685 } 17686 17687 function instantiateTypeWithAlias(type: Type, mapper: TypeMapper, aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined): Type { 17688 if (!couldContainTypeVariables(type)) { 17689 return type; 17690 } 17691 if (instantiationDepth === 100 || instantiationCount >= 5000000) { 17692 // We have reached 100 recursive type instantiations, or 5M type instantiations caused by the same statement 17693 // or expression. There is a very high likelyhood we're dealing with a combination of infinite generic types 17694 // that perpetually generate new type identities, so we stop the recursion here by yielding the error type. 17695 tracing?.instant(tracing.Phase.CheckTypes, "instantiateType_DepthLimit", { typeId: type.id, instantiationDepth, instantiationCount }); 17696 error(currentNode, Diagnostics.Type_instantiation_is_excessively_deep_and_possibly_infinite); 17697 return errorType; 17698 } 17699 totalInstantiationCount++; 17700 instantiationCount++; 17701 instantiationDepth++; 17702 const result = instantiateTypeWorker(type, mapper, aliasSymbol, aliasTypeArguments); 17703 instantiationDepth--; 17704 return result; 17705 } 17706 17707 function instantiateTypeWorker(type: Type, mapper: TypeMapper, aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined): Type { 17708 const flags = type.flags; 17709 if (flags & TypeFlags.TypeParameter) { 17710 return getMappedType(type, mapper); 17711 } 17712 if (flags & TypeFlags.Object) { 17713 const objectFlags = (type as ObjectType).objectFlags; 17714 if (objectFlags & (ObjectFlags.Reference | ObjectFlags.Anonymous | ObjectFlags.Mapped)) { 17715 if (objectFlags & ObjectFlags.Reference && !(type as TypeReference).node) { 17716 const resolvedTypeArguments = (type as TypeReference).resolvedTypeArguments; 17717 const newTypeArguments = instantiateTypes(resolvedTypeArguments, mapper); 17718 return newTypeArguments !== resolvedTypeArguments ? createNormalizedTypeReference((type as TypeReference).target, newTypeArguments) : type; 17719 } 17720 if (objectFlags & ObjectFlags.ReverseMapped) { 17721 return instantiateReverseMappedType(type as ReverseMappedType, mapper); 17722 } 17723 return getObjectTypeInstantiation(type as TypeReference | AnonymousType | MappedType, mapper, aliasSymbol, aliasTypeArguments); 17724 } 17725 return type; 17726 } 17727 if (flags & TypeFlags.UnionOrIntersection) { 17728 const origin = type.flags & TypeFlags.Union ? (type as UnionType).origin : undefined; 17729 const types = origin && origin.flags & TypeFlags.UnionOrIntersection ? (origin as UnionOrIntersectionType).types : (type as UnionOrIntersectionType).types; 17730 const newTypes = instantiateTypes(types, mapper); 17731 if (newTypes === types && aliasSymbol === type.aliasSymbol) { 17732 return type; 17733 } 17734 const newAliasSymbol = aliasSymbol || type.aliasSymbol; 17735 const newAliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(type.aliasTypeArguments, mapper); 17736 return flags & TypeFlags.Intersection || origin && origin.flags & TypeFlags.Intersection ? 17737 getIntersectionType(newTypes, newAliasSymbol, newAliasTypeArguments) : 17738 getUnionType(newTypes, UnionReduction.Literal, newAliasSymbol, newAliasTypeArguments); 17739 } 17740 if (flags & TypeFlags.Index) { 17741 return getIndexType(instantiateType((type as IndexType).type, mapper)); 17742 } 17743 if (flags & TypeFlags.TemplateLiteral) { 17744 return getTemplateLiteralType((type as TemplateLiteralType).texts, instantiateTypes((type as TemplateLiteralType).types, mapper)); 17745 } 17746 if (flags & TypeFlags.StringMapping) { 17747 return getStringMappingType((type as StringMappingType).symbol, instantiateType((type as StringMappingType).type, mapper)); 17748 } 17749 if (flags & TypeFlags.IndexedAccess) { 17750 const newAliasSymbol = aliasSymbol || type.aliasSymbol; 17751 const newAliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(type.aliasTypeArguments, mapper); 17752 return getIndexedAccessType(instantiateType((type as IndexedAccessType).objectType, mapper), instantiateType((type as IndexedAccessType).indexType, mapper), (type as IndexedAccessType).accessFlags, /*accessNode*/ undefined, newAliasSymbol, newAliasTypeArguments); 17753 } 17754 if (flags & TypeFlags.Conditional) { 17755 return getConditionalTypeInstantiation(type as ConditionalType, combineTypeMappers((type as ConditionalType).mapper, mapper), aliasSymbol, aliasTypeArguments); 17756 } 17757 if (flags & TypeFlags.Substitution) { 17758 const newBaseType = instantiateType((type as SubstitutionType).baseType, mapper); 17759 const newConstraint = instantiateType((type as SubstitutionType).constraint, mapper); 17760 // A substitution type originates in the true branch of a conditional type and can be resolved 17761 // to just the base type in the same cases as the conditional type resolves to its true branch 17762 // (because the base type is then known to satisfy the constraint). 17763 if (newBaseType.flags & TypeFlags.TypeVariable && isGenericType(newConstraint)) { 17764 return getSubstitutionType(newBaseType, newConstraint); 17765 } 17766 if (newConstraint.flags & TypeFlags.AnyOrUnknown || isTypeAssignableTo(getRestrictiveInstantiation(newBaseType), getRestrictiveInstantiation(newConstraint))) { 17767 return newBaseType; 17768 } 17769 return newBaseType.flags & TypeFlags.TypeVariable ? getSubstitutionType(newBaseType, newConstraint) : getIntersectionType([newConstraint, newBaseType]); 17770 } 17771 return type; 17772 } 17773 17774 function instantiateReverseMappedType(type: ReverseMappedType, mapper: TypeMapper) { 17775 const innerMappedType = instantiateType(type.mappedType, mapper); 17776 if (!(getObjectFlags(innerMappedType) & ObjectFlags.Mapped)) { 17777 return type; 17778 } 17779 const innerIndexType = instantiateType(type.constraintType, mapper); 17780 if (!(innerIndexType.flags & TypeFlags.Index)) { 17781 return type; 17782 } 17783 const instantiated = inferTypeForHomomorphicMappedType( 17784 instantiateType(type.source, mapper), 17785 innerMappedType as MappedType, 17786 innerIndexType as IndexType 17787 ); 17788 if (instantiated) { 17789 return instantiated; 17790 } 17791 return type; // Nested invocation of `inferTypeForHomomorphicMappedType` or the `source` instantiated into something unmappable 17792 } 17793 17794 function getUniqueLiteralFilledInstantiation(type: Type) { 17795 return type.flags & (TypeFlags.Primitive | TypeFlags.AnyOrUnknown | TypeFlags.Never) ? type : 17796 type.uniqueLiteralFilledInstantiation || (type.uniqueLiteralFilledInstantiation = instantiateType(type, uniqueLiteralMapper)); 17797 } 17798 17799 function getPermissiveInstantiation(type: Type) { 17800 return type.flags & (TypeFlags.Primitive | TypeFlags.AnyOrUnknown | TypeFlags.Never) ? type : 17801 type.permissiveInstantiation || (type.permissiveInstantiation = instantiateType(type, permissiveMapper)); 17802 } 17803 17804 function getRestrictiveInstantiation(type: Type) { 17805 if (type.flags & (TypeFlags.Primitive | TypeFlags.AnyOrUnknown | TypeFlags.Never)) { 17806 return type; 17807 } 17808 if (type.restrictiveInstantiation) { 17809 return type.restrictiveInstantiation; 17810 } 17811 type.restrictiveInstantiation = instantiateType(type, restrictiveMapper); 17812 // We set the following so we don't attempt to set the restrictive instance of a restrictive instance 17813 // which is redundant - we'll produce new type identities, but all type params have already been mapped. 17814 // This also gives us a way to detect restrictive instances upon comparisons and _disable_ the "distributeive constraint" 17815 // assignability check for them, which is distinctly unsafe, as once you have a restrctive instance, all the type parameters 17816 // are constrained to `unknown` and produce tons of false positives/negatives! 17817 type.restrictiveInstantiation.restrictiveInstantiation = type.restrictiveInstantiation; 17818 return type.restrictiveInstantiation; 17819 } 17820 17821 function instantiateIndexInfo(info: IndexInfo, mapper: TypeMapper) { 17822 return createIndexInfo(info.keyType, instantiateType(info.type, mapper), info.isReadonly, info.declaration); 17823 } 17824 17825 // Returns true if the given expression contains (at any level of nesting) a function or arrow expression 17826 // that is subject to contextual typing. 17827 function isContextSensitive(node: Expression | MethodDeclaration | ObjectLiteralElementLike | JsxAttributeLike | JsxChild): boolean { 17828 Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); 17829 switch (node.kind) { 17830 case SyntaxKind.FunctionExpression: 17831 case SyntaxKind.ArrowFunction: 17832 case SyntaxKind.MethodDeclaration: 17833 case SyntaxKind.FunctionDeclaration: // Function declarations can have context when annotated with a jsdoc @type 17834 return isContextSensitiveFunctionLikeDeclaration(node as FunctionExpression | ArrowFunction | MethodDeclaration); 17835 case SyntaxKind.ObjectLiteralExpression: 17836 return some((node as ObjectLiteralExpression).properties, isContextSensitive); 17837 case SyntaxKind.ArrayLiteralExpression: 17838 return some((node as ArrayLiteralExpression).elements, isContextSensitive); 17839 case SyntaxKind.ConditionalExpression: 17840 return isContextSensitive((node as ConditionalExpression).whenTrue) || 17841 isContextSensitive((node as ConditionalExpression).whenFalse); 17842 case SyntaxKind.BinaryExpression: 17843 return ((node as BinaryExpression).operatorToken.kind === SyntaxKind.BarBarToken || (node as BinaryExpression).operatorToken.kind === SyntaxKind.QuestionQuestionToken) && 17844 (isContextSensitive((node as BinaryExpression).left) || isContextSensitive((node as BinaryExpression).right)); 17845 case SyntaxKind.PropertyAssignment: 17846 return isContextSensitive((node as PropertyAssignment).initializer); 17847 case SyntaxKind.ParenthesizedExpression: 17848 return isContextSensitive((node as ParenthesizedExpression).expression); 17849 case SyntaxKind.JsxAttributes: 17850 return some((node as JsxAttributes).properties, isContextSensitive) || isJsxOpeningElement(node.parent) && some(node.parent.parent.children, isContextSensitive); 17851 case SyntaxKind.JsxAttribute: { 17852 // If there is no initializer, JSX attribute has a boolean value of true which is not context sensitive. 17853 const { initializer } = node as JsxAttribute; 17854 return !!initializer && isContextSensitive(initializer); 17855 } 17856 case SyntaxKind.JsxExpression: { 17857 // It is possible to that node.expression is undefined (e.g <div x={} />) 17858 const { expression } = node as JsxExpression; 17859 return !!expression && isContextSensitive(expression); 17860 } 17861 } 17862 17863 return false; 17864 } 17865 17866 function isContextSensitiveFunctionLikeDeclaration(node: FunctionLikeDeclaration): boolean { 17867 return hasContextSensitiveParameters(node) || hasContextSensitiveReturnExpression(node); 17868 } 17869 17870 function hasContextSensitiveReturnExpression(node: FunctionLikeDeclaration) { 17871 // TODO(anhans): A block should be context-sensitive if it has a context-sensitive return value. 17872 return !node.typeParameters && !getEffectiveReturnTypeNode(node) && !!node.body && node.body.kind !== SyntaxKind.Block && isContextSensitive(node.body); 17873 } 17874 17875 function isContextSensitiveFunctionOrObjectLiteralMethod(func: Node): func is FunctionExpression | ArrowFunction | MethodDeclaration { 17876 return (isFunctionExpressionOrArrowFunction(func) || isObjectLiteralMethod(func)) && 17877 isContextSensitiveFunctionLikeDeclaration(func); 17878 } 17879 17880 function getTypeWithoutSignatures(type: Type): Type { 17881 if (type.flags & TypeFlags.Object) { 17882 const resolved = resolveStructuredTypeMembers(type as ObjectType); 17883 if (resolved.constructSignatures.length || resolved.callSignatures.length) { 17884 const result = createObjectType(ObjectFlags.Anonymous, type.symbol); 17885 result.members = resolved.members; 17886 result.properties = resolved.properties; 17887 result.callSignatures = emptyArray; 17888 result.constructSignatures = emptyArray; 17889 result.indexInfos = emptyArray; 17890 return result; 17891 } 17892 } 17893 else if (type.flags & TypeFlags.Intersection) { 17894 return getIntersectionType(map((type as IntersectionType).types, getTypeWithoutSignatures)); 17895 } 17896 return type; 17897 } 17898 17899 // TYPE CHECKING 17900 17901 function isTypeIdenticalTo(source: Type, target: Type): boolean { 17902 return isTypeRelatedTo(source, target, identityRelation); 17903 } 17904 17905 function compareTypesIdentical(source: Type, target: Type): Ternary { 17906 return isTypeRelatedTo(source, target, identityRelation) ? Ternary.True : Ternary.False; 17907 } 17908 17909 function compareTypesAssignable(source: Type, target: Type): Ternary { 17910 return isTypeRelatedTo(source, target, assignableRelation) ? Ternary.True : Ternary.False; 17911 } 17912 17913 function compareTypesSubtypeOf(source: Type, target: Type): Ternary { 17914 return isTypeRelatedTo(source, target, subtypeRelation) ? Ternary.True : Ternary.False; 17915 } 17916 17917 function isTypeSubtypeOf(source: Type, target: Type): boolean { 17918 return isTypeRelatedTo(source, target, subtypeRelation); 17919 } 17920 17921 function isTypeAssignableTo(source: Type, target: Type): boolean { 17922 return isTypeRelatedTo(source, target, assignableRelation); 17923 } 17924 17925 // An object type S is considered to be derived from an object type T if 17926 // S is a union type and every constituent of S is derived from T, 17927 // T is a union type and S is derived from at least one constituent of T, or 17928 // S is a type variable with a base constraint that is derived from T, 17929 // T is one of the global types Object and Function and S is a subtype of T, or 17930 // T occurs directly or indirectly in an 'extends' clause of S. 17931 // Note that this check ignores type parameters and only considers the 17932 // inheritance hierarchy. 17933 function isTypeDerivedFrom(source: Type, target: Type): boolean { 17934 return source.flags & TypeFlags.Union ? every((source as UnionType).types, t => isTypeDerivedFrom(t, target)) : 17935 target.flags & TypeFlags.Union ? some((target as UnionType).types, t => isTypeDerivedFrom(source, t)) : 17936 source.flags & TypeFlags.InstantiableNonPrimitive ? isTypeDerivedFrom(getBaseConstraintOfType(source) || unknownType, target) : 17937 target === globalObjectType ? !!(source.flags & (TypeFlags.Object | TypeFlags.NonPrimitive)) : 17938 target === globalFunctionType ? !!(source.flags & TypeFlags.Object) && isFunctionObjectType(source as ObjectType) : 17939 hasBaseType(source, getTargetType(target)) || (isArrayType(target) && !isReadonlyArrayType(target) && isTypeDerivedFrom(source, globalReadonlyArrayType)); 17940 } 17941 17942 /** 17943 * This is *not* a bi-directional relationship. 17944 * If one needs to check both directions for comparability, use a second call to this function or 'checkTypeComparableTo'. 17945 * 17946 * A type S is comparable to a type T if some (but not necessarily all) of the possible values of S are also possible values of T. 17947 * It is used to check following cases: 17948 * - the types of the left and right sides of equality/inequality operators (`===`, `!==`, `==`, `!=`). 17949 * - the types of `case` clause expressions and their respective `switch` expressions. 17950 * - the type of an expression in a type assertion with the type being asserted. 17951 */ 17952 function isTypeComparableTo(source: Type, target: Type): boolean { 17953 return isTypeRelatedTo(source, target, comparableRelation); 17954 } 17955 17956 function areTypesComparable(type1: Type, type2: Type): boolean { 17957 return isTypeComparableTo(type1, type2) || isTypeComparableTo(type2, type1); 17958 } 17959 17960 function checkTypeAssignableTo(source: Type, target: Type, errorNode: Node | undefined, headMessage?: DiagnosticMessage, containingMessageChain?: () => DiagnosticMessageChain | undefined, errorOutputObject?: { errors?: Diagnostic[] }): boolean { 17961 return checkTypeRelatedTo(source, target, assignableRelation, errorNode, headMessage, containingMessageChain, errorOutputObject); 17962 } 17963 17964 /** 17965 * Like `checkTypeAssignableTo`, but if it would issue an error, instead performs structural comparisons of the types using the given expression node to 17966 * attempt to issue more specific errors on, for example, specific object literal properties or tuple members. 17967 */ 17968 function checkTypeAssignableToAndOptionallyElaborate(source: Type, target: Type, errorNode: Node | undefined, expr: Expression | undefined, headMessage?: DiagnosticMessage, containingMessageChain?: () => DiagnosticMessageChain | undefined): boolean { 17969 return checkTypeRelatedToAndOptionallyElaborate(source, target, assignableRelation, errorNode, expr, headMessage, containingMessageChain, /*errorOutputContainer*/ undefined); 17970 } 17971 17972 function checkTypeRelatedToAndOptionallyElaborate( 17973 source: Type, 17974 target: Type, 17975 relation: ESMap<string, RelationComparisonResult>, 17976 errorNode: Node | undefined, 17977 expr: Expression | undefined, 17978 headMessage: DiagnosticMessage | undefined, 17979 containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, 17980 errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } | undefined 17981 ): boolean { 17982 if (isTypeRelatedTo(source, target, relation)) return true; 17983 if (!errorNode || !elaborateError(expr, source, target, relation, headMessage, containingMessageChain, errorOutputContainer)) { 17984 return checkTypeRelatedTo(source, target, relation, errorNode, headMessage, containingMessageChain, errorOutputContainer); 17985 } 17986 return false; 17987 } 17988 17989 function isOrHasGenericConditional(type: Type): boolean { 17990 return !!(type.flags & TypeFlags.Conditional || (type.flags & TypeFlags.Intersection && some((type as IntersectionType).types, isOrHasGenericConditional))); 17991 } 17992 17993 function elaborateError( 17994 node: Expression | undefined, 17995 source: Type, 17996 target: Type, 17997 relation: ESMap<string, RelationComparisonResult>, 17998 headMessage: DiagnosticMessage | undefined, 17999 containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, 18000 errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } | undefined 18001 ): boolean { 18002 if (!node || isOrHasGenericConditional(target)) return false; 18003 if (!checkTypeRelatedTo(source, target, relation, /*errorNode*/ undefined) 18004 && elaborateDidYouMeanToCallOrConstruct(node, source, target, relation, headMessage, containingMessageChain, errorOutputContainer)) { 18005 return true; 18006 } 18007 switch (node.kind) { 18008 case SyntaxKind.JsxExpression: 18009 case SyntaxKind.ParenthesizedExpression: 18010 return elaborateError((node as ParenthesizedExpression | JsxExpression).expression, source, target, relation, headMessage, containingMessageChain, errorOutputContainer); 18011 case SyntaxKind.BinaryExpression: 18012 switch ((node as BinaryExpression).operatorToken.kind) { 18013 case SyntaxKind.EqualsToken: 18014 case SyntaxKind.CommaToken: 18015 return elaborateError((node as BinaryExpression).right, source, target, relation, headMessage, containingMessageChain, errorOutputContainer); 18016 } 18017 break; 18018 case SyntaxKind.ObjectLiteralExpression: 18019 return elaborateObjectLiteral(node as ObjectLiteralExpression, source, target, relation, containingMessageChain, errorOutputContainer); 18020 case SyntaxKind.ArrayLiteralExpression: 18021 return elaborateArrayLiteral(node as ArrayLiteralExpression, source, target, relation, containingMessageChain, errorOutputContainer); 18022 case SyntaxKind.JsxAttributes: 18023 return elaborateJsxComponents(node as JsxAttributes, source, target, relation, containingMessageChain, errorOutputContainer); 18024 case SyntaxKind.ArrowFunction: 18025 return elaborateArrowFunction(node as ArrowFunction, source, target, relation, containingMessageChain, errorOutputContainer); 18026 } 18027 return false; 18028 } 18029 18030 function elaborateDidYouMeanToCallOrConstruct( 18031 node: Expression, 18032 source: Type, 18033 target: Type, 18034 relation: ESMap<string, RelationComparisonResult>, 18035 headMessage: DiagnosticMessage | undefined, 18036 containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, 18037 errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } | undefined 18038 ): boolean { 18039 const callSignatures = getSignaturesOfType(source, SignatureKind.Call); 18040 const constructSignatures = getSignaturesOfType(source, SignatureKind.Construct); 18041 for (const signatures of [constructSignatures, callSignatures]) { 18042 if (some(signatures, s => { 18043 const returnType = getReturnTypeOfSignature(s); 18044 return !(returnType.flags & (TypeFlags.Any | TypeFlags.Never)) && checkTypeRelatedTo(returnType, target, relation, /*errorNode*/ undefined); 18045 })) { 18046 const resultObj: { errors?: Diagnostic[] } = errorOutputContainer || {}; 18047 checkTypeAssignableTo(source, target, node, headMessage, containingMessageChain, resultObj); 18048 const diagnostic = resultObj.errors![resultObj.errors!.length - 1]; 18049 addRelatedInfo(diagnostic, createDiagnosticForNode( 18050 node, 18051 signatures === constructSignatures ? Diagnostics.Did_you_mean_to_use_new_with_this_expression : Diagnostics.Did_you_mean_to_call_this_expression 18052 )); 18053 return true; 18054 } 18055 } 18056 return false; 18057 } 18058 18059 function elaborateArrowFunction( 18060 node: ArrowFunction, 18061 source: Type, 18062 target: Type, 18063 relation: ESMap<string, RelationComparisonResult>, 18064 containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, 18065 errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } | undefined 18066 ): boolean { 18067 // Don't elaborate blocks 18068 if (isBlock(node.body)) { 18069 return false; 18070 } 18071 // Or functions with annotated parameter types 18072 if (some(node.parameters, ts.hasType)) { 18073 return false; 18074 } 18075 const sourceSig = getSingleCallSignature(source); 18076 if (!sourceSig) { 18077 return false; 18078 } 18079 const targetSignatures = getSignaturesOfType(target, SignatureKind.Call); 18080 if (!length(targetSignatures)) { 18081 return false; 18082 } 18083 const returnExpression = node.body; 18084 const sourceReturn = getReturnTypeOfSignature(sourceSig); 18085 const targetReturn = getUnionType(map(targetSignatures, getReturnTypeOfSignature)); 18086 if (!checkTypeRelatedTo(sourceReturn, targetReturn, relation, /*errorNode*/ undefined)) { 18087 const elaborated = returnExpression && elaborateError(returnExpression, sourceReturn, targetReturn, relation, /*headMessage*/ undefined, containingMessageChain, errorOutputContainer); 18088 if (elaborated) { 18089 return elaborated; 18090 } 18091 const resultObj: { errors?: Diagnostic[] } = errorOutputContainer || {}; 18092 checkTypeRelatedTo(sourceReturn, targetReturn, relation, returnExpression, /*message*/ undefined, containingMessageChain, resultObj); 18093 if (resultObj.errors) { 18094 if (target.symbol && length(target.symbol.declarations)) { 18095 addRelatedInfo(resultObj.errors[resultObj.errors.length - 1], createDiagnosticForNode( 18096 target.symbol.declarations![0], 18097 Diagnostics.The_expected_type_comes_from_the_return_type_of_this_signature, 18098 )); 18099 } 18100 if ((getFunctionFlags(node) & FunctionFlags.Async) === 0 18101 // exclude cases where source itself is promisy - this way we don't make a suggestion when relating 18102 // an IPromise and a Promise that are slightly different 18103 && !getTypeOfPropertyOfType(sourceReturn, "then" as __String) 18104 && checkTypeRelatedTo(createPromiseType(sourceReturn), targetReturn, relation, /*errorNode*/ undefined) 18105 ) { 18106 addRelatedInfo(resultObj.errors[resultObj.errors.length - 1], createDiagnosticForNode( 18107 node, 18108 Diagnostics.Did_you_mean_to_mark_this_function_as_async 18109 )); 18110 } 18111 return true; 18112 } 18113 } 18114 return false; 18115 } 18116 18117 function getBestMatchIndexedAccessTypeOrUndefined(source: Type, target: Type, nameType: Type) { 18118 const idx = getIndexedAccessTypeOrUndefined(target, nameType); 18119 if (idx) { 18120 return idx; 18121 } 18122 if (target.flags & TypeFlags.Union) { 18123 const best = getBestMatchingType(source, target as UnionType); 18124 if (best) { 18125 return getIndexedAccessTypeOrUndefined(best, nameType); 18126 } 18127 } 18128 } 18129 18130 function checkExpressionForMutableLocationWithContextualType(next: Expression, sourcePropType: Type) { 18131 next.contextualType = sourcePropType; 18132 try { 18133 return checkExpressionForMutableLocation(next, CheckMode.Contextual, sourcePropType); 18134 } 18135 finally { 18136 next.contextualType = undefined; 18137 } 18138 } 18139 18140 type ElaborationIterator = IterableIterator<{ errorNode: Node, innerExpression: Expression | undefined, nameType: Type, errorMessage?: DiagnosticMessage | undefined }>; 18141 /** 18142 * For every element returned from the iterator, checks that element to issue an error on a property of that element's type 18143 * If that element would issue an error, we first attempt to dive into that element's inner expression and issue a more specific error by recuring into `elaborateError` 18144 * Otherwise, we issue an error on _every_ element which fail the assignability check 18145 */ 18146 function elaborateElementwise( 18147 iterator: ElaborationIterator, 18148 source: Type, 18149 target: Type, 18150 relation: ESMap<string, RelationComparisonResult>, 18151 containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, 18152 errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } | undefined 18153 ) { 18154 // Assignability failure - check each prop individually, and if that fails, fall back on the bad error span 18155 let reportedError = false; 18156 for (let status = iterator.next(); !status.done; status = iterator.next()) { 18157 const { errorNode: prop, innerExpression: next, nameType, errorMessage } = status.value; 18158 let targetPropType = getBestMatchIndexedAccessTypeOrUndefined(source, target, nameType); 18159 if (!targetPropType || targetPropType.flags & TypeFlags.IndexedAccess) continue; // Don't elaborate on indexes on generic variables 18160 let sourcePropType = getIndexedAccessTypeOrUndefined(source, nameType); 18161 if (!sourcePropType) continue; 18162 const propName = getPropertyNameFromIndex(nameType, /*accessNode*/ undefined); 18163 if (!checkTypeRelatedTo(sourcePropType, targetPropType, relation, /*errorNode*/ undefined)) { 18164 const elaborated = next && elaborateError(next, sourcePropType, targetPropType, relation, /*headMessage*/ undefined, containingMessageChain, errorOutputContainer); 18165 reportedError = true; 18166 if (!elaborated) { 18167 // Issue error on the prop itself, since the prop couldn't elaborate the error 18168 const resultObj: { errors?: Diagnostic[] } = errorOutputContainer || {}; 18169 // Use the expression type, if available 18170 const specificSource = next ? checkExpressionForMutableLocationWithContextualType(next, sourcePropType) : sourcePropType; 18171 if (exactOptionalPropertyTypes && isExactOptionalPropertyMismatch(specificSource, targetPropType)) { 18172 const diag = createDiagnosticForNode(prop, Diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_type_of_the_target, typeToString(specificSource), typeToString(targetPropType)); 18173 diagnostics.add(diag); 18174 resultObj.errors = [diag]; 18175 } 18176 else { 18177 const targetIsOptional = !!(propName && (getPropertyOfType(target, propName) || unknownSymbol).flags & SymbolFlags.Optional); 18178 const sourceIsOptional = !!(propName && (getPropertyOfType(source, propName) || unknownSymbol).flags & SymbolFlags.Optional); 18179 targetPropType = removeMissingType(targetPropType, targetIsOptional); 18180 sourcePropType = removeMissingType(sourcePropType, targetIsOptional && sourceIsOptional); 18181 const result = checkTypeRelatedTo(specificSource, targetPropType, relation, prop, errorMessage, containingMessageChain, resultObj); 18182 if (result && specificSource !== sourcePropType) { 18183 // If for whatever reason the expression type doesn't yield an error, make sure we still issue an error on the sourcePropType 18184 checkTypeRelatedTo(sourcePropType, targetPropType, relation, prop, errorMessage, containingMessageChain, resultObj); 18185 } 18186 } 18187 if (resultObj.errors) { 18188 const reportedDiag = resultObj.errors[resultObj.errors.length - 1]; 18189 const propertyName = isTypeUsableAsPropertyName(nameType) ? getPropertyNameFromType(nameType) : undefined; 18190 const targetProp = propertyName !== undefined ? getPropertyOfType(target, propertyName) : undefined; 18191 18192 let issuedElaboration = false; 18193 if (!targetProp) { 18194 const indexInfo = getApplicableIndexInfo(target, nameType); 18195 if (indexInfo && indexInfo.declaration && !getSourceFileOfNode(indexInfo.declaration).hasNoDefaultLib) { 18196 issuedElaboration = true; 18197 addRelatedInfo(reportedDiag, createDiagnosticForNode(indexInfo.declaration, Diagnostics.The_expected_type_comes_from_this_index_signature)); 18198 } 18199 } 18200 18201 if (!issuedElaboration && (targetProp && length(targetProp.declarations) || target.symbol && length(target.symbol.declarations))) { 18202 const targetNode = targetProp && length(targetProp.declarations) ? targetProp.declarations![0] : target.symbol.declarations![0]; 18203 if (!getSourceFileOfNode(targetNode).hasNoDefaultLib) { 18204 addRelatedInfo(reportedDiag, createDiagnosticForNode( 18205 targetNode, 18206 Diagnostics.The_expected_type_comes_from_property_0_which_is_declared_here_on_type_1, 18207 propertyName && !(nameType.flags & TypeFlags.UniqueESSymbol) ? unescapeLeadingUnderscores(propertyName) : typeToString(nameType), 18208 typeToString(target) 18209 )); 18210 } 18211 } 18212 } 18213 } 18214 } 18215 } 18216 return reportedError; 18217 } 18218 18219 function *generateJsxAttributes(node: JsxAttributes): ElaborationIterator { 18220 if (!length(node.properties)) return; 18221 for (const prop of node.properties) { 18222 if (isJsxSpreadAttribute(prop) || isHyphenatedJsxName(idText(prop.name))) continue; 18223 yield { errorNode: prop.name, innerExpression: prop.initializer, nameType: getStringLiteralType(idText(prop.name)) }; 18224 } 18225 } 18226 18227 function *generateJsxChildren(node: JsxElement, getInvalidTextDiagnostic: () => DiagnosticMessage): ElaborationIterator { 18228 if (!length(node.children)) return; 18229 let memberOffset = 0; 18230 for (let i = 0; i < node.children.length; i++) { 18231 const child = node.children[i]; 18232 const nameType = getNumberLiteralType(i - memberOffset); 18233 const elem = getElaborationElementForJsxChild(child, nameType, getInvalidTextDiagnostic); 18234 if (elem) { 18235 yield elem; 18236 } 18237 else { 18238 memberOffset++; 18239 } 18240 } 18241 } 18242 18243 function getElaborationElementForJsxChild(child: JsxChild, nameType: LiteralType, getInvalidTextDiagnostic: () => DiagnosticMessage) { 18244 switch (child.kind) { 18245 case SyntaxKind.JsxExpression: 18246 // child is of the type of the expression 18247 return { errorNode: child, innerExpression: child.expression, nameType }; 18248 case SyntaxKind.JsxText: 18249 if (child.containsOnlyTriviaWhiteSpaces) { 18250 break; // Whitespace only jsx text isn't real jsx text 18251 } 18252 // child is a string 18253 return { errorNode: child, innerExpression: undefined, nameType, errorMessage: getInvalidTextDiagnostic() }; 18254 case SyntaxKind.JsxElement: 18255 case SyntaxKind.JsxSelfClosingElement: 18256 case SyntaxKind.JsxFragment: 18257 // child is of type JSX.Element 18258 return { errorNode: child, innerExpression: child, nameType }; 18259 default: 18260 return Debug.assertNever(child, "Found invalid jsx child"); 18261 } 18262 } 18263 18264 function elaborateJsxComponents( 18265 node: JsxAttributes, 18266 source: Type, 18267 target: Type, 18268 relation: ESMap<string, RelationComparisonResult>, 18269 containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, 18270 errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } | undefined 18271 ) { 18272 let result = elaborateElementwise(generateJsxAttributes(node), source, target, relation, containingMessageChain, errorOutputContainer); 18273 let invalidTextDiagnostic: DiagnosticMessage | undefined; 18274 if (isJsxOpeningElement(node.parent) && isJsxElement(node.parent.parent)) { 18275 const containingElement = node.parent.parent; 18276 const childPropName = getJsxElementChildrenPropertyName(getJsxNamespaceAt(node)); 18277 const childrenPropName = childPropName === undefined ? "children" : unescapeLeadingUnderscores(childPropName); 18278 const childrenNameType = getStringLiteralType(childrenPropName); 18279 const childrenTargetType = getIndexedAccessType(target, childrenNameType); 18280 const validChildren = getSemanticJsxChildren(containingElement.children); 18281 if (!length(validChildren)) { 18282 return result; 18283 } 18284 const moreThanOneRealChildren = length(validChildren) > 1; 18285 const arrayLikeTargetParts = filterType(childrenTargetType, isArrayOrTupleLikeType); 18286 const nonArrayLikeTargetParts = filterType(childrenTargetType, t => !isArrayOrTupleLikeType(t)); 18287 if (moreThanOneRealChildren) { 18288 if (arrayLikeTargetParts !== neverType) { 18289 const realSource = createTupleType(checkJsxChildren(containingElement, CheckMode.Normal)); 18290 const children = generateJsxChildren(containingElement, getInvalidTextualChildDiagnostic); 18291 result = elaborateElementwise(children, realSource, arrayLikeTargetParts, relation, containingMessageChain, errorOutputContainer) || result; 18292 } 18293 else if (!isTypeRelatedTo(getIndexedAccessType(source, childrenNameType), childrenTargetType, relation)) { 18294 // arity mismatch 18295 result = true; 18296 const diag = error( 18297 containingElement.openingElement.tagName, 18298 Diagnostics.This_JSX_tag_s_0_prop_expects_a_single_child_of_type_1_but_multiple_children_were_provided, 18299 childrenPropName, 18300 typeToString(childrenTargetType) 18301 ); 18302 if (errorOutputContainer && errorOutputContainer.skipLogging) { 18303 (errorOutputContainer.errors || (errorOutputContainer.errors = [])).push(diag); 18304 } 18305 } 18306 } 18307 else { 18308 if (nonArrayLikeTargetParts !== neverType) { 18309 const child = validChildren[0]; 18310 const elem = getElaborationElementForJsxChild(child, childrenNameType, getInvalidTextualChildDiagnostic); 18311 if (elem) { 18312 result = elaborateElementwise( 18313 (function*() { yield elem; })(), 18314 source, 18315 target, 18316 relation, 18317 containingMessageChain, 18318 errorOutputContainer 18319 ) || result; 18320 } 18321 } 18322 else if (!isTypeRelatedTo(getIndexedAccessType(source, childrenNameType), childrenTargetType, relation)) { 18323 // arity mismatch 18324 result = true; 18325 const diag = error( 18326 containingElement.openingElement.tagName, 18327 Diagnostics.This_JSX_tag_s_0_prop_expects_type_1_which_requires_multiple_children_but_only_a_single_child_was_provided, 18328 childrenPropName, 18329 typeToString(childrenTargetType) 18330 ); 18331 if (errorOutputContainer && errorOutputContainer.skipLogging) { 18332 (errorOutputContainer.errors || (errorOutputContainer.errors = [])).push(diag); 18333 } 18334 } 18335 } 18336 } 18337 return result; 18338 18339 function getInvalidTextualChildDiagnostic() { 18340 if (!invalidTextDiagnostic) { 18341 const tagNameText = getTextOfNode(node.parent.tagName); 18342 const childPropName = getJsxElementChildrenPropertyName(getJsxNamespaceAt(node)); 18343 const childrenPropName = childPropName === undefined ? "children" : unescapeLeadingUnderscores(childPropName); 18344 const childrenTargetType = getIndexedAccessType(target, getStringLiteralType(childrenPropName)); 18345 const diagnostic = Diagnostics._0_components_don_t_accept_text_as_child_elements_Text_in_JSX_has_the_type_string_but_the_expected_type_of_1_is_2; 18346 invalidTextDiagnostic = { ...diagnostic, key: "!!ALREADY FORMATTED!!", message: formatMessage(/*_dummy*/ undefined, diagnostic, tagNameText, childrenPropName, typeToString(childrenTargetType)) }; 18347 } 18348 return invalidTextDiagnostic; 18349 } 18350 } 18351 18352 function *generateLimitedTupleElements(node: ArrayLiteralExpression, target: Type): ElaborationIterator { 18353 const len = length(node.elements); 18354 if (!len) return; 18355 for (let i = 0; i < len; i++) { 18356 // Skip elements which do not exist in the target - a length error on the tuple overall is likely better than an error on a mismatched index signature 18357 if (isTupleLikeType(target) && !getPropertyOfType(target, ("" + i) as __String)) continue; 18358 const elem = node.elements[i]; 18359 if (isOmittedExpression(elem)) continue; 18360 const nameType = getNumberLiteralType(i); 18361 yield { errorNode: elem, innerExpression: elem, nameType }; 18362 } 18363 } 18364 18365 function elaborateArrayLiteral( 18366 node: ArrayLiteralExpression, 18367 source: Type, 18368 target: Type, 18369 relation: ESMap<string, RelationComparisonResult>, 18370 containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, 18371 errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } | undefined 18372 ) { 18373 if (target.flags & (TypeFlags.Primitive | TypeFlags.Never)) return false; 18374 if (isTupleLikeType(source)) { 18375 return elaborateElementwise(generateLimitedTupleElements(node, target), source, target, relation, containingMessageChain, errorOutputContainer); 18376 } 18377 // recreate a tuple from the elements, if possible 18378 // Since we're re-doing the expression type, we need to reapply the contextual type 18379 const oldContext = node.contextualType; 18380 node.contextualType = target; 18381 try { 18382 const tupleizedType = checkArrayLiteral(node, CheckMode.Contextual, /*forceTuple*/ true); 18383 node.contextualType = oldContext; 18384 if (isTupleLikeType(tupleizedType)) { 18385 return elaborateElementwise(generateLimitedTupleElements(node, target), tupleizedType, target, relation, containingMessageChain, errorOutputContainer); 18386 } 18387 return false; 18388 } 18389 finally { 18390 node.contextualType = oldContext; 18391 } 18392 } 18393 18394 function *generateObjectLiteralElements(node: ObjectLiteralExpression): ElaborationIterator { 18395 if (!length(node.properties)) return; 18396 for (const prop of node.properties) { 18397 if (isSpreadAssignment(prop)) continue; 18398 const type = getLiteralTypeFromProperty(getSymbolOfNode(prop), TypeFlags.StringOrNumberLiteralOrUnique); 18399 if (!type || (type.flags & TypeFlags.Never)) { 18400 continue; 18401 } 18402 switch (prop.kind) { 18403 case SyntaxKind.SetAccessor: 18404 case SyntaxKind.GetAccessor: 18405 case SyntaxKind.MethodDeclaration: 18406 case SyntaxKind.ShorthandPropertyAssignment: 18407 yield { errorNode: prop.name, innerExpression: undefined, nameType: type }; 18408 break; 18409 case SyntaxKind.PropertyAssignment: 18410 yield { errorNode: prop.name, innerExpression: prop.initializer, nameType: type, errorMessage: isComputedNonLiteralName(prop.name) ? Diagnostics.Type_of_computed_property_s_value_is_0_which_is_not_assignable_to_type_1 : undefined }; 18411 break; 18412 default: 18413 Debug.assertNever(prop); 18414 } 18415 } 18416 } 18417 18418 function elaborateObjectLiteral( 18419 node: ObjectLiteralExpression, 18420 source: Type, 18421 target: Type, 18422 relation: ESMap<string, RelationComparisonResult>, 18423 containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, 18424 errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } | undefined 18425 ) { 18426 if (target.flags & (TypeFlags.Primitive | TypeFlags.Never)) return false; 18427 return elaborateElementwise(generateObjectLiteralElements(node), source, target, relation, containingMessageChain, errorOutputContainer); 18428 } 18429 18430 /** 18431 * This is *not* a bi-directional relationship. 18432 * If one needs to check both directions for comparability, use a second call to this function or 'isTypeComparableTo'. 18433 */ 18434 function checkTypeComparableTo(source: Type, target: Type, errorNode: Node, headMessage?: DiagnosticMessage, containingMessageChain?: () => DiagnosticMessageChain | undefined): boolean { 18435 return checkTypeRelatedTo(source, target, comparableRelation, errorNode, headMessage, containingMessageChain); 18436 } 18437 18438 function isSignatureAssignableTo(source: Signature, 18439 target: Signature, 18440 ignoreReturnTypes: boolean): boolean { 18441 return compareSignaturesRelated(source, target, ignoreReturnTypes ? SignatureCheckMode.IgnoreReturnTypes : 0, /*reportErrors*/ false, 18442 /*errorReporter*/ undefined, /*errorReporter*/ undefined, compareTypesAssignable, /*reportUnreliableMarkers*/ undefined) !== Ternary.False; 18443 } 18444 18445 type ErrorReporter = (message: DiagnosticMessage, arg0?: string, arg1?: string) => void; 18446 18447 /** 18448 * Returns true if `s` is `(...args: any[]) => any` or `(this: any, ...args: any[]) => any` 18449 */ 18450 function isAnySignature(s: Signature) { 18451 return !s.typeParameters && (!s.thisParameter || isTypeAny(getTypeOfParameter(s.thisParameter))) && s.parameters.length === 1 && 18452 signatureHasRestParameter(s) && (getTypeOfParameter(s.parameters[0]) === anyArrayType || isTypeAny(getTypeOfParameter(s.parameters[0]))) && 18453 isTypeAny(getReturnTypeOfSignature(s)); 18454 } 18455 18456 /** 18457 * See signatureRelatedTo, compareSignaturesIdentical 18458 */ 18459 function compareSignaturesRelated(source: Signature, 18460 target: Signature, 18461 checkMode: SignatureCheckMode, 18462 reportErrors: boolean, 18463 errorReporter: ErrorReporter | undefined, 18464 incompatibleErrorReporter: ((source: Type, target: Type) => void) | undefined, 18465 compareTypes: TypeComparer, 18466 reportUnreliableMarkers: TypeMapper | undefined): Ternary { 18467 // TODO (drosen): De-duplicate code between related functions. 18468 if (source === target) { 18469 return Ternary.True; 18470 } 18471 18472 if (isAnySignature(target)) { 18473 return Ternary.True; 18474 } 18475 18476 const targetCount = getParameterCount(target); 18477 const sourceHasMoreParameters = !hasEffectiveRestParameter(target) && 18478 (checkMode & SignatureCheckMode.StrictArity ? hasEffectiveRestParameter(source) || getParameterCount(source) > targetCount : getMinArgumentCount(source) > targetCount); 18479 if (sourceHasMoreParameters) { 18480 return Ternary.False; 18481 } 18482 18483 if (source.typeParameters && source.typeParameters !== target.typeParameters) { 18484 target = getCanonicalSignature(target); 18485 source = instantiateSignatureInContextOf(source, target, /*inferenceContext*/ undefined, compareTypes); 18486 } 18487 18488 const sourceCount = getParameterCount(source); 18489 const sourceRestType = getNonArrayRestType(source); 18490 const targetRestType = getNonArrayRestType(target); 18491 if (sourceRestType || targetRestType) { 18492 void instantiateType(sourceRestType || targetRestType, reportUnreliableMarkers); 18493 } 18494 18495 const kind = target.declaration ? target.declaration.kind : SyntaxKind.Unknown; 18496 const strictVariance = !(checkMode & SignatureCheckMode.Callback) && strictFunctionTypes && kind !== SyntaxKind.MethodDeclaration && 18497 kind !== SyntaxKind.MethodSignature && kind !== SyntaxKind.Constructor; 18498 let result = Ternary.True; 18499 18500 const sourceThisType = getThisTypeOfSignature(source); 18501 if (sourceThisType && sourceThisType !== voidType) { 18502 const targetThisType = getThisTypeOfSignature(target); 18503 if (targetThisType) { 18504 // void sources are assignable to anything. 18505 const related = !strictVariance && compareTypes(sourceThisType, targetThisType, /*reportErrors*/ false) 18506 || compareTypes(targetThisType, sourceThisType, reportErrors); 18507 if (!related) { 18508 if (reportErrors) { 18509 errorReporter!(Diagnostics.The_this_types_of_each_signature_are_incompatible); 18510 } 18511 return Ternary.False; 18512 } 18513 result &= related; 18514 } 18515 } 18516 18517 const paramCount = sourceRestType || targetRestType ? Math.min(sourceCount, targetCount) : Math.max(sourceCount, targetCount); 18518 const restIndex = sourceRestType || targetRestType ? paramCount - 1 : -1; 18519 18520 for (let i = 0; i < paramCount; i++) { 18521 const sourceType = i === restIndex ? getRestTypeAtPosition(source, i) : tryGetTypeAtPosition(source, i); 18522 const targetType = i === restIndex ? getRestTypeAtPosition(target, i) : tryGetTypeAtPosition(target, i); 18523 if (sourceType && targetType) { 18524 // In order to ensure that any generic type Foo<T> is at least co-variant with respect to T no matter 18525 // how Foo uses T, we need to relate parameters bi-variantly (given that parameters are input positions, 18526 // they naturally relate only contra-variantly). However, if the source and target parameters both have 18527 // function types with a single call signature, we know we are relating two callback parameters. In 18528 // that case it is sufficient to only relate the parameters of the signatures co-variantly because, 18529 // similar to return values, callback parameters are output positions. This means that a Promise<T>, 18530 // where T is used only in callback parameter positions, will be co-variant (as opposed to bi-variant) 18531 // with respect to T. 18532 const sourceSig = checkMode & SignatureCheckMode.Callback ? undefined : getSingleCallSignature(getNonNullableType(sourceType)); 18533 const targetSig = checkMode & SignatureCheckMode.Callback ? undefined : getSingleCallSignature(getNonNullableType(targetType)); 18534 const callbacks = sourceSig && targetSig && !getTypePredicateOfSignature(sourceSig) && !getTypePredicateOfSignature(targetSig) && 18535 (getTypeFacts(sourceType) & TypeFacts.IsUndefinedOrNull) === (getTypeFacts(targetType) & TypeFacts.IsUndefinedOrNull); 18536 let related = callbacks ? 18537 compareSignaturesRelated(targetSig, sourceSig, (checkMode & SignatureCheckMode.StrictArity) | (strictVariance ? SignatureCheckMode.StrictCallback : SignatureCheckMode.BivariantCallback), reportErrors, errorReporter, incompatibleErrorReporter, compareTypes, reportUnreliableMarkers) : 18538 !(checkMode & SignatureCheckMode.Callback) && !strictVariance && compareTypes(sourceType, targetType, /*reportErrors*/ false) || compareTypes(targetType, sourceType, reportErrors); 18539 // With strict arity, (x: number | undefined) => void is a subtype of (x?: number | undefined) => void 18540 if (related && checkMode & SignatureCheckMode.StrictArity && i >= getMinArgumentCount(source) && i < getMinArgumentCount(target) && compareTypes(sourceType, targetType, /*reportErrors*/ false)) { 18541 related = Ternary.False; 18542 } 18543 if (!related) { 18544 if (reportErrors) { 18545 errorReporter!(Diagnostics.Types_of_parameters_0_and_1_are_incompatible, 18546 unescapeLeadingUnderscores(getParameterNameAtPosition(source, i)), 18547 unescapeLeadingUnderscores(getParameterNameAtPosition(target, i))); 18548 } 18549 return Ternary.False; 18550 } 18551 result &= related; 18552 } 18553 } 18554 18555 if (!(checkMode & SignatureCheckMode.IgnoreReturnTypes)) { 18556 // If a signature resolution is already in-flight, skip issuing a circularity error 18557 // here and just use the `any` type directly 18558 const targetReturnType = isResolvingReturnTypeOfSignature(target) ? anyType 18559 : target.declaration && isJSConstructor(target.declaration) ? getDeclaredTypeOfClassOrInterface(getMergedSymbol(target.declaration.symbol)) 18560 : getReturnTypeOfSignature(target); 18561 if (targetReturnType === voidType || targetReturnType === anyType) { 18562 return result; 18563 } 18564 const sourceReturnType = isResolvingReturnTypeOfSignature(source) ? anyType 18565 : source.declaration && isJSConstructor(source.declaration) ? getDeclaredTypeOfClassOrInterface(getMergedSymbol(source.declaration.symbol)) 18566 : getReturnTypeOfSignature(source); 18567 18568 // The following block preserves behavior forbidding boolean returning functions from being assignable to type guard returning functions 18569 const targetTypePredicate = getTypePredicateOfSignature(target); 18570 if (targetTypePredicate) { 18571 const sourceTypePredicate = getTypePredicateOfSignature(source); 18572 if (sourceTypePredicate) { 18573 result &= compareTypePredicateRelatedTo(sourceTypePredicate, targetTypePredicate, reportErrors, errorReporter, compareTypes); 18574 } 18575 else if (isIdentifierTypePredicate(targetTypePredicate)) { 18576 if (reportErrors) { 18577 errorReporter!(Diagnostics.Signature_0_must_be_a_type_predicate, signatureToString(source)); 18578 } 18579 return Ternary.False; 18580 } 18581 } 18582 else { 18583 // When relating callback signatures, we still need to relate return types bi-variantly as otherwise 18584 // the containing type wouldn't be co-variant. For example, interface Foo<T> { add(cb: () => T): void } 18585 // wouldn't be co-variant for T without this rule. 18586 result &= checkMode & SignatureCheckMode.BivariantCallback && compareTypes(targetReturnType, sourceReturnType, /*reportErrors*/ false) || 18587 compareTypes(sourceReturnType, targetReturnType, reportErrors); 18588 if (!result && reportErrors && incompatibleErrorReporter) { 18589 incompatibleErrorReporter(sourceReturnType, targetReturnType); 18590 } 18591 } 18592 18593 } 18594 18595 return result; 18596 } 18597 18598 function compareTypePredicateRelatedTo( 18599 source: TypePredicate, 18600 target: TypePredicate, 18601 reportErrors: boolean, 18602 errorReporter: ErrorReporter | undefined, 18603 compareTypes: (s: Type, t: Type, reportErrors?: boolean) => Ternary): Ternary { 18604 if (source.kind !== target.kind) { 18605 if (reportErrors) { 18606 errorReporter!(Diagnostics.A_this_based_type_guard_is_not_compatible_with_a_parameter_based_type_guard); 18607 errorReporter!(Diagnostics.Type_predicate_0_is_not_assignable_to_1, typePredicateToString(source), typePredicateToString(target)); 18608 } 18609 return Ternary.False; 18610 } 18611 18612 if (source.kind === TypePredicateKind.Identifier || source.kind === TypePredicateKind.AssertsIdentifier) { 18613 if (source.parameterIndex !== (target as IdentifierTypePredicate).parameterIndex) { 18614 if (reportErrors) { 18615 errorReporter!(Diagnostics.Parameter_0_is_not_in_the_same_position_as_parameter_1, source.parameterName, (target as IdentifierTypePredicate).parameterName); 18616 errorReporter!(Diagnostics.Type_predicate_0_is_not_assignable_to_1, typePredicateToString(source), typePredicateToString(target)); 18617 } 18618 return Ternary.False; 18619 } 18620 } 18621 18622 const related = source.type === target.type ? Ternary.True : 18623 source.type && target.type ? compareTypes(source.type, target.type, reportErrors) : 18624 Ternary.False; 18625 if (related === Ternary.False && reportErrors) { 18626 errorReporter!(Diagnostics.Type_predicate_0_is_not_assignable_to_1, typePredicateToString(source), typePredicateToString(target)); 18627 } 18628 return related; 18629 } 18630 18631 function isImplementationCompatibleWithOverload(implementation: Signature, overload: Signature): boolean { 18632 const erasedSource = getErasedSignature(implementation); 18633 const erasedTarget = getErasedSignature(overload); 18634 18635 // First see if the return types are compatible in either direction. 18636 const sourceReturnType = getReturnTypeOfSignature(erasedSource); 18637 const targetReturnType = getReturnTypeOfSignature(erasedTarget); 18638 if (targetReturnType === voidType 18639 || isTypeRelatedTo(targetReturnType, sourceReturnType, assignableRelation) 18640 || isTypeRelatedTo(sourceReturnType, targetReturnType, assignableRelation)) { 18641 18642 return isSignatureAssignableTo(erasedSource, erasedTarget, /*ignoreReturnTypes*/ true); 18643 } 18644 18645 return false; 18646 } 18647 18648 function isEmptyResolvedType(t: ResolvedType) { 18649 return t !== anyFunctionType && 18650 t.properties.length === 0 && 18651 t.callSignatures.length === 0 && 18652 t.constructSignatures.length === 0 && 18653 t.indexInfos.length === 0; 18654 } 18655 18656 function isEmptyObjectType(type: Type): boolean { 18657 return type.flags & TypeFlags.Object ? !isGenericMappedType(type) && isEmptyResolvedType(resolveStructuredTypeMembers(type as ObjectType)) : 18658 type.flags & TypeFlags.NonPrimitive ? true : 18659 type.flags & TypeFlags.Union ? some((type as UnionType).types, isEmptyObjectType) : 18660 type.flags & TypeFlags.Intersection ? every((type as UnionType).types, isEmptyObjectType) : 18661 false; 18662 } 18663 18664 function isEmptyAnonymousObjectType(type: Type) { 18665 return !!(getObjectFlags(type) & ObjectFlags.Anonymous && ( 18666 (type as ResolvedType).members && isEmptyResolvedType(type as ResolvedType) || 18667 type.symbol && type.symbol.flags & SymbolFlags.TypeLiteral && getMembersOfSymbol(type.symbol).size === 0)); 18668 } 18669 18670 function isUnknownLikeUnionType(type: Type) { 18671 if (strictNullChecks && type.flags & TypeFlags.Union) { 18672 if (!((type as UnionType).objectFlags & ObjectFlags.IsUnknownLikeUnionComputed)) { 18673 const types = (type as UnionType).types; 18674 (type as UnionType).objectFlags |= ObjectFlags.IsUnknownLikeUnionComputed | (types.length >= 3 && types[0].flags & TypeFlags.Undefined && 18675 types[1].flags & TypeFlags.Null && some(types, isEmptyAnonymousObjectType) ? ObjectFlags.IsUnknownLikeUnion : 0); 18676 } 18677 return !!((type as UnionType).objectFlags & ObjectFlags.IsUnknownLikeUnion); 18678 } 18679 return false; 18680 } 18681 18682 function containsUndefinedType(type: Type) { 18683 return !!((type.flags & TypeFlags.Union ? (type as UnionType).types[0] : type).flags & TypeFlags.Undefined); 18684 } 18685 18686 function isStringIndexSignatureOnlyType(type: Type): boolean { 18687 return type.flags & TypeFlags.Object && !isGenericMappedType(type) && getPropertiesOfType(type).length === 0 && getIndexInfosOfType(type).length === 1 && !!getIndexInfoOfType(type, stringType) || 18688 type.flags & TypeFlags.UnionOrIntersection && every((type as UnionOrIntersectionType).types, isStringIndexSignatureOnlyType) || 18689 false; 18690 } 18691 18692 function isEnumTypeRelatedTo(sourceSymbol: Symbol, targetSymbol: Symbol, errorReporter?: ErrorReporter) { 18693 if (sourceSymbol === targetSymbol) { 18694 return true; 18695 } 18696 const id = getSymbolId(sourceSymbol) + "," + getSymbolId(targetSymbol); 18697 const entry = enumRelation.get(id); 18698 if (entry !== undefined && !(!(entry & RelationComparisonResult.Reported) && entry & RelationComparisonResult.Failed && errorReporter)) { 18699 return !!(entry & RelationComparisonResult.Succeeded); 18700 } 18701 if (sourceSymbol.escapedName !== targetSymbol.escapedName || !(sourceSymbol.flags & SymbolFlags.RegularEnum) || !(targetSymbol.flags & SymbolFlags.RegularEnum)) { 18702 enumRelation.set(id, RelationComparisonResult.Failed | RelationComparisonResult.Reported); 18703 return false; 18704 } 18705 const targetEnumType = getTypeOfSymbol(targetSymbol); 18706 for (const property of getPropertiesOfType(getTypeOfSymbol(sourceSymbol))) { 18707 if (property.flags & SymbolFlags.EnumMember) { 18708 const targetProperty = getPropertyOfType(targetEnumType, property.escapedName); 18709 if (!targetProperty || !(targetProperty.flags & SymbolFlags.EnumMember)) { 18710 if (errorReporter) { 18711 errorReporter(Diagnostics.Property_0_is_missing_in_type_1, symbolName(property), 18712 typeToString(getDeclaredTypeOfSymbol(targetSymbol), /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType)); 18713 enumRelation.set(id, RelationComparisonResult.Failed | RelationComparisonResult.Reported); 18714 } 18715 else { 18716 enumRelation.set(id, RelationComparisonResult.Failed); 18717 } 18718 return false; 18719 } 18720 } 18721 } 18722 enumRelation.set(id, RelationComparisonResult.Succeeded); 18723 return true; 18724 } 18725 18726 function isSimpleTypeRelatedTo(source: Type, target: Type, relation: ESMap<string, RelationComparisonResult>, errorReporter?: ErrorReporter) { 18727 const s = source.flags; 18728 const t = target.flags; 18729 if (t & TypeFlags.AnyOrUnknown || s & TypeFlags.Never || source === wildcardType) return true; 18730 if (t & TypeFlags.Never) return false; 18731 if (s & TypeFlags.StringLike && t & TypeFlags.String) return true; 18732 if (s & TypeFlags.StringLiteral && s & TypeFlags.EnumLiteral && 18733 t & TypeFlags.StringLiteral && !(t & TypeFlags.EnumLiteral) && 18734 (source as StringLiteralType).value === (target as StringLiteralType).value) return true; 18735 if (s & TypeFlags.NumberLike && t & TypeFlags.Number) return true; 18736 if (s & TypeFlags.NumberLiteral && s & TypeFlags.EnumLiteral && 18737 t & TypeFlags.NumberLiteral && !(t & TypeFlags.EnumLiteral) && 18738 (source as NumberLiteralType).value === (target as NumberLiteralType).value) return true; 18739 if (s & TypeFlags.BigIntLike && t & TypeFlags.BigInt) return true; 18740 if (s & TypeFlags.BooleanLike && t & TypeFlags.Boolean) return true; 18741 if (s & TypeFlags.ESSymbolLike && t & TypeFlags.ESSymbol) return true; 18742 if (s & TypeFlags.Enum && t & TypeFlags.Enum && isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter)) return true; 18743 if (s & TypeFlags.EnumLiteral && t & TypeFlags.EnumLiteral) { 18744 if (s & TypeFlags.Union && t & TypeFlags.Union && isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter)) return true; 18745 if (s & TypeFlags.Literal && t & TypeFlags.Literal && 18746 (source as LiteralType).value === (target as LiteralType).value && 18747 isEnumTypeRelatedTo(getParentOfSymbol(source.symbol)!, getParentOfSymbol(target.symbol)!, errorReporter)) return true; 18748 } 18749 // In non-strictNullChecks mode, `undefined` and `null` are assignable to anything except `never`. 18750 // Since unions and intersections may reduce to `never`, we exclude them here. 18751 if (s & TypeFlags.Undefined && (!strictNullChecks && !(t & TypeFlags.UnionOrIntersection) || t & (TypeFlags.Undefined | TypeFlags.Void))) return true; 18752 if (s & TypeFlags.Null && (!strictNullChecks && !(t & TypeFlags.UnionOrIntersection) || t & TypeFlags.Null)) return true; 18753 if (s & TypeFlags.Object && t & TypeFlags.NonPrimitive && !(relation === strictSubtypeRelation && isEmptyAnonymousObjectType(source) && !(getObjectFlags(source) & ObjectFlags.FreshLiteral))) return true; 18754 if (relation === assignableRelation || relation === comparableRelation) { 18755 if (s & TypeFlags.Any) return true; 18756 // Type number or any numeric literal type is assignable to any numeric enum type or any 18757 // numeric enum literal type. This rule exists for backwards compatibility reasons because 18758 // bit-flag enum types sometimes look like literal enum types with numeric literal values. 18759 if (s & (TypeFlags.Number | TypeFlags.NumberLiteral) && !(s & TypeFlags.EnumLiteral) && ( 18760 t & TypeFlags.Enum || relation === assignableRelation && t & TypeFlags.NumberLiteral && t & TypeFlags.EnumLiteral)) return true; 18761 // Anything is assignable to a union containing undefined, null, and {} 18762 if (isUnknownLikeUnionType(target)) return true; 18763 } 18764 return false; 18765 } 18766 18767 function isTypeRelatedTo(source: Type, target: Type, relation: ESMap<string, RelationComparisonResult>) { 18768 if (isFreshLiteralType(source)) { 18769 source = (source as FreshableType).regularType; 18770 } 18771 if (isFreshLiteralType(target)) { 18772 target = (target as FreshableType).regularType; 18773 } 18774 if (source === target) { 18775 return true; 18776 } 18777 if (relation !== identityRelation) { 18778 if (relation === comparableRelation && !(target.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(target, source, relation) || isSimpleTypeRelatedTo(source, target, relation)) { 18779 return true; 18780 } 18781 } 18782 else if (!((source.flags | target.flags) & (TypeFlags.UnionOrIntersection | TypeFlags.IndexedAccess | TypeFlags.Conditional | TypeFlags.Substitution))) { 18783 // We have excluded types that may simplify to other forms, so types must have identical flags 18784 if (source.flags !== target.flags) return false; 18785 if (source.flags & TypeFlags.Singleton) return true; 18786 } 18787 if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) { 18788 const related = relation.get(getRelationKey(source, target, IntersectionState.None, relation, /*ignoreConstraints*/ false)); 18789 if (related !== undefined) { 18790 return !!(related & RelationComparisonResult.Succeeded); 18791 } 18792 } 18793 if (source.flags & TypeFlags.StructuredOrInstantiable || target.flags & TypeFlags.StructuredOrInstantiable) { 18794 return checkTypeRelatedTo(source, target, relation, /*errorNode*/ undefined); 18795 } 18796 return false; 18797 } 18798 18799 function isIgnoredJsxProperty(source: Type, sourceProp: Symbol) { 18800 return getObjectFlags(source) & ObjectFlags.JsxAttributes && isHyphenatedJsxName(sourceProp.escapedName); 18801 } 18802 18803 function getNormalizedType(type: Type, writing: boolean): Type { 18804 while (true) { 18805 const t = isFreshLiteralType(type) ? (type as FreshableType).regularType : 18806 getObjectFlags(type) & ObjectFlags.Reference ? (type as TypeReference).node ? createTypeReference((type as TypeReference).target, getTypeArguments(type as TypeReference)) : getSingleBaseForNonAugmentingSubtype(type) || type : 18807 type.flags & TypeFlags.UnionOrIntersection ? getNormalizedUnionOrIntersectionType(type as UnionOrIntersectionType, writing) : 18808 type.flags & TypeFlags.Substitution ? writing ? (type as SubstitutionType).baseType : getSubstitutionIntersection(type as SubstitutionType) : 18809 type.flags & TypeFlags.Simplifiable ? getSimplifiedType(type, writing) : 18810 type; 18811 if (t === type) return t; 18812 type = t; 18813 } 18814 } 18815 18816 function getNormalizedUnionOrIntersectionType(type: UnionOrIntersectionType, writing: boolean) { 18817 const reduced = getReducedType(type); 18818 if (reduced !== type) { 18819 return reduced; 18820 } 18821 if (type.flags & TypeFlags.Intersection && some((type as IntersectionType).types, isEmptyAnonymousObjectType)) { 18822 const normalizedTypes = sameMap(type.types, t => getNormalizedType(t, writing)); 18823 if (normalizedTypes !== type.types) { 18824 return getIntersectionType(normalizedTypes); 18825 } 18826 } 18827 return type; 18828 } 18829 18830 /** 18831 * Checks if 'source' is related to 'target' (e.g.: is a assignable to). 18832 * @param source The left-hand-side of the relation. 18833 * @param target The right-hand-side of the relation. 18834 * @param relation The relation considered. One of 'identityRelation', 'subtypeRelation', 'assignableRelation', or 'comparableRelation'. 18835 * Used as both to determine which checks are performed and as a cache of previously computed results. 18836 * @param errorNode The suggested node upon which all errors will be reported, if defined. This may or may not be the actual node used. 18837 * @param headMessage If the error chain should be prepended by a head message, then headMessage will be used. 18838 * @param containingMessageChain A chain of errors to prepend any new errors found. 18839 * @param errorOutputContainer Return the diagnostic. Do not log if 'skipLogging' is truthy. 18840 */ 18841 function checkTypeRelatedTo( 18842 source: Type, 18843 target: Type, 18844 relation: ESMap<string, RelationComparisonResult>, 18845 errorNode: Node | undefined, 18846 headMessage?: DiagnosticMessage, 18847 containingMessageChain?: () => DiagnosticMessageChain | undefined, 18848 errorOutputContainer?: { errors?: Diagnostic[], skipLogging?: boolean }, 18849 ): boolean { 18850 18851 let errorInfo: DiagnosticMessageChain | undefined; 18852 let relatedInfo: [DiagnosticRelatedInformation, ...DiagnosticRelatedInformation[]] | undefined; 18853 let maybeKeys: string[]; 18854 let sourceStack: Type[]; 18855 let targetStack: Type[]; 18856 let maybeCount = 0; 18857 let sourceDepth = 0; 18858 let targetDepth = 0; 18859 let expandingFlags = ExpandingFlags.None; 18860 let overflow = false; 18861 let overrideNextErrorInfo = 0; // How many `reportRelationError` calls should be skipped in the elaboration pyramid 18862 let lastSkippedInfo: [Type, Type] | undefined; 18863 let incompatibleStack: [DiagnosticMessage, (string | number)?, (string | number)?, (string | number)?, (string | number)?][] | undefined; 18864 let inPropertyCheck = false; 18865 18866 Debug.assert(relation !== identityRelation || !errorNode, "no error reporting in identity checking"); 18867 18868 const result = isRelatedTo(source, target, RecursionFlags.Both, /*reportErrors*/ !!errorNode, headMessage); 18869 if (incompatibleStack) { 18870 reportIncompatibleStack(); 18871 } 18872 if (overflow) { 18873 tracing?.instant(tracing.Phase.CheckTypes, "checkTypeRelatedTo_DepthLimit", { sourceId: source.id, targetId: target.id, depth: sourceDepth, targetDepth }); 18874 const diag = error(errorNode || currentNode, Diagnostics.Excessive_stack_depth_comparing_types_0_and_1, typeToString(source), typeToString(target)); 18875 if (errorOutputContainer) { 18876 (errorOutputContainer.errors || (errorOutputContainer.errors = [])).push(diag); 18877 } 18878 } 18879 else if (errorInfo) { 18880 if (containingMessageChain) { 18881 const chain = containingMessageChain(); 18882 if (chain) { 18883 concatenateDiagnosticMessageChains(chain, errorInfo); 18884 errorInfo = chain; 18885 } 18886 } 18887 18888 let relatedInformation: DiagnosticRelatedInformation[] | undefined; 18889 // Check if we should issue an extra diagnostic to produce a quickfix for a slightly incorrect import statement 18890 if (headMessage && errorNode && !result && source.symbol) { 18891 const links = getSymbolLinks(source.symbol); 18892 if (links.originatingImport && !isImportCall(links.originatingImport)) { 18893 const helpfulRetry = checkTypeRelatedTo(getTypeOfSymbol(links.target!), target, relation, /*errorNode*/ undefined); 18894 if (helpfulRetry) { 18895 // Likely an incorrect import. Issue a helpful diagnostic to produce a quickfix to change the import 18896 const diag = createDiagnosticForNode(links.originatingImport, Diagnostics.Type_originates_at_this_import_A_namespace_style_import_cannot_be_called_or_constructed_and_will_cause_a_failure_at_runtime_Consider_using_a_default_import_or_import_require_here_instead); 18897 relatedInformation = append(relatedInformation, diag); // Cause the error to appear with the error that triggered it 18898 } 18899 } 18900 } 18901 const diag = createDiagnosticForNodeFromMessageChain(errorNode!, errorInfo, relatedInformation); 18902 if (relatedInfo) { 18903 addRelatedInfo(diag, ...relatedInfo); 18904 } 18905 if (errorOutputContainer) { 18906 (errorOutputContainer.errors || (errorOutputContainer.errors = [])).push(diag); 18907 } 18908 if (!errorOutputContainer || !errorOutputContainer.skipLogging) { 18909 diagnostics.add(diag); 18910 } 18911 } 18912 if (errorNode && errorOutputContainer && errorOutputContainer.skipLogging && result === Ternary.False) { 18913 Debug.assert(!!errorOutputContainer.errors, "missed opportunity to interact with error."); 18914 } 18915 18916 18917 return result !== Ternary.False; 18918 18919 function resetErrorInfo(saved: ReturnType<typeof captureErrorCalculationState>) { 18920 errorInfo = saved.errorInfo; 18921 lastSkippedInfo = saved.lastSkippedInfo; 18922 incompatibleStack = saved.incompatibleStack; 18923 overrideNextErrorInfo = saved.overrideNextErrorInfo; 18924 relatedInfo = saved.relatedInfo; 18925 } 18926 18927 function captureErrorCalculationState() { 18928 return { 18929 errorInfo, 18930 lastSkippedInfo, 18931 incompatibleStack: incompatibleStack?.slice(), 18932 overrideNextErrorInfo, 18933 relatedInfo: relatedInfo?.slice() as [DiagnosticRelatedInformation, ...DiagnosticRelatedInformation[]] | undefined, 18934 }; 18935 } 18936 18937 function reportIncompatibleError(message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number) { 18938 overrideNextErrorInfo++; // Suppress the next relation error 18939 lastSkippedInfo = undefined; // Reset skipped info cache 18940 (incompatibleStack ||= []).push([message, arg0, arg1, arg2, arg3]); 18941 } 18942 18943 function reportIncompatibleStack() { 18944 const stack = incompatibleStack || []; 18945 incompatibleStack = undefined; 18946 const info = lastSkippedInfo; 18947 lastSkippedInfo = undefined; 18948 if (stack.length === 1) { 18949 reportError(...stack[0]); 18950 if (info) { 18951 // Actually do the last relation error 18952 reportRelationError(/*headMessage*/ undefined, ...info); 18953 } 18954 return; 18955 } 18956 // The first error will be the innermost, while the last will be the outermost - so by popping off the end, 18957 // we can build from left to right 18958 let path = ""; 18959 const secondaryRootErrors: [DiagnosticMessage, (string | number)?, (string | number)?, (string | number)?, (string | number)?][] = []; 18960 while (stack.length) { 18961 const [msg, ...args] = stack.pop()!; 18962 switch (msg.code) { 18963 case Diagnostics.Types_of_property_0_are_incompatible.code: { 18964 // Parenthesize a `new` if there is one 18965 if (path.indexOf("new ") === 0) { 18966 path = `(${path})`; 18967 } 18968 const str = "" + args[0]; 18969 // If leading, just print back the arg (irrespective of if it's a valid identifier) 18970 if (path.length === 0) { 18971 path = `${str}`; 18972 } 18973 // Otherwise write a dotted name if possible 18974 else if (isIdentifierText(str, getEmitScriptTarget(compilerOptions))) { 18975 path = `${path}.${str}`; 18976 } 18977 // Failing that, check if the name is already a computed name 18978 else if (str[0] === "[" && str[str.length - 1] === "]") { 18979 path = `${path}${str}`; 18980 } 18981 // And finally write out a computed name as a last resort 18982 else { 18983 path = `${path}[${str}]`; 18984 } 18985 break; 18986 } 18987 case Diagnostics.Call_signature_return_types_0_and_1_are_incompatible.code: 18988 case Diagnostics.Construct_signature_return_types_0_and_1_are_incompatible.code: 18989 case Diagnostics.Call_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code: 18990 case Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code: { 18991 if (path.length === 0) { 18992 // Don't flatten signature compatability errors at the start of a chain - instead prefer 18993 // to unify (the with no arguments bit is excessive for printback) and print them back 18994 let mappedMsg = msg; 18995 if (msg.code === Diagnostics.Call_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code) { 18996 mappedMsg = Diagnostics.Call_signature_return_types_0_and_1_are_incompatible; 18997 } 18998 else if (msg.code === Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code) { 18999 mappedMsg = Diagnostics.Construct_signature_return_types_0_and_1_are_incompatible; 19000 } 19001 secondaryRootErrors.unshift([mappedMsg, args[0], args[1]]); 19002 } 19003 else { 19004 const prefix = (msg.code === Diagnostics.Construct_signature_return_types_0_and_1_are_incompatible.code || 19005 msg.code === Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code) 19006 ? "new " 19007 : ""; 19008 const params = (msg.code === Diagnostics.Call_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code || 19009 msg.code === Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code) 19010 ? "" 19011 : "..."; 19012 path = `${prefix}${path}(${params})`; 19013 } 19014 break; 19015 } 19016 case Diagnostics.Type_at_position_0_in_source_is_not_compatible_with_type_at_position_1_in_target.code: { 19017 secondaryRootErrors.unshift([Diagnostics.Type_at_position_0_in_source_is_not_compatible_with_type_at_position_1_in_target, args[0], args[1]]); 19018 break; 19019 } 19020 case Diagnostics.Type_at_positions_0_through_1_in_source_is_not_compatible_with_type_at_position_2_in_target.code: { 19021 secondaryRootErrors.unshift([Diagnostics.Type_at_positions_0_through_1_in_source_is_not_compatible_with_type_at_position_2_in_target, args[0], args[1], args[2]]); 19022 break; 19023 } 19024 default: 19025 return Debug.fail(`Unhandled Diagnostic: ${msg.code}`); 19026 } 19027 } 19028 if (path) { 19029 reportError(path[path.length - 1] === ")" 19030 ? Diagnostics.The_types_returned_by_0_are_incompatible_between_these_types 19031 : Diagnostics.The_types_of_0_are_incompatible_between_these_types, 19032 path 19033 ); 19034 } 19035 else { 19036 // Remove the innermost secondary error as it will duplicate the error already reported by `reportRelationError` on entry 19037 secondaryRootErrors.shift(); 19038 } 19039 for (const [msg, ...args] of secondaryRootErrors) { 19040 const originalValue = msg.elidedInCompatabilityPyramid; 19041 msg.elidedInCompatabilityPyramid = false; // Temporarily override elision to ensure error is reported 19042 reportError(msg, ...args); 19043 msg.elidedInCompatabilityPyramid = originalValue; 19044 } 19045 if (info) { 19046 // Actually do the last relation error 19047 reportRelationError(/*headMessage*/ undefined, ...info); 19048 } 19049 } 19050 19051 function reportError(message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): void { 19052 Debug.assert(!!errorNode); 19053 if (incompatibleStack) reportIncompatibleStack(); 19054 if (message.elidedInCompatabilityPyramid) return; 19055 errorInfo = chainDiagnosticMessages(errorInfo, message, arg0, arg1, arg2, arg3); 19056 } 19057 19058 function associateRelatedInfo(info: DiagnosticRelatedInformation) { 19059 Debug.assert(!!errorInfo); 19060 if (!relatedInfo) { 19061 relatedInfo = [info]; 19062 } 19063 else { 19064 relatedInfo.push(info); 19065 } 19066 } 19067 19068 function reportRelationError(message: DiagnosticMessage | undefined, source: Type, target: Type) { 19069 if (incompatibleStack) reportIncompatibleStack(); 19070 const [sourceType, targetType] = getTypeNamesForErrorDisplay(source, target); 19071 let generalizedSource = source; 19072 let generalizedSourceType = sourceType; 19073 19074 if (isLiteralType(source) && !typeCouldHaveTopLevelSingletonTypes(target)) { 19075 generalizedSource = getBaseTypeOfLiteralType(source); 19076 Debug.assert(!isTypeAssignableTo(generalizedSource, target), "generalized source shouldn't be assignable"); 19077 generalizedSourceType = getTypeNameForErrorDisplay(generalizedSource); 19078 } 19079 19080 if (target.flags & TypeFlags.TypeParameter && target !== markerSuperTypeForCheck && target !== markerSubTypeForCheck) { 19081 const constraint = getBaseConstraintOfType(target); 19082 let needsOriginalSource; 19083 if (constraint && (isTypeAssignableTo(generalizedSource, constraint) || (needsOriginalSource = isTypeAssignableTo(source, constraint)))) { 19084 reportError( 19085 Diagnostics._0_is_assignable_to_the_constraint_of_type_1_but_1_could_be_instantiated_with_a_different_subtype_of_constraint_2, 19086 needsOriginalSource ? sourceType : generalizedSourceType, 19087 targetType, 19088 typeToString(constraint), 19089 ); 19090 } 19091 else { 19092 errorInfo = undefined; 19093 reportError( 19094 Diagnostics._0_could_be_instantiated_with_an_arbitrary_type_which_could_be_unrelated_to_1, 19095 targetType, 19096 generalizedSourceType 19097 ); 19098 } 19099 } 19100 19101 if (!message) { 19102 if (relation === comparableRelation) { 19103 message = Diagnostics.Type_0_is_not_comparable_to_type_1; 19104 } 19105 else if (sourceType === targetType) { 19106 message = Diagnostics.Type_0_is_not_assignable_to_type_1_Two_different_types_with_this_name_exist_but_they_are_unrelated; 19107 } 19108 else if (exactOptionalPropertyTypes && getExactOptionalUnassignableProperties(source, target).length) { 19109 message = Diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties; 19110 } 19111 else { 19112 if (source.flags & TypeFlags.StringLiteral && target.flags & TypeFlags.Union) { 19113 const suggestedType = getSuggestedTypeForNonexistentStringLiteralType(source as StringLiteralType, target as UnionType); 19114 if (suggestedType) { 19115 reportError(Diagnostics.Type_0_is_not_assignable_to_type_1_Did_you_mean_2, generalizedSourceType, targetType, typeToString(suggestedType)); 19116 return; 19117 } 19118 } 19119 message = Diagnostics.Type_0_is_not_assignable_to_type_1; 19120 } 19121 } 19122 else if (message === Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1 19123 && exactOptionalPropertyTypes 19124 && getExactOptionalUnassignableProperties(source, target).length) { 19125 message = Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties; 19126 } 19127 19128 reportError(message, generalizedSourceType, targetType); 19129 } 19130 19131 function tryElaborateErrorsForPrimitivesAndObjects(source: Type, target: Type) { 19132 const sourceType = symbolValueDeclarationIsContextSensitive(source.symbol) ? typeToString(source, source.symbol.valueDeclaration) : typeToString(source); 19133 const targetType = symbolValueDeclarationIsContextSensitive(target.symbol) ? typeToString(target, target.symbol.valueDeclaration) : typeToString(target); 19134 19135 if ((globalStringType === source && stringType === target) || 19136 (globalNumberType === source && numberType === target) || 19137 (globalBooleanType === source && booleanType === target) || 19138 (getGlobalESSymbolType() === source && esSymbolType === target)) { 19139 reportError(Diagnostics._0_is_a_primitive_but_1_is_a_wrapper_object_Prefer_using_0_when_possible, targetType, sourceType); 19140 } 19141 } 19142 19143 /** 19144 * Try and elaborate array and tuple errors. Returns false 19145 * if we have found an elaboration, or we should ignore 19146 * any other elaborations when relating the `source` and 19147 * `target` types. 19148 */ 19149 function tryElaborateArrayLikeErrors(source: Type, target: Type, reportErrors: boolean): boolean { 19150 /** 19151 * The spec for elaboration is: 19152 * - If the source is a readonly tuple and the target is a mutable array or tuple, elaborate on mutability and skip property elaborations. 19153 * - If the source is a tuple then skip property elaborations if the target is an array or tuple. 19154 * - If the source is a readonly array and the target is a mutable array or tuple, elaborate on mutability and skip property elaborations. 19155 * - If the source an array then skip property elaborations if the target is a tuple. 19156 */ 19157 if (isTupleType(source)) { 19158 if (source.target.readonly && isMutableArrayOrTuple(target)) { 19159 if (reportErrors) { 19160 reportError(Diagnostics.The_type_0_is_readonly_and_cannot_be_assigned_to_the_mutable_type_1, typeToString(source), typeToString(target)); 19161 } 19162 return false; 19163 } 19164 return isArrayOrTupleType(target); 19165 } 19166 if (isReadonlyArrayType(source) && isMutableArrayOrTuple(target)) { 19167 if (reportErrors) { 19168 reportError(Diagnostics.The_type_0_is_readonly_and_cannot_be_assigned_to_the_mutable_type_1, typeToString(source), typeToString(target)); 19169 } 19170 return false; 19171 } 19172 if (isTupleType(target)) { 19173 return isArrayType(source); 19174 } 19175 return true; 19176 } 19177 19178 function isRelatedToWorker(source: Type, target: Type, reportErrors: boolean) { 19179 return isRelatedTo(source, target, RecursionFlags.Both, reportErrors); 19180 } 19181 19182 /** 19183 * Compare two types and return 19184 * * Ternary.True if they are related with no assumptions, 19185 * * Ternary.Maybe if they are related with assumptions of other relationships, or 19186 * * Ternary.False if they are not related. 19187 */ 19188 function isRelatedTo(originalSource: Type, originalTarget: Type, recursionFlags: RecursionFlags = RecursionFlags.Both, reportErrors = false, headMessage?: DiagnosticMessage, intersectionState = IntersectionState.None): Ternary { 19189 // Before normalization: if `source` is type an object type, and `target` is primitive, 19190 // skip all the checks we don't need and just return `isSimpleTypeRelatedTo` result 19191 if (originalSource.flags & TypeFlags.Object && originalTarget.flags & TypeFlags.Primitive) { 19192 if (isSimpleTypeRelatedTo(originalSource, originalTarget, relation, reportErrors ? reportError : undefined)) { 19193 return Ternary.True; 19194 } 19195 if (reportErrors) { 19196 reportErrorResults(originalSource, originalTarget, originalSource, originalTarget, headMessage); 19197 } 19198 return Ternary.False; 19199 } 19200 19201 // Normalize the source and target types: Turn fresh literal types into regular literal types, 19202 // turn deferred type references into regular type references, simplify indexed access and 19203 // conditional types, and resolve substitution types to either the substitution (on the source 19204 // side) or the type variable (on the target side). 19205 const source = getNormalizedType(originalSource, /*writing*/ false); 19206 let target = getNormalizedType(originalTarget, /*writing*/ true); 19207 19208 if (source === target) return Ternary.True; 19209 19210 if (relation === identityRelation) { 19211 if (source.flags !== target.flags) return Ternary.False; 19212 if (source.flags & TypeFlags.Singleton) return Ternary.True; 19213 traceUnionsOrIntersectionsTooLarge(source, target); 19214 return recursiveTypeRelatedTo(source, target, /*reportErrors*/ false, IntersectionState.None, recursionFlags); 19215 } 19216 19217 // We fastpath comparing a type parameter to exactly its constraint, as this is _super_ common, 19218 // and otherwise, for type parameters in large unions, causes us to need to compare the union to itself, 19219 // as we break down the _target_ union first, _then_ get the source constraint - so for every 19220 // member of the target, we attempt to find a match in the source. This avoids that in cases where 19221 // the target is exactly the constraint. 19222 if (source.flags & TypeFlags.TypeParameter && getConstraintOfType(source) === target) { 19223 return Ternary.True; 19224 } 19225 19226 // See if we're relating a definitely non-nullable type to a union that includes null and/or undefined 19227 // plus a single non-nullable type. If so, remove null and/or undefined from the target type. 19228 if (source.flags & TypeFlags.DefinitelyNonNullable && target.flags & TypeFlags.Union) { 19229 const types = (target as UnionType).types; 19230 const candidate = types.length === 2 && types[0].flags & TypeFlags.Nullable ? types[1] : 19231 types.length === 3 && types[0].flags & TypeFlags.Nullable && types[1].flags & TypeFlags.Nullable ? types[2] : 19232 undefined; 19233 if (candidate && !(candidate.flags & TypeFlags.Nullable)) { 19234 target = getNormalizedType(candidate, /*writing*/ true); 19235 if (source === target) return Ternary.True; 19236 } 19237 } 19238 19239 if (relation === comparableRelation && !(target.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(target, source, relation) || 19240 isSimpleTypeRelatedTo(source, target, relation, reportErrors ? reportError : undefined)) return Ternary.True; 19241 19242 if (source.flags & TypeFlags.StructuredOrInstantiable || target.flags & TypeFlags.StructuredOrInstantiable) { 19243 const isPerformingExcessPropertyChecks = !(intersectionState & IntersectionState.Target) && (isObjectLiteralType(source) && getObjectFlags(source) & ObjectFlags.FreshLiteral); 19244 if (isPerformingExcessPropertyChecks) { 19245 if (hasExcessProperties(source as FreshObjectLiteralType, target, reportErrors)) { 19246 if (reportErrors) { 19247 reportRelationError(headMessage, source, originalTarget.aliasSymbol ? originalTarget : target); 19248 } 19249 return Ternary.False; 19250 } 19251 } 19252 19253 const isPerformingCommonPropertyChecks = (relation !== comparableRelation || isUnitType(source)) && 19254 !(intersectionState & IntersectionState.Target) && 19255 source.flags & (TypeFlags.Primitive | TypeFlags.Object | TypeFlags.Intersection) && source !== globalObjectType && 19256 target.flags & (TypeFlags.Object | TypeFlags.Intersection) && isWeakType(target) && 19257 (getPropertiesOfType(source).length > 0 || typeHasCallOrConstructSignatures(source)); 19258 const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes); 19259 if (isPerformingCommonPropertyChecks && !hasCommonProperties(source, target, isComparingJsxAttributes)) { 19260 if (reportErrors) { 19261 const sourceString = typeToString(originalSource.aliasSymbol ? originalSource : source); 19262 const targetString = typeToString(originalTarget.aliasSymbol ? originalTarget : target); 19263 const calls = getSignaturesOfType(source, SignatureKind.Call); 19264 const constructs = getSignaturesOfType(source, SignatureKind.Construct); 19265 if (calls.length > 0 && isRelatedTo(getReturnTypeOfSignature(calls[0]), target, RecursionFlags.Source, /*reportErrors*/ false) || 19266 constructs.length > 0 && isRelatedTo(getReturnTypeOfSignature(constructs[0]), target, RecursionFlags.Source, /*reportErrors*/ false)) { 19267 reportError(Diagnostics.Value_of_type_0_has_no_properties_in_common_with_type_1_Did_you_mean_to_call_it, sourceString, targetString); 19268 } 19269 else { 19270 reportError(Diagnostics.Type_0_has_no_properties_in_common_with_type_1, sourceString, targetString); 19271 } 19272 } 19273 return Ternary.False; 19274 } 19275 19276 traceUnionsOrIntersectionsTooLarge(source, target); 19277 19278 const skipCaching = source.flags & TypeFlags.Union && (source as UnionType).types.length < 4 && !(target.flags & TypeFlags.Union) || 19279 target.flags & TypeFlags.Union && (target as UnionType).types.length < 4 && !(source.flags & TypeFlags.StructuredOrInstantiable); 19280 const result = skipCaching ? 19281 unionOrIntersectionRelatedTo(source, target, reportErrors, intersectionState) : 19282 recursiveTypeRelatedTo(source, target, reportErrors, intersectionState, recursionFlags); 19283 if (result) { 19284 return result; 19285 } 19286 } 19287 19288 if (reportErrors) { 19289 reportErrorResults(originalSource, originalTarget, source, target, headMessage); 19290 } 19291 return Ternary.False; 19292 } 19293 19294 function reportErrorResults(originalSource: Type, originalTarget: Type, source: Type, target: Type, headMessage: DiagnosticMessage | undefined) { 19295 const sourceHasBase = !!getSingleBaseForNonAugmentingSubtype(originalSource); 19296 const targetHasBase = !!getSingleBaseForNonAugmentingSubtype(originalTarget); 19297 source = (originalSource.aliasSymbol || sourceHasBase) ? originalSource : source; 19298 target = (originalTarget.aliasSymbol || targetHasBase) ? originalTarget : target; 19299 let maybeSuppress = overrideNextErrorInfo > 0; 19300 if (maybeSuppress) { 19301 overrideNextErrorInfo--; 19302 } 19303 if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) { 19304 const currentError = errorInfo; 19305 tryElaborateArrayLikeErrors(source, target, /*reportErrors*/ true); 19306 if (errorInfo !== currentError) { 19307 maybeSuppress = !!errorInfo; 19308 } 19309 } 19310 if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Primitive) { 19311 tryElaborateErrorsForPrimitivesAndObjects(source, target); 19312 } 19313 else if (source.symbol && source.flags & TypeFlags.Object && globalObjectType === source) { 19314 reportError(Diagnostics.The_Object_type_is_assignable_to_very_few_other_types_Did_you_mean_to_use_the_any_type_instead); 19315 } 19316 else if (getObjectFlags(source) & ObjectFlags.JsxAttributes && target.flags & TypeFlags.Intersection) { 19317 const targetTypes = (target as IntersectionType).types; 19318 const intrinsicAttributes = getJsxType(JsxNames.IntrinsicAttributes, errorNode); 19319 const intrinsicClassAttributes = getJsxType(JsxNames.IntrinsicClassAttributes, errorNode); 19320 if (!isErrorType(intrinsicAttributes) && !isErrorType(intrinsicClassAttributes) && 19321 (contains(targetTypes, intrinsicAttributes) || contains(targetTypes, intrinsicClassAttributes))) { 19322 // do not report top error 19323 return; 19324 } 19325 } 19326 else { 19327 errorInfo = elaborateNeverIntersection(errorInfo, originalTarget); 19328 } 19329 if (!headMessage && maybeSuppress) { 19330 lastSkippedInfo = [source, target]; 19331 // Used by, eg, missing property checking to replace the top-level message with a more informative one 19332 return; 19333 } 19334 reportRelationError(headMessage, source, target); 19335 if (source.flags & TypeFlags.TypeParameter && source.symbol?.declarations?.[0] && !getConstraintOfType(source as TypeVariable)) { 19336 const syntheticParam = cloneTypeParameter(source as TypeParameter); 19337 syntheticParam.constraint = instantiateType(target, makeUnaryTypeMapper(source, syntheticParam)); 19338 if (hasNonCircularBaseConstraint(syntheticParam)) { 19339 const targetConstraintString = typeToString(target, source.symbol.declarations[0]); 19340 associateRelatedInfo(createDiagnosticForNode(source.symbol.declarations[0], Diagnostics.This_type_parameter_might_need_an_extends_0_constraint, targetConstraintString)); 19341 } 19342 } 19343 } 19344 19345 function traceUnionsOrIntersectionsTooLarge(source: Type, target: Type): void { 19346 if (!tracing) { 19347 return; 19348 } 19349 19350 if ((source.flags & TypeFlags.UnionOrIntersection) && (target.flags & TypeFlags.UnionOrIntersection)) { 19351 const sourceUnionOrIntersection = source as UnionOrIntersectionType; 19352 const targetUnionOrIntersection = target as UnionOrIntersectionType; 19353 19354 if (sourceUnionOrIntersection.objectFlags & targetUnionOrIntersection.objectFlags & ObjectFlags.PrimitiveUnion) { 19355 // There's a fast path for comparing primitive unions 19356 return; 19357 } 19358 19359 const sourceSize = sourceUnionOrIntersection.types.length; 19360 const targetSize = targetUnionOrIntersection.types.length; 19361 if (sourceSize * targetSize > 1E6) { 19362 tracing.instant(tracing.Phase.CheckTypes, "traceUnionsOrIntersectionsTooLarge_DepthLimit", { 19363 sourceId: source.id, 19364 sourceSize, 19365 targetId: target.id, 19366 targetSize, 19367 pos: errorNode?.pos, 19368 end: errorNode?.end 19369 }); 19370 } 19371 } 19372 } 19373 19374 function getTypeOfPropertyInTypes(types: Type[], name: __String) { 19375 const appendPropType = (propTypes: Type[] | undefined, type: Type) => { 19376 type = getApparentType(type); 19377 const prop = type.flags & TypeFlags.UnionOrIntersection ? getPropertyOfUnionOrIntersectionType(type as UnionOrIntersectionType, name) : getPropertyOfObjectType(type, name); 19378 const propType = prop && getTypeOfSymbol(prop) || getApplicableIndexInfoForName(type, name)?.type || undefinedType; 19379 return append(propTypes, propType); 19380 }; 19381 return getUnionType(reduceLeft(types, appendPropType, /*initial*/ undefined) || emptyArray); 19382 } 19383 19384 function hasExcessProperties(source: FreshObjectLiteralType, target: Type, reportErrors: boolean): boolean { 19385 if (!isExcessPropertyCheckTarget(target) || !noImplicitAny && getObjectFlags(target) & ObjectFlags.JSLiteral) { 19386 return false; // Disable excess property checks on JS literals to simulate having an implicit "index signature" - but only outside of noImplicitAny 19387 } 19388 const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes); 19389 if ((relation === assignableRelation || relation === comparableRelation) && 19390 (isTypeSubsetOf(globalObjectType, target) || (!isComparingJsxAttributes && isEmptyObjectType(target)))) { 19391 return false; 19392 } 19393 let reducedTarget = target; 19394 let checkTypes: Type[] | undefined; 19395 if (target.flags & TypeFlags.Union) { 19396 reducedTarget = findMatchingDiscriminantType(source, target as UnionType, isRelatedTo) || filterPrimitivesIfContainsNonPrimitive(target as UnionType); 19397 checkTypes = reducedTarget.flags & TypeFlags.Union ? (reducedTarget as UnionType).types : [reducedTarget]; 19398 } 19399 for (const prop of getPropertiesOfType(source)) { 19400 if (shouldCheckAsExcessProperty(prop, source.symbol) && !isIgnoredJsxProperty(source, prop)) { 19401 if (!isKnownProperty(reducedTarget, prop.escapedName, isComparingJsxAttributes)) { 19402 if (reportErrors) { 19403 // Report error in terms of object types in the target as those are the only ones 19404 // we check in isKnownProperty. 19405 const errorTarget = filterType(reducedTarget, isExcessPropertyCheckTarget); 19406 // We know *exactly* where things went wrong when comparing the types. 19407 // Use this property as the error node as this will be more helpful in 19408 // reasoning about what went wrong. 19409 if (!errorNode) return Debug.fail(); 19410 if (isJsxAttributes(errorNode) || isJsxOpeningLikeElement(errorNode) || isJsxOpeningLikeElement(errorNode.parent)) { 19411 // JsxAttributes has an object-literal flag and undergo same type-assignablity check as normal object-literal. 19412 // However, using an object-literal error message will be very confusing to the users so we give different a message. 19413 if (prop.valueDeclaration && isJsxAttribute(prop.valueDeclaration) && getSourceFileOfNode(errorNode) === getSourceFileOfNode(prop.valueDeclaration.name)) { 19414 // Note that extraneous children (as in `<NoChild>extra</NoChild>`) don't pass this check, 19415 // since `children` is a SyntaxKind.PropertySignature instead of a SyntaxKind.JsxAttribute. 19416 errorNode = prop.valueDeclaration.name; 19417 } 19418 const propName = symbolToString(prop); 19419 const suggestionSymbol = getSuggestedSymbolForNonexistentJSXAttribute(propName, errorTarget); 19420 const suggestion = suggestionSymbol ? symbolToString(suggestionSymbol) : undefined; 19421 if (suggestion) { 19422 reportError(Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2, propName, typeToString(errorTarget), suggestion); 19423 } 19424 else { 19425 reportError(Diagnostics.Property_0_does_not_exist_on_type_1, propName, typeToString(errorTarget)); 19426 } 19427 } 19428 else { 19429 // use the property's value declaration if the property is assigned inside the literal itself 19430 const objectLiteralDeclaration = source.symbol?.declarations && firstOrUndefined(source.symbol.declarations); 19431 let suggestion: string | undefined; 19432 if (prop.valueDeclaration && findAncestor(prop.valueDeclaration, d => d === objectLiteralDeclaration) && getSourceFileOfNode(objectLiteralDeclaration) === getSourceFileOfNode(errorNode)) { 19433 const propDeclaration = prop.valueDeclaration as ObjectLiteralElementLike; 19434 Debug.assertNode(propDeclaration, isObjectLiteralElementLike); 19435 19436 errorNode = propDeclaration; 19437 19438 const name = propDeclaration.name!; 19439 if (isIdentifier(name)) { 19440 suggestion = getSuggestionForNonexistentProperty(name, errorTarget); 19441 } 19442 } 19443 if (suggestion !== undefined) { 19444 reportError(Diagnostics.Object_literal_may_only_specify_known_properties_but_0_does_not_exist_in_type_1_Did_you_mean_to_write_2, 19445 symbolToString(prop), typeToString(errorTarget), suggestion); 19446 } 19447 else { 19448 reportError(Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1, 19449 symbolToString(prop), typeToString(errorTarget)); 19450 } 19451 } 19452 } 19453 return true; 19454 } 19455 if (checkTypes && !isRelatedTo(getTypeOfSymbol(prop), getTypeOfPropertyInTypes(checkTypes, prop.escapedName), RecursionFlags.Both, reportErrors)) { 19456 if (reportErrors) { 19457 reportIncompatibleError(Diagnostics.Types_of_property_0_are_incompatible, symbolToString(prop)); 19458 } 19459 return true; 19460 } 19461 } 19462 } 19463 return false; 19464 } 19465 19466 function shouldCheckAsExcessProperty(prop: Symbol, container: Symbol) { 19467 return prop.valueDeclaration && container.valueDeclaration && prop.valueDeclaration.parent === container.valueDeclaration; 19468 } 19469 19470 function unionOrIntersectionRelatedTo(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary { 19471 // Note that these checks are specifically ordered to produce correct results. In particular, 19472 // we need to deconstruct unions before intersections (because unions are always at the top), 19473 // and we need to handle "each" relations before "some" relations for the same kind of type. 19474 if (source.flags & TypeFlags.Union) { 19475 return relation === comparableRelation ? 19476 someTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive), intersectionState) : 19477 eachTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive), intersectionState); 19478 } 19479 if (target.flags & TypeFlags.Union) { 19480 return typeRelatedToSomeType(getRegularTypeOfObjectLiteral(source), target as UnionType, reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive)); 19481 } 19482 if (target.flags & TypeFlags.Intersection) { 19483 return typeRelatedToEachType(source, target as IntersectionType, reportErrors, IntersectionState.Target); 19484 } 19485 // Source is an intersection. For the comparable relation, if the target is a primitive type we hoist the 19486 // constraints of all non-primitive types in the source into a new intersection. We do this because the 19487 // intersection may further constrain the constraints of the non-primitive types. For example, given a type 19488 // parameter 'T extends 1 | 2', the intersection 'T & 1' should be reduced to '1' such that it doesn't 19489 // appear to be comparable to '2'. 19490 if (relation === comparableRelation && target.flags & TypeFlags.Primitive) { 19491 const constraints = sameMap((source as IntersectionType).types, t => t.flags & TypeFlags.Instantiable ? getBaseConstraintOfType(t) || unknownType : t); 19492 if (constraints !== (source as IntersectionType).types) { 19493 source = getIntersectionType(constraints); 19494 if (source.flags & TypeFlags.Never) { 19495 return Ternary.False; 19496 } 19497 if (!(source.flags & TypeFlags.Intersection)) { 19498 return isRelatedTo(source, target, RecursionFlags.Source, /*reportErrors*/ false) || 19499 isRelatedTo(target, source, RecursionFlags.Source, /*reportErrors*/ false); 19500 } 19501 } 19502 } 19503 // Check to see if any constituents of the intersection are immediately related to the target. 19504 // Don't report errors though. Elaborating on whether a source constituent is related to the target is 19505 // not actually useful and leads to some confusing error messages. Instead, we rely on the caller 19506 // checking whether the full intersection viewed as an object is related to the target. 19507 return someTypeRelatedToType(source as IntersectionType, target, /*reportErrors*/ false, IntersectionState.Source); 19508 } 19509 19510 function eachTypeRelatedToSomeType(source: UnionOrIntersectionType, target: UnionOrIntersectionType): Ternary { 19511 let result = Ternary.True; 19512 const sourceTypes = source.types; 19513 for (const sourceType of sourceTypes) { 19514 const related = typeRelatedToSomeType(sourceType, target, /*reportErrors*/ false); 19515 if (!related) { 19516 return Ternary.False; 19517 } 19518 result &= related; 19519 } 19520 return result; 19521 } 19522 19523 function typeRelatedToSomeType(source: Type, target: UnionOrIntersectionType, reportErrors: boolean): Ternary { 19524 const targetTypes = target.types; 19525 if (target.flags & TypeFlags.Union) { 19526 if (containsType(targetTypes, source)) { 19527 return Ternary.True; 19528 } 19529 const match = getMatchingUnionConstituentForType(target as UnionType, source); 19530 if (match) { 19531 const related = isRelatedTo(source, match, RecursionFlags.Target, /*reportErrors*/ false); 19532 if (related) { 19533 return related; 19534 } 19535 } 19536 } 19537 for (const type of targetTypes) { 19538 const related = isRelatedTo(source, type, RecursionFlags.Target, /*reportErrors*/ false); 19539 if (related) { 19540 return related; 19541 } 19542 } 19543 if (reportErrors) { 19544 // Elaborate only if we can find a best matching type in the target union 19545 const bestMatchingType = getBestMatchingType(source, target, isRelatedTo); 19546 if (bestMatchingType) { 19547 isRelatedTo(source, bestMatchingType, RecursionFlags.Target, /*reportErrors*/ true); 19548 } 19549 } 19550 return Ternary.False; 19551 } 19552 19553 function typeRelatedToEachType(source: Type, target: IntersectionType, reportErrors: boolean, intersectionState: IntersectionState): Ternary { 19554 let result = Ternary.True; 19555 const targetTypes = target.types; 19556 for (const targetType of targetTypes) { 19557 const related = isRelatedTo(source, targetType, RecursionFlags.Target, reportErrors, /*headMessage*/ undefined, intersectionState); 19558 if (!related) { 19559 return Ternary.False; 19560 } 19561 result &= related; 19562 } 19563 return result; 19564 } 19565 19566 function someTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary { 19567 const sourceTypes = source.types; 19568 if (source.flags & TypeFlags.Union && containsType(sourceTypes, target)) { 19569 return Ternary.True; 19570 } 19571 const len = sourceTypes.length; 19572 for (let i = 0; i < len; i++) { 19573 const related = isRelatedTo(sourceTypes[i], target, RecursionFlags.Source, reportErrors && i === len - 1, /*headMessage*/ undefined, intersectionState); 19574 if (related) { 19575 return related; 19576 } 19577 } 19578 return Ternary.False; 19579 } 19580 19581 function getUndefinedStrippedTargetIfNeeded(source: Type, target: Type) { 19582 // As a builtin type, `undefined` is a very low type ID - making it almsot always first, making this a very fast check to see 19583 // if we need to strip `undefined` from the target 19584 if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union && 19585 !((source as UnionType).types[0].flags & TypeFlags.Undefined) && (target as UnionType).types[0].flags & TypeFlags.Undefined) { 19586 return extractTypesOfKind(target, ~TypeFlags.Undefined); 19587 } 19588 return target; 19589 } 19590 19591 function eachTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary { 19592 let result = Ternary.True; 19593 const sourceTypes = source.types; 19594 // We strip `undefined` from the target if the `source` trivially doesn't contain it for our correspondence-checking fastpath 19595 // since `undefined` is frequently added by optionality and would otherwise spoil a potentially useful correspondence 19596 const undefinedStrippedTarget = getUndefinedStrippedTargetIfNeeded(source, target as UnionType); 19597 for (let i = 0; i < sourceTypes.length; i++) { 19598 const sourceType = sourceTypes[i]; 19599 if (undefinedStrippedTarget.flags & TypeFlags.Union && sourceTypes.length >= (undefinedStrippedTarget as UnionType).types.length && sourceTypes.length % (undefinedStrippedTarget as UnionType).types.length === 0) { 19600 // many unions are mappings of one another; in such cases, simply comparing members at the same index can shortcut the comparison 19601 // such unions will have identical lengths, and their corresponding elements will match up. Another common scenario is where a large 19602 // union has a union of objects intersected with it. In such cases, if the input was, eg `("a" | "b" | "c") & (string | boolean | {} | {whatever})`, 19603 // the result will have the structure `"a" | "b" | "c" | "a" & {} | "b" & {} | "c" & {} | "a" & {whatever} | "b" & {whatever} | "c" & {whatever}` 19604 // - the resulting union has a length which is a multiple of the original union, and the elements correspond modulo the length of the original union 19605 const related = isRelatedTo(sourceType, (undefinedStrippedTarget as UnionType).types[i % (undefinedStrippedTarget as UnionType).types.length], RecursionFlags.Both, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState); 19606 if (related) { 19607 result &= related; 19608 continue; 19609 } 19610 } 19611 const related = isRelatedTo(sourceType, target, RecursionFlags.Source, reportErrors, /*headMessage*/ undefined, intersectionState); 19612 if (!related) { 19613 return Ternary.False; 19614 } 19615 result &= related; 19616 } 19617 return result; 19618 } 19619 19620 function typeArgumentsRelatedTo(sources: readonly Type[] = emptyArray, targets: readonly Type[] = emptyArray, variances: readonly VarianceFlags[] = emptyArray, reportErrors: boolean, intersectionState: IntersectionState): Ternary { 19621 if (sources.length !== targets.length && relation === identityRelation) { 19622 return Ternary.False; 19623 } 19624 const length = sources.length <= targets.length ? sources.length : targets.length; 19625 let result = Ternary.True; 19626 for (let i = 0; i < length; i++) { 19627 // When variance information isn't available we default to covariance. This happens 19628 // in the process of computing variance information for recursive types and when 19629 // comparing 'this' type arguments. 19630 const varianceFlags = i < variances.length ? variances[i] : VarianceFlags.Covariant; 19631 const variance = varianceFlags & VarianceFlags.VarianceMask; 19632 // We ignore arguments for independent type parameters (because they're never witnessed). 19633 if (variance !== VarianceFlags.Independent) { 19634 const s = sources[i]; 19635 const t = targets[i]; 19636 let related = Ternary.True; 19637 if (varianceFlags & VarianceFlags.Unmeasurable) { 19638 // Even an `Unmeasurable` variance works out without a structural check if the source and target are _identical_. 19639 // We can't simply assume invariance, because `Unmeasurable` marks nonlinear relations, for example, a relation tained by 19640 // the `-?` modifier in a mapped type (where, no matter how the inputs are related, the outputs still might not be) 19641 related = relation === identityRelation ? isRelatedTo(s, t, RecursionFlags.Both, /*reportErrors*/ false) : compareTypesIdentical(s, t); 19642 } 19643 else if (variance === VarianceFlags.Covariant) { 19644 related = isRelatedTo(s, t, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); 19645 } 19646 else if (variance === VarianceFlags.Contravariant) { 19647 related = isRelatedTo(t, s, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); 19648 } 19649 else if (variance === VarianceFlags.Bivariant) { 19650 // In the bivariant case we first compare contravariantly without reporting 19651 // errors. Then, if that doesn't succeed, we compare covariantly with error 19652 // reporting. Thus, error elaboration will be based on the the covariant check, 19653 // which is generally easier to reason about. 19654 related = isRelatedTo(t, s, RecursionFlags.Both, /*reportErrors*/ false); 19655 if (!related) { 19656 related = isRelatedTo(s, t, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); 19657 } 19658 } 19659 else { 19660 // In the invariant case we first compare covariantly, and only when that 19661 // succeeds do we proceed to compare contravariantly. Thus, error elaboration 19662 // will typically be based on the covariant check. 19663 related = isRelatedTo(s, t, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); 19664 if (related) { 19665 related &= isRelatedTo(t, s, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); 19666 } 19667 } 19668 if (!related) { 19669 return Ternary.False; 19670 } 19671 result &= related; 19672 } 19673 } 19674 return result; 19675 } 19676 19677 // Determine if possibly recursive types are related. First, check if the result is already available in the global cache. 19678 // Second, check if we have already started a comparison of the given two types in which case we assume the result to be true. 19679 // Third, check if both types are part of deeply nested chains of generic type instantiations and if so assume the types are 19680 // equal and infinitely expanding. Fourth, if we have reached a depth of 100 nested comparisons, assume we have runaway recursion 19681 // and issue an error. Otherwise, actually compare the structure of the two types. 19682 function recursiveTypeRelatedTo(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState, recursionFlags: RecursionFlags): Ternary { 19683 if (overflow) { 19684 return Ternary.False; 19685 } 19686 const id = getRelationKey(source, target, intersectionState, relation, /*ingnoreConstraints*/ false); 19687 const entry = relation.get(id); 19688 if (entry !== undefined) { 19689 if (reportErrors && entry & RelationComparisonResult.Failed && !(entry & RelationComparisonResult.Reported)) { 19690 // We are elaborating errors and the cached result is an unreported failure. The result will be reported 19691 // as a failure, and should be updated as a reported failure by the bottom of this function. 19692 } 19693 else { 19694 if (outofbandVarianceMarkerHandler) { 19695 // We're in the middle of variance checking - integrate any unmeasurable/unreliable flags from this cached component 19696 const saved = entry & RelationComparisonResult.ReportsMask; 19697 if (saved & RelationComparisonResult.ReportsUnmeasurable) { 19698 instantiateType(source, reportUnmeasurableMapper); 19699 } 19700 if (saved & RelationComparisonResult.ReportsUnreliable) { 19701 instantiateType(source, reportUnreliableMapper); 19702 } 19703 } 19704 return entry & RelationComparisonResult.Succeeded ? Ternary.True : Ternary.False; 19705 } 19706 } 19707 if (!maybeKeys) { 19708 maybeKeys = []; 19709 sourceStack = []; 19710 targetStack = []; 19711 } 19712 else { 19713 // A key that starts with "*" is an indication that we have type references that reference constrained 19714 // type parameters. For such keys we also check against the key we would have gotten if all type parameters 19715 // were unconstrained. 19716 const broadestEquivalentId = id.startsWith("*") ? getRelationKey(source, target, intersectionState, relation, /*ignoreConstraints*/ true) : undefined; 19717 for (let i = 0; i < maybeCount; i++) { 19718 // If source and target are already being compared, consider them related with assumptions 19719 if (id === maybeKeys[i] || broadestEquivalentId && broadestEquivalentId === maybeKeys[i]) { 19720 return Ternary.Maybe; 19721 } 19722 } 19723 if (sourceDepth === 100 || targetDepth === 100) { 19724 overflow = true; 19725 return Ternary.False; 19726 } 19727 } 19728 const maybeStart = maybeCount; 19729 maybeKeys[maybeCount] = id; 19730 maybeCount++; 19731 const saveExpandingFlags = expandingFlags; 19732 if (recursionFlags & RecursionFlags.Source) { 19733 sourceStack[sourceDepth] = source; 19734 sourceDepth++; 19735 if (!(expandingFlags & ExpandingFlags.Source) && isDeeplyNestedType(source, sourceStack, sourceDepth)) expandingFlags |= ExpandingFlags.Source; 19736 } 19737 if (recursionFlags & RecursionFlags.Target) { 19738 targetStack[targetDepth] = target; 19739 targetDepth++; 19740 if (!(expandingFlags & ExpandingFlags.Target) && isDeeplyNestedType(target, targetStack, targetDepth)) expandingFlags |= ExpandingFlags.Target; 19741 } 19742 let originalHandler: typeof outofbandVarianceMarkerHandler; 19743 let propagatingVarianceFlags: RelationComparisonResult = 0; 19744 if (outofbandVarianceMarkerHandler) { 19745 originalHandler = outofbandVarianceMarkerHandler; 19746 outofbandVarianceMarkerHandler = onlyUnreliable => { 19747 propagatingVarianceFlags |= onlyUnreliable ? RelationComparisonResult.ReportsUnreliable : RelationComparisonResult.ReportsUnmeasurable; 19748 return originalHandler!(onlyUnreliable); 19749 }; 19750 } 19751 19752 let result: Ternary; 19753 if (expandingFlags === ExpandingFlags.Both) { 19754 tracing?.instant(tracing.Phase.CheckTypes, "recursiveTypeRelatedTo_DepthLimit", { 19755 sourceId: source.id, 19756 sourceIdStack: sourceStack.map(t => t.id), 19757 targetId: target.id, 19758 targetIdStack: targetStack.map(t => t.id), 19759 depth: sourceDepth, 19760 targetDepth 19761 }); 19762 result = Ternary.Maybe; 19763 } 19764 else { 19765 tracing?.push(tracing.Phase.CheckTypes, "structuredTypeRelatedTo", { sourceId: source.id, targetId: target.id }); 19766 result = structuredTypeRelatedTo(source, target, reportErrors, intersectionState); 19767 tracing?.pop(); 19768 } 19769 19770 if (outofbandVarianceMarkerHandler) { 19771 outofbandVarianceMarkerHandler = originalHandler; 19772 } 19773 if (recursionFlags & RecursionFlags.Source) { 19774 sourceDepth--; 19775 } 19776 if (recursionFlags & RecursionFlags.Target) { 19777 targetDepth--; 19778 } 19779 expandingFlags = saveExpandingFlags; 19780 if (result) { 19781 if (result === Ternary.True || (sourceDepth === 0 && targetDepth === 0)) { 19782 if (result === Ternary.True || result === Ternary.Maybe) { 19783 // If result is definitely true, record all maybe keys as having succeeded. Also, record Ternary.Maybe 19784 // results as having succeeded once we reach depth 0, but never record Ternary.Unknown results. 19785 for (let i = maybeStart; i < maybeCount; i++) { 19786 relation.set(maybeKeys[i], RelationComparisonResult.Succeeded | propagatingVarianceFlags); 19787 } 19788 } 19789 maybeCount = maybeStart; 19790 } 19791 } 19792 else { 19793 // A false result goes straight into global cache (when something is false under 19794 // assumptions it will also be false without assumptions) 19795 relation.set(id, (reportErrors ? RelationComparisonResult.Reported : 0) | RelationComparisonResult.Failed | propagatingVarianceFlags); 19796 maybeCount = maybeStart; 19797 } 19798 return result; 19799 } 19800 19801 function structuredTypeRelatedTo(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary { 19802 const saveErrorInfo = captureErrorCalculationState(); 19803 let result = structuredTypeRelatedToWorker(source, target, reportErrors, intersectionState, saveErrorInfo); 19804 if (relation !== identityRelation) { 19805 // The combined constraint of an intersection type is the intersection of the constraints of 19806 // the constituents. When an intersection type contains instantiable types with union type 19807 // constraints, there are situations where we need to examine the combined constraint. One is 19808 // when the target is a union type. Another is when the intersection contains types belonging 19809 // to one of the disjoint domains. For example, given type variables T and U, each with the 19810 // constraint 'string | number', the combined constraint of 'T & U' is 'string | number' and 19811 // we need to check this constraint against a union on the target side. Also, given a type 19812 // variable V constrained to 'string | number', 'V & number' has a combined constraint of 19813 // 'string & number | number & number' which reduces to just 'number'. 19814 // This also handles type parameters, as a type parameter with a union constraint compared against a union 19815 // needs to have its constraint hoisted into an intersection with said type parameter, this way 19816 // the type param can be compared with itself in the target (with the influence of its constraint to match other parts) 19817 // For example, if `T extends 1 | 2` and `U extends 2 | 3` and we compare `T & U` to `T & U & (1 | 2 | 3)` 19818 if (!result && (source.flags & TypeFlags.Intersection || source.flags & TypeFlags.TypeParameter && target.flags & TypeFlags.Union)) { 19819 const constraint = getEffectiveConstraintOfIntersection(source.flags & TypeFlags.Intersection ? (source as IntersectionType).types: [source], !!(target.flags & TypeFlags.Union)); 19820 if (constraint && everyType(constraint, c => c !== source)) { // Skip comparison if expansion contains the source itself 19821 // TODO: Stack errors so we get a pyramid for the "normal" comparison above, _and_ a second for this 19822 result = isRelatedTo(constraint, target, RecursionFlags.Source, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState); 19823 } 19824 } 19825 // For certain combinations involving intersections and optional, excess, or mismatched properties we need 19826 // an extra property check where the intersection is viewed as a single object. The following are motivating 19827 // examples that all should be errors, but aren't without this extra property check: 19828 // 19829 // let obj: { a: { x: string } } & { c: number } = { a: { x: 'hello', y: 2 }, c: 5 }; // Nested excess property 19830 // 19831 // declare let wrong: { a: { y: string } }; 19832 // let weak: { a?: { x?: number } } & { c?: string } = wrong; // Nested weak object type 19833 // 19834 // function foo<T extends object>(x: { a?: string }, y: T & { a: boolean }) { 19835 // x = y; // Mismatched property in source intersection 19836 // } 19837 // 19838 // We suppress recursive intersection property checks because they can generate lots of work when relating 19839 // recursive intersections that are structurally similar but not exactly identical. See #37854. 19840 if (result && !inPropertyCheck && ( 19841 target.flags & TypeFlags.Intersection && !isGenericObjectType(target) && source.flags & (TypeFlags.Object | TypeFlags.Intersection) || 19842 isNonGenericObjectType(target) && !isArrayOrTupleType(target) && source.flags & TypeFlags.Intersection && getApparentType(source).flags & TypeFlags.StructuredType && !some((source as IntersectionType).types, t => !!(getObjectFlags(t) & ObjectFlags.NonInferrableType)))) { 19843 inPropertyCheck = true; 19844 result &= propertiesRelatedTo(source, target, reportErrors, /*excludedProperties*/ undefined, IntersectionState.None); 19845 inPropertyCheck = false; 19846 } 19847 } 19848 if (result) { 19849 resetErrorInfo(saveErrorInfo); 19850 } 19851 return result; 19852 } 19853 19854 function structuredTypeRelatedToWorker(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState, saveErrorInfo: ReturnType<typeof captureErrorCalculationState>): Ternary { 19855 let result: Ternary; 19856 let originalErrorInfo: DiagnosticMessageChain | undefined; 19857 let varianceCheckFailed = false; 19858 let sourceFlags = source.flags; 19859 const targetFlags = target.flags; 19860 if (relation === identityRelation) { 19861 // We've already checked that source.flags and target.flags are identical 19862 if (sourceFlags & TypeFlags.UnionOrIntersection) { 19863 let result = eachTypeRelatedToSomeType(source as UnionOrIntersectionType, target as UnionOrIntersectionType); 19864 if (result) { 19865 result &= eachTypeRelatedToSomeType(target as UnionOrIntersectionType, source as UnionOrIntersectionType); 19866 } 19867 return result; 19868 } 19869 if (sourceFlags & TypeFlags.Index) { 19870 return isRelatedTo((source as IndexType).type, (target as IndexType).type, RecursionFlags.Both, /*reportErrors*/ false); 19871 } 19872 if (sourceFlags & TypeFlags.IndexedAccess) { 19873 if (result = isRelatedTo((source as IndexedAccessType).objectType, (target as IndexedAccessType).objectType, RecursionFlags.Both, /*reportErrors*/ false)) { 19874 if (result &= isRelatedTo((source as IndexedAccessType).indexType, (target as IndexedAccessType).indexType, RecursionFlags.Both, /*reportErrors*/ false)) { 19875 return result; 19876 } 19877 } 19878 } 19879 if (sourceFlags & TypeFlags.Conditional) { 19880 if ((source as ConditionalType).root.isDistributive === (target as ConditionalType).root.isDistributive) { 19881 if (result = isRelatedTo((source as ConditionalType).checkType, (target as ConditionalType).checkType, RecursionFlags.Both, /*reportErrors*/ false)) { 19882 if (result &= isRelatedTo((source as ConditionalType).extendsType, (target as ConditionalType).extendsType, RecursionFlags.Both, /*reportErrors*/ false)) { 19883 if (result &= isRelatedTo(getTrueTypeFromConditionalType(source as ConditionalType), getTrueTypeFromConditionalType(target as ConditionalType), RecursionFlags.Both, /*reportErrors*/ false)) { 19884 if (result &= isRelatedTo(getFalseTypeFromConditionalType(source as ConditionalType), getFalseTypeFromConditionalType(target as ConditionalType), RecursionFlags.Both, /*reportErrors*/ false)) { 19885 return result; 19886 } 19887 } 19888 } 19889 } 19890 } 19891 } 19892 if (sourceFlags & TypeFlags.Substitution) { 19893 if (result = isRelatedTo((source as SubstitutionType).baseType, (target as SubstitutionType).baseType, RecursionFlags.Both, /*reportErrors*/ false)) { 19894 if (result &= isRelatedTo((source as SubstitutionType).constraint, (target as SubstitutionType).constraint, RecursionFlags.Both, /*reportErrors*/ false)) { 19895 return result; 19896 } 19897 } 19898 } 19899 if (!(sourceFlags & TypeFlags.Object)) { 19900 return Ternary.False; 19901 } 19902 } 19903 else if (sourceFlags & TypeFlags.UnionOrIntersection || targetFlags & TypeFlags.UnionOrIntersection) { 19904 if (result = unionOrIntersectionRelatedTo(source, target, reportErrors, intersectionState)) { 19905 return result; 19906 } 19907 // The ordered decomposition above doesn't handle all cases. Specifically, we also need to handle: 19908 // Source is instantiable (e.g. source has union or intersection constraint). 19909 // Source is an object, target is a union (e.g. { a, b: boolean } <=> { a, b: true } | { a, b: false }). 19910 // Source is an intersection, target is an object (e.g. { a } & { b } <=> { a, b }). 19911 // Source is an intersection, target is a union (e.g. { a } & { b: boolean } <=> { a, b: true } | { a, b: false }). 19912 // Source is an intersection, target instantiable (e.g. string & { tag } <=> T["a"] constrained to string & { tag }). 19913 if (!(sourceFlags & TypeFlags.Instantiable || 19914 sourceFlags & TypeFlags.Object && targetFlags & TypeFlags.Union || 19915 sourceFlags & TypeFlags.Intersection && targetFlags & (TypeFlags.Object | TypeFlags.Union | TypeFlags.Instantiable))) { 19916 return Ternary.False; 19917 } 19918 } 19919 19920 // We limit alias variance probing to only object and conditional types since their alias behavior 19921 // is more predictable than other, interned types, which may or may not have an alias depending on 19922 // the order in which things were checked. 19923 if (sourceFlags & (TypeFlags.Object | TypeFlags.Conditional) && source.aliasSymbol && source.aliasTypeArguments && 19924 source.aliasSymbol === target.aliasSymbol && !(isMarkerType(source) || isMarkerType(target))) { 19925 const variances = getAliasVariances(source.aliasSymbol); 19926 if (variances === emptyArray) { 19927 return Ternary.Unknown; 19928 } 19929 const varianceResult = relateVariances(source.aliasTypeArguments, target.aliasTypeArguments, variances, intersectionState); 19930 if (varianceResult !== undefined) { 19931 return varianceResult; 19932 } 19933 } 19934 19935 // For a generic type T and a type U that is assignable to T, [...U] is assignable to T, U is assignable to readonly [...T], 19936 // and U is assignable to [...T] when U is constrained to a mutable array or tuple type. 19937 if (isSingleElementGenericTupleType(source) && !source.target.readonly && (result = isRelatedTo(getTypeArguments(source)[0], target, RecursionFlags.Source)) || 19938 isSingleElementGenericTupleType(target) && (target.target.readonly || isMutableArrayOrTuple(getBaseConstraintOfType(source) || source)) && (result = isRelatedTo(source, getTypeArguments(target)[0], RecursionFlags.Target))) { 19939 return result; 19940 } 19941 19942 if (targetFlags & TypeFlags.TypeParameter) { 19943 // A source type { [P in Q]: X } is related to a target type T if keyof T is related to Q and X is related to T[Q]. 19944 if (getObjectFlags(source) & ObjectFlags.Mapped && !(source as MappedType).declaration.nameType && isRelatedTo(getIndexType(target), getConstraintTypeFromMappedType(source as MappedType), RecursionFlags.Both)) { 19945 19946 if (!(getMappedTypeModifiers(source as MappedType) & MappedTypeModifiers.IncludeOptional)) { 19947 const templateType = getTemplateTypeFromMappedType(source as MappedType); 19948 const indexedAccessType = getIndexedAccessType(target, getTypeParameterFromMappedType(source as MappedType)); 19949 if (result = isRelatedTo(templateType, indexedAccessType, RecursionFlags.Both, reportErrors)) { 19950 return result; 19951 } 19952 } 19953 } 19954 if (relation === comparableRelation && sourceFlags & TypeFlags.TypeParameter) { 19955 // This is a carve-out in comparability to essentially forbid comparing a type parameter 19956 // with another type parameter unless one extends the other. (Remember: comparability is mostly bidirectional!) 19957 let constraint = getConstraintOfTypeParameter(source); 19958 if (constraint && hasNonCircularBaseConstraint(source)) { 19959 while (constraint && someType(constraint, c => !!(c.flags & TypeFlags.TypeParameter))) { 19960 if (result = isRelatedTo(constraint, target, RecursionFlags.Source, /*reportErrors*/ false)) { 19961 return result; 19962 } 19963 constraint = getConstraintOfTypeParameter(constraint); 19964 } 19965 } 19966 return Ternary.False; 19967 } 19968 } 19969 else if (targetFlags & TypeFlags.Index) { 19970 const targetType = (target as IndexType).type; 19971 // A keyof S is related to a keyof T if T is related to S. 19972 if (sourceFlags & TypeFlags.Index) { 19973 if (result = isRelatedTo(targetType, (source as IndexType).type, RecursionFlags.Both, /*reportErrors*/ false)) { 19974 return result; 19975 } 19976 } 19977 if (isTupleType(targetType)) { 19978 // An index type can have a tuple type target when the tuple type contains variadic elements. 19979 // Check if the source is related to the known keys of the tuple type. 19980 if (result = isRelatedTo(source, getKnownKeysOfTupleType(targetType), RecursionFlags.Target, reportErrors)) { 19981 return result; 19982 } 19983 } 19984 else { 19985 // A type S is assignable to keyof T if S is assignable to keyof C, where C is the 19986 // simplified form of T or, if T doesn't simplify, the constraint of T. 19987 const constraint = getSimplifiedTypeOrConstraint(targetType); 19988 if (constraint) { 19989 // We require Ternary.True here such that circular constraints don't cause 19990 // false positives. For example, given 'T extends { [K in keyof T]: string }', 19991 // 'keyof T' has itself as its constraint and produces a Ternary.Maybe when 19992 // related to other types. 19993 if (isRelatedTo(source, getIndexType(constraint, (target as IndexType).stringsOnly), RecursionFlags.Target, reportErrors) === Ternary.True) { 19994 return Ternary.True; 19995 } 19996 } 19997 else if (isGenericMappedType(targetType)) { 19998 // generic mapped types that don't simplify or have a constraint still have a very simple set of keys we can compare against 19999 // - their nameType or constraintType. 20000 // In many ways, this comparison is a deferred version of what `getIndexTypeForMappedType` does to actually resolve the keys for _non_-generic types 20001 20002 const nameType = getNameTypeFromMappedType(targetType); 20003 const constraintType = getConstraintTypeFromMappedType(targetType); 20004 let targetKeys; 20005 if (nameType && isMappedTypeWithKeyofConstraintDeclaration(targetType)) { 20006 // we need to get the apparent mappings and union them with the generic mappings, since some properties may be 20007 // missing from the `constraintType` which will otherwise be mapped in the object 20008 const modifiersType = getApparentType(getModifiersTypeFromMappedType(targetType)); 20009 const mappedKeys: Type[] = []; 20010 forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType( 20011 modifiersType, 20012 TypeFlags.StringOrNumberLiteralOrUnique, 20013 /*stringsOnly*/ false, 20014 t => void mappedKeys.push(instantiateType(nameType, appendTypeMapping(targetType.mapper, getTypeParameterFromMappedType(targetType), t))) 20015 ); 20016 // We still need to include the non-apparent (and thus still generic) keys in the target side of the comparison (in case they're in the source side) 20017 targetKeys = getUnionType([...mappedKeys, nameType]); 20018 } 20019 else { 20020 targetKeys = nameType || constraintType; 20021 } 20022 if (isRelatedTo(source, targetKeys, RecursionFlags.Target, reportErrors) === Ternary.True) { 20023 return Ternary.True; 20024 } 20025 } 20026 } 20027 } 20028 else if (targetFlags & TypeFlags.IndexedAccess) { 20029 if (sourceFlags & TypeFlags.IndexedAccess) { 20030 // Relate components directly before falling back to constraint relationships 20031 // A type S[K] is related to a type T[J] if S is related to T and K is related to J. 20032 if (result = isRelatedTo((source as IndexedAccessType).objectType, (target as IndexedAccessType).objectType, RecursionFlags.Both, reportErrors)) { 20033 result &= isRelatedTo((source as IndexedAccessType).indexType, (target as IndexedAccessType).indexType, RecursionFlags.Both, reportErrors); 20034 } 20035 if (result) { 20036 return result; 20037 } 20038 if (reportErrors) { 20039 originalErrorInfo = errorInfo; 20040 } 20041 } 20042 // A type S is related to a type T[K] if S is related to C, where C is the base 20043 // constraint of T[K] for writing. 20044 if (relation === assignableRelation || relation === comparableRelation) { 20045 const objectType = (target as IndexedAccessType).objectType; 20046 const indexType = (target as IndexedAccessType).indexType; 20047 const baseObjectType = getBaseConstraintOfType(objectType) || objectType; 20048 const baseIndexType = getBaseConstraintOfType(indexType) || indexType; 20049 if (!isGenericObjectType(baseObjectType) && !isGenericIndexType(baseIndexType)) { 20050 const accessFlags = AccessFlags.Writing | (baseObjectType !== objectType ? AccessFlags.NoIndexSignatures : 0); 20051 const constraint = getIndexedAccessTypeOrUndefined(baseObjectType, baseIndexType, accessFlags); 20052 if (constraint) { 20053 if (reportErrors && originalErrorInfo) { 20054 // create a new chain for the constraint error 20055 resetErrorInfo(saveErrorInfo); 20056 } 20057 if (result = isRelatedTo(source, constraint, RecursionFlags.Target, reportErrors, /* headMessage */ undefined, intersectionState)) { 20058 return result; 20059 } 20060 // prefer the shorter chain of the constraint comparison chain, and the direct comparison chain 20061 if (reportErrors && originalErrorInfo && errorInfo) { 20062 errorInfo = countMessageChainBreadth([originalErrorInfo]) <= countMessageChainBreadth([errorInfo]) ? originalErrorInfo : errorInfo; 20063 } 20064 } 20065 } 20066 } 20067 if (reportErrors) { 20068 originalErrorInfo = undefined; 20069 } 20070 } 20071 else if (isGenericMappedType(target) && relation !== identityRelation) { 20072 // Check if source type `S` is related to target type `{ [P in Q]: T }` or `{ [P in Q as R]: T}`. 20073 const keysRemapped = !!target.declaration.nameType; 20074 const templateType = getTemplateTypeFromMappedType(target); 20075 const modifiers = getMappedTypeModifiers(target); 20076 if (!(modifiers & MappedTypeModifiers.ExcludeOptional)) { 20077 // If the mapped type has shape `{ [P in Q]: T[P] }`, 20078 // source `S` is related to target if `T` = `S`, i.e. `S` is related to `{ [P in Q]: S[P] }`. 20079 if (!keysRemapped && templateType.flags & TypeFlags.IndexedAccess && (templateType as IndexedAccessType).objectType === source && 20080 (templateType as IndexedAccessType).indexType === getTypeParameterFromMappedType(target)) { 20081 return Ternary.True; 20082 } 20083 if (!isGenericMappedType(source)) { 20084 // If target has shape `{ [P in Q as R]: T}`, then its keys have type `R`. 20085 // If target has shape `{ [P in Q]: T }`, then its keys have type `Q`. 20086 const targetKeys = keysRemapped ? getNameTypeFromMappedType(target)! : getConstraintTypeFromMappedType(target); 20087 // Type of the keys of source type `S`, i.e. `keyof S`. 20088 const sourceKeys = getIndexType(source, /*stringsOnly*/ undefined, /*noIndexSignatures*/ true); 20089 const includeOptional = modifiers & MappedTypeModifiers.IncludeOptional; 20090 const filteredByApplicability = includeOptional ? intersectTypes(targetKeys, sourceKeys) : undefined; 20091 // A source type `S` is related to a target type `{ [P in Q]: T }` if `Q` is related to `keyof S` and `S[Q]` is related to `T`. 20092 // A source type `S` is related to a target type `{ [P in Q as R]: T }` if `R` is related to `keyof S` and `S[R]` is related to `T. 20093 // A source type `S` is related to a target type `{ [P in Q]?: T }` if some constituent `Q'` of `Q` is related to `keyof S` and `S[Q']` is related to `T`. 20094 // A source type `S` is related to a target type `{ [P in Q as R]?: T }` if some constituent `R'` of `R` is related to `keyof S` and `S[R']` is related to `T`. 20095 if (includeOptional 20096 ? !(filteredByApplicability!.flags & TypeFlags.Never) 20097 : isRelatedTo(targetKeys, sourceKeys, RecursionFlags.Both)) { 20098 const templateType = getTemplateTypeFromMappedType(target); 20099 const typeParameter = getTypeParameterFromMappedType(target); 20100 20101 // Fastpath: When the template type has the form `Obj[P]` where `P` is the mapped type parameter, directly compare source `S` with `Obj` 20102 // to avoid creating the (potentially very large) number of new intermediate types made by manufacturing `S[P]`. 20103 const nonNullComponent = extractTypesOfKind(templateType, ~TypeFlags.Nullable); 20104 if (!keysRemapped && nonNullComponent.flags & TypeFlags.IndexedAccess && (nonNullComponent as IndexedAccessType).indexType === typeParameter) { 20105 if (result = isRelatedTo(source, (nonNullComponent as IndexedAccessType).objectType, RecursionFlags.Target, reportErrors)) { 20106 return result; 20107 } 20108 } 20109 else { 20110 // We need to compare the type of a property on the source type `S` to the type of the same property on the target type, 20111 // so we need to construct an indexing type representing a property, and then use indexing type to index the source type for comparison. 20112 20113 // If the target type has shape `{ [P in Q]: T }`, then a property of the target has type `P`. 20114 // If the target type has shape `{ [P in Q]?: T }`, then a property of the target has type `P`, 20115 // but the property is optional, so we only want to compare properties `P` that are common between `keyof S` and `Q`. 20116 // If the target type has shape `{ [P in Q as R]: T }`, then a property of the target has type `R`. 20117 // If the target type has shape `{ [P in Q as R]?: T }`, then a property of the target has type `R`, 20118 // but the property is optional, so we only want to compare properties `R` that are common between `keyof S` and `R`. 20119 const indexingType = keysRemapped 20120 ? (filteredByApplicability || targetKeys) 20121 : filteredByApplicability 20122 ? getIntersectionType([filteredByApplicability, typeParameter]) 20123 : typeParameter; 20124 const indexedAccessType = getIndexedAccessType(source, indexingType); 20125 // Compare `S[indexingType]` to `T`, where `T` is the type of a property of the target type. 20126 if (result = isRelatedTo(indexedAccessType, templateType, RecursionFlags.Both, reportErrors)) { 20127 return result; 20128 } 20129 } 20130 } 20131 originalErrorInfo = errorInfo; 20132 resetErrorInfo(saveErrorInfo); 20133 } 20134 } 20135 } 20136 else if (targetFlags & TypeFlags.Conditional) { 20137 // If we reach 10 levels of nesting for the same conditional type, assume it is an infinitely expanding recursive 20138 // conditional type and bail out with a Ternary.Maybe result. 20139 if (isDeeplyNestedType(target, targetStack, targetDepth, 10)) { 20140 return Ternary.Maybe; 20141 } 20142 const c = target as ConditionalType; 20143 // We check for a relationship to a conditional type target only when the conditional type has no 20144 // 'infer' positions and is not distributive or is distributive but doesn't reference the check type 20145 // parameter in either of the result types. 20146 if (!c.root.inferTypeParameters && !isDistributionDependent(c.root)) { 20147 // Check if the conditional is always true or always false but still deferred for distribution purposes. 20148 const skipTrue = !isTypeAssignableTo(getPermissiveInstantiation(c.checkType), getPermissiveInstantiation(c.extendsType)); 20149 const skipFalse = !skipTrue && isTypeAssignableTo(getRestrictiveInstantiation(c.checkType), getRestrictiveInstantiation(c.extendsType)); 20150 // TODO: Find a nice way to include potential conditional type breakdowns in error output, if they seem good (they usually don't) 20151 if (result = skipTrue ? Ternary.True : isRelatedTo(source, getTrueTypeFromConditionalType(c), RecursionFlags.Target, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState)) { 20152 result &= skipFalse ? Ternary.True : isRelatedTo(source, getFalseTypeFromConditionalType(c), RecursionFlags.Target, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState); 20153 if (result) { 20154 return result; 20155 } 20156 } 20157 } 20158 } 20159 else if (targetFlags & TypeFlags.TemplateLiteral) { 20160 if (sourceFlags & TypeFlags.TemplateLiteral) { 20161 if (relation === comparableRelation) { 20162 return templateLiteralTypesDefinitelyUnrelated(source as TemplateLiteralType, target as TemplateLiteralType) ? Ternary.False : Ternary.True; 20163 } 20164 // Report unreliable variance for type variables referenced in template literal type placeholders. 20165 // For example, `foo-${number}` is related to `foo-${string}` even though number isn't related to string. 20166 instantiateType(source, reportUnreliableMapper); 20167 } 20168 if (isTypeMatchedByTemplateLiteralType(source, target as TemplateLiteralType)) { 20169 return Ternary.True; 20170 } 20171 } 20172 else if (target.flags & TypeFlags.StringMapping) { 20173 if (!(source.flags & TypeFlags.StringMapping)) { 20174 if (isMemberOfStringMapping(source, target)) { 20175 return Ternary.True; 20176 } 20177 } 20178 } 20179 20180 if (sourceFlags & TypeFlags.TypeVariable) { 20181 // IndexedAccess comparisons are handled above in the `targetFlags & TypeFlage.IndexedAccess` branch 20182 if (!(sourceFlags & TypeFlags.IndexedAccess && targetFlags & TypeFlags.IndexedAccess)) { 20183 const constraint = getConstraintOfType(source as TypeVariable) || unknownType; 20184 // hi-speed no-this-instantiation check (less accurate, but avoids costly `this`-instantiation when the constraint will suffice), see #28231 for report on why this is needed 20185 if (result = isRelatedTo(constraint, target, RecursionFlags.Source, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState)) { 20186 return result; 20187 } 20188 // slower, fuller, this-instantiated check (necessary when comparing raw `this` types from base classes), see `subclassWithPolymorphicThisIsAssignable.ts` test for example 20189 else if (result = isRelatedTo(getTypeWithThisArgument(constraint, source), target, RecursionFlags.Source, reportErrors && constraint !== unknownType && !(targetFlags & sourceFlags & TypeFlags.TypeParameter), /*headMessage*/ undefined, intersectionState)) { 20190 return result; 20191 } 20192 if (isMappedTypeGenericIndexedAccess(source)) { 20193 // For an indexed access type { [P in K]: E}[X], above we have already explored an instantiation of E with X 20194 // substituted for P. We also want to explore type { [P in K]: E }[C], where C is the constraint of X. 20195 const indexConstraint = getConstraintOfType((source as IndexedAccessType).indexType); 20196 if (indexConstraint) { 20197 if (result = isRelatedTo(getIndexedAccessType((source as IndexedAccessType).objectType, indexConstraint), target, RecursionFlags.Source, reportErrors)) { 20198 return result; 20199 } 20200 } 20201 } 20202 } 20203 } 20204 else if (sourceFlags & TypeFlags.Index) { 20205 if (result = isRelatedTo(keyofConstraintType, target, RecursionFlags.Source, reportErrors)) { 20206 return result; 20207 } 20208 } 20209 else if (sourceFlags & TypeFlags.TemplateLiteral && !(targetFlags & TypeFlags.Object)) { 20210 if (!(targetFlags & TypeFlags.TemplateLiteral)) { 20211 const constraint = getBaseConstraintOfType(source); 20212 if (constraint && constraint !== source && (result = isRelatedTo(constraint, target, RecursionFlags.Source, reportErrors))) { 20213 return result; 20214 } 20215 } 20216 } 20217 else if (sourceFlags & TypeFlags.StringMapping) { 20218 if (targetFlags & TypeFlags.StringMapping) { 20219 if ((source as StringMappingType).symbol !== (target as StringMappingType).symbol) { 20220 return Ternary.False; 20221 } 20222 if (result = isRelatedTo((source as StringMappingType).type, (target as StringMappingType).type, RecursionFlags.Both, reportErrors)) { 20223 return result; 20224 } 20225 } 20226 else { 20227 const constraint = getBaseConstraintOfType(source); 20228 if (constraint && (result = isRelatedTo(constraint, target, RecursionFlags.Source, reportErrors))) { 20229 return result; 20230 } 20231 } 20232 } 20233 else if (sourceFlags & TypeFlags.Conditional) { 20234 // If we reach 10 levels of nesting for the same conditional type, assume it is an infinitely expanding recursive 20235 // conditional type and bail out with a Ternary.Maybe result. 20236 if (isDeeplyNestedType(source, sourceStack, sourceDepth, 10)) { 20237 return Ternary.Maybe; 20238 } 20239 if (targetFlags & TypeFlags.Conditional) { 20240 // Two conditional types 'T1 extends U1 ? X1 : Y1' and 'T2 extends U2 ? X2 : Y2' are related if 20241 // one of T1 and T2 is related to the other, U1 and U2 are identical types, X1 is related to X2, 20242 // and Y1 is related to Y2. 20243 const sourceParams = (source as ConditionalType).root.inferTypeParameters; 20244 let sourceExtends = (source as ConditionalType).extendsType; 20245 let mapper: TypeMapper | undefined; 20246 if (sourceParams) { 20247 // If the source has infer type parameters, we instantiate them in the context of the target 20248 const ctx = createInferenceContext(sourceParams, /*signature*/ undefined, InferenceFlags.None, isRelatedToWorker); 20249 inferTypes(ctx.inferences, (target as ConditionalType).extendsType, sourceExtends, InferencePriority.NoConstraints | InferencePriority.AlwaysStrict); 20250 sourceExtends = instantiateType(sourceExtends, ctx.mapper); 20251 mapper = ctx.mapper; 20252 } 20253 if (isTypeIdenticalTo(sourceExtends, (target as ConditionalType).extendsType) && 20254 (isRelatedTo((source as ConditionalType).checkType, (target as ConditionalType).checkType, RecursionFlags.Both) || isRelatedTo((target as ConditionalType).checkType, (source as ConditionalType).checkType, RecursionFlags.Both))) { 20255 if (result = isRelatedTo(instantiateType(getTrueTypeFromConditionalType(source as ConditionalType), mapper), getTrueTypeFromConditionalType(target as ConditionalType), RecursionFlags.Both, reportErrors)) { 20256 result &= isRelatedTo(getFalseTypeFromConditionalType(source as ConditionalType), getFalseTypeFromConditionalType(target as ConditionalType), RecursionFlags.Both, reportErrors); 20257 } 20258 if (result) { 20259 return result; 20260 } 20261 } 20262 } 20263 else { 20264 // conditionals aren't related to one another via distributive constraint as it is much too inaccurate and allows way 20265 // more assignments than are desirable (since it maps the source check type to its constraint, it loses information) 20266 const distributiveConstraint = hasNonCircularBaseConstraint(source) ? getConstraintOfDistributiveConditionalType(source as ConditionalType) : undefined; 20267 if (distributiveConstraint) { 20268 if (result = isRelatedTo(distributiveConstraint, target, RecursionFlags.Source, reportErrors)) { 20269 return result; 20270 } 20271 } 20272 } 20273 20274 // conditionals _can_ be related to one another via normal constraint, as, eg, `A extends B ? O : never` should be assignable to `O` 20275 // when `O` is a conditional (`never` is trivially assignable to `O`, as is `O`!). 20276 const defaultConstraint = getDefaultConstraintOfConditionalType(source as ConditionalType); 20277 if (defaultConstraint) { 20278 if (result = isRelatedTo(defaultConstraint, target, RecursionFlags.Source, reportErrors)) { 20279 return result; 20280 } 20281 } 20282 } 20283 else { 20284 // An empty object type is related to any mapped type that includes a '?' modifier. 20285 if (relation !== subtypeRelation && relation !== strictSubtypeRelation && isPartialMappedType(target) && isEmptyObjectType(source)) { 20286 return Ternary.True; 20287 } 20288 if (isGenericMappedType(target)) { 20289 if (isGenericMappedType(source)) { 20290 if (result = mappedTypeRelatedTo(source, target, reportErrors)) { 20291 return result; 20292 } 20293 } 20294 return Ternary.False; 20295 } 20296 const sourceIsPrimitive = !!(sourceFlags & TypeFlags.Primitive); 20297 if (relation !== identityRelation) { 20298 source = getApparentType(source); 20299 sourceFlags = source.flags; 20300 } 20301 else if (isGenericMappedType(source)) { 20302 return Ternary.False; 20303 } 20304 if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source as TypeReference).target === (target as TypeReference).target && 20305 !isTupleType(source) && !(isMarkerType(source) || isMarkerType(target))) { 20306 // When strictNullChecks is disabled, the element type of the empty array literal is undefinedWideningType, 20307 // and an empty array literal wouldn't be assignable to a `never[]` without this check. 20308 if (isEmptyArrayLiteralType(source)) { 20309 return Ternary.True; 20310 } 20311 // We have type references to the same generic type, and the type references are not marker 20312 // type references (which are intended by be compared structurally). Obtain the variance 20313 // information for the type parameters and relate the type arguments accordingly. 20314 const variances = getVariances((source as TypeReference).target); 20315 // We return Ternary.Maybe for a recursive invocation of getVariances (signalled by emptyArray). This 20316 // effectively means we measure variance only from type parameter occurrences that aren't nested in 20317 // recursive instantiations of the generic type. 20318 if (variances === emptyArray) { 20319 return Ternary.Unknown; 20320 } 20321 const varianceResult = relateVariances(getTypeArguments(source as TypeReference), getTypeArguments(target as TypeReference), variances, intersectionState); 20322 if (varianceResult !== undefined) { 20323 return varianceResult; 20324 } 20325 } 20326 else if (isReadonlyArrayType(target) ? isArrayOrTupleType(source) : isArrayType(target) && isTupleType(source) && !source.target.readonly) { 20327 if (relation !== identityRelation) { 20328 return isRelatedTo(getIndexTypeOfType(source, numberType) || anyType, getIndexTypeOfType(target, numberType) || anyType, RecursionFlags.Both, reportErrors); 20329 } 20330 else { 20331 // By flags alone, we know that the `target` is a readonly array while the source is a normal array or tuple 20332 // or `target` is an array and source is a tuple - in both cases the types cannot be identical, by construction 20333 return Ternary.False; 20334 } 20335 } 20336 // Consider a fresh empty object literal type "closed" under the subtype relationship - this way `{} <- {[idx: string]: any} <- fresh({})` 20337 // and not `{} <- fresh({}) <- {[idx: string]: any}` 20338 else if ((relation === subtypeRelation || relation === strictSubtypeRelation) && isEmptyObjectType(target) && getObjectFlags(target) & ObjectFlags.FreshLiteral && !isEmptyObjectType(source)) { 20339 return Ternary.False; 20340 } 20341 // Even if relationship doesn't hold for unions, intersections, or generic type references, 20342 // it may hold in a structural comparison. 20343 // In a check of the form X = A & B, we will have previously checked if A relates to X or B relates 20344 // to X. Failing both of those we want to check if the aggregation of A and B's members structurally 20345 // relates to X. Thus, we include intersection types on the source side here. 20346 if (sourceFlags & (TypeFlags.Object | TypeFlags.Intersection) && targetFlags & TypeFlags.Object) { 20347 // Report structural errors only if we haven't reported any errors yet 20348 const reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo.errorInfo && !sourceIsPrimitive; 20349 result = propertiesRelatedTo(source, target, reportStructuralErrors, /*excludedProperties*/ undefined, intersectionState); 20350 if (result) { 20351 result &= signaturesRelatedTo(source, target, SignatureKind.Call, reportStructuralErrors); 20352 if (result) { 20353 result &= signaturesRelatedTo(source, target, SignatureKind.Construct, reportStructuralErrors); 20354 if (result) { 20355 result &= indexSignaturesRelatedTo(source, target, sourceIsPrimitive, reportStructuralErrors, intersectionState); 20356 } 20357 } 20358 } 20359 if (varianceCheckFailed && result) { 20360 errorInfo = originalErrorInfo || errorInfo || saveErrorInfo.errorInfo; // Use variance error (there is no structural one) and return false 20361 } 20362 else if (result) { 20363 return result; 20364 } 20365 } 20366 // If S is an object type and T is a discriminated union, S may be related to T if 20367 // there exists a constituent of T for every combination of the discriminants of S 20368 // with respect to T. We do not report errors here, as we will use the existing 20369 // error result from checking each constituent of the union. 20370 if (sourceFlags & (TypeFlags.Object | TypeFlags.Intersection) && targetFlags & TypeFlags.Union) { 20371 const objectOnlyTarget = extractTypesOfKind(target, TypeFlags.Object | TypeFlags.Intersection | TypeFlags.Substitution); 20372 if (objectOnlyTarget.flags & TypeFlags.Union) { 20373 const result = typeRelatedToDiscriminatedType(source, objectOnlyTarget as UnionType); 20374 if (result) { 20375 return result; 20376 } 20377 } 20378 } 20379 } 20380 return Ternary.False; 20381 20382 function countMessageChainBreadth(info: DiagnosticMessageChain[] | undefined): number { 20383 if (!info) return 0; 20384 return reduceLeft(info, (value, chain) => value + 1 + countMessageChainBreadth(chain.next), 0); 20385 } 20386 20387 function relateVariances(sourceTypeArguments: readonly Type[] | undefined, targetTypeArguments: readonly Type[] | undefined, variances: VarianceFlags[], intersectionState: IntersectionState) { 20388 if (result = typeArgumentsRelatedTo(sourceTypeArguments, targetTypeArguments, variances, reportErrors, intersectionState)) { 20389 return result; 20390 } 20391 if (some(variances, v => !!(v & VarianceFlags.AllowsStructuralFallback))) { 20392 // If some type parameter was `Unmeasurable` or `Unreliable`, and we couldn't pass by assuming it was identical, then we 20393 // have to allow a structural fallback check 20394 // We elide the variance-based error elaborations, since those might not be too helpful, since we'll potentially 20395 // be assuming identity of the type parameter. 20396 originalErrorInfo = undefined; 20397 resetErrorInfo(saveErrorInfo); 20398 return undefined; 20399 } 20400 const allowStructuralFallback = targetTypeArguments && hasCovariantVoidArgument(targetTypeArguments, variances); 20401 varianceCheckFailed = !allowStructuralFallback; 20402 // The type arguments did not relate appropriately, but it may be because we have no variance 20403 // information (in which case typeArgumentsRelatedTo defaulted to covariance for all type 20404 // arguments). It might also be the case that the target type has a 'void' type argument for 20405 // a covariant type parameter that is only used in return positions within the generic type 20406 // (in which case any type argument is permitted on the source side). In those cases we proceed 20407 // with a structural comparison. Otherwise, we know for certain the instantiations aren't 20408 // related and we can return here. 20409 if (variances !== emptyArray && !allowStructuralFallback) { 20410 // In some cases generic types that are covariant in regular type checking mode become 20411 // invariant in --strictFunctionTypes mode because one or more type parameters are used in 20412 // both co- and contravariant positions. In order to make it easier to diagnose *why* such 20413 // types are invariant, if any of the type parameters are invariant we reset the reported 20414 // errors and instead force a structural comparison (which will include elaborations that 20415 // reveal the reason). 20416 // We can switch on `reportErrors` here, since varianceCheckFailed guarantees we return `False`, 20417 // we can return `False` early here to skip calculating the structural error message we don't need. 20418 if (varianceCheckFailed && !(reportErrors && some(variances, v => (v & VarianceFlags.VarianceMask) === VarianceFlags.Invariant))) { 20419 return Ternary.False; 20420 } 20421 // We remember the original error information so we can restore it in case the structural 20422 // comparison unexpectedly succeeds. This can happen when the structural comparison result 20423 // is a Ternary.Maybe for example caused by the recursion depth limiter. 20424 originalErrorInfo = errorInfo; 20425 resetErrorInfo(saveErrorInfo); 20426 } 20427 } 20428 } 20429 20430 // A type [P in S]: X is related to a type [Q in T]: Y if T is related to S and X' is 20431 // related to Y, where X' is an instantiation of X in which P is replaced with Q. Notice 20432 // that S and T are contra-variant whereas X and Y are co-variant. 20433 function mappedTypeRelatedTo(source: MappedType, target: MappedType, reportErrors: boolean): Ternary { 20434 const modifiersRelated = relation === comparableRelation || (relation === identityRelation ? getMappedTypeModifiers(source) === getMappedTypeModifiers(target) : 20435 getCombinedMappedTypeOptionality(source) <= getCombinedMappedTypeOptionality(target)); 20436 if (modifiersRelated) { 20437 let result: Ternary; 20438 const targetConstraint = getConstraintTypeFromMappedType(target); 20439 const sourceConstraint = instantiateType(getConstraintTypeFromMappedType(source), getCombinedMappedTypeOptionality(source) < 0 ? reportUnmeasurableMapper : reportUnreliableMapper); 20440 if (result = isRelatedTo(targetConstraint, sourceConstraint, RecursionFlags.Both, reportErrors)) { 20441 const mapper = createTypeMapper([getTypeParameterFromMappedType(source)], [getTypeParameterFromMappedType(target)]); 20442 if (instantiateType(getNameTypeFromMappedType(source), mapper) === instantiateType(getNameTypeFromMappedType(target), mapper)) { 20443 return result & isRelatedTo(instantiateType(getTemplateTypeFromMappedType(source), mapper), getTemplateTypeFromMappedType(target), RecursionFlags.Both, reportErrors); 20444 } 20445 } 20446 } 20447 return Ternary.False; 20448 } 20449 20450 function typeRelatedToDiscriminatedType(source: Type, target: UnionType) { 20451 // 1. Generate the combinations of discriminant properties & types 'source' can satisfy. 20452 // a. If the number of combinations is above a set limit, the comparison is too complex. 20453 // 2. Filter 'target' to the subset of types whose discriminants exist in the matrix. 20454 // a. If 'target' does not satisfy all discriminants in the matrix, 'source' is not related. 20455 // 3. For each type in the filtered 'target', determine if all non-discriminant properties of 20456 // 'target' are related to a property in 'source'. 20457 // 20458 // NOTE: See ~/tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithDiscriminatedUnion.ts 20459 // for examples. 20460 20461 const sourceProperties = getPropertiesOfType(source); 20462 const sourcePropertiesFiltered = findDiscriminantProperties(sourceProperties, target); 20463 if (!sourcePropertiesFiltered) return Ternary.False; 20464 20465 // Though we could compute the number of combinations as we generate 20466 // the matrix, this would incur additional memory overhead due to 20467 // array allocations. To reduce this overhead, we first compute 20468 // the number of combinations to ensure we will not surpass our 20469 // fixed limit before incurring the cost of any allocations: 20470 let numCombinations = 1; 20471 for (const sourceProperty of sourcePropertiesFiltered) { 20472 numCombinations *= countTypes(getNonMissingTypeOfSymbol(sourceProperty)); 20473 if (numCombinations > 25) { 20474 // We've reached the complexity limit. 20475 tracing?.instant(tracing.Phase.CheckTypes, "typeRelatedToDiscriminatedType_DepthLimit", { sourceId: source.id, targetId: target.id, numCombinations }); 20476 return Ternary.False; 20477 } 20478 } 20479 20480 // Compute the set of types for each discriminant property. 20481 const sourceDiscriminantTypes: Type[][] = new Array<Type[]>(sourcePropertiesFiltered.length); 20482 const excludedProperties = new Set<__String>(); 20483 for (let i = 0; i < sourcePropertiesFiltered.length; i++) { 20484 const sourceProperty = sourcePropertiesFiltered[i]; 20485 const sourcePropertyType = getNonMissingTypeOfSymbol(sourceProperty); 20486 sourceDiscriminantTypes[i] = sourcePropertyType.flags & TypeFlags.Union 20487 ? (sourcePropertyType as UnionType).types 20488 : [sourcePropertyType]; 20489 excludedProperties.add(sourceProperty.escapedName); 20490 } 20491 20492 // Match each combination of the cartesian product of discriminant properties to one or more 20493 // constituents of 'target'. If any combination does not have a match then 'source' is not relatable. 20494 const discriminantCombinations = cartesianProduct(sourceDiscriminantTypes); 20495 const matchingTypes: Type[] = []; 20496 for (const combination of discriminantCombinations) { 20497 let hasMatch = false; 20498 outer: for (const type of target.types) { 20499 for (let i = 0; i < sourcePropertiesFiltered.length; i++) { 20500 const sourceProperty = sourcePropertiesFiltered[i]; 20501 const targetProperty = getPropertyOfType(type, sourceProperty.escapedName); 20502 if (!targetProperty) continue outer; 20503 if (sourceProperty === targetProperty) continue; 20504 // We compare the source property to the target in the context of a single discriminant type. 20505 const related = propertyRelatedTo(source, target, sourceProperty, targetProperty, _ => combination[i], /*reportErrors*/ false, IntersectionState.None, /*skipOptional*/ strictNullChecks || relation === comparableRelation); 20506 // If the target property could not be found, or if the properties were not related, 20507 // then this constituent is not a match. 20508 if (!related) { 20509 continue outer; 20510 } 20511 } 20512 pushIfUnique(matchingTypes, type, equateValues); 20513 hasMatch = true; 20514 } 20515 if (!hasMatch) { 20516 // We failed to match any type for this combination. 20517 return Ternary.False; 20518 } 20519 } 20520 20521 // Compare the remaining non-discriminant properties of each match. 20522 let result = Ternary.True; 20523 for (const type of matchingTypes) { 20524 result &= propertiesRelatedTo(source, type, /*reportErrors*/ false, excludedProperties, IntersectionState.None); 20525 if (result) { 20526 result &= signaturesRelatedTo(source, type, SignatureKind.Call, /*reportStructuralErrors*/ false); 20527 if (result) { 20528 result &= signaturesRelatedTo(source, type, SignatureKind.Construct, /*reportStructuralErrors*/ false); 20529 if (result && !(isTupleType(source) && isTupleType(type))) { 20530 // Comparing numeric index types when both `source` and `type` are tuples is unnecessary as the 20531 // element types should be sufficiently covered by `propertiesRelatedTo`. It also causes problems 20532 // with index type assignability as the types for the excluded discriminants are still included 20533 // in the index type. 20534 result &= indexSignaturesRelatedTo(source, type, /*sourceIsPrimitive*/ false, /*reportStructuralErrors*/ false, IntersectionState.None); 20535 } 20536 } 20537 } 20538 if (!result) { 20539 return result; 20540 } 20541 } 20542 return result; 20543 } 20544 20545 function excludeProperties(properties: Symbol[], excludedProperties: Set<__String> | undefined) { 20546 if (!excludedProperties || properties.length === 0) return properties; 20547 let result: Symbol[] | undefined; 20548 for (let i = 0; i < properties.length; i++) { 20549 if (!excludedProperties.has(properties[i].escapedName)) { 20550 if (result) { 20551 result.push(properties[i]); 20552 } 20553 } 20554 else if (!result) { 20555 result = properties.slice(0, i); 20556 } 20557 } 20558 return result || properties; 20559 } 20560 20561 function isPropertySymbolTypeRelated(sourceProp: Symbol, targetProp: Symbol, getTypeOfSourceProperty: (sym: Symbol) => Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary { 20562 const targetIsOptional = strictNullChecks && !!(getCheckFlags(targetProp) & CheckFlags.Partial); 20563 const effectiveTarget = addOptionality(getNonMissingTypeOfSymbol(targetProp), /*isProperty*/ false, targetIsOptional); 20564 const effectiveSource = getTypeOfSourceProperty(sourceProp); 20565 return isRelatedTo(effectiveSource, effectiveTarget, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); 20566 } 20567 20568 function propertyRelatedTo(source: Type, target: Type, sourceProp: Symbol, targetProp: Symbol, getTypeOfSourceProperty: (sym: Symbol) => Type, reportErrors: boolean, intersectionState: IntersectionState, skipOptional: boolean): Ternary { 20569 const sourcePropFlags = getDeclarationModifierFlagsFromSymbol(sourceProp); 20570 const targetPropFlags = getDeclarationModifierFlagsFromSymbol(targetProp); 20571 if (sourcePropFlags & ModifierFlags.Private || targetPropFlags & ModifierFlags.Private) { 20572 if (sourceProp.valueDeclaration !== targetProp.valueDeclaration) { 20573 if (reportErrors) { 20574 if (sourcePropFlags & ModifierFlags.Private && targetPropFlags & ModifierFlags.Private) { 20575 reportError(Diagnostics.Types_have_separate_declarations_of_a_private_property_0, symbolToString(targetProp)); 20576 } 20577 else { 20578 reportError(Diagnostics.Property_0_is_private_in_type_1_but_not_in_type_2, symbolToString(targetProp), 20579 typeToString(sourcePropFlags & ModifierFlags.Private ? source : target), 20580 typeToString(sourcePropFlags & ModifierFlags.Private ? target : source)); 20581 } 20582 } 20583 return Ternary.False; 20584 } 20585 } 20586 else if (targetPropFlags & ModifierFlags.Protected) { 20587 if (!isValidOverrideOf(sourceProp, targetProp)) { 20588 if (reportErrors) { 20589 reportError(Diagnostics.Property_0_is_protected_but_type_1_is_not_a_class_derived_from_2, symbolToString(targetProp), 20590 typeToString(getDeclaringClass(sourceProp) || source), typeToString(getDeclaringClass(targetProp) || target)); 20591 } 20592 return Ternary.False; 20593 } 20594 } 20595 else if (sourcePropFlags & ModifierFlags.Protected) { 20596 if (reportErrors) { 20597 reportError(Diagnostics.Property_0_is_protected_in_type_1_but_public_in_type_2, 20598 symbolToString(targetProp), typeToString(source), typeToString(target)); 20599 } 20600 return Ternary.False; 20601 } 20602 20603 // Ensure {readonly a: whatever} is not a subtype of {a: whatever}, 20604 // while {a: whatever} is a subtype of {readonly a: whatever}. 20605 // This ensures the subtype relationship is ordered, and preventing declaration order 20606 // from deciding which type "wins" in union subtype reduction. 20607 // They're still assignable to one another, since `readonly` doesn't affect assignability. 20608 // This is only applied during the strictSubtypeRelation -- currently used in subtype reduction 20609 if ( 20610 relation === strictSubtypeRelation && 20611 isReadonlySymbol(sourceProp) && !isReadonlySymbol(targetProp) 20612 ) { 20613 return Ternary.False; 20614 } 20615 // If the target comes from a partial union prop, allow `undefined` in the target type 20616 const related = isPropertySymbolTypeRelated(sourceProp, targetProp, getTypeOfSourceProperty, reportErrors, intersectionState); 20617 if (!related) { 20618 if (reportErrors) { 20619 reportIncompatibleError(Diagnostics.Types_of_property_0_are_incompatible, symbolToString(targetProp)); 20620 } 20621 return Ternary.False; 20622 } 20623 // When checking for comparability, be more lenient with optional properties. 20624 if (!skipOptional && sourceProp.flags & SymbolFlags.Optional && targetProp.flags & SymbolFlags.ClassMember && !(targetProp.flags & SymbolFlags.Optional)) { 20625 // TypeScript 1.0 spec (April 2014): 3.8.3 20626 // S is a subtype of a type T, and T is a supertype of S if ... 20627 // S' and T are object types and, for each member M in T.. 20628 // M is a property and S' contains a property N where 20629 // if M is a required property, N is also a required property 20630 // (M - property in T) 20631 // (N - property in S) 20632 if (reportErrors) { 20633 reportError(Diagnostics.Property_0_is_optional_in_type_1_but_required_in_type_2, 20634 symbolToString(targetProp), typeToString(source), typeToString(target)); 20635 } 20636 return Ternary.False; 20637 } 20638 return related; 20639 } 20640 20641 function reportUnmatchedProperty(source: Type, target: Type, unmatchedProperty: Symbol, requireOptionalProperties: boolean) { 20642 let shouldSkipElaboration = false; 20643 // give specific error in case where private names have the same description 20644 if (unmatchedProperty.valueDeclaration 20645 && isNamedDeclaration(unmatchedProperty.valueDeclaration) 20646 && isPrivateIdentifier(unmatchedProperty.valueDeclaration.name) 20647 && source.symbol 20648 && source.symbol.flags & SymbolFlags.Class) { 20649 const privateIdentifierDescription = unmatchedProperty.valueDeclaration.name.escapedText; 20650 const symbolTableKey = getSymbolNameForPrivateIdentifier(source.symbol, privateIdentifierDescription); 20651 if (symbolTableKey && getPropertyOfType(source, symbolTableKey)) { 20652 const sourceName = factory.getDeclarationName(source.symbol.valueDeclaration); 20653 const targetName = factory.getDeclarationName(target.symbol.valueDeclaration); 20654 reportError( 20655 Diagnostics.Property_0_in_type_1_refers_to_a_different_member_that_cannot_be_accessed_from_within_type_2, 20656 diagnosticName(privateIdentifierDescription), 20657 diagnosticName(sourceName.escapedText === "" ? anon : sourceName), 20658 diagnosticName(targetName.escapedText === "" ? anon : targetName)); 20659 return; 20660 } 20661 } 20662 const props = arrayFrom(getUnmatchedProperties(source, target, requireOptionalProperties, /*matchDiscriminantProperties*/ false)); 20663 if (!headMessage || (headMessage.code !== Diagnostics.Class_0_incorrectly_implements_interface_1.code && 20664 headMessage.code !== Diagnostics.Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass.code)) { 20665 shouldSkipElaboration = true; // Retain top-level error for interface implementing issues, otherwise omit it 20666 } 20667 if (props.length === 1) { 20668 const propName = symbolToString(unmatchedProperty, /*enclosingDeclaration*/ undefined, SymbolFlags.None, SymbolFormatFlags.AllowAnyNodeKind | SymbolFormatFlags.WriteComputedProps); 20669 reportError(Diagnostics.Property_0_is_missing_in_type_1_but_required_in_type_2, propName, ...getTypeNamesForErrorDisplay(source, target)); 20670 if (length(unmatchedProperty.declarations)) { 20671 associateRelatedInfo(createDiagnosticForNode(unmatchedProperty.declarations![0], Diagnostics._0_is_declared_here, propName)); 20672 } 20673 if (shouldSkipElaboration && errorInfo) { 20674 overrideNextErrorInfo++; 20675 } 20676 } 20677 else if (tryElaborateArrayLikeErrors(source, target, /*reportErrors*/ false)) { 20678 if (props.length > 5) { // arbitrary cutoff for too-long list form 20679 reportError(Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2_and_3_more, typeToString(source), typeToString(target), map(props.slice(0, 4), p => symbolToString(p)).join(", "), props.length - 4); 20680 } 20681 else { 20682 reportError(Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2, typeToString(source), typeToString(target), map(props, p => symbolToString(p)).join(", ")); 20683 } 20684 if (shouldSkipElaboration && errorInfo) { 20685 overrideNextErrorInfo++; 20686 } 20687 } 20688 // No array like or unmatched property error - just issue top level error (errorInfo = undefined) 20689 } 20690 20691 function propertiesRelatedTo(source: Type, target: Type, reportErrors: boolean, excludedProperties: Set<__String> | undefined, intersectionState: IntersectionState): Ternary { 20692 if (relation === identityRelation) { 20693 return propertiesIdenticalTo(source, target, excludedProperties); 20694 } 20695 let result = Ternary.True; 20696 if (isTupleType(target)) { 20697 if (isArrayOrTupleType(source)) { 20698 if (!target.target.readonly && (isReadonlyArrayType(source) || isTupleType(source) && source.target.readonly)) { 20699 return Ternary.False; 20700 } 20701 const sourceArity = getTypeReferenceArity(source); 20702 const targetArity = getTypeReferenceArity(target); 20703 const sourceRestFlag = isTupleType(source) ? source.target.combinedFlags & ElementFlags.Rest : ElementFlags.Rest; 20704 const targetRestFlag = target.target.combinedFlags & ElementFlags.Rest; 20705 const sourceMinLength = isTupleType(source) ? source.target.minLength : 0; 20706 const targetMinLength = target.target.minLength; 20707 if (!sourceRestFlag && sourceArity < targetMinLength) { 20708 if (reportErrors) { 20709 reportError(Diagnostics.Source_has_0_element_s_but_target_requires_1, sourceArity, targetMinLength); 20710 } 20711 return Ternary.False; 20712 } 20713 if (!targetRestFlag && targetArity < sourceMinLength) { 20714 if (reportErrors) { 20715 reportError(Diagnostics.Source_has_0_element_s_but_target_allows_only_1, sourceMinLength, targetArity); 20716 } 20717 return Ternary.False; 20718 } 20719 if (!targetRestFlag && (sourceRestFlag || targetArity < sourceArity)) { 20720 if (reportErrors) { 20721 if (sourceMinLength < targetMinLength) { 20722 reportError(Diagnostics.Target_requires_0_element_s_but_source_may_have_fewer, targetMinLength); 20723 } 20724 else { 20725 reportError(Diagnostics.Target_allows_only_0_element_s_but_source_may_have_more, targetArity); 20726 } 20727 } 20728 return Ternary.False; 20729 } 20730 const sourceTypeArguments = getTypeArguments(source); 20731 const targetTypeArguments = getTypeArguments(target); 20732 const startCount = Math.min(isTupleType(source) ? getStartElementCount(source.target, ElementFlags.NonRest) : 0, getStartElementCount(target.target, ElementFlags.NonRest)); 20733 const endCount = Math.min(isTupleType(source) ? getEndElementCount(source.target, ElementFlags.NonRest) : 0, targetRestFlag ? getEndElementCount(target.target, ElementFlags.NonRest) : 0); 20734 let canExcludeDiscriminants = !!excludedProperties; 20735 for (let i = 0; i < targetArity; i++) { 20736 const sourceIndex = i < targetArity - endCount ? i : i + sourceArity - targetArity; 20737 const sourceFlags = isTupleType(source) && (i < startCount || i >= targetArity - endCount) ? source.target.elementFlags[sourceIndex] : ElementFlags.Rest; 20738 const targetFlags = target.target.elementFlags[i]; 20739 if (targetFlags & ElementFlags.Variadic && !(sourceFlags & ElementFlags.Variadic)) { 20740 if (reportErrors) { 20741 reportError(Diagnostics.Source_provides_no_match_for_variadic_element_at_position_0_in_target, i); 20742 } 20743 return Ternary.False; 20744 } 20745 if (sourceFlags & ElementFlags.Variadic && !(targetFlags & ElementFlags.Variable)) { 20746 if (reportErrors) { 20747 reportError(Diagnostics.Variadic_element_at_position_0_in_source_does_not_match_element_at_position_1_in_target, sourceIndex, i); 20748 } 20749 return Ternary.False; 20750 } 20751 if (targetFlags & ElementFlags.Required && !(sourceFlags & ElementFlags.Required)) { 20752 if (reportErrors) { 20753 reportError(Diagnostics.Source_provides_no_match_for_required_element_at_position_0_in_target, i); 20754 } 20755 return Ternary.False; 20756 } 20757 // We can only exclude discriminant properties if we have not yet encountered a variable-length element. 20758 if (canExcludeDiscriminants) { 20759 if (sourceFlags & ElementFlags.Variable || targetFlags & ElementFlags.Variable) { 20760 canExcludeDiscriminants = false; 20761 } 20762 if (canExcludeDiscriminants && excludedProperties?.has(("" + i) as __String)) { 20763 continue; 20764 } 20765 } 20766 const sourceType = !isTupleType(source) ? sourceTypeArguments[0] : 20767 i < startCount || i >= targetArity - endCount ? removeMissingType(sourceTypeArguments[sourceIndex], !!(sourceFlags & targetFlags & ElementFlags.Optional)) : 20768 getElementTypeOfSliceOfTupleType(source, startCount, endCount) || neverType; 20769 const targetType = targetTypeArguments[i]; 20770 const targetCheckType = sourceFlags & ElementFlags.Variadic && targetFlags & ElementFlags.Rest ? createArrayType(targetType) : 20771 removeMissingType(targetType, !!(targetFlags & ElementFlags.Optional)); 20772 const related = isRelatedTo(sourceType, targetCheckType, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); 20773 if (!related) { 20774 if (reportErrors && (targetArity > 1 || sourceArity > 1)) { 20775 if (i < startCount || i >= targetArity - endCount || sourceArity - startCount - endCount === 1) { 20776 reportIncompatibleError(Diagnostics.Type_at_position_0_in_source_is_not_compatible_with_type_at_position_1_in_target, sourceIndex, i); 20777 } 20778 else { 20779 reportIncompatibleError(Diagnostics.Type_at_positions_0_through_1_in_source_is_not_compatible_with_type_at_position_2_in_target, startCount, sourceArity - endCount - 1, i); 20780 } 20781 } 20782 return Ternary.False; 20783 } 20784 result &= related; 20785 } 20786 return result; 20787 } 20788 if (target.target.combinedFlags & ElementFlags.Variable) { 20789 return Ternary.False; 20790 } 20791 } 20792 const requireOptionalProperties = (relation === subtypeRelation || relation === strictSubtypeRelation) && !isObjectLiteralType(source) && !isEmptyArrayLiteralType(source) && !isTupleType(source); 20793 const unmatchedProperty = getUnmatchedProperty(source, target, requireOptionalProperties, /*matchDiscriminantProperties*/ false); 20794 if (unmatchedProperty) { 20795 if (reportErrors && shouldReportUnmatchedPropertyError(source, target)) { 20796 reportUnmatchedProperty(source, target, unmatchedProperty, requireOptionalProperties); 20797 } 20798 return Ternary.False; 20799 } 20800 if (isObjectLiteralType(target)) { 20801 for (const sourceProp of excludeProperties(getPropertiesOfType(source), excludedProperties)) { 20802 if (!getPropertyOfObjectType(target, sourceProp.escapedName)) { 20803 const sourceType = getTypeOfSymbol(sourceProp); 20804 if (!(sourceType.flags & TypeFlags.Undefined)) { 20805 if (reportErrors) { 20806 reportError(Diagnostics.Property_0_does_not_exist_on_type_1, symbolToString(sourceProp), typeToString(target)); 20807 } 20808 return Ternary.False; 20809 } 20810 } 20811 } 20812 } 20813 // We only call this for union target types when we're attempting to do excess property checking - in those cases, we want to get _all possible props_ 20814 // from the target union, across all members 20815 const properties = getPropertiesOfType(target); 20816 const numericNamesOnly = isTupleType(source) && isTupleType(target); 20817 for (const targetProp of excludeProperties(properties, excludedProperties)) { 20818 const name = targetProp.escapedName; 20819 if (!(targetProp.flags & SymbolFlags.Prototype) && (!numericNamesOnly || isNumericLiteralName(name) || name === "length")) { 20820 const sourceProp = getPropertyOfType(source, name); 20821 if (sourceProp && sourceProp !== targetProp) { 20822 const related = propertyRelatedTo(source, target, sourceProp, targetProp, getNonMissingTypeOfSymbol, reportErrors, intersectionState, relation === comparableRelation); 20823 if (!related) { 20824 return Ternary.False; 20825 } 20826 result &= related; 20827 } 20828 } 20829 } 20830 return result; 20831 } 20832 20833 function propertiesIdenticalTo(source: Type, target: Type, excludedProperties: Set<__String> | undefined): Ternary { 20834 if (!(source.flags & TypeFlags.Object && target.flags & TypeFlags.Object)) { 20835 return Ternary.False; 20836 } 20837 const sourceProperties = excludeProperties(getPropertiesOfObjectType(source), excludedProperties); 20838 const targetProperties = excludeProperties(getPropertiesOfObjectType(target), excludedProperties); 20839 if (sourceProperties.length !== targetProperties.length) { 20840 return Ternary.False; 20841 } 20842 let result = Ternary.True; 20843 for (const sourceProp of sourceProperties) { 20844 const targetProp = getPropertyOfObjectType(target, sourceProp.escapedName); 20845 if (!targetProp) { 20846 return Ternary.False; 20847 } 20848 const related = compareProperties(sourceProp, targetProp, isRelatedTo); 20849 if (!related) { 20850 return Ternary.False; 20851 } 20852 result &= related; 20853 } 20854 return result; 20855 } 20856 20857 function signaturesRelatedTo(source: Type, target: Type, kind: SignatureKind, reportErrors: boolean): Ternary { 20858 if (relation === identityRelation) { 20859 return signaturesIdenticalTo(source, target, kind); 20860 } 20861 if (target === anyFunctionType || source === anyFunctionType) { 20862 return Ternary.True; 20863 } 20864 20865 const sourceIsJSConstructor = source.symbol && isJSConstructor(source.symbol.valueDeclaration); 20866 const targetIsJSConstructor = target.symbol && isJSConstructor(target.symbol.valueDeclaration); 20867 20868 const sourceSignatures = getSignaturesOfType(source, (sourceIsJSConstructor && kind === SignatureKind.Construct) ? 20869 SignatureKind.Call : kind); 20870 const targetSignatures = getSignaturesOfType(target, (targetIsJSConstructor && kind === SignatureKind.Construct) ? 20871 SignatureKind.Call : kind); 20872 20873 if (kind === SignatureKind.Construct && sourceSignatures.length && targetSignatures.length) { 20874 const sourceIsAbstract = !!(sourceSignatures[0].flags & SignatureFlags.Abstract); 20875 const targetIsAbstract = !!(targetSignatures[0].flags & SignatureFlags.Abstract); 20876 if (sourceIsAbstract && !targetIsAbstract) { 20877 // An abstract constructor type is not assignable to a non-abstract constructor type 20878 // as it would otherwise be possible to new an abstract class. Note that the assignability 20879 // check we perform for an extends clause excludes construct signatures from the target, 20880 // so this check never proceeds. 20881 if (reportErrors) { 20882 reportError(Diagnostics.Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type); 20883 } 20884 return Ternary.False; 20885 } 20886 if (!constructorVisibilitiesAreCompatible(sourceSignatures[0], targetSignatures[0], reportErrors)) { 20887 return Ternary.False; 20888 } 20889 } 20890 20891 let result = Ternary.True; 20892 const incompatibleReporter = kind === SignatureKind.Construct ? reportIncompatibleConstructSignatureReturn : reportIncompatibleCallSignatureReturn; 20893 const sourceObjectFlags = getObjectFlags(source); 20894 const targetObjectFlags = getObjectFlags(target); 20895 if (sourceObjectFlags & ObjectFlags.Instantiated && targetObjectFlags & ObjectFlags.Instantiated && source.symbol === target.symbol || 20896 sourceObjectFlags & ObjectFlags.Reference && targetObjectFlags & ObjectFlags.Reference && (source as TypeReference).target === (target as TypeReference).target) { 20897 // We have instantiations of the same anonymous type (which typically will be the type of a 20898 // method). Simply do a pairwise comparison of the signatures in the two signature lists instead 20899 // of the much more expensive N * M comparison matrix we explore below. We erase type parameters 20900 // as they are known to always be the same. 20901 for (let i = 0; i < targetSignatures.length; i++) { 20902 const related = signatureRelatedTo(sourceSignatures[i], targetSignatures[i], /*erase*/ true, reportErrors, incompatibleReporter(sourceSignatures[i], targetSignatures[i])); 20903 if (!related) { 20904 return Ternary.False; 20905 } 20906 result &= related; 20907 } 20908 } 20909 else if (sourceSignatures.length === 1 && targetSignatures.length === 1) { 20910 // For simple functions (functions with a single signature) we only erase type parameters for 20911 // the comparable relation. Otherwise, if the source signature is generic, we instantiate it 20912 // in the context of the target signature before checking the relationship. Ideally we'd do 20913 // this regardless of the number of signatures, but the potential costs are prohibitive due 20914 // to the quadratic nature of the logic below. 20915 const eraseGenerics = relation === comparableRelation || !!compilerOptions.noStrictGenericChecks; 20916 const sourceSignature = first(sourceSignatures); 20917 const targetSignature = first(targetSignatures); 20918 result = signatureRelatedTo(sourceSignature, targetSignature, eraseGenerics, reportErrors, incompatibleReporter(sourceSignature, targetSignature)); 20919 if (!result && reportErrors && kind === SignatureKind.Construct && (sourceObjectFlags & targetObjectFlags) && 20920 (targetSignature.declaration?.kind === SyntaxKind.Constructor || sourceSignature.declaration?.kind === SyntaxKind.Constructor)) { 20921 const constructSignatureToString = (signature: Signature) => 20922 signatureToString(signature, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrowStyleSignature, kind); 20923 reportError(Diagnostics.Type_0_is_not_assignable_to_type_1, constructSignatureToString(sourceSignature), constructSignatureToString(targetSignature)); 20924 reportError(Diagnostics.Types_of_construct_signatures_are_incompatible); 20925 return result; 20926 } 20927 } 20928 else { 20929 outer: for (const t of targetSignatures) { 20930 const saveErrorInfo = captureErrorCalculationState(); 20931 // Only elaborate errors from the first failure 20932 let shouldElaborateErrors = reportErrors; 20933 for (const s of sourceSignatures) { 20934 const related = signatureRelatedTo(s, t, /*erase*/ true, shouldElaborateErrors, incompatibleReporter(s, t)); 20935 if (related) { 20936 result &= related; 20937 resetErrorInfo(saveErrorInfo); 20938 continue outer; 20939 } 20940 shouldElaborateErrors = false; 20941 } 20942 if (shouldElaborateErrors) { 20943 reportError(Diagnostics.Type_0_provides_no_match_for_the_signature_1, 20944 typeToString(source), 20945 signatureToString(t, /*enclosingDeclaration*/ undefined, /*flags*/ undefined, kind)); 20946 } 20947 return Ternary.False; 20948 } 20949 } 20950 return result; 20951 } 20952 20953 function shouldReportUnmatchedPropertyError(source: Type, target: Type): boolean { 20954 const typeCallSignatures = getSignaturesOfStructuredType(source, SignatureKind.Call); 20955 const typeConstructSignatures = getSignaturesOfStructuredType(source, SignatureKind.Construct); 20956 const typeProperties = getPropertiesOfObjectType(source); 20957 if ((typeCallSignatures.length || typeConstructSignatures.length) && !typeProperties.length) { 20958 if ((getSignaturesOfType(target, SignatureKind.Call).length && typeCallSignatures.length) || 20959 (getSignaturesOfType(target, SignatureKind.Construct).length && typeConstructSignatures.length)) { 20960 return true; // target has similar signature kinds to source, still focus on the unmatched property 20961 } 20962 return false; 20963 } 20964 return true; 20965 } 20966 20967 function reportIncompatibleCallSignatureReturn(siga: Signature, sigb: Signature) { 20968 if (siga.parameters.length === 0 && sigb.parameters.length === 0) { 20969 return (source: Type, target: Type) => reportIncompatibleError(Diagnostics.Call_signatures_with_no_arguments_have_incompatible_return_types_0_and_1, typeToString(source), typeToString(target)); 20970 } 20971 return (source: Type, target: Type) => reportIncompatibleError(Diagnostics.Call_signature_return_types_0_and_1_are_incompatible, typeToString(source), typeToString(target)); 20972 } 20973 20974 function reportIncompatibleConstructSignatureReturn(siga: Signature, sigb: Signature) { 20975 if (siga.parameters.length === 0 && sigb.parameters.length === 0) { 20976 return (source: Type, target: Type) => reportIncompatibleError(Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1, typeToString(source), typeToString(target)); 20977 } 20978 return (source: Type, target: Type) => reportIncompatibleError(Diagnostics.Construct_signature_return_types_0_and_1_are_incompatible, typeToString(source), typeToString(target)); 20979 } 20980 20981 /** 20982 * See signatureAssignableTo, compareSignaturesIdentical 20983 */ 20984 function signatureRelatedTo(source: Signature, target: Signature, erase: boolean, reportErrors: boolean, incompatibleReporter: (source: Type, target: Type) => void): Ternary { 20985 return compareSignaturesRelated(erase ? getErasedSignature(source) : source, erase ? getErasedSignature(target) : target, 20986 relation === strictSubtypeRelation ? SignatureCheckMode.StrictArity : 0, reportErrors, reportError, incompatibleReporter, isRelatedToWorker, reportUnreliableMapper); 20987 } 20988 20989 function signaturesIdenticalTo(source: Type, target: Type, kind: SignatureKind): Ternary { 20990 const sourceSignatures = getSignaturesOfType(source, kind); 20991 const targetSignatures = getSignaturesOfType(target, kind); 20992 if (sourceSignatures.length !== targetSignatures.length) { 20993 return Ternary.False; 20994 } 20995 let result = Ternary.True; 20996 for (let i = 0; i < sourceSignatures.length; i++) { 20997 const related = compareSignaturesIdentical(sourceSignatures[i], targetSignatures[i], /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ false, isRelatedTo); 20998 if (!related) { 20999 return Ternary.False; 21000 } 21001 result &= related; 21002 } 21003 return result; 21004 } 21005 21006 function membersRelatedToIndexInfo(source: Type, targetInfo: IndexInfo, reportErrors: boolean): Ternary { 21007 let result = Ternary.True; 21008 const keyType = targetInfo.keyType; 21009 const props = source.flags & TypeFlags.Intersection ? getPropertiesOfUnionOrIntersectionType(source as IntersectionType) : getPropertiesOfObjectType(source); 21010 for (const prop of props) { 21011 // Skip over ignored JSX and symbol-named members 21012 if (isIgnoredJsxProperty(source, prop)) { 21013 continue; 21014 } 21015 if (isApplicableIndexType(getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique), keyType)) { 21016 const propType = getNonMissingTypeOfSymbol(prop); 21017 const type = exactOptionalPropertyTypes || propType.flags & TypeFlags.Undefined || keyType === numberType || !(prop.flags & SymbolFlags.Optional) 21018 ? propType 21019 : getTypeWithFacts(propType, TypeFacts.NEUndefined); 21020 const related = isRelatedTo(type, targetInfo.type, RecursionFlags.Both, reportErrors); 21021 if (!related) { 21022 if (reportErrors) { 21023 reportError(Diagnostics.Property_0_is_incompatible_with_index_signature, symbolToString(prop)); 21024 } 21025 return Ternary.False; 21026 } 21027 result &= related; 21028 } 21029 } 21030 for (const info of getIndexInfosOfType(source)) { 21031 if (isApplicableIndexType(info.keyType, keyType)) { 21032 const related = indexInfoRelatedTo(info, targetInfo, reportErrors); 21033 if (!related) { 21034 return Ternary.False; 21035 } 21036 result &= related; 21037 } 21038 } 21039 return result; 21040 } 21041 21042 function indexInfoRelatedTo(sourceInfo: IndexInfo, targetInfo: IndexInfo, reportErrors: boolean) { 21043 const related = isRelatedTo(sourceInfo.type, targetInfo.type, RecursionFlags.Both, reportErrors); 21044 if (!related && reportErrors) { 21045 if (sourceInfo.keyType === targetInfo.keyType) { 21046 reportError(Diagnostics._0_index_signatures_are_incompatible, typeToString(sourceInfo.keyType)); 21047 } 21048 else { 21049 reportError(Diagnostics._0_and_1_index_signatures_are_incompatible, typeToString(sourceInfo.keyType), typeToString(targetInfo.keyType)); 21050 } 21051 } 21052 return related; 21053 } 21054 21055 function indexSignaturesRelatedTo(source: Type, target: Type, sourceIsPrimitive: boolean, reportErrors: boolean, intersectionState: IntersectionState): Ternary { 21056 if (relation === identityRelation) { 21057 return indexSignaturesIdenticalTo(source, target); 21058 } 21059 const indexInfos = getIndexInfosOfType(target); 21060 const targetHasStringIndex = some(indexInfos, info => info.keyType === stringType); 21061 let result = Ternary.True; 21062 for (const targetInfo of indexInfos) { 21063 const related = !sourceIsPrimitive && targetHasStringIndex && targetInfo.type.flags & TypeFlags.Any ? Ternary.True : 21064 isGenericMappedType(source) && targetHasStringIndex ? isRelatedTo(getTemplateTypeFromMappedType(source), targetInfo.type, RecursionFlags.Both, reportErrors) : 21065 typeRelatedToIndexInfo(source, targetInfo, reportErrors, intersectionState); 21066 if (!related) { 21067 return Ternary.False; 21068 } 21069 result &= related; 21070 } 21071 return result; 21072 } 21073 21074 function typeRelatedToIndexInfo(source: Type, targetInfo: IndexInfo, reportErrors: boolean, intersectionState: IntersectionState): Ternary { 21075 const sourceInfo = getApplicableIndexInfo(source, targetInfo.keyType); 21076 if (sourceInfo) { 21077 return indexInfoRelatedTo(sourceInfo, targetInfo, reportErrors); 21078 } 21079 if (!(intersectionState & IntersectionState.Source) && isObjectTypeWithInferableIndex(source)) { 21080 // Intersection constituents are never considered to have an inferred index signature 21081 return membersRelatedToIndexInfo(source, targetInfo, reportErrors); 21082 } 21083 if (reportErrors) { 21084 reportError(Diagnostics.Index_signature_for_type_0_is_missing_in_type_1, typeToString(targetInfo.keyType), typeToString(source)); 21085 } 21086 return Ternary.False; 21087 } 21088 21089 function indexSignaturesIdenticalTo(source: Type, target: Type): Ternary { 21090 const sourceInfos = getIndexInfosOfType(source); 21091 const targetInfos = getIndexInfosOfType(target); 21092 if (sourceInfos.length !== targetInfos.length) { 21093 return Ternary.False; 21094 } 21095 for (const targetInfo of targetInfos) { 21096 const sourceInfo = getIndexInfoOfType(source, targetInfo.keyType); 21097 if (!(sourceInfo && isRelatedTo(sourceInfo.type, targetInfo.type, RecursionFlags.Both) && sourceInfo.isReadonly === targetInfo.isReadonly)) { 21098 return Ternary.False; 21099 } 21100 } 21101 return Ternary.True; 21102 } 21103 21104 function constructorVisibilitiesAreCompatible(sourceSignature: Signature, targetSignature: Signature, reportErrors: boolean) { 21105 if (!sourceSignature.declaration || !targetSignature.declaration) { 21106 return true; 21107 } 21108 21109 const sourceAccessibility = getSelectedEffectiveModifierFlags(sourceSignature.declaration, ModifierFlags.NonPublicAccessibilityModifier); 21110 const targetAccessibility = getSelectedEffectiveModifierFlags(targetSignature.declaration, ModifierFlags.NonPublicAccessibilityModifier); 21111 21112 // A public, protected and private signature is assignable to a private signature. 21113 if (targetAccessibility === ModifierFlags.Private) { 21114 return true; 21115 } 21116 21117 // A public and protected signature is assignable to a protected signature. 21118 if (targetAccessibility === ModifierFlags.Protected && sourceAccessibility !== ModifierFlags.Private) { 21119 return true; 21120 } 21121 21122 // Only a public signature is assignable to public signature. 21123 if (targetAccessibility !== ModifierFlags.Protected && !sourceAccessibility) { 21124 return true; 21125 } 21126 21127 if (reportErrors) { 21128 reportError(Diagnostics.Cannot_assign_a_0_constructor_type_to_a_1_constructor_type, visibilityToString(sourceAccessibility), visibilityToString(targetAccessibility)); 21129 } 21130 21131 return false; 21132 } 21133 } 21134 21135 function typeCouldHaveTopLevelSingletonTypes(type: Type): boolean { 21136 // Okay, yes, 'boolean' is a union of 'true | false', but that's not useful 21137 // in error reporting scenarios. If you need to use this function but that detail matters, 21138 // feel free to add a flag. 21139 if (type.flags & TypeFlags.Boolean) { 21140 return false; 21141 } 21142 21143 if (type.flags & TypeFlags.UnionOrIntersection) { 21144 return !!forEach((type as IntersectionType).types, typeCouldHaveTopLevelSingletonTypes); 21145 } 21146 21147 if (type.flags & TypeFlags.Instantiable) { 21148 const constraint = getConstraintOfType(type); 21149 if (constraint && constraint !== type) { 21150 return typeCouldHaveTopLevelSingletonTypes(constraint); 21151 } 21152 } 21153 21154 return isUnitType(type) || !!(type.flags & TypeFlags.TemplateLiteral) || !!(type.flags & TypeFlags.StringMapping); 21155 } 21156 21157 function getExactOptionalUnassignableProperties(source: Type, target: Type) { 21158 if (isTupleType(source) && isTupleType(target)) return emptyArray; 21159 return getPropertiesOfType(target) 21160 .filter(targetProp => isExactOptionalPropertyMismatch(getTypeOfPropertyOfType(source, targetProp.escapedName), getTypeOfSymbol(targetProp))); 21161 } 21162 21163 function isExactOptionalPropertyMismatch(source: Type | undefined, target: Type | undefined) { 21164 return !!source && !!target && maybeTypeOfKind(source, TypeFlags.Undefined) && !!containsMissingType(target); 21165 } 21166 21167 function getExactOptionalProperties(type: Type) { 21168 return getPropertiesOfType(type).filter(targetProp => containsMissingType(getTypeOfSymbol(targetProp))); 21169 } 21170 21171 function getBestMatchingType(source: Type, target: UnionOrIntersectionType, isRelatedTo = compareTypesAssignable) { 21172 return findMatchingDiscriminantType(source, target, isRelatedTo, /*skipPartial*/ true) || 21173 findMatchingTypeReferenceOrTypeAliasReference(source, target) || 21174 findBestTypeForObjectLiteral(source, target) || 21175 findBestTypeForInvokable(source, target) || 21176 findMostOverlappyType(source, target); 21177 } 21178 21179 function discriminateTypeByDiscriminableItems(target: UnionType, discriminators: [() => Type, __String][], related: (source: Type, target: Type) => boolean | Ternary, defaultValue?: undefined, skipPartial?: boolean): Type | undefined; 21180 function discriminateTypeByDiscriminableItems(target: UnionType, discriminators: [() => Type, __String][], related: (source: Type, target: Type) => boolean | Ternary, defaultValue: Type, skipPartial?: boolean): Type; 21181 function discriminateTypeByDiscriminableItems(target: UnionType, discriminators: [() => Type, __String][], related: (source: Type, target: Type) => boolean | Ternary, defaultValue?: Type, skipPartial?: boolean) { 21182 // undefined=unknown, true=discriminated, false=not discriminated 21183 // The state of each type progresses from left to right. Discriminated types stop at 'true'. 21184 const discriminable = target.types.map(_ => undefined) as (boolean | undefined)[]; 21185 for (const [getDiscriminatingType, propertyName] of discriminators) { 21186 const targetProp = getUnionOrIntersectionProperty(target, propertyName); 21187 if (skipPartial && targetProp && getCheckFlags(targetProp) & CheckFlags.ReadPartial) { 21188 continue; 21189 } 21190 let i = 0; 21191 for (const type of target.types) { 21192 const targetType = getTypeOfPropertyOfType(type, propertyName); 21193 if (targetType && related(getDiscriminatingType(), targetType)) { 21194 discriminable[i] = discriminable[i] === undefined ? true : discriminable[i]; 21195 } 21196 else { 21197 discriminable[i] = false; 21198 } 21199 i++; 21200 } 21201 } 21202 const match = discriminable.indexOf(/*searchElement*/ true); 21203 if (match === -1) { 21204 return defaultValue; 21205 } 21206 // make sure exactly 1 matches before returning it 21207 let nextMatch = discriminable.indexOf(/*searchElement*/ true, match + 1); 21208 while (nextMatch !== -1) { 21209 if (!isTypeIdenticalTo(target.types[match], target.types[nextMatch])) { 21210 return defaultValue; 21211 } 21212 nextMatch = discriminable.indexOf(/*searchElement*/ true, nextMatch + 1); 21213 } 21214 return target.types[match]; 21215 } 21216 21217 /** 21218 * A type is 'weak' if it is an object type with at least one optional property 21219 * and no required properties, call/construct signatures or index signatures 21220 */ 21221 function isWeakType(type: Type): boolean { 21222 if (type.flags & TypeFlags.Object) { 21223 const resolved = resolveStructuredTypeMembers(type as ObjectType); 21224 return resolved.callSignatures.length === 0 && resolved.constructSignatures.length === 0 && resolved.indexInfos.length === 0 && 21225 resolved.properties.length > 0 && every(resolved.properties, p => !!(p.flags & SymbolFlags.Optional)); 21226 } 21227 if (type.flags & TypeFlags.Intersection) { 21228 return every((type as IntersectionType).types, isWeakType); 21229 } 21230 return false; 21231 } 21232 21233 function hasCommonProperties(source: Type, target: Type, isComparingJsxAttributes: boolean) { 21234 for (const prop of getPropertiesOfType(source)) { 21235 if (isKnownProperty(target, prop.escapedName, isComparingJsxAttributes)) { 21236 return true; 21237 } 21238 } 21239 return false; 21240 } 21241 21242 function getVariances(type: GenericType): VarianceFlags[] { 21243 // Arrays and tuples are known to be covariant, no need to spend time computing this. 21244 return type === globalArrayType || type === globalReadonlyArrayType || type.objectFlags & ObjectFlags.Tuple ? 21245 arrayVariances : 21246 getVariancesWorker(type.symbol, type.typeParameters); 21247 } 21248 21249 function getAliasVariances(symbol: Symbol) { 21250 return getVariancesWorker(symbol, getSymbolLinks(symbol).typeParameters); 21251 } 21252 21253 // Return an array containing the variance of each type parameter. The variance is effectively 21254 // a digest of the type comparisons that occur for each type argument when instantiations of the 21255 // generic type are structurally compared. We infer the variance information by comparing 21256 // instantiations of the generic type for type arguments with known relations. The function 21257 // returns the emptyArray singleton when invoked recursively for the given generic type. 21258 function getVariancesWorker(symbol: Symbol, typeParameters: readonly TypeParameter[] = emptyArray): VarianceFlags[] { 21259 const links = getSymbolLinks(symbol); 21260 if (!links.variances) { 21261 tracing?.push(tracing.Phase.CheckTypes, "getVariancesWorker", { arity: typeParameters.length, id: getTypeId(getDeclaredTypeOfSymbol(symbol)) }); 21262 links.variances = emptyArray; 21263 const variances = []; 21264 for (const tp of typeParameters) { 21265 const modifiers = getVarianceModifiers(tp); 21266 let variance = modifiers & ModifierFlags.Out ? 21267 modifiers & ModifierFlags.In ? VarianceFlags.Invariant : VarianceFlags.Covariant : 21268 modifiers & ModifierFlags.In ? VarianceFlags.Contravariant : undefined; 21269 if (variance === undefined) { 21270 let unmeasurable = false; 21271 let unreliable = false; 21272 const oldHandler = outofbandVarianceMarkerHandler; 21273 outofbandVarianceMarkerHandler = (onlyUnreliable) => onlyUnreliable ? unreliable = true : unmeasurable = true; 21274 // We first compare instantiations where the type parameter is replaced with 21275 // marker types that have a known subtype relationship. From this we can infer 21276 // invariance, covariance, contravariance or bivariance. 21277 const typeWithSuper = createMarkerType(symbol, tp, markerSuperType); 21278 const typeWithSub = createMarkerType(symbol, tp, markerSubType); 21279 variance = (isTypeAssignableTo(typeWithSub, typeWithSuper) ? VarianceFlags.Covariant : 0) | 21280 (isTypeAssignableTo(typeWithSuper, typeWithSub) ? VarianceFlags.Contravariant : 0); 21281 // If the instantiations appear to be related bivariantly it may be because the 21282 // type parameter is independent (i.e. it isn't witnessed anywhere in the generic 21283 // type). To determine this we compare instantiations where the type parameter is 21284 // replaced with marker types that are known to be unrelated. 21285 if (variance === VarianceFlags.Bivariant && isTypeAssignableTo(createMarkerType(symbol, tp, markerOtherType), typeWithSuper)) { 21286 variance = VarianceFlags.Independent; 21287 } 21288 outofbandVarianceMarkerHandler = oldHandler; 21289 if (unmeasurable || unreliable) { 21290 if (unmeasurable) { 21291 variance |= VarianceFlags.Unmeasurable; 21292 } 21293 if (unreliable) { 21294 variance |= VarianceFlags.Unreliable; 21295 } 21296 } 21297 } 21298 variances.push(variance); 21299 } 21300 links.variances = variances; 21301 tracing?.pop({ variances: variances.map(Debug.formatVariance) }); 21302 } 21303 return links.variances; 21304 } 21305 21306 function createMarkerType(symbol: Symbol, source: TypeParameter, target: Type) { 21307 const mapper = makeUnaryTypeMapper(source, target); 21308 const type = getDeclaredTypeOfSymbol(symbol); 21309 if (isErrorType(type)) { 21310 return type; 21311 } 21312 const result = symbol.flags & SymbolFlags.TypeAlias ? 21313 getTypeAliasInstantiation(symbol, instantiateTypes(getSymbolLinks(symbol).typeParameters!, mapper)) : 21314 createTypeReference(type as GenericType, instantiateTypes((type as GenericType).typeParameters, mapper)); 21315 markerTypes.add(getTypeId(result)); 21316 return result; 21317 } 21318 21319 function isMarkerType(type: Type) { 21320 return markerTypes.has(getTypeId(type)); 21321 } 21322 21323 function getVarianceModifiers(tp: TypeParameter): ModifierFlags { 21324 return (some(tp.symbol?.declarations, d => hasSyntacticModifier(d, ModifierFlags.In)) ? ModifierFlags.In : 0) | 21325 (some(tp.symbol?.declarations, d => hasSyntacticModifier(d, ModifierFlags.Out)) ? ModifierFlags.Out: 0); 21326 } 21327 21328 // Return true if the given type reference has a 'void' type argument for a covariant type parameter. 21329 // See comment at call in recursiveTypeRelatedTo for when this case matters. 21330 function hasCovariantVoidArgument(typeArguments: readonly Type[], variances: VarianceFlags[]): boolean { 21331 for (let i = 0; i < variances.length; i++) { 21332 if ((variances[i] & VarianceFlags.VarianceMask) === VarianceFlags.Covariant && typeArguments[i].flags & TypeFlags.Void) { 21333 return true; 21334 } 21335 } 21336 return false; 21337 } 21338 21339 function isUnconstrainedTypeParameter(type: Type) { 21340 return type.flags & TypeFlags.TypeParameter && !getConstraintOfTypeParameter(type as TypeParameter); 21341 } 21342 21343 function isNonDeferredTypeReference(type: Type): type is TypeReference { 21344 return !!(getObjectFlags(type) & ObjectFlags.Reference) && !(type as TypeReference).node; 21345 } 21346 21347 function isTypeReferenceWithGenericArguments(type: Type): boolean { 21348 return isNonDeferredTypeReference(type) && some(getTypeArguments(type), t => !!(t.flags & TypeFlags.TypeParameter) || isTypeReferenceWithGenericArguments(t)); 21349 } 21350 21351 function getGenericTypeReferenceRelationKey(source: TypeReference, target: TypeReference, postFix: string, ignoreConstraints: boolean) { 21352 const typeParameters: Type[] = []; 21353 let constraintMarker = ""; 21354 const sourceId = getTypeReferenceId(source, 0); 21355 const targetId = getTypeReferenceId(target, 0); 21356 return `${constraintMarker}${sourceId},${targetId}${postFix}`; 21357 // getTypeReferenceId(A<T, number, U>) returns "111=0-12=1" 21358 // where A.id=111 and number.id=12 21359 function getTypeReferenceId(type: TypeReference, depth = 0) { 21360 let result = "" + type.target.id; 21361 for (const t of getTypeArguments(type)) { 21362 if (t.flags & TypeFlags.TypeParameter) { 21363 if (ignoreConstraints || isUnconstrainedTypeParameter(t)) { 21364 let index = typeParameters.indexOf(t); 21365 if (index < 0) { 21366 index = typeParameters.length; 21367 typeParameters.push(t); 21368 } 21369 result += "=" + index; 21370 continue; 21371 } 21372 // We mark type references that reference constrained type parameters such that we know to obtain 21373 // and look for a "broadest equivalent key" in the cache. 21374 constraintMarker = "*"; 21375 } 21376 else if (depth < 4 && isTypeReferenceWithGenericArguments(t)) { 21377 result += "<" + getTypeReferenceId(t as TypeReference, depth + 1) + ">"; 21378 continue; 21379 } 21380 result += "-" + t.id; 21381 } 21382 return result; 21383 } 21384 } 21385 21386 /** 21387 * To improve caching, the relation key for two generic types uses the target's id plus ids of the type parameters. 21388 * For other cases, the types ids are used. 21389 */ 21390 function getRelationKey(source: Type, target: Type, intersectionState: IntersectionState, relation: ESMap<string, RelationComparisonResult>, ignoreConstraints: boolean) { 21391 if (relation === identityRelation && source.id > target.id) { 21392 const temp = source; 21393 source = target; 21394 target = temp; 21395 } 21396 const postFix = intersectionState ? ":" + intersectionState : ""; 21397 return isTypeReferenceWithGenericArguments(source) && isTypeReferenceWithGenericArguments(target) ? 21398 getGenericTypeReferenceRelationKey(source as TypeReference, target as TypeReference, postFix, ignoreConstraints) : 21399 `${source.id},${target.id}${postFix}`; 21400 } 21401 21402 // Invoke the callback for each underlying property symbol of the given symbol and return the first 21403 // value that isn't undefined. 21404 function forEachProperty<T>(prop: Symbol, callback: (p: Symbol) => T): T | undefined { 21405 if (getCheckFlags(prop) & CheckFlags.Synthetic) { 21406 for (const t of (prop as TransientSymbol).containingType!.types) { 21407 const p = getPropertyOfType(t, prop.escapedName); 21408 const result = p && forEachProperty(p, callback); 21409 if (result) { 21410 return result; 21411 } 21412 } 21413 return undefined; 21414 } 21415 return callback(prop); 21416 } 21417 21418 // Return the declaring class type of a property or undefined if property not declared in class 21419 function getDeclaringClass(prop: Symbol) { 21420 return prop.parent && prop.parent.flags & SymbolFlags.Class ? getDeclaredTypeOfSymbol(getParentOfSymbol(prop)!) as InterfaceType : undefined; 21421 } 21422 21423 // Return the inherited type of the given property or undefined if property doesn't exist in a base class. 21424 function getTypeOfPropertyInBaseClass(property: Symbol) { 21425 const classType = getDeclaringClass(property); 21426 const baseClassType = classType && getBaseTypes(classType)[0]; 21427 return baseClassType && getTypeOfPropertyOfType(baseClassType, property.escapedName); 21428 } 21429 21430 // Return true if some underlying source property is declared in a class that derives 21431 // from the given base class. 21432 function isPropertyInClassDerivedFrom(prop: Symbol, baseClass: Type | undefined) { 21433 return forEachProperty(prop, sp => { 21434 const sourceClass = getDeclaringClass(sp); 21435 return sourceClass ? hasBaseType(sourceClass, baseClass) : false; 21436 }); 21437 } 21438 21439 // Return true if source property is a valid override of protected parts of target property. 21440 function isValidOverrideOf(sourceProp: Symbol, targetProp: Symbol) { 21441 return !forEachProperty(targetProp, tp => getDeclarationModifierFlagsFromSymbol(tp) & ModifierFlags.Protected ? 21442 !isPropertyInClassDerivedFrom(sourceProp, getDeclaringClass(tp)) : false); 21443 } 21444 21445 // Return true if the given class derives from each of the declaring classes of the protected 21446 // constituents of the given property. 21447 function isClassDerivedFromDeclaringClasses<T extends Type>(checkClass: T, prop: Symbol, writing: boolean) { 21448 return forEachProperty(prop, p => getDeclarationModifierFlagsFromSymbol(p, writing) & ModifierFlags.Protected ? 21449 !hasBaseType(checkClass, getDeclaringClass(p)) : false) ? undefined : checkClass; 21450 } 21451 21452 // Return true if the given type is deeply nested. We consider this to be the case when structural type comparisons 21453 // for maxDepth or more occurrences or instantiations of the type have been recorded on the given stack. It is possible, 21454 // though highly unlikely, for this test to be true in a situation where a chain of instantiations is not infinitely 21455 // expanding. Effectively, we will generate a false positive when two types are structurally equal to at least maxDepth 21456 // levels, but unequal at some level beyond that. 21457 // In addition, this will also detect when an indexed access has been chained off of maxDepth more times (which is 21458 // essentially the dual of the structural comparison), and likewise mark the type as deeply nested, potentially adding 21459 // false positives for finite but deeply expanding indexed accesses (eg, for `Q[P1][P2][P3][P4][P5]`). 21460 // It also detects when a recursive type reference has expanded maxDepth or more times, e.g. if the true branch of 21461 // `type A<T> = null extends T ? [A<NonNullable<T>>] : [T]` 21462 // has expanded into `[A<NonNullable<NonNullable<NonNullable<NonNullable<NonNullable<T>>>>>>]`. In such cases we need 21463 // to terminate the expansion, and we do so here. 21464 function isDeeplyNestedType(type: Type, stack: Type[], depth: number, maxDepth = 3): boolean { 21465 if (depth >= maxDepth) { 21466 const identity = getRecursionIdentity(type); 21467 let count = 0; 21468 let lastTypeId = 0; 21469 for (let i = 0; i < depth; i++) { 21470 const t = stack[i]; 21471 if (getRecursionIdentity(t) === identity) { 21472 // We only count occurrences with a higher type id than the previous occurrence, since higher 21473 // type ids are an indicator of newer instantiations caused by recursion. 21474 if (t.id >= lastTypeId) { 21475 count++; 21476 if (count >= maxDepth) { 21477 return true; 21478 } 21479 } 21480 lastTypeId = t.id; 21481 } 21482 } 21483 } 21484 return false; 21485 } 21486 21487 // The recursion identity of a type is an object identity that is shared among multiple instantiations of the type. 21488 // We track recursion identities in order to identify deeply nested and possibly infinite type instantiations with 21489 // the same origin. For example, when type parameters are in scope in an object type such as { x: T }, all 21490 // instantiations of that type have the same recursion identity. The default recursion identity is the object 21491 // identity of the type, meaning that every type is unique. Generally, types with constituents that could circularly 21492 // reference the type have a recursion identity that differs from the object identity. 21493 function getRecursionIdentity(type: Type): object { 21494 // Object and array literals are known not to contain recursive references and don't need a recursion identity. 21495 if (type.flags & TypeFlags.Object && !isObjectOrArrayLiteralType(type)) { 21496 if (getObjectFlags(type) && ObjectFlags.Reference && (type as TypeReference).node) { 21497 // Deferred type references are tracked through their associated AST node. This gives us finer 21498 // granularity than using their associated target because each manifest type reference has a 21499 // unique AST node. 21500 return (type as TypeReference).node!; 21501 } 21502 if (type.symbol && !(getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol.flags & SymbolFlags.Class)) { 21503 // We track all object types that have an associated symbol (representing the origin of the type), but 21504 // exclude the static side of classes from this check since it shares its symbol with the instance side. 21505 return type.symbol; 21506 } 21507 if (isTupleType(type)) { 21508 // Tuple types are tracked through their target type 21509 return type.target; 21510 } 21511 } 21512 if (type.flags & TypeFlags.TypeParameter) { 21513 return type.symbol; 21514 } 21515 if (type.flags & TypeFlags.IndexedAccess) { 21516 // Identity is the leftmost object type in a chain of indexed accesses, eg, in A[P][Q] it is A 21517 do { 21518 type = (type as IndexedAccessType).objectType; 21519 } while (type.flags & TypeFlags.IndexedAccess); 21520 return type; 21521 } 21522 if (type.flags & TypeFlags.Conditional) { 21523 // The root object represents the origin of the conditional type 21524 return (type as ConditionalType).root; 21525 } 21526 return type; 21527 } 21528 21529 function isPropertyIdenticalTo(sourceProp: Symbol, targetProp: Symbol): boolean { 21530 return compareProperties(sourceProp, targetProp, compareTypesIdentical) !== Ternary.False; 21531 } 21532 21533 function compareProperties(sourceProp: Symbol, targetProp: Symbol, compareTypes: (source: Type, target: Type) => Ternary): Ternary { 21534 // Two members are considered identical when 21535 // - they are public properties with identical names, optionality, and types, 21536 // - they are private or protected properties originating in the same declaration and having identical types 21537 if (sourceProp === targetProp) { 21538 return Ternary.True; 21539 } 21540 const sourcePropAccessibility = getDeclarationModifierFlagsFromSymbol(sourceProp) & ModifierFlags.NonPublicAccessibilityModifier; 21541 const targetPropAccessibility = getDeclarationModifierFlagsFromSymbol(targetProp) & ModifierFlags.NonPublicAccessibilityModifier; 21542 if (sourcePropAccessibility !== targetPropAccessibility) { 21543 return Ternary.False; 21544 } 21545 if (sourcePropAccessibility) { 21546 if (getTargetSymbol(sourceProp) !== getTargetSymbol(targetProp)) { 21547 return Ternary.False; 21548 } 21549 } 21550 else { 21551 if ((sourceProp.flags & SymbolFlags.Optional) !== (targetProp.flags & SymbolFlags.Optional)) { 21552 return Ternary.False; 21553 } 21554 } 21555 if (isReadonlySymbol(sourceProp) !== isReadonlySymbol(targetProp)) { 21556 return Ternary.False; 21557 } 21558 return compareTypes(getTypeOfSymbol(sourceProp), getTypeOfSymbol(targetProp)); 21559 } 21560 21561 function isMatchingSignature(source: Signature, target: Signature, partialMatch: boolean) { 21562 const sourceParameterCount = getParameterCount(source); 21563 const targetParameterCount = getParameterCount(target); 21564 const sourceMinArgumentCount = getMinArgumentCount(source); 21565 const targetMinArgumentCount = getMinArgumentCount(target); 21566 const sourceHasRestParameter = hasEffectiveRestParameter(source); 21567 const targetHasRestParameter = hasEffectiveRestParameter(target); 21568 // A source signature matches a target signature if the two signatures have the same number of required, 21569 // optional, and rest parameters. 21570 if (sourceParameterCount === targetParameterCount && 21571 sourceMinArgumentCount === targetMinArgumentCount && 21572 sourceHasRestParameter === targetHasRestParameter) { 21573 return true; 21574 } 21575 // A source signature partially matches a target signature if the target signature has no fewer required 21576 // parameters 21577 if (partialMatch && sourceMinArgumentCount <= targetMinArgumentCount) { 21578 return true; 21579 } 21580 return false; 21581 } 21582 21583 /** 21584 * See signatureRelatedTo, compareSignaturesIdentical 21585 */ 21586 function compareSignaturesIdentical(source: Signature, target: Signature, partialMatch: boolean, ignoreThisTypes: boolean, ignoreReturnTypes: boolean, compareTypes: (s: Type, t: Type) => Ternary): Ternary { 21587 // TODO (drosen): De-duplicate code between related functions. 21588 if (source === target) { 21589 return Ternary.True; 21590 } 21591 if (!(isMatchingSignature(source, target, partialMatch))) { 21592 return Ternary.False; 21593 } 21594 // Check that the two signatures have the same number of type parameters. 21595 if (length(source.typeParameters) !== length(target.typeParameters)) { 21596 return Ternary.False; 21597 } 21598 // Check that type parameter constraints and defaults match. If they do, instantiate the source 21599 // signature with the type parameters of the target signature and continue the comparison. 21600 if (target.typeParameters) { 21601 const mapper = createTypeMapper(source.typeParameters!, target.typeParameters); 21602 for (let i = 0; i < target.typeParameters.length; i++) { 21603 const s = source.typeParameters![i]; 21604 const t = target.typeParameters[i]; 21605 if (!(s === t || compareTypes(instantiateType(getConstraintFromTypeParameter(s), mapper) || unknownType, getConstraintFromTypeParameter(t) || unknownType) && 21606 compareTypes(instantiateType(getDefaultFromTypeParameter(s), mapper) || unknownType, getDefaultFromTypeParameter(t) || unknownType))) { 21607 return Ternary.False; 21608 } 21609 } 21610 source = instantiateSignature(source, mapper, /*eraseTypeParameters*/ true); 21611 } 21612 let result = Ternary.True; 21613 if (!ignoreThisTypes) { 21614 const sourceThisType = getThisTypeOfSignature(source); 21615 if (sourceThisType) { 21616 const targetThisType = getThisTypeOfSignature(target); 21617 if (targetThisType) { 21618 const related = compareTypes(sourceThisType, targetThisType); 21619 if (!related) { 21620 return Ternary.False; 21621 } 21622 result &= related; 21623 } 21624 } 21625 } 21626 const targetLen = getParameterCount(target); 21627 for (let i = 0; i < targetLen; i++) { 21628 const s = getTypeAtPosition(source, i); 21629 const t = getTypeAtPosition(target, i); 21630 const related = compareTypes(t, s); 21631 if (!related) { 21632 return Ternary.False; 21633 } 21634 result &= related; 21635 } 21636 if (!ignoreReturnTypes) { 21637 const sourceTypePredicate = getTypePredicateOfSignature(source); 21638 const targetTypePredicate = getTypePredicateOfSignature(target); 21639 result &= sourceTypePredicate || targetTypePredicate ? 21640 compareTypePredicatesIdentical(sourceTypePredicate, targetTypePredicate, compareTypes) : 21641 compareTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target)); 21642 } 21643 return result; 21644 } 21645 21646 function compareTypePredicatesIdentical(source: TypePredicate | undefined, target: TypePredicate | undefined, compareTypes: (s: Type, t: Type) => Ternary): Ternary { 21647 return !(source && target && typePredicateKindsMatch(source, target)) ? Ternary.False : 21648 source.type === target.type ? Ternary.True : 21649 source.type && target.type ? compareTypes(source.type, target.type) : 21650 Ternary.False; 21651 } 21652 21653 function literalTypesWithSameBaseType(types: Type[]): boolean { 21654 let commonBaseType: Type | undefined; 21655 for (const t of types) { 21656 if (!(t.flags & TypeFlags.Never)) { 21657 const baseType = getBaseTypeOfLiteralType(t); 21658 commonBaseType ??= baseType; 21659 if (baseType === t || baseType !== commonBaseType) { 21660 return false; 21661 } 21662 } 21663 } 21664 return true; 21665 } 21666 21667 function getCombinedTypeFlags(types: Type[]): TypeFlags { 21668 return reduceLeft(types, (flags, t) => flags | (t.flags & TypeFlags.Union ? getCombinedTypeFlags((t as UnionType).types) : t.flags), 0); 21669 } 21670 21671 function getCommonSupertype(types: Type[]): Type { 21672 if (types.length === 1) { 21673 return types[0]; 21674 } 21675 // Remove nullable types from each of the candidates. 21676 const primaryTypes = strictNullChecks ? sameMap(types, t => filterType(t, u => !(u.flags & TypeFlags.Nullable))) : types; 21677 // When the candidate types are all literal types with the same base type, return a union 21678 // of those literal types. Otherwise, return the leftmost type for which no type to the 21679 // right is a supertype. 21680 const superTypeOrUnion = literalTypesWithSameBaseType(primaryTypes) ? 21681 getUnionType(primaryTypes) : 21682 reduceLeft(primaryTypes, (s, t) => isTypeSubtypeOf(s, t) ? t : s)!; 21683 // Add any nullable types that occurred in the candidates back to the result. 21684 return primaryTypes === types ? superTypeOrUnion : getNullableType(superTypeOrUnion, getCombinedTypeFlags(types) & TypeFlags.Nullable); 21685 } 21686 21687 // Return the leftmost type for which no type to the right is a subtype. 21688 function getCommonSubtype(types: Type[]) { 21689 return reduceLeft(types, (s, t) => isTypeSubtypeOf(t, s) ? t : s)!; 21690 } 21691 21692 function isArrayType(type: Type): type is TypeReference { 21693 return !!(getObjectFlags(type) & ObjectFlags.Reference) && ((type as TypeReference).target === globalArrayType || (type as TypeReference).target === globalReadonlyArrayType); 21694 } 21695 21696 function isReadonlyArrayType(type: Type): boolean { 21697 return !!(getObjectFlags(type) & ObjectFlags.Reference) && (type as TypeReference).target === globalReadonlyArrayType; 21698 } 21699 21700 function isArrayOrTupleType(type: Type): type is TypeReference { 21701 return isArrayType(type) || isTupleType(type); 21702 } 21703 21704 function isMutableArrayOrTuple(type: Type): boolean { 21705 return isArrayType(type) && !isReadonlyArrayType(type) || isTupleType(type) && !type.target.readonly; 21706 } 21707 21708 function getElementTypeOfArrayType(type: Type): Type | undefined { 21709 return isArrayType(type) ? getTypeArguments(type)[0] : undefined; 21710 } 21711 21712 function isArrayLikeType(type: Type): boolean { 21713 // A type is array-like if it is a reference to the global Array or global ReadonlyArray type, 21714 // or if it is not the undefined or null type and if it is assignable to ReadonlyArray<any> 21715 return isArrayType(type) || !(type.flags & TypeFlags.Nullable) && isTypeAssignableTo(type, anyReadonlyArrayType); 21716 } 21717 21718 function getSingleBaseForNonAugmentingSubtype(type: Type) { 21719 if (!(getObjectFlags(type) & ObjectFlags.Reference) || !(getObjectFlags((type as TypeReference).target) & ObjectFlags.ClassOrInterface)) { 21720 return undefined; 21721 } 21722 if (getObjectFlags(type) & ObjectFlags.IdenticalBaseTypeCalculated) { 21723 return getObjectFlags(type) & ObjectFlags.IdenticalBaseTypeExists ? (type as TypeReference).cachedEquivalentBaseType : undefined; 21724 } 21725 (type as TypeReference).objectFlags |= ObjectFlags.IdenticalBaseTypeCalculated; 21726 const target = (type as TypeReference).target as InterfaceType; 21727 if (getObjectFlags(target) & ObjectFlags.Class) { 21728 const baseTypeNode = getBaseTypeNodeOfClass(target); 21729 // A base type expression may circularly reference the class itself (e.g. as an argument to function call), so we only 21730 // check for base types specified as simple qualified names. 21731 if (baseTypeNode && baseTypeNode.expression.kind !== SyntaxKind.Identifier && baseTypeNode.expression.kind !== SyntaxKind.PropertyAccessExpression) { 21732 return undefined; 21733 } 21734 } 21735 const bases = getBaseTypes(target); 21736 if (bases.length !== 1) { 21737 return undefined; 21738 } 21739 if (getMembersOfSymbol(type.symbol).size) { 21740 return undefined; // If the interface has any members, they may subtype members in the base, so we should do a full structural comparison 21741 } 21742 let instantiatedBase = !length(target.typeParameters) ? bases[0] : instantiateType(bases[0], createTypeMapper(target.typeParameters!, getTypeArguments(type as TypeReference).slice(0, target.typeParameters!.length))); 21743 if (length(getTypeArguments(type as TypeReference)) > length(target.typeParameters)) { 21744 instantiatedBase = getTypeWithThisArgument(instantiatedBase, last(getTypeArguments(type as TypeReference))); 21745 } 21746 (type as TypeReference).objectFlags |= ObjectFlags.IdenticalBaseTypeExists; 21747 return (type as TypeReference).cachedEquivalentBaseType = instantiatedBase; 21748 } 21749 21750 function isEmptyLiteralType(type: Type): boolean { 21751 return strictNullChecks ? type === implicitNeverType : type === undefinedWideningType; 21752 } 21753 21754 function isEmptyArrayLiteralType(type: Type): boolean { 21755 const elementType = getElementTypeOfArrayType(type); 21756 return !!elementType && isEmptyLiteralType(elementType); 21757 } 21758 21759 function isTupleLikeType(type: Type): boolean { 21760 return isTupleType(type) || !!getPropertyOfType(type, "0" as __String); 21761 } 21762 21763 function isArrayOrTupleLikeType(type: Type): boolean { 21764 return isArrayLikeType(type) || isTupleLikeType(type); 21765 } 21766 21767 function getTupleElementType(type: Type, index: number) { 21768 const propType = getTypeOfPropertyOfType(type, "" + index as __String); 21769 if (propType) { 21770 return propType; 21771 } 21772 if (everyType(type, isTupleType)) { 21773 return mapType(type, t => getRestTypeOfTupleType(t as TupleTypeReference) || undefinedType); 21774 } 21775 return undefined; 21776 } 21777 21778 function isNeitherUnitTypeNorNever(type: Type): boolean { 21779 return !(type.flags & (TypeFlags.Unit | TypeFlags.Never)); 21780 } 21781 21782 function isUnitType(type: Type): boolean { 21783 return !!(type.flags & TypeFlags.Unit); 21784 } 21785 21786 function isUnitLikeType(type: Type): boolean { 21787 // Intersections that reduce to 'never' (e.g. 'T & null' where 'T extends {}') are not unit types. 21788 const t = getBaseConstraintOrType(type); 21789 // Scan intersections such that tagged literal types are considered unit types. 21790 return t.flags & TypeFlags.Intersection ? some((t as IntersectionType).types, isUnitType) : isUnitType(t); 21791 } 21792 21793 function extractUnitType(type: Type) { 21794 return type.flags & TypeFlags.Intersection ? find((type as IntersectionType).types, isUnitType) || type : type; 21795 } 21796 21797 function isLiteralType(type: Type): boolean { 21798 return type.flags & TypeFlags.Boolean ? true : 21799 type.flags & TypeFlags.Union ? type.flags & TypeFlags.EnumLiteral ? true : every((type as UnionType).types, isUnitType) : 21800 isUnitType(type); 21801 } 21802 21803 function getBaseTypeOfLiteralType(type: Type): Type { 21804 return type.flags & TypeFlags.EnumLiteral ? getBaseTypeOfEnumLiteralType(type as LiteralType) : 21805 type.flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) ? stringType : 21806 type.flags & TypeFlags.NumberLiteral ? numberType : 21807 type.flags & TypeFlags.BigIntLiteral ? bigintType : 21808 type.flags & TypeFlags.BooleanLiteral ? booleanType : 21809 type.flags & TypeFlags.Union ? getBaseTypeOfLiteralTypeUnion(type as UnionType) : 21810 type; 21811 } 21812 21813 function getBaseTypeOfLiteralTypeUnion(type: UnionType) { 21814 const key = `B${getTypeId(type)}`; 21815 return getCachedType(key) ?? setCachedType(key, mapType(type, getBaseTypeOfLiteralType)); 21816 } 21817 21818 function getWidenedLiteralType(type: Type): Type { 21819 return type.flags & TypeFlags.EnumLiteral && isFreshLiteralType(type) ? getBaseTypeOfEnumLiteralType(type as LiteralType) : 21820 type.flags & TypeFlags.StringLiteral && isFreshLiteralType(type) ? stringType : 21821 type.flags & TypeFlags.NumberLiteral && isFreshLiteralType(type) ? numberType : 21822 type.flags & TypeFlags.BigIntLiteral && isFreshLiteralType(type) ? bigintType : 21823 type.flags & TypeFlags.BooleanLiteral && isFreshLiteralType(type) ? booleanType : 21824 type.flags & TypeFlags.Union ? mapType(type as UnionType, getWidenedLiteralType) : 21825 type; 21826 } 21827 21828 function getWidenedUniqueESSymbolType(type: Type): Type { 21829 return type.flags & TypeFlags.UniqueESSymbol ? esSymbolType : 21830 type.flags & TypeFlags.Union ? mapType(type as UnionType, getWidenedUniqueESSymbolType) : 21831 type; 21832 } 21833 21834 function getWidenedLiteralLikeTypeForContextualType(type: Type, contextualType: Type | undefined) { 21835 if (!isLiteralOfContextualType(type, contextualType)) { 21836 type = getWidenedUniqueESSymbolType(getWidenedLiteralType(type)); 21837 } 21838 return getRegularTypeOfLiteralType(type); 21839 } 21840 21841 function getWidenedLiteralLikeTypeForContextualReturnTypeIfNeeded(type: Type | undefined, contextualSignatureReturnType: Type | undefined, isAsync: boolean) { 21842 if (type && isUnitType(type)) { 21843 const contextualType = !contextualSignatureReturnType ? undefined : 21844 isAsync ? getPromisedTypeOfPromise(contextualSignatureReturnType) : 21845 contextualSignatureReturnType; 21846 type = getWidenedLiteralLikeTypeForContextualType(type, contextualType); 21847 } 21848 return type; 21849 } 21850 21851 function getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded(type: Type | undefined, contextualSignatureReturnType: Type | undefined, kind: IterationTypeKind, isAsyncGenerator: boolean) { 21852 if (type && isUnitType(type)) { 21853 const contextualType = !contextualSignatureReturnType ? undefined : 21854 getIterationTypeOfGeneratorFunctionReturnType(kind, contextualSignatureReturnType, isAsyncGenerator); 21855 type = getWidenedLiteralLikeTypeForContextualType(type, contextualType); 21856 } 21857 return type; 21858 } 21859 21860 /** 21861 * Check if a Type was written as a tuple type literal. 21862 * Prefer using isTupleLikeType() unless the use of `elementTypes`/`getTypeArguments` is required. 21863 */ 21864 function isTupleType(type: Type): type is TupleTypeReference { 21865 return !!(getObjectFlags(type) & ObjectFlags.Reference && (type as TypeReference).target.objectFlags & ObjectFlags.Tuple); 21866 } 21867 21868 function isGenericTupleType(type: Type): type is TupleTypeReference { 21869 return isTupleType(type) && !!(type.target.combinedFlags & ElementFlags.Variadic); 21870 } 21871 21872 function isSingleElementGenericTupleType(type: Type): type is TupleTypeReference { 21873 return isGenericTupleType(type) && type.target.elementFlags.length === 1; 21874 } 21875 21876 function getRestTypeOfTupleType(type: TupleTypeReference) { 21877 return getElementTypeOfSliceOfTupleType(type, type.target.fixedLength); 21878 } 21879 21880 function getRestArrayTypeOfTupleType(type: TupleTypeReference) { 21881 const restType = getRestTypeOfTupleType(type); 21882 return restType && createArrayType(restType); 21883 } 21884 21885 function getElementTypeOfSliceOfTupleType(type: TupleTypeReference, index: number, endSkipCount = 0, writing = false) { 21886 const length = getTypeReferenceArity(type) - endSkipCount; 21887 if (index < length) { 21888 const typeArguments = getTypeArguments(type); 21889 const elementTypes: Type[] = []; 21890 for (let i = index; i < length; i++) { 21891 const t = typeArguments[i]; 21892 elementTypes.push(type.target.elementFlags[i] & ElementFlags.Variadic ? getIndexedAccessType(t, numberType) : t); 21893 } 21894 return writing ? getIntersectionType(elementTypes) : getUnionType(elementTypes); 21895 } 21896 return undefined; 21897 } 21898 21899 function isTupleTypeStructureMatching(t1: TupleTypeReference, t2: TupleTypeReference) { 21900 return getTypeReferenceArity(t1) === getTypeReferenceArity(t2) && 21901 every(t1.target.elementFlags, (f, i) => (f & ElementFlags.Variable) === (t2.target.elementFlags[i] & ElementFlags.Variable)); 21902 } 21903 21904 function isZeroBigInt({value}: BigIntLiteralType) { 21905 return value.base10Value === "0"; 21906 } 21907 21908 function removeDefinitelyFalsyTypes(type: Type): Type { 21909 return filterType(type, t => !!(getTypeFacts(t) & TypeFacts.Truthy)); 21910 } 21911 21912 function extractDefinitelyFalsyTypes(type: Type): Type { 21913 return mapType(type, getDefinitelyFalsyPartOfType); 21914 } 21915 21916 function getDefinitelyFalsyPartOfType(type: Type): Type { 21917 return type.flags & TypeFlags.String ? emptyStringType : 21918 type.flags & TypeFlags.Number ? zeroType : 21919 type.flags & TypeFlags.BigInt ? zeroBigIntType : 21920 type === regularFalseType || 21921 type === falseType || 21922 type.flags & (TypeFlags.Void | TypeFlags.Undefined | TypeFlags.Null | TypeFlags.AnyOrUnknown) || 21923 type.flags & TypeFlags.StringLiteral && (type as StringLiteralType).value === "" || 21924 type.flags & TypeFlags.NumberLiteral && (type as NumberLiteralType).value === 0 || 21925 type.flags & TypeFlags.BigIntLiteral && isZeroBigInt(type as BigIntLiteralType) ? type : 21926 neverType; 21927 } 21928 21929 /** 21930 * Add undefined or null or both to a type if they are missing. 21931 * @param type - type to add undefined and/or null to if not present 21932 * @param flags - Either TypeFlags.Undefined or TypeFlags.Null, or both 21933 */ 21934 function getNullableType(type: Type, flags: TypeFlags): Type { 21935 const missing = (flags & ~type.flags) & (TypeFlags.Undefined | TypeFlags.Null); 21936 return missing === 0 ? type : 21937 missing === TypeFlags.Undefined ? getUnionType([type, undefinedType]) : 21938 missing === TypeFlags.Null ? getUnionType([type, nullType]) : 21939 getUnionType([type, undefinedType, nullType]); 21940 } 21941 21942 function getOptionalType(type: Type, isProperty = false): Type { 21943 Debug.assert(strictNullChecks); 21944 const missingOrUndefined = isProperty ? missingType : undefinedType; 21945 return type.flags & TypeFlags.Undefined || type.flags & TypeFlags.Union && (type as UnionType).types[0] === missingOrUndefined ? type : getUnionType([type, missingOrUndefined]); 21946 } 21947 21948 function getGlobalNonNullableTypeInstantiation(type: Type) { 21949 if (!deferredGlobalNonNullableTypeAlias) { 21950 deferredGlobalNonNullableTypeAlias = getGlobalSymbol("NonNullable" as __String, SymbolFlags.TypeAlias, /*diagnostic*/ undefined) || unknownSymbol; 21951 } 21952 return deferredGlobalNonNullableTypeAlias !== unknownSymbol ? 21953 getTypeAliasInstantiation(deferredGlobalNonNullableTypeAlias, [type]) : 21954 getIntersectionType([type, emptyObjectType]); 21955 } 21956 21957 function getNonNullableType(type: Type): Type { 21958 return strictNullChecks ? getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type; 21959 } 21960 21961 function addOptionalTypeMarker(type: Type) { 21962 return strictNullChecks ? getUnionType([type, optionalType]) : type; 21963 } 21964 21965 function removeOptionalTypeMarker(type: Type): Type { 21966 return strictNullChecks ? removeType(type, optionalType) : type; 21967 } 21968 21969 function propagateOptionalTypeMarker(type: Type, node: OptionalChain, wasOptional: boolean) { 21970 return wasOptional ? isOutermostOptionalChain(node) ? getOptionalType(type) : addOptionalTypeMarker(type) : type; 21971 } 21972 21973 function getOptionalExpressionType(exprType: Type, expression: Expression) { 21974 return isExpressionOfOptionalChainRoot(expression) ? getNonNullableType(exprType) : 21975 isOptionalChain(expression) ? removeOptionalTypeMarker(exprType) : 21976 exprType; 21977 } 21978 21979 function removeMissingType(type: Type, isOptional: boolean) { 21980 return exactOptionalPropertyTypes && isOptional ? removeType(type, missingType) : type; 21981 } 21982 21983 function containsMissingType(type: Type) { 21984 return exactOptionalPropertyTypes && (type === missingType || type.flags & TypeFlags.Union && containsType((type as UnionType).types, missingType)); 21985 } 21986 21987 function removeMissingOrUndefinedType(type: Type): Type { 21988 return exactOptionalPropertyTypes ? removeType(type, missingType) : getTypeWithFacts(type, TypeFacts.NEUndefined); 21989 } 21990 21991 /** 21992 * Is source potentially coercible to target type under `==`. 21993 * Assumes that `source` is a constituent of a union, hence 21994 * the boolean literal flag on the LHS, but not on the RHS. 21995 * 21996 * This does not fully replicate the semantics of `==`. The 21997 * intention is to catch cases that are clearly not right. 21998 * 21999 * Comparing (string | number) to number should not remove the 22000 * string element. 22001 * 22002 * Comparing (string | number) to 1 will remove the string 22003 * element, though this is not sound. This is a pragmatic 22004 * choice. 22005 * 22006 * @see narrowTypeByEquality 22007 * 22008 * @param source 22009 * @param target 22010 */ 22011 function isCoercibleUnderDoubleEquals(source: Type, target: Type): boolean { 22012 return ((source.flags & (TypeFlags.Number | TypeFlags.String | TypeFlags.BooleanLiteral)) !== 0) 22013 && ((target.flags & (TypeFlags.Number | TypeFlags.String | TypeFlags.Boolean)) !== 0); 22014 } 22015 22016 /** 22017 * Return true if type was inferred from an object literal, written as an object type literal, or is the shape of a module 22018 * with no call or construct signatures. 22019 */ 22020 function isObjectTypeWithInferableIndex(type: Type): boolean { 22021 const objectFlags = getObjectFlags(type); 22022 return type.flags & TypeFlags.Intersection 22023 ? every((type as IntersectionType).types, isObjectTypeWithInferableIndex) 22024 : !!( 22025 type.symbol 22026 && (type.symbol.flags & (SymbolFlags.ObjectLiteral | SymbolFlags.TypeLiteral | SymbolFlags.Enum | SymbolFlags.ValueModule)) !== 0 22027 && !(type.symbol.flags & SymbolFlags.Class) 22028 && !typeHasCallOrConstructSignatures(type) 22029 ) || !!( 22030 objectFlags & ObjectFlags.ObjectRestType 22031 ) || !!(objectFlags & ObjectFlags.ReverseMapped && isObjectTypeWithInferableIndex((type as ReverseMappedType).source)); 22032 } 22033 22034 function createSymbolWithType(source: Symbol, type: Type | undefined) { 22035 const symbol = createSymbol(source.flags, source.escapedName, getCheckFlags(source) & CheckFlags.Readonly); 22036 symbol.declarations = source.declarations; 22037 symbol.parent = source.parent; 22038 symbol.type = type; 22039 symbol.target = source; 22040 if (source.valueDeclaration) { 22041 symbol.valueDeclaration = source.valueDeclaration; 22042 } 22043 const nameType = getSymbolLinks(source).nameType; 22044 if (nameType) { 22045 symbol.nameType = nameType; 22046 } 22047 return symbol; 22048 } 22049 22050 function transformTypeOfMembers(type: Type, f: (propertyType: Type) => Type) { 22051 const members = createSymbolTable(); 22052 for (const property of getPropertiesOfObjectType(type)) { 22053 const original = getTypeOfSymbol(property); 22054 const updated = f(original); 22055 members.set(property.escapedName, updated === original ? property : createSymbolWithType(property, updated)); 22056 } 22057 return members; 22058 } 22059 22060 /** 22061 * If the the provided object literal is subject to the excess properties check, 22062 * create a new that is exempt. Recursively mark object literal members as exempt. 22063 * Leave signatures alone since they are not subject to the check. 22064 */ 22065 function getRegularTypeOfObjectLiteral(type: Type): Type { 22066 if (!(isObjectLiteralType(type) && getObjectFlags(type) & ObjectFlags.FreshLiteral)) { 22067 return type; 22068 } 22069 const regularType = (type as FreshObjectLiteralType).regularType; 22070 if (regularType) { 22071 return regularType; 22072 } 22073 22074 const resolved = type as ResolvedType; 22075 const members = transformTypeOfMembers(type, getRegularTypeOfObjectLiteral); 22076 const regularNew = createAnonymousType(resolved.symbol, members, resolved.callSignatures, resolved.constructSignatures, resolved.indexInfos); 22077 regularNew.flags = resolved.flags; 22078 regularNew.objectFlags |= resolved.objectFlags & ~ObjectFlags.FreshLiteral; 22079 (type as FreshObjectLiteralType).regularType = regularNew; 22080 return regularNew; 22081 } 22082 22083 function createWideningContext(parent: WideningContext | undefined, propertyName: __String | undefined, siblings: Type[] | undefined): WideningContext { 22084 return { parent, propertyName, siblings, resolvedProperties: undefined }; 22085 } 22086 22087 function getSiblingsOfContext(context: WideningContext): Type[] { 22088 if (!context.siblings) { 22089 const siblings: Type[] = []; 22090 for (const type of getSiblingsOfContext(context.parent!)) { 22091 if (isObjectLiteralType(type)) { 22092 const prop = getPropertyOfObjectType(type, context.propertyName!); 22093 if (prop) { 22094 forEachType(getTypeOfSymbol(prop), t => { 22095 siblings.push(t); 22096 }); 22097 } 22098 } 22099 } 22100 context.siblings = siblings; 22101 } 22102 return context.siblings; 22103 } 22104 22105 function getPropertiesOfContext(context: WideningContext): Symbol[] { 22106 if (!context.resolvedProperties) { 22107 const names = new Map<string, Symbol>() as UnderscoreEscapedMap<Symbol>; 22108 for (const t of getSiblingsOfContext(context)) { 22109 if (isObjectLiteralType(t) && !(getObjectFlags(t) & ObjectFlags.ContainsSpread)) { 22110 for (const prop of getPropertiesOfType(t)) { 22111 names.set(prop.escapedName, prop); 22112 } 22113 } 22114 } 22115 context.resolvedProperties = arrayFrom(names.values()); 22116 } 22117 return context.resolvedProperties; 22118 } 22119 22120 function getWidenedProperty(prop: Symbol, context: WideningContext | undefined): Symbol { 22121 if (!(prop.flags & SymbolFlags.Property)) { 22122 // Since get accessors already widen their return value there is no need to 22123 // widen accessor based properties here. 22124 return prop; 22125 } 22126 const original = getTypeOfSymbol(prop); 22127 const propContext = context && createWideningContext(context, prop.escapedName, /*siblings*/ undefined); 22128 const widened = getWidenedTypeWithContext(original, propContext); 22129 return widened === original ? prop : createSymbolWithType(prop, widened); 22130 } 22131 22132 function getUndefinedProperty(prop: Symbol) { 22133 const cached = undefinedProperties.get(prop.escapedName); 22134 if (cached) { 22135 return cached; 22136 } 22137 const result = createSymbolWithType(prop, missingType); 22138 result.flags |= SymbolFlags.Optional; 22139 undefinedProperties.set(prop.escapedName, result); 22140 return result; 22141 } 22142 22143 function getWidenedTypeOfObjectLiteral(type: Type, context: WideningContext | undefined): Type { 22144 const members = createSymbolTable(); 22145 for (const prop of getPropertiesOfObjectType(type)) { 22146 members.set(prop.escapedName, getWidenedProperty(prop, context)); 22147 } 22148 if (context) { 22149 for (const prop of getPropertiesOfContext(context)) { 22150 if (!members.has(prop.escapedName)) { 22151 members.set(prop.escapedName, getUndefinedProperty(prop)); 22152 } 22153 } 22154 } 22155 const result = createAnonymousType(type.symbol, members, emptyArray, emptyArray, 22156 sameMap(getIndexInfosOfType(type), info => createIndexInfo(info.keyType, getWidenedType(info.type), info.isReadonly))); 22157 result.objectFlags |= (getObjectFlags(type) & (ObjectFlags.JSLiteral | ObjectFlags.NonInferrableType)); // Retain js literal flag through widening 22158 return result; 22159 } 22160 22161 function getWidenedType(type: Type) { 22162 return getWidenedTypeWithContext(type, /*context*/ undefined); 22163 } 22164 22165 function getWidenedTypeWithContext(type: Type, context: WideningContext | undefined): Type { 22166 if (getObjectFlags(type) & ObjectFlags.RequiresWidening) { 22167 if (context === undefined && type.widened) { 22168 return type.widened; 22169 } 22170 let result: Type | undefined; 22171 if (type.flags & (TypeFlags.Any | TypeFlags.Nullable)) { 22172 result = anyType; 22173 } 22174 else if (isObjectLiteralType(type)) { 22175 result = getWidenedTypeOfObjectLiteral(type, context); 22176 } 22177 else if (type.flags & TypeFlags.Union) { 22178 const unionContext = context || createWideningContext(/*parent*/ undefined, /*propertyName*/ undefined, (type as UnionType).types); 22179 const widenedTypes = sameMap((type as UnionType).types, t => t.flags & TypeFlags.Nullable ? t : getWidenedTypeWithContext(t, unionContext)); 22180 // Widening an empty object literal transitions from a highly restrictive type to 22181 // a highly inclusive one. For that reason we perform subtype reduction here if the 22182 // union includes empty object types (e.g. reducing {} | string to just {}). 22183 result = getUnionType(widenedTypes, some(widenedTypes, isEmptyObjectType) ? UnionReduction.Subtype : UnionReduction.Literal); 22184 } 22185 else if (type.flags & TypeFlags.Intersection) { 22186 result = getIntersectionType(sameMap((type as IntersectionType).types, getWidenedType)); 22187 } 22188 else if (isArrayOrTupleType(type)) { 22189 result = createTypeReference(type.target, sameMap(getTypeArguments(type), getWidenedType)); 22190 } 22191 if (result && context === undefined) { 22192 type.widened = result; 22193 } 22194 return result || type; 22195 } 22196 return type; 22197 } 22198 22199 /** 22200 * Reports implicit any errors that occur as a result of widening 'null' and 'undefined' 22201 * to 'any'. A call to reportWideningErrorsInType is normally accompanied by a call to 22202 * getWidenedType. But in some cases getWidenedType is called without reporting errors 22203 * (type argument inference is an example). 22204 * 22205 * The return value indicates whether an error was in fact reported. The particular circumstances 22206 * are on a best effort basis. Currently, if the null or undefined that causes widening is inside 22207 * an object literal property (arbitrarily deeply), this function reports an error. If no error is 22208 * reported, reportImplicitAnyError is a suitable fallback to report a general error. 22209 */ 22210 function reportWideningErrorsInType(type: Type): boolean { 22211 let errorReported = false; 22212 if (getObjectFlags(type) & ObjectFlags.ContainsWideningType) { 22213 if (type.flags & TypeFlags.Union) { 22214 if (some((type as UnionType).types, isEmptyObjectType)) { 22215 errorReported = true; 22216 } 22217 else { 22218 for (const t of (type as UnionType).types) { 22219 if (reportWideningErrorsInType(t)) { 22220 errorReported = true; 22221 } 22222 } 22223 } 22224 } 22225 if (isArrayOrTupleType(type)) { 22226 for (const t of getTypeArguments(type)) { 22227 if (reportWideningErrorsInType(t)) { 22228 errorReported = true; 22229 } 22230 } 22231 } 22232 if (isObjectLiteralType(type)) { 22233 for (const p of getPropertiesOfObjectType(type)) { 22234 const t = getTypeOfSymbol(p); 22235 if (getObjectFlags(t) & ObjectFlags.ContainsWideningType) { 22236 if (!reportWideningErrorsInType(t)) { 22237 error(p.valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, symbolToString(p), typeToString(getWidenedType(t))); 22238 } 22239 errorReported = true; 22240 } 22241 } 22242 } 22243 } 22244 return errorReported; 22245 } 22246 22247 function reportImplicitAny(declaration: Declaration, type: Type, wideningKind?: WideningKind) { 22248 const typeAsString = typeToString(getWidenedType(type)); 22249 if (isInJSFile(declaration) && !isCheckJsEnabledForFile(getSourceFileOfNode(declaration), compilerOptions)) { 22250 // Only report implicit any errors/suggestions in TS and ts-check JS files 22251 return; 22252 } 22253 let diagnostic: DiagnosticMessage; 22254 switch (declaration.kind) { 22255 case SyntaxKind.BinaryExpression: 22256 case SyntaxKind.PropertyDeclaration: 22257 case SyntaxKind.PropertySignature: 22258 diagnostic = noImplicitAny ? Diagnostics.Member_0_implicitly_has_an_1_type : Diagnostics.Member_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage; 22259 break; 22260 case SyntaxKind.Parameter: 22261 const param = declaration as ParameterDeclaration; 22262 if (isIdentifier(param.name) && 22263 (isCallSignatureDeclaration(param.parent) || isMethodSignature(param.parent) || isFunctionTypeNode(param.parent)) && 22264 param.parent.parameters.indexOf(param) > -1 && 22265 (resolveName(param, param.name.escapedText, SymbolFlags.Type, undefined, param.name.escapedText, /*isUse*/ true) || 22266 param.name.originalKeywordKind && isTypeNodeKind(param.name.originalKeywordKind))) { 22267 const newName = "arg" + param.parent.parameters.indexOf(param); 22268 const typeName = declarationNameToString(param.name) + (param.dotDotDotToken ? "[]" : ""); 22269 errorOrSuggestion(noImplicitAny, declaration, Diagnostics.Parameter_has_a_name_but_no_type_Did_you_mean_0_Colon_1, newName, typeName); 22270 return; 22271 } 22272 diagnostic = (declaration as ParameterDeclaration).dotDotDotToken ? 22273 noImplicitAny ? Diagnostics.Rest_parameter_0_implicitly_has_an_any_type : Diagnostics.Rest_parameter_0_implicitly_has_an_any_type_but_a_better_type_may_be_inferred_from_usage : 22274 noImplicitAny ? Diagnostics.Parameter_0_implicitly_has_an_1_type : Diagnostics.Parameter_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage; 22275 break; 22276 case SyntaxKind.BindingElement: 22277 diagnostic = Diagnostics.Binding_element_0_implicitly_has_an_1_type; 22278 if (!noImplicitAny) { 22279 // Don't issue a suggestion for binding elements since the codefix doesn't yet support them. 22280 return; 22281 } 22282 break; 22283 case SyntaxKind.JSDocFunctionType: 22284 error(declaration, Diagnostics.Function_type_which_lacks_return_type_annotation_implicitly_has_an_0_return_type, typeAsString); 22285 return; 22286 case SyntaxKind.FunctionDeclaration: 22287 case SyntaxKind.MethodDeclaration: 22288 case SyntaxKind.MethodSignature: 22289 case SyntaxKind.GetAccessor: 22290 case SyntaxKind.SetAccessor: 22291 case SyntaxKind.FunctionExpression: 22292 case SyntaxKind.ArrowFunction: 22293 if (noImplicitAny && !(declaration as NamedDeclaration).name) { 22294 if (wideningKind === WideningKind.GeneratorYield) { 22295 error(declaration, Diagnostics.Generator_implicitly_has_yield_type_0_because_it_does_not_yield_any_values_Consider_supplying_a_return_type_annotation, typeAsString); 22296 } 22297 else { 22298 error(declaration, Diagnostics.Function_expression_which_lacks_return_type_annotation_implicitly_has_an_0_return_type, typeAsString); 22299 } 22300 return; 22301 } 22302 diagnostic = !noImplicitAny ? Diagnostics._0_implicitly_has_an_1_return_type_but_a_better_type_may_be_inferred_from_usage : 22303 wideningKind === WideningKind.GeneratorYield ? Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_yield_type : 22304 Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type; 22305 break; 22306 case SyntaxKind.MappedType: 22307 if (noImplicitAny) { 22308 error(declaration, Diagnostics.Mapped_object_type_implicitly_has_an_any_template_type); 22309 } 22310 return; 22311 default: 22312 diagnostic = noImplicitAny ? Diagnostics.Variable_0_implicitly_has_an_1_type : Diagnostics.Variable_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage; 22313 } 22314 errorOrSuggestion(noImplicitAny, declaration, diagnostic, declarationNameToString(getNameOfDeclaration(declaration)), typeAsString); 22315 } 22316 22317 function reportErrorsFromWidening(declaration: Declaration, type: Type, wideningKind?: WideningKind) { 22318 addLazyDiagnostic(() => { 22319 if (noImplicitAny && getObjectFlags(type) & ObjectFlags.ContainsWideningType && (!wideningKind || !getContextualSignatureForFunctionLikeDeclaration(declaration as FunctionLikeDeclaration))) { 22320 // Report implicit any error within type if possible, otherwise report error on declaration 22321 if (!reportWideningErrorsInType(type)) { 22322 reportImplicitAny(declaration, type, wideningKind); 22323 } 22324 } 22325 }); 22326 } 22327 22328 function applyToParameterTypes(source: Signature, target: Signature, callback: (s: Type, t: Type) => void) { 22329 const sourceCount = getParameterCount(source); 22330 const targetCount = getParameterCount(target); 22331 const sourceRestType = getEffectiveRestType(source); 22332 const targetRestType = getEffectiveRestType(target); 22333 const targetNonRestCount = targetRestType ? targetCount - 1 : targetCount; 22334 const paramCount = sourceRestType ? targetNonRestCount : Math.min(sourceCount, targetNonRestCount); 22335 const sourceThisType = getThisTypeOfSignature(source); 22336 if (sourceThisType) { 22337 const targetThisType = getThisTypeOfSignature(target); 22338 if (targetThisType) { 22339 callback(sourceThisType, targetThisType); 22340 } 22341 } 22342 for (let i = 0; i < paramCount; i++) { 22343 callback(getTypeAtPosition(source, i), getTypeAtPosition(target, i)); 22344 } 22345 if (targetRestType) { 22346 callback(getRestTypeAtPosition(source, paramCount), targetRestType); 22347 } 22348 } 22349 22350 function applyToReturnTypes(source: Signature, target: Signature, callback: (s: Type, t: Type) => void) { 22351 const sourceTypePredicate = getTypePredicateOfSignature(source); 22352 const targetTypePredicate = getTypePredicateOfSignature(target); 22353 if (sourceTypePredicate && targetTypePredicate && typePredicateKindsMatch(sourceTypePredicate, targetTypePredicate) && sourceTypePredicate.type && targetTypePredicate.type) { 22354 callback(sourceTypePredicate.type, targetTypePredicate.type); 22355 } 22356 else { 22357 callback(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target)); 22358 } 22359 } 22360 22361 function createInferenceContext(typeParameters: readonly TypeParameter[], signature: Signature | undefined, flags: InferenceFlags, compareTypes?: TypeComparer): InferenceContext { 22362 return createInferenceContextWorker(typeParameters.map(createInferenceInfo), signature, flags, compareTypes || compareTypesAssignable); 22363 } 22364 22365 function cloneInferenceContext<T extends InferenceContext | undefined>(context: T, extraFlags: InferenceFlags = 0): InferenceContext | T & undefined { 22366 return context && createInferenceContextWorker(map(context.inferences, cloneInferenceInfo), context.signature, context.flags | extraFlags, context.compareTypes); 22367 } 22368 22369 function createInferenceContextWorker(inferences: InferenceInfo[], signature: Signature | undefined, flags: InferenceFlags, compareTypes: TypeComparer): InferenceContext { 22370 const context: InferenceContext = { 22371 inferences, 22372 signature, 22373 flags, 22374 compareTypes, 22375 mapper: reportUnmeasurableMapper, // initialize to a noop mapper so the context object is available, but the underlying object shape is right upon construction 22376 nonFixingMapper: reportUnmeasurableMapper, 22377 }; 22378 context.mapper = makeFixingMapperForContext(context); 22379 context.nonFixingMapper = makeNonFixingMapperForContext(context); 22380 return context; 22381 } 22382 22383 function makeFixingMapperForContext(context: InferenceContext) { 22384 return makeDeferredTypeMapper(map(context.inferences, i => i.typeParameter), map(context.inferences, (inference, i) => () => { 22385 if (!inference.isFixed) { 22386 // Before we commit to a particular inference (and thus lock out any further inferences), 22387 // we infer from any intra-expression inference sites we have collected. 22388 inferFromIntraExpressionSites(context); 22389 clearCachedInferences(context.inferences); 22390 inference.isFixed = true; 22391 } 22392 return getInferredType(context, i); 22393 })); 22394 } 22395 22396 function makeNonFixingMapperForContext(context: InferenceContext) { 22397 return makeDeferredTypeMapper(map(context.inferences, i => i.typeParameter), map(context.inferences, (_, i) => () => { 22398 return getInferredType(context, i); 22399 })); 22400 } 22401 22402 function clearCachedInferences(inferences: InferenceInfo[]) { 22403 for (const inference of inferences) { 22404 if (!inference.isFixed) { 22405 inference.inferredType = undefined; 22406 } 22407 } 22408 } 22409 22410 function addIntraExpressionInferenceSite(context: InferenceContext, node: Expression | MethodDeclaration, type: Type) { 22411 (context.intraExpressionInferenceSites ??= []).push({ node, type }); 22412 } 22413 22414 // We collect intra-expression inference sites within object and array literals to handle cases where 22415 // inferred types flow between context sensitive element expressions. For example: 22416 // 22417 // declare function foo<T>(arg: [(n: number) => T, (x: T) => void]): void; 22418 // foo([_a => 0, n => n.toFixed()]); 22419 // 22420 // Above, both arrow functions in the tuple argument are context sensitive, thus both are omitted from the 22421 // pass that collects inferences from the non-context sensitive parts of the arguments. In the subsequent 22422 // pass where nothing is omitted, we need to commit to an inference for T in order to contextually type the 22423 // parameter in the second arrow function, but we want to first infer from the return type of the first 22424 // arrow function. This happens automatically when the arrow functions are discrete arguments (because we 22425 // infer from each argument before processing the next), but when the arrow functions are elements of an 22426 // object or array literal, we need to perform intra-expression inferences early. 22427 function inferFromIntraExpressionSites(context: InferenceContext) { 22428 if (context.intraExpressionInferenceSites) { 22429 for (const { node, type } of context.intraExpressionInferenceSites) { 22430 const contextualType = node.kind === SyntaxKind.MethodDeclaration ? 22431 getContextualTypeForObjectLiteralMethod(node as MethodDeclaration, ContextFlags.NoConstraints) : 22432 getContextualType(node, ContextFlags.NoConstraints); 22433 if (contextualType) { 22434 inferTypes(context.inferences, type, contextualType); 22435 } 22436 } 22437 context.intraExpressionInferenceSites = undefined; 22438 } 22439 } 22440 22441 function createInferenceInfo(typeParameter: TypeParameter): InferenceInfo { 22442 return { 22443 typeParameter, 22444 candidates: undefined, 22445 contraCandidates: undefined, 22446 inferredType: undefined, 22447 priority: undefined, 22448 topLevel: true, 22449 isFixed: false, 22450 impliedArity: undefined 22451 }; 22452 } 22453 22454 function cloneInferenceInfo(inference: InferenceInfo): InferenceInfo { 22455 return { 22456 typeParameter: inference.typeParameter, 22457 candidates: inference.candidates && inference.candidates.slice(), 22458 contraCandidates: inference.contraCandidates && inference.contraCandidates.slice(), 22459 inferredType: inference.inferredType, 22460 priority: inference.priority, 22461 topLevel: inference.topLevel, 22462 isFixed: inference.isFixed, 22463 impliedArity: inference.impliedArity 22464 }; 22465 } 22466 22467 function cloneInferredPartOfContext(context: InferenceContext): InferenceContext | undefined { 22468 const inferences = filter(context.inferences, hasInferenceCandidates); 22469 return inferences.length ? 22470 createInferenceContextWorker(map(inferences, cloneInferenceInfo), context.signature, context.flags, context.compareTypes) : 22471 undefined; 22472 } 22473 22474 function getMapperFromContext<T extends InferenceContext | undefined>(context: T): TypeMapper | T & undefined { 22475 return context && context.mapper; 22476 } 22477 22478 // Return true if the given type could possibly reference a type parameter for which 22479 // we perform type inference (i.e. a type parameter of a generic function). We cache 22480 // results for union and intersection types for performance reasons. 22481 function couldContainTypeVariables(type: Type): boolean { 22482 const objectFlags = getObjectFlags(type); 22483 if (objectFlags & ObjectFlags.CouldContainTypeVariablesComputed) { 22484 return !!(objectFlags & ObjectFlags.CouldContainTypeVariables); 22485 } 22486 const result = !!(type.flags & TypeFlags.Instantiable || 22487 type.flags & TypeFlags.Object && !isNonGenericTopLevelType(type) && ( 22488 objectFlags & ObjectFlags.Reference && ((type as TypeReference).node || forEach(getTypeArguments(type as TypeReference), couldContainTypeVariables)) || 22489 objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && type.symbol.declarations || 22490 objectFlags & (ObjectFlags.Mapped | ObjectFlags.ReverseMapped | ObjectFlags.ObjectRestType | ObjectFlags.InstantiationExpressionType)) || 22491 type.flags & TypeFlags.UnionOrIntersection && !(type.flags & TypeFlags.EnumLiteral) && !isNonGenericTopLevelType(type) && some((type as UnionOrIntersectionType).types, couldContainTypeVariables)); 22492 if (type.flags & TypeFlags.ObjectFlagsType) { 22493 (type as ObjectFlagsType).objectFlags |= ObjectFlags.CouldContainTypeVariablesComputed | (result ? ObjectFlags.CouldContainTypeVariables : 0); 22494 } 22495 return result; 22496 } 22497 22498 function isNonGenericTopLevelType(type: Type) { 22499 if (type.aliasSymbol && !type.aliasTypeArguments) { 22500 const declaration = getDeclarationOfKind(type.aliasSymbol, SyntaxKind.TypeAliasDeclaration); 22501 return !!(declaration && findAncestor(declaration.parent, n => n.kind === SyntaxKind.SourceFile ? true : n.kind === SyntaxKind.ModuleDeclaration ? false : "quit")); 22502 } 22503 return false; 22504 } 22505 22506 function isTypeParameterAtTopLevel(type: Type, typeParameter: TypeParameter): boolean { 22507 return !!(type === typeParameter || 22508 type.flags & TypeFlags.UnionOrIntersection && some((type as UnionOrIntersectionType).types, t => isTypeParameterAtTopLevel(t, typeParameter)) || 22509 type.flags & TypeFlags.Conditional && (getTrueTypeFromConditionalType(type as ConditionalType) === typeParameter || getFalseTypeFromConditionalType(type as ConditionalType) === typeParameter)); 22510 } 22511 22512 /** Create an object with properties named in the string literal type. Every property has type `any` */ 22513 function createEmptyObjectTypeFromStringLiteral(type: Type) { 22514 const members = createSymbolTable(); 22515 forEachType(type, t => { 22516 if (!(t.flags & TypeFlags.StringLiteral)) { 22517 return; 22518 } 22519 const name = escapeLeadingUnderscores((t as StringLiteralType).value); 22520 const literalProp = createSymbol(SymbolFlags.Property, name); 22521 literalProp.type = anyType; 22522 if (t.symbol) { 22523 literalProp.declarations = t.symbol.declarations; 22524 literalProp.valueDeclaration = t.symbol.valueDeclaration; 22525 } 22526 members.set(name, literalProp); 22527 }); 22528 const indexInfos = type.flags & TypeFlags.String ? [createIndexInfo(stringType, emptyObjectType, /*isReadonly*/ false)] : emptyArray; 22529 return createAnonymousType(undefined, members, emptyArray, emptyArray, indexInfos); 22530 } 22531 22532 /** 22533 * Infer a suitable input type for a homomorphic mapped type { [P in keyof T]: X }. We construct 22534 * an object type with the same set of properties as the source type, where the type of each 22535 * property is computed by inferring from the source property type to X for the type 22536 * variable T[P] (i.e. we treat the type T[P] as the type variable we're inferring for). 22537 */ 22538 function inferTypeForHomomorphicMappedType(source: Type, target: MappedType, constraint: IndexType): Type | undefined { 22539 if (inInferTypeForHomomorphicMappedType) { 22540 return undefined; 22541 } 22542 const key = source.id + "," + target.id + "," + constraint.id; 22543 if (reverseMappedCache.has(key)) { 22544 return reverseMappedCache.get(key); 22545 } 22546 inInferTypeForHomomorphicMappedType = true; 22547 const type = createReverseMappedType(source, target, constraint); 22548 inInferTypeForHomomorphicMappedType = false; 22549 reverseMappedCache.set(key, type); 22550 return type; 22551 } 22552 22553 // We consider a type to be partially inferable if it isn't marked non-inferable or if it is 22554 // an object literal type with at least one property of an inferable type. For example, an object 22555 // literal { a: 123, b: x => true } is marked non-inferable because it contains a context sensitive 22556 // arrow function, but is considered partially inferable because property 'a' has an inferable type. 22557 function isPartiallyInferableType(type: Type): boolean { 22558 return !(getObjectFlags(type) & ObjectFlags.NonInferrableType) || 22559 isObjectLiteralType(type) && some(getPropertiesOfType(type), prop => isPartiallyInferableType(getTypeOfSymbol(prop))) || 22560 isTupleType(type) && some(getTypeArguments(type), isPartiallyInferableType); 22561 } 22562 22563 function createReverseMappedType(source: Type, target: MappedType, constraint: IndexType) { 22564 // We consider a source type reverse mappable if it has a string index signature or if 22565 // it has one or more properties and is of a partially inferable type. 22566 if (!(getIndexInfoOfType(source, stringType) || getPropertiesOfType(source).length !== 0 && isPartiallyInferableType(source))) { 22567 return undefined; 22568 } 22569 // For arrays and tuples we infer new arrays and tuples where the reverse mapping has been 22570 // applied to the element type(s). 22571 if (isArrayType(source)) { 22572 return createArrayType(inferReverseMappedType(getTypeArguments(source)[0], target, constraint), isReadonlyArrayType(source)); 22573 } 22574 if (isTupleType(source)) { 22575 const elementTypes = map(getTypeArguments(source), t => inferReverseMappedType(t, target, constraint)); 22576 const elementFlags = getMappedTypeModifiers(target) & MappedTypeModifiers.IncludeOptional ? 22577 sameMap(source.target.elementFlags, f => f & ElementFlags.Optional ? ElementFlags.Required : f) : 22578 source.target.elementFlags; 22579 return createTupleType(elementTypes, elementFlags, source.target.readonly, source.target.labeledElementDeclarations); 22580 } 22581 // For all other object types we infer a new object type where the reverse mapping has been 22582 // applied to the type of each property. 22583 const reversed = createObjectType(ObjectFlags.ReverseMapped | ObjectFlags.Anonymous, /*symbol*/ undefined) as ReverseMappedType; 22584 reversed.source = source; 22585 reversed.mappedType = target; 22586 reversed.constraintType = constraint; 22587 return reversed; 22588 } 22589 22590 function getTypeOfReverseMappedSymbol(symbol: ReverseMappedSymbol) { 22591 const links = getSymbolLinks(symbol); 22592 if (!links.type) { 22593 links.type = inferReverseMappedType(symbol.propertyType, symbol.mappedType, symbol.constraintType); 22594 } 22595 return links.type; 22596 } 22597 22598 function inferReverseMappedType(sourceType: Type, target: MappedType, constraint: IndexType): Type { 22599 const typeParameter = getIndexedAccessType(constraint.type, getTypeParameterFromMappedType(target)) as TypeParameter; 22600 const templateType = getTemplateTypeFromMappedType(target); 22601 const inference = createInferenceInfo(typeParameter); 22602 inferTypes([inference], sourceType, templateType); 22603 return getTypeFromInference(inference) || unknownType; 22604 } 22605 22606 function* getUnmatchedProperties(source: Type, target: Type, requireOptionalProperties: boolean, matchDiscriminantProperties: boolean): IterableIterator<Symbol> { 22607 const properties = getPropertiesOfType(target); 22608 for (const targetProp of properties) { 22609 // TODO: remove this when we support static private identifier fields and find other solutions to get privateNamesAndStaticFields test to pass 22610 if (isStaticPrivateIdentifierProperty(targetProp)) { 22611 continue; 22612 } 22613 if (requireOptionalProperties || !(targetProp.flags & SymbolFlags.Optional || getCheckFlags(targetProp) & CheckFlags.Partial)) { 22614 const sourceProp = getPropertyOfType(source, targetProp.escapedName); 22615 if (!sourceProp) { 22616 yield targetProp; 22617 } 22618 else if (matchDiscriminantProperties) { 22619 const targetType = getTypeOfSymbol(targetProp); 22620 if (targetType.flags & TypeFlags.Unit) { 22621 const sourceType = getTypeOfSymbol(sourceProp); 22622 if (!(sourceType.flags & TypeFlags.Any || getRegularTypeOfLiteralType(sourceType) === getRegularTypeOfLiteralType(targetType))) { 22623 yield targetProp; 22624 } 22625 } 22626 } 22627 } 22628 } 22629 } 22630 22631 function getUnmatchedProperty(source: Type, target: Type, requireOptionalProperties: boolean, matchDiscriminantProperties: boolean): Symbol | undefined { 22632 const result = getUnmatchedProperties(source, target, requireOptionalProperties, matchDiscriminantProperties).next(); 22633 if (!result.done) return result.value; 22634 } 22635 22636 function tupleTypesDefinitelyUnrelated(source: TupleTypeReference, target: TupleTypeReference) { 22637 return !(target.target.combinedFlags & ElementFlags.Variadic) && target.target.minLength > source.target.minLength || 22638 !target.target.hasRestElement && (source.target.hasRestElement || target.target.fixedLength < source.target.fixedLength); 22639 } 22640 22641 function typesDefinitelyUnrelated(source: Type, target: Type) { 22642 // Two tuple types with incompatible arities are definitely unrelated. 22643 // Two object types that each have a property that is unmatched in the other are definitely unrelated. 22644 return isTupleType(source) && isTupleType(target) ? tupleTypesDefinitelyUnrelated(source, target) : 22645 !!getUnmatchedProperty(source, target, /*requireOptionalProperties*/ false, /*matchDiscriminantProperties*/ true) && 22646 !!getUnmatchedProperty(target, source, /*requireOptionalProperties*/ false, /*matchDiscriminantProperties*/ false); 22647 } 22648 22649 function getTypeFromInference(inference: InferenceInfo) { 22650 return inference.candidates ? getUnionType(inference.candidates, UnionReduction.Subtype) : 22651 inference.contraCandidates ? getIntersectionType(inference.contraCandidates) : 22652 undefined; 22653 } 22654 22655 function hasSkipDirectInferenceFlag(node: Node) { 22656 return !!getNodeLinks(node).skipDirectInference; 22657 } 22658 22659 function isFromInferenceBlockedSource(type: Type) { 22660 return !!(type.symbol && some(type.symbol.declarations, hasSkipDirectInferenceFlag)); 22661 } 22662 22663 function templateLiteralTypesDefinitelyUnrelated(source: TemplateLiteralType, target: TemplateLiteralType) { 22664 // Two template literal types with diffences in their starting or ending text spans are definitely unrelated. 22665 const sourceStart = source.texts[0]; 22666 const targetStart = target.texts[0]; 22667 const sourceEnd = source.texts[source.texts.length - 1]; 22668 const targetEnd = target.texts[target.texts.length - 1]; 22669 const startLen = Math.min(sourceStart.length, targetStart.length); 22670 const endLen = Math.min(sourceEnd.length, targetEnd.length); 22671 return sourceStart.slice(0, startLen) !== targetStart.slice(0, startLen) || 22672 sourceEnd.slice(sourceEnd.length - endLen) !== targetEnd.slice(targetEnd.length - endLen); 22673 } 22674 22675 /** 22676 * Tests whether the provided string can be parsed as a number. 22677 * @param s The string to test. 22678 * @param roundTripOnly Indicates the resulting number matches the input when converted back to a string. 22679 */ 22680 function isValidNumberString(s: string, roundTripOnly: boolean): boolean { 22681 if (s === "") return false; 22682 const n = +s; 22683 return isFinite(n) && (!roundTripOnly || "" + n === s); 22684 } 22685 22686 /** 22687 * @param text a valid bigint string excluding a trailing `n`, but including a possible prefix `-`. Use `isValidBigIntString(text, roundTripOnly)` before calling this function. 22688 */ 22689 function parseBigIntLiteralType(text: string) { 22690 const negative = text.startsWith("-"); 22691 const base10Value = parsePseudoBigInt(`${negative ? text.slice(1) : text}n`); 22692 return getBigIntLiteralType({ negative, base10Value }); 22693 } 22694 22695 /** 22696 * Tests whether the provided string can be parsed as a bigint. 22697 * @param s The string to test. 22698 * @param roundTripOnly Indicates the resulting bigint matches the input when converted back to a string. 22699 */ 22700 function isValidBigIntString(s: string, roundTripOnly: boolean): boolean { 22701 if (s === "") return false; 22702 const scanner = createScanner(ScriptTarget.ESNext, /*skipTrivia*/ false); 22703 let success = true; 22704 scanner.setOnError(() => success = false); 22705 scanner.setText(s + "n"); 22706 let result = scanner.scan(); 22707 const negative = result === SyntaxKind.MinusToken; 22708 if (negative) { 22709 result = scanner.scan(); 22710 } 22711 const flags = scanner.getTokenFlags(); 22712 // validate that 22713 // * scanning proceeded without error 22714 // * a bigint can be scanned, and that when it is scanned, it is 22715 // * the full length of the input string (so the scanner is one character beyond the augmented input length) 22716 // * it does not contain a numeric seperator (the `BigInt` constructor does not accept a numeric seperator in its input) 22717 return success && result === SyntaxKind.BigIntLiteral && scanner.getTextPos() === (s.length + 1) && !(flags & TokenFlags.ContainsSeparator) 22718 && (!roundTripOnly || s === pseudoBigIntToString({ negative, base10Value: parsePseudoBigInt(scanner.getTokenValue()) })); 22719 } 22720 22721 function isMemberOfStringMapping(source: Type, target: Type): boolean { 22722 if (target.flags & (TypeFlags.String | TypeFlags.Any)) { 22723 return true; 22724 } 22725 if (target.flags & TypeFlags.TemplateLiteral) { 22726 return isTypeAssignableTo(source, target); 22727 } 22728 if (target.flags & TypeFlags.StringMapping) { 22729 // We need to see whether applying the same mappings of the target 22730 // onto the source would produce an identical type *and* that 22731 // it's compatible with the inner-most non-string-mapped type. 22732 // 22733 // The intuition here is that if same mappings don't affect the source at all, 22734 // and the source is compatible with the unmapped target, then they must 22735 // still reside in the same domain. 22736 const mappingStack = []; 22737 while (target.flags & TypeFlags.StringMapping) { 22738 mappingStack.unshift(target.symbol); 22739 target = (target as StringMappingType).type; 22740 } 22741 const mappedSource = reduceLeft(mappingStack, (memo, value) => getStringMappingType(value, memo), source); 22742 return mappedSource === source && isMemberOfStringMapping(source, target); 22743 } 22744 return false; 22745 } 22746 22747 function isValidTypeForTemplateLiteralPlaceholder(source: Type, target: Type): boolean { 22748 if (source === target || target.flags & (TypeFlags.Any | TypeFlags.String)) { 22749 return true; 22750 } 22751 if (source.flags & TypeFlags.StringLiteral) { 22752 const value = (source as StringLiteralType).value; 22753 return !!(target.flags & TypeFlags.Number && isValidNumberString(value, /*roundTripOnly*/ false) || 22754 target.flags & TypeFlags.BigInt && isValidBigIntString(value, /*roundTripOnly*/ false) || 22755 target.flags & (TypeFlags.BooleanLiteral | TypeFlags.Nullable) && value === (target as IntrinsicType).intrinsicName || 22756 target.flags & TypeFlags.StringMapping && isMemberOfStringMapping(getStringLiteralType(value), target)); 22757 } 22758 if (source.flags & TypeFlags.TemplateLiteral) { 22759 const texts = (source as TemplateLiteralType).texts; 22760 return texts.length === 2 && texts[0] === "" && texts[1] === "" && isTypeAssignableTo((source as TemplateLiteralType).types[0], target); 22761 } 22762 return isTypeAssignableTo(source, target); 22763 } 22764 22765 function inferTypesFromTemplateLiteralType(source: Type, target: TemplateLiteralType): Type[] | undefined { 22766 return source.flags & TypeFlags.StringLiteral ? inferFromLiteralPartsToTemplateLiteral([(source as StringLiteralType).value], emptyArray, target) : 22767 source.flags & TypeFlags.TemplateLiteral ? 22768 arraysEqual((source as TemplateLiteralType).texts, target.texts) ? map((source as TemplateLiteralType).types, getStringLikeTypeForType) : 22769 inferFromLiteralPartsToTemplateLiteral((source as TemplateLiteralType).texts, (source as TemplateLiteralType).types, target) : 22770 undefined; 22771 } 22772 22773 function isTypeMatchedByTemplateLiteralType(source: Type, target: TemplateLiteralType): boolean { 22774 const inferences = inferTypesFromTemplateLiteralType(source, target); 22775 return !!inferences && every(inferences, (r, i) => isValidTypeForTemplateLiteralPlaceholder(r, target.types[i])); 22776 } 22777 22778 function getStringLikeTypeForType(type: Type) { 22779 return type.flags & (TypeFlags.Any | TypeFlags.StringLike) ? type : getTemplateLiteralType(["", ""], [type]); 22780 } 22781 22782 // This function infers from the text parts and type parts of a source literal to a target template literal. The number 22783 // of text parts is always one more than the number of type parts, and a source string literal is treated as a source 22784 // with one text part and zero type parts. The function returns an array of inferred string or template literal types 22785 // corresponding to the placeholders in the target template literal, or undefined if the source doesn't match the target. 22786 // 22787 // We first check that the starting source text part matches the starting target text part, and that the ending source 22788 // text part ends matches the ending target text part. We then iterate through the remaining target text parts, finding 22789 // a match for each in the source and inferring string or template literal types created from the segments of the source 22790 // that occur between the matches. During this iteration, seg holds the index of the current text part in the sourceTexts 22791 // array and pos holds the current character position in the current text part. 22792 // 22793 // Consider inference from type `<<${string}>.<${number}-${number}>>` to type `<${string}.${string}>`, i.e. 22794 // sourceTexts = ['<<', '>.<', '-', '>>'] 22795 // sourceTypes = [string, number, number] 22796 // target.texts = ['<', '.', '>'] 22797 // We first match '<' in the target to the start of '<<' in the source and '>' in the target to the end of '>>' in 22798 // the source. The first match for the '.' in target occurs at character 1 in the source text part at index 1, and thus 22799 // the first inference is the template literal type `<${string}>`. The remainder of the source makes up the second 22800 // inference, the template literal type `<${number}-${number}>`. 22801 function inferFromLiteralPartsToTemplateLiteral(sourceTexts: readonly string[], sourceTypes: readonly Type[], target: TemplateLiteralType): Type[] | undefined { 22802 const lastSourceIndex = sourceTexts.length - 1; 22803 const sourceStartText = sourceTexts[0]; 22804 const sourceEndText = sourceTexts[lastSourceIndex]; 22805 const targetTexts = target.texts; 22806 const lastTargetIndex = targetTexts.length - 1; 22807 const targetStartText = targetTexts[0]; 22808 const targetEndText = targetTexts[lastTargetIndex]; 22809 if (lastSourceIndex === 0 && sourceStartText.length < targetStartText.length + targetEndText.length || 22810 !sourceStartText.startsWith(targetStartText) || !sourceEndText.endsWith(targetEndText)) return undefined; 22811 const remainingEndText = sourceEndText.slice(0, sourceEndText.length - targetEndText.length); 22812 const matches: Type[] = []; 22813 let seg = 0; 22814 let pos = targetStartText.length; 22815 for (let i = 1; i < lastTargetIndex; i++) { 22816 const delim = targetTexts[i]; 22817 if (delim.length > 0) { 22818 let s = seg; 22819 let p = pos; 22820 while (true) { 22821 p = getSourceText(s).indexOf(delim, p); 22822 if (p >= 0) break; 22823 s++; 22824 if (s === sourceTexts.length) return undefined; 22825 p = 0; 22826 } 22827 addMatch(s, p); 22828 pos += delim.length; 22829 } 22830 else if (pos < getSourceText(seg).length) { 22831 addMatch(seg, pos + 1); 22832 } 22833 else if (seg < lastSourceIndex) { 22834 addMatch(seg + 1, 0); 22835 } 22836 else { 22837 return undefined; 22838 } 22839 } 22840 addMatch(lastSourceIndex, getSourceText(lastSourceIndex).length); 22841 return matches; 22842 function getSourceText(index: number) { 22843 return index < lastSourceIndex ? sourceTexts[index] : remainingEndText; 22844 } 22845 function addMatch(s: number, p: number) { 22846 const matchType = s === seg ? 22847 getStringLiteralType(getSourceText(s).slice(pos, p)) : 22848 getTemplateLiteralType( 22849 [sourceTexts[seg].slice(pos), ...sourceTexts.slice(seg + 1, s), getSourceText(s).slice(0, p)], 22850 sourceTypes.slice(seg, s)); 22851 matches.push(matchType); 22852 seg = s; 22853 pos = p; 22854 } 22855 } 22856 22857 function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type, priority: InferencePriority = 0, contravariant = false) { 22858 let bivariant = false; 22859 let propagationType: Type; 22860 let inferencePriority = InferencePriority.MaxValue; 22861 let allowComplexConstraintInference = true; 22862 let visited: ESMap<string, number>; 22863 let sourceStack: object[]; 22864 let targetStack: object[]; 22865 let expandingFlags = ExpandingFlags.None; 22866 inferFromTypes(originalSource, originalTarget); 22867 22868 function inferFromTypes(source: Type, target: Type): void { 22869 if (!couldContainTypeVariables(target)) { 22870 return; 22871 } 22872 if (source === wildcardType) { 22873 // We are inferring from an 'any' type. We want to infer this type for every type parameter 22874 // referenced in the target type, so we record it as the propagation type and infer from the 22875 // target to itself. Then, as we find candidates we substitute the propagation type. 22876 const savePropagationType = propagationType; 22877 propagationType = source; 22878 inferFromTypes(target, target); 22879 propagationType = savePropagationType; 22880 return; 22881 } 22882 if (source.aliasSymbol && source.aliasSymbol === target.aliasSymbol) { 22883 if (source.aliasTypeArguments) { 22884 // Source and target are types originating in the same generic type alias declaration. 22885 // Simply infer from source type arguments to target type arguments. 22886 inferFromTypeArguments(source.aliasTypeArguments, target.aliasTypeArguments!, getAliasVariances(source.aliasSymbol)); 22887 } 22888 // And if there weren't any type arguments, there's no reason to run inference as the types must be the same. 22889 return; 22890 } 22891 if (source === target && source.flags & TypeFlags.UnionOrIntersection) { 22892 // When source and target are the same union or intersection type, just relate each constituent 22893 // type to itself. 22894 for (const t of (source as UnionOrIntersectionType).types) { 22895 inferFromTypes(t, t); 22896 } 22897 return; 22898 } 22899 if (target.flags & TypeFlags.Union) { 22900 // First, infer between identically matching source and target constituents and remove the 22901 // matching types. 22902 const [tempSources, tempTargets] = inferFromMatchingTypes(source.flags & TypeFlags.Union ? (source as UnionType).types : [source], (target as UnionType).types, isTypeOrBaseIdenticalTo); 22903 // Next, infer between closely matching source and target constituents and remove 22904 // the matching types. Types closely match when they are instantiations of the same 22905 // object type or instantiations of the same type alias. 22906 const [sources, targets] = inferFromMatchingTypes(tempSources, tempTargets, isTypeCloselyMatchedBy); 22907 if (targets.length === 0) { 22908 return; 22909 } 22910 target = getUnionType(targets); 22911 if (sources.length === 0) { 22912 // All source constituents have been matched and there is nothing further to infer from. 22913 // However, simply making no inferences is undesirable because it could ultimately mean 22914 // inferring a type parameter constraint. Instead, make a lower priority inference from 22915 // the full source to whatever remains in the target. For example, when inferring from 22916 // string to 'string | T', make a lower priority inference of string for T. 22917 inferWithPriority(source, target, InferencePriority.NakedTypeVariable); 22918 return; 22919 } 22920 source = getUnionType(sources); 22921 } 22922 else if (target.flags & TypeFlags.Intersection && some((target as IntersectionType).types, 22923 t => !!getInferenceInfoForType(t) || (isGenericMappedType(t) && !!getInferenceInfoForType(getHomomorphicTypeVariable(t) || neverType)))) { 22924 // We reduce intersection types only when they contain naked type parameters. For example, when 22925 // inferring from 'string[] & { extra: any }' to 'string[] & T' we want to remove string[] and 22926 // infer { extra: any } for T. But when inferring to 'string[] & Iterable<T>' we want to keep the 22927 // string[] on the source side and infer string for T. 22928 // Likewise, we consider a homomorphic mapped type constrainted to the target type parameter as similar to a "naked type variable" 22929 // in such scenarios. 22930 if (!(source.flags & TypeFlags.Union)) { 22931 // Infer between identically matching source and target constituents and remove the matching types. 22932 const [sources, targets] = inferFromMatchingTypes(source.flags & TypeFlags.Intersection ? (source as IntersectionType).types : [source], (target as IntersectionType).types, isTypeIdenticalTo); 22933 if (sources.length === 0 || targets.length === 0) { 22934 return; 22935 } 22936 source = getIntersectionType(sources); 22937 target = getIntersectionType(targets); 22938 } 22939 } 22940 else if (target.flags & (TypeFlags.IndexedAccess | TypeFlags.Substitution)) { 22941 target = getActualTypeVariable(target); 22942 } 22943 if (target.flags & TypeFlags.TypeVariable) { 22944 // Skip inference if the source is "blocked", which is used by the language service to 22945 // prevent inference on nodes currently being edited. 22946 if (isFromInferenceBlockedSource(source)) { 22947 return; 22948 } 22949 const inference = getInferenceInfoForType(target); 22950 if (inference) { 22951 // If target is a type parameter, make an inference, unless the source type contains 22952 // a "non-inferrable" type. Types with this flag set are markers used to prevent inference. 22953 // 22954 // For example: 22955 // - anyFunctionType is a wildcard type that's used to avoid contextually typing functions; 22956 // it's internal, so should not be exposed to the user by adding it as a candidate. 22957 // - autoType (and autoArrayType) is a special "any" used in control flow; like anyFunctionType, 22958 // it's internal and should not be observable. 22959 // - silentNeverType is returned by getInferredType when instantiating a generic function for 22960 // inference (and a type variable has no mapping). 22961 // 22962 // This flag is infectious; if we produce Box<never> (where never is silentNeverType), Box<never> is 22963 // also non-inferrable. 22964 // 22965 // As a special case, also ignore nonInferrableAnyType, which is a special form of the any type 22966 // used as a stand-in for binding elements when they are being inferred. 22967 if (getObjectFlags(source) & ObjectFlags.NonInferrableType || source === nonInferrableAnyType) { 22968 return; 22969 } 22970 if (!inference.isFixed) { 22971 if (inference.priority === undefined || priority < inference.priority) { 22972 inference.candidates = undefined; 22973 inference.contraCandidates = undefined; 22974 inference.topLevel = true; 22975 inference.priority = priority; 22976 } 22977 if (priority === inference.priority) { 22978 const candidate = propagationType || source; 22979 // We make contravariant inferences only if we are in a pure contravariant position, 22980 // i.e. only if we have not descended into a bivariant position. 22981 if (contravariant && !bivariant) { 22982 if (!contains(inference.contraCandidates, candidate)) { 22983 inference.contraCandidates = append(inference.contraCandidates, candidate); 22984 clearCachedInferences(inferences); 22985 } 22986 } 22987 else if (!contains(inference.candidates, candidate)) { 22988 inference.candidates = append(inference.candidates, candidate); 22989 clearCachedInferences(inferences); 22990 } 22991 } 22992 if (!(priority & InferencePriority.ReturnType) && target.flags & TypeFlags.TypeParameter && inference.topLevel && !isTypeParameterAtTopLevel(originalTarget, target as TypeParameter)) { 22993 inference.topLevel = false; 22994 clearCachedInferences(inferences); 22995 } 22996 } 22997 inferencePriority = Math.min(inferencePriority, priority); 22998 return; 22999 } 23000 // Infer to the simplified version of an indexed access, if possible, to (hopefully) expose more bare type parameters to the inference engine 23001 const simplified = getSimplifiedType(target, /*writing*/ false); 23002 if (simplified !== target) { 23003 inferFromTypes(source, simplified); 23004 } 23005 else if (target.flags & TypeFlags.IndexedAccess) { 23006 const indexType = getSimplifiedType((target as IndexedAccessType).indexType, /*writing*/ false); 23007 // Generally simplifications of instantiable indexes are avoided to keep relationship checking correct, however if our target is an access, we can consider 23008 // that key of that access to be "instantiated", since we're looking to find the infernce goal in any way we can. 23009 if (indexType.flags & TypeFlags.Instantiable) { 23010 const simplified = distributeIndexOverObjectType(getSimplifiedType((target as IndexedAccessType).objectType, /*writing*/ false), indexType, /*writing*/ false); 23011 if (simplified && simplified !== target) { 23012 inferFromTypes(source, simplified); 23013 } 23014 } 23015 } 23016 } 23017 if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && ( 23018 (source as TypeReference).target === (target as TypeReference).target || isArrayType(source) && isArrayType(target)) && 23019 !((source as TypeReference).node && (target as TypeReference).node)) { 23020 // If source and target are references to the same generic type, infer from type arguments 23021 inferFromTypeArguments(getTypeArguments(source as TypeReference), getTypeArguments(target as TypeReference), getVariances((source as TypeReference).target)); 23022 } 23023 else if (source.flags & TypeFlags.Index && target.flags & TypeFlags.Index) { 23024 inferFromContravariantTypes((source as IndexType).type, (target as IndexType).type); 23025 } 23026 else if ((isLiteralType(source) || source.flags & TypeFlags.String) && target.flags & TypeFlags.Index) { 23027 const empty = createEmptyObjectTypeFromStringLiteral(source); 23028 inferFromContravariantTypesWithPriority(empty, (target as IndexType).type, InferencePriority.LiteralKeyof); 23029 } 23030 else if (source.flags & TypeFlags.IndexedAccess && target.flags & TypeFlags.IndexedAccess) { 23031 inferFromTypes((source as IndexedAccessType).objectType, (target as IndexedAccessType).objectType); 23032 inferFromTypes((source as IndexedAccessType).indexType, (target as IndexedAccessType).indexType); 23033 } 23034 else if (source.flags & TypeFlags.StringMapping && target.flags & TypeFlags.StringMapping) { 23035 if ((source as StringMappingType).symbol === (target as StringMappingType).symbol) { 23036 inferFromTypes((source as StringMappingType).type, (target as StringMappingType).type); 23037 } 23038 } 23039 else if (source.flags & TypeFlags.Substitution) { 23040 inferFromTypes((source as SubstitutionType).baseType, target); 23041 inferWithPriority(getSubstitutionIntersection(source as SubstitutionType), target, InferencePriority.SubstituteSource); // Make substitute inference at a lower priority 23042 } 23043 else if (target.flags & TypeFlags.Conditional) { 23044 invokeOnce(source, target, inferToConditionalType); 23045 } 23046 else if (target.flags & TypeFlags.UnionOrIntersection) { 23047 inferToMultipleTypes(source, (target as UnionOrIntersectionType).types, target.flags); 23048 } 23049 else if (source.flags & TypeFlags.Union) { 23050 // Source is a union or intersection type, infer from each constituent type 23051 const sourceTypes = (source as UnionOrIntersectionType).types; 23052 for (const sourceType of sourceTypes) { 23053 inferFromTypes(sourceType, target); 23054 } 23055 } 23056 else if (target.flags & TypeFlags.TemplateLiteral) { 23057 inferToTemplateLiteralType(source, target as TemplateLiteralType); 23058 } 23059 else { 23060 source = getReducedType(source); 23061 if (!(priority & InferencePriority.NoConstraints && source.flags & (TypeFlags.Intersection | TypeFlags.Instantiable))) { 23062 const apparentSource = getApparentType(source); 23063 // getApparentType can return _any_ type, since an indexed access or conditional may simplify to any other type. 23064 // If that occurs and it doesn't simplify to an object or intersection, we'll need to restart `inferFromTypes` 23065 // with the simplified source. 23066 if (apparentSource !== source && allowComplexConstraintInference && !(apparentSource.flags & (TypeFlags.Object | TypeFlags.Intersection))) { 23067 // TODO: The `allowComplexConstraintInference` flag is a hack! This forbids inference from complex constraints within constraints! 23068 // This isn't required algorithmically, but rather is used to lower the memory burden caused by performing inference 23069 // that is _too good_ in projects with complicated constraints (eg, fp-ts). In such cases, if we did not limit ourselves 23070 // here, we might produce more valid inferences for types, causing us to do more checks and perform more instantiations 23071 // (in addition to the extra stack depth here) which, in turn, can push the already close process over its limit. 23072 // TL;DR: If we ever become generally more memory efficient (or our resource budget ever increases), we should just 23073 // remove this `allowComplexConstraintInference` flag. 23074 allowComplexConstraintInference = false; 23075 return inferFromTypes(apparentSource, target); 23076 } 23077 source = apparentSource; 23078 } 23079 if (source.flags & (TypeFlags.Object | TypeFlags.Intersection)) { 23080 invokeOnce(source, target, inferFromObjectTypes); 23081 } 23082 } 23083 } 23084 23085 function inferWithPriority(source: Type, target: Type, newPriority: InferencePriority) { 23086 const savePriority = priority; 23087 priority |= newPriority; 23088 inferFromTypes(source, target); 23089 priority = savePriority; 23090 } 23091 23092 function inferFromContravariantTypesWithPriority(source: Type, target: Type, newPriority: InferencePriority) { 23093 const savePriority = priority; 23094 priority |= newPriority; 23095 inferFromContravariantTypes(source, target); 23096 priority = savePriority; 23097 } 23098 23099 function inferToMultipleTypesWithPriority(source: Type, targets: Type[], targetFlags: TypeFlags, newPriority: InferencePriority) { 23100 const savePriority = priority; 23101 priority |= newPriority; 23102 inferToMultipleTypes(source, targets, targetFlags); 23103 priority = savePriority; 23104 } 23105 23106 function invokeOnce(source: Type, target: Type, action: (source: Type, target: Type) => void) { 23107 const key = source.id + "," + target.id; 23108 const status = visited && visited.get(key); 23109 if (status !== undefined) { 23110 inferencePriority = Math.min(inferencePriority, status); 23111 return; 23112 } 23113 (visited || (visited = new Map<string, number>())).set(key, InferencePriority.Circularity); 23114 const saveInferencePriority = inferencePriority; 23115 inferencePriority = InferencePriority.MaxValue; 23116 // We stop inferring and report a circularity if we encounter duplicate recursion identities on both 23117 // the source side and the target side. 23118 const saveExpandingFlags = expandingFlags; 23119 const sourceIdentity = getRecursionIdentity(source); 23120 const targetIdentity = getRecursionIdentity(target); 23121 if (contains(sourceStack, sourceIdentity)) expandingFlags |= ExpandingFlags.Source; 23122 if (contains(targetStack, targetIdentity)) expandingFlags |= ExpandingFlags.Target; 23123 if (expandingFlags !== ExpandingFlags.Both) { 23124 (sourceStack || (sourceStack = [])).push(sourceIdentity); 23125 (targetStack || (targetStack = [])).push(targetIdentity); 23126 action(source, target); 23127 targetStack.pop(); 23128 sourceStack.pop(); 23129 } 23130 else { 23131 inferencePriority = InferencePriority.Circularity; 23132 } 23133 expandingFlags = saveExpandingFlags; 23134 visited.set(key, inferencePriority); 23135 inferencePriority = Math.min(inferencePriority, saveInferencePriority); 23136 } 23137 23138 function inferFromMatchingTypes(sources: Type[], targets: Type[], matches: (s: Type, t: Type) => boolean): [Type[], Type[]] { 23139 let matchedSources: Type[] | undefined; 23140 let matchedTargets: Type[] | undefined; 23141 for (const t of targets) { 23142 for (const s of sources) { 23143 if (matches(s, t)) { 23144 inferFromTypes(s, t); 23145 matchedSources = appendIfUnique(matchedSources, s); 23146 matchedTargets = appendIfUnique(matchedTargets, t); 23147 } 23148 } 23149 } 23150 return [ 23151 matchedSources ? filter(sources, t => !contains(matchedSources, t)) : sources, 23152 matchedTargets ? filter(targets, t => !contains(matchedTargets, t)) : targets, 23153 ]; 23154 } 23155 23156 function inferFromTypeArguments(sourceTypes: readonly Type[], targetTypes: readonly Type[], variances: readonly VarianceFlags[]) { 23157 const count = sourceTypes.length < targetTypes.length ? sourceTypes.length : targetTypes.length; 23158 for (let i = 0; i < count; i++) { 23159 if (i < variances.length && (variances[i] & VarianceFlags.VarianceMask) === VarianceFlags.Contravariant) { 23160 inferFromContravariantTypes(sourceTypes[i], targetTypes[i]); 23161 } 23162 else { 23163 inferFromTypes(sourceTypes[i], targetTypes[i]); 23164 } 23165 } 23166 } 23167 23168 function inferFromContravariantTypes(source: Type, target: Type) { 23169 contravariant = !contravariant; 23170 inferFromTypes(source, target); 23171 contravariant = !contravariant; 23172 } 23173 23174 function inferFromContravariantTypesIfStrictFunctionTypes(source: Type, target: Type) { 23175 if (strictFunctionTypes || priority & InferencePriority.AlwaysStrict) { 23176 inferFromContravariantTypes(source, target); 23177 } 23178 else { 23179 inferFromTypes(source, target); 23180 } 23181 } 23182 23183 function getInferenceInfoForType(type: Type) { 23184 if (type.flags & TypeFlags.TypeVariable) { 23185 for (const inference of inferences) { 23186 if (type === inference.typeParameter) { 23187 return inference; 23188 } 23189 } 23190 } 23191 return undefined; 23192 } 23193 23194 function getSingleTypeVariableFromIntersectionTypes(types: Type[]) { 23195 let typeVariable: Type | undefined; 23196 for (const type of types) { 23197 const t = type.flags & TypeFlags.Intersection && find((type as IntersectionType).types, t => !!getInferenceInfoForType(t)); 23198 if (!t || typeVariable && t !== typeVariable) { 23199 return undefined; 23200 } 23201 typeVariable = t; 23202 } 23203 return typeVariable; 23204 } 23205 23206 function inferToMultipleTypes(source: Type, targets: Type[], targetFlags: TypeFlags) { 23207 let typeVariableCount = 0; 23208 if (targetFlags & TypeFlags.Union) { 23209 let nakedTypeVariable: Type | undefined; 23210 const sources = source.flags & TypeFlags.Union ? (source as UnionType).types : [source]; 23211 const matched = new Array<boolean>(sources.length); 23212 let inferenceCircularity = false; 23213 // First infer to types that are not naked type variables. For each source type we 23214 // track whether inferences were made from that particular type to some target with 23215 // equal priority (i.e. of equal quality) to what we would infer for a naked type 23216 // parameter. 23217 for (const t of targets) { 23218 if (getInferenceInfoForType(t)) { 23219 nakedTypeVariable = t; 23220 typeVariableCount++; 23221 } 23222 else { 23223 for (let i = 0; i < sources.length; i++) { 23224 const saveInferencePriority = inferencePriority; 23225 inferencePriority = InferencePriority.MaxValue; 23226 inferFromTypes(sources[i], t); 23227 if (inferencePriority === priority) matched[i] = true; 23228 inferenceCircularity = inferenceCircularity || inferencePriority === InferencePriority.Circularity; 23229 inferencePriority = Math.min(inferencePriority, saveInferencePriority); 23230 } 23231 } 23232 } 23233 if (typeVariableCount === 0) { 23234 // If every target is an intersection of types containing a single naked type variable, 23235 // make a lower priority inference to that type variable. This handles inferring from 23236 // 'A | B' to 'T & (X | Y)' where we want to infer 'A | B' for T. 23237 const intersectionTypeVariable = getSingleTypeVariableFromIntersectionTypes(targets); 23238 if (intersectionTypeVariable) { 23239 inferWithPriority(source, intersectionTypeVariable, InferencePriority.NakedTypeVariable); 23240 } 23241 return; 23242 } 23243 // If the target has a single naked type variable and no inference circularities were 23244 // encountered above (meaning we explored the types fully), create a union of the source 23245 // types from which no inferences have been made so far and infer from that union to the 23246 // naked type variable. 23247 if (typeVariableCount === 1 && !inferenceCircularity) { 23248 const unmatched = flatMap(sources, (s, i) => matched[i] ? undefined : s); 23249 if (unmatched.length) { 23250 inferFromTypes(getUnionType(unmatched), nakedTypeVariable!); 23251 return; 23252 } 23253 } 23254 } 23255 else { 23256 // We infer from types that are not naked type variables first so that inferences we 23257 // make from nested naked type variables and given slightly higher priority by virtue 23258 // of being first in the candidates array. 23259 for (const t of targets) { 23260 if (getInferenceInfoForType(t)) { 23261 typeVariableCount++; 23262 } 23263 else { 23264 inferFromTypes(source, t); 23265 } 23266 } 23267 } 23268 // Inferences directly to naked type variables are given lower priority as they are 23269 // less specific. For example, when inferring from Promise<string> to T | Promise<T>, 23270 // we want to infer string for T, not Promise<string> | string. For intersection types 23271 // we only infer to single naked type variables. 23272 if (targetFlags & TypeFlags.Intersection ? typeVariableCount === 1 : typeVariableCount > 0) { 23273 for (const t of targets) { 23274 if (getInferenceInfoForType(t)) { 23275 inferWithPriority(source, t, InferencePriority.NakedTypeVariable); 23276 } 23277 } 23278 } 23279 } 23280 23281 function inferToMappedType(source: Type, target: MappedType, constraintType: Type): boolean { 23282 if (constraintType.flags & TypeFlags.Union) { 23283 let result = false; 23284 for (const type of (constraintType as UnionType).types) { 23285 result = inferToMappedType(source, target, type) || result; 23286 } 23287 return result; 23288 } 23289 if (constraintType.flags & TypeFlags.Index) { 23290 // We're inferring from some source type S to a homomorphic mapped type { [P in keyof T]: X }, 23291 // where T is a type variable. Use inferTypeForHomomorphicMappedType to infer a suitable source 23292 // type and then make a secondary inference from that type to T. We make a secondary inference 23293 // such that direct inferences to T get priority over inferences to Partial<T>, for example. 23294 const inference = getInferenceInfoForType((constraintType as IndexType).type); 23295 if (inference && !inference.isFixed && !isFromInferenceBlockedSource(source)) { 23296 const inferredType = inferTypeForHomomorphicMappedType(source, target, constraintType as IndexType); 23297 if (inferredType) { 23298 // We assign a lower priority to inferences made from types containing non-inferrable 23299 // types because we may only have a partial result (i.e. we may have failed to make 23300 // reverse inferences for some properties). 23301 inferWithPriority(inferredType, inference.typeParameter, 23302 getObjectFlags(source) & ObjectFlags.NonInferrableType ? 23303 InferencePriority.PartialHomomorphicMappedType : 23304 InferencePriority.HomomorphicMappedType); 23305 } 23306 } 23307 return true; 23308 } 23309 if (constraintType.flags & TypeFlags.TypeParameter) { 23310 // We're inferring from some source type S to a mapped type { [P in K]: X }, where K is a type 23311 // parameter. First infer from 'keyof S' to K. 23312 inferWithPriority(getIndexType(source), constraintType, InferencePriority.MappedTypeConstraint); 23313 // If K is constrained to a type C, also infer to C. Thus, for a mapped type { [P in K]: X }, 23314 // where K extends keyof T, we make the same inferences as for a homomorphic mapped type 23315 // { [P in keyof T]: X }. This enables us to make meaningful inferences when the target is a 23316 // Pick<T, K>. 23317 const extendedConstraint = getConstraintOfType(constraintType); 23318 if (extendedConstraint && inferToMappedType(source, target, extendedConstraint)) { 23319 return true; 23320 } 23321 // If no inferences can be made to K's constraint, infer from a union of the property types 23322 // in the source to the template type X. 23323 const propTypes = map(getPropertiesOfType(source), getTypeOfSymbol); 23324 const indexTypes = map(getIndexInfosOfType(source), info => info !== enumNumberIndexInfo ? info.type : neverType); 23325 inferFromTypes(getUnionType(concatenate(propTypes, indexTypes)), getTemplateTypeFromMappedType(target)); 23326 return true; 23327 } 23328 return false; 23329 } 23330 23331 function inferToConditionalType(source: Type, target: ConditionalType) { 23332 if (source.flags & TypeFlags.Conditional) { 23333 inferFromTypes((source as ConditionalType).checkType, target.checkType); 23334 inferFromTypes((source as ConditionalType).extendsType, target.extendsType); 23335 inferFromTypes(getTrueTypeFromConditionalType(source as ConditionalType), getTrueTypeFromConditionalType(target)); 23336 inferFromTypes(getFalseTypeFromConditionalType(source as ConditionalType), getFalseTypeFromConditionalType(target)); 23337 } 23338 else { 23339 const targetTypes = [getTrueTypeFromConditionalType(target), getFalseTypeFromConditionalType(target)]; 23340 inferToMultipleTypesWithPriority(source, targetTypes, target.flags, contravariant ? InferencePriority.ContravariantConditional : 0); 23341 } 23342 } 23343 23344 function inferToTemplateLiteralType(source: Type, target: TemplateLiteralType) { 23345 const matches = inferTypesFromTemplateLiteralType(source, target); 23346 const types = target.types; 23347 // When the target template literal contains only placeholders (meaning that inference is intended to extract 23348 // single characters and remainder strings) and inference fails to produce matches, we want to infer 'never' for 23349 // each placeholder such that instantiation with the inferred value(s) produces 'never', a type for which an 23350 // assignment check will fail. If we make no inferences, we'll likely end up with the constraint 'string' which, 23351 // upon instantiation, would collapse all the placeholders to just 'string', and an assignment check might 23352 // succeed. That would be a pointless and confusing outcome. 23353 if (matches || every(target.texts, s => s.length === 0)) { 23354 for (let i = 0; i < types.length; i++) { 23355 const source = matches ? matches[i] : neverType; 23356 const target = types[i]; 23357 23358 // If we are inferring from a string literal type to a type variable whose constraint includes one of the 23359 // allowed template literal placeholder types, infer from a literal type corresponding to the constraint. 23360 if (source.flags & TypeFlags.StringLiteral && target.flags & TypeFlags.TypeVariable) { 23361 const inferenceContext = getInferenceInfoForType(target); 23362 const constraint = inferenceContext ? getBaseConstraintOfType(inferenceContext.typeParameter) : undefined; 23363 if (constraint && !isTypeAny(constraint)) { 23364 const constraintTypes = constraint.flags & TypeFlags.Union ? (constraint as UnionType).types : [constraint]; 23365 let allTypeFlags: TypeFlags = reduceLeft(constraintTypes, (flags, t) => flags | t.flags, 0 as TypeFlags); 23366 23367 // If the constraint contains `string`, we don't need to look for a more preferred type 23368 if (!(allTypeFlags & TypeFlags.String)) { 23369 const str = (source as StringLiteralType).value; 23370 23371 // If the type contains `number` or a number literal and the string isn't a valid number, exclude numbers 23372 if (allTypeFlags & TypeFlags.NumberLike && !isValidNumberString(str, /*roundTripOnly*/ true)) { 23373 allTypeFlags &= ~TypeFlags.NumberLike; 23374 } 23375 23376 // If the type contains `bigint` or a bigint literal and the string isn't a valid bigint, exclude bigints 23377 if (allTypeFlags & TypeFlags.BigIntLike && !isValidBigIntString(str, /*roundTripOnly*/ true)) { 23378 allTypeFlags &= ~TypeFlags.BigIntLike; 23379 } 23380 23381 // for each type in the constraint, find the highest priority matching type 23382 const matchingType = reduceLeft(constraintTypes, (left, right) => 23383 !(right.flags & allTypeFlags) ? left : 23384 left.flags & TypeFlags.String ? left : right.flags & TypeFlags.String ? source : 23385 left.flags & TypeFlags.TemplateLiteral ? left : right.flags & TypeFlags.TemplateLiteral && isTypeMatchedByTemplateLiteralType(source, right as TemplateLiteralType) ? source : 23386 left.flags & TypeFlags.StringMapping ? left : right.flags & TypeFlags.StringMapping && str === applyStringMapping(right.symbol, str) ? source : 23387 left.flags & TypeFlags.StringLiteral ? left : right.flags & TypeFlags.StringLiteral && (right as StringLiteralType).value === str ? right : 23388 left.flags & TypeFlags.Number ? left : right.flags & TypeFlags.Number ? getNumberLiteralType(+str) : 23389 left.flags & TypeFlags.Enum ? left : right.flags & TypeFlags.Enum ? getNumberLiteralType(+str) : 23390 left.flags & TypeFlags.NumberLiteral ? left : right.flags & TypeFlags.NumberLiteral && (right as NumberLiteralType).value === +str ? right : 23391 left.flags & TypeFlags.BigInt ? left : right.flags & TypeFlags.BigInt ? parseBigIntLiteralType(str) : 23392 left.flags & TypeFlags.BigIntLiteral ? left : right.flags & TypeFlags.BigIntLiteral && pseudoBigIntToString((right as BigIntLiteralType).value) === str ? right : 23393 left.flags & TypeFlags.Boolean ? left : right.flags & TypeFlags.Boolean ? str === "true" ? trueType : str === "false" ? falseType : booleanType : 23394 left.flags & TypeFlags.BooleanLiteral ? left : right.flags & TypeFlags.BooleanLiteral && (right as IntrinsicType).intrinsicName === str ? right : 23395 left.flags & TypeFlags.Undefined ? left : right.flags & TypeFlags.Undefined && (right as IntrinsicType).intrinsicName === str ? right : 23396 left.flags & TypeFlags.Null ? left : right.flags & TypeFlags.Null && (right as IntrinsicType).intrinsicName === str ? right : 23397 left, 23398 neverType as Type); 23399 23400 if (!(matchingType.flags & TypeFlags.Never)) { 23401 inferFromTypes(matchingType, target); 23402 continue; 23403 } 23404 } 23405 } 23406 } 23407 23408 inferFromTypes(source, target); 23409 } 23410 } 23411 } 23412 23413 function inferFromObjectTypes(source: Type, target: Type) { 23414 if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && ( 23415 (source as TypeReference).target === (target as TypeReference).target || isArrayType(source) && isArrayType(target))) { 23416 // If source and target are references to the same generic type, infer from type arguments 23417 inferFromTypeArguments(getTypeArguments(source as TypeReference), getTypeArguments(target as TypeReference), getVariances((source as TypeReference).target)); 23418 return; 23419 } 23420 if (isGenericMappedType(source) && isGenericMappedType(target)) { 23421 // The source and target types are generic types { [P in S]: X } and { [P in T]: Y }, so we infer 23422 // from S to T and from X to Y. 23423 inferFromTypes(getConstraintTypeFromMappedType(source), getConstraintTypeFromMappedType(target)); 23424 inferFromTypes(getTemplateTypeFromMappedType(source), getTemplateTypeFromMappedType(target)); 23425 const sourceNameType = getNameTypeFromMappedType(source); 23426 const targetNameType = getNameTypeFromMappedType(target); 23427 if (sourceNameType && targetNameType) inferFromTypes(sourceNameType, targetNameType); 23428 } 23429 if (getObjectFlags(target) & ObjectFlags.Mapped && !(target as MappedType).declaration.nameType) { 23430 const constraintType = getConstraintTypeFromMappedType(target as MappedType); 23431 if (inferToMappedType(source, target as MappedType, constraintType)) { 23432 return; 23433 } 23434 } 23435 // Infer from the members of source and target only if the two types are possibly related 23436 if (!typesDefinitelyUnrelated(source, target)) { 23437 if (isArrayOrTupleType(source)) { 23438 if (isTupleType(target)) { 23439 const sourceArity = getTypeReferenceArity(source); 23440 const targetArity = getTypeReferenceArity(target); 23441 const elementTypes = getTypeArguments(target); 23442 const elementFlags = target.target.elementFlags; 23443 // When source and target are tuple types with the same structure (fixed, variadic, and rest are matched 23444 // to the same kind in each position), simply infer between the element types. 23445 if (isTupleType(source) && isTupleTypeStructureMatching(source, target)) { 23446 for (let i = 0; i < targetArity; i++) { 23447 inferFromTypes(getTypeArguments(source)[i], elementTypes[i]); 23448 } 23449 return; 23450 } 23451 const startLength = isTupleType(source) ? Math.min(source.target.fixedLength, target.target.fixedLength) : 0; 23452 const endLength = Math.min(isTupleType(source) ? getEndElementCount(source.target, ElementFlags.Fixed) : 0, 23453 target.target.hasRestElement ? getEndElementCount(target.target, ElementFlags.Fixed) : 0); 23454 // Infer between starting fixed elements. 23455 for (let i = 0; i < startLength; i++) { 23456 inferFromTypes(getTypeArguments(source)[i], elementTypes[i]); 23457 } 23458 if (!isTupleType(source) || sourceArity - startLength - endLength === 1 && source.target.elementFlags[startLength] & ElementFlags.Rest) { 23459 // Single rest element remains in source, infer from that to every element in target 23460 const restType = getTypeArguments(source)[startLength]; 23461 for (let i = startLength; i < targetArity - endLength; i++) { 23462 inferFromTypes(elementFlags[i] & ElementFlags.Variadic ? createArrayType(restType) : restType, elementTypes[i]); 23463 } 23464 } 23465 else { 23466 const middleLength = targetArity - startLength - endLength; 23467 if (middleLength === 2 && elementFlags[startLength] & elementFlags[startLength + 1] & ElementFlags.Variadic && isTupleType(source)) { 23468 // Middle of target is [...T, ...U] and source is tuple type 23469 const targetInfo = getInferenceInfoForType(elementTypes[startLength]); 23470 if (targetInfo && targetInfo.impliedArity !== undefined) { 23471 // Infer slices from source based on implied arity of T. 23472 inferFromTypes(sliceTupleType(source, startLength, endLength + sourceArity - targetInfo.impliedArity), elementTypes[startLength]); 23473 inferFromTypes(sliceTupleType(source, startLength + targetInfo.impliedArity, endLength), elementTypes[startLength + 1]); 23474 } 23475 } 23476 else if (middleLength === 1 && elementFlags[startLength] & ElementFlags.Variadic) { 23477 // Middle of target is exactly one variadic element. Infer the slice between the fixed parts in the source. 23478 // If target ends in optional element(s), make a lower priority a speculative inference. 23479 const endsInOptional = target.target.elementFlags[targetArity - 1] & ElementFlags.Optional; 23480 const sourceSlice = isTupleType(source) ? sliceTupleType(source, startLength, endLength) : createArrayType(getTypeArguments(source)[0]); 23481 inferWithPriority(sourceSlice, elementTypes[startLength], endsInOptional ? InferencePriority.SpeculativeTuple : 0); 23482 } 23483 else if (middleLength === 1 && elementFlags[startLength] & ElementFlags.Rest) { 23484 // Middle of target is exactly one rest element. If middle of source is not empty, infer union of middle element types. 23485 const restType = isTupleType(source) ? getElementTypeOfSliceOfTupleType(source, startLength, endLength) : getTypeArguments(source)[0]; 23486 if (restType) { 23487 inferFromTypes(restType, elementTypes[startLength]); 23488 } 23489 } 23490 } 23491 // Infer between ending fixed elements 23492 for (let i = 0; i < endLength; i++) { 23493 inferFromTypes(getTypeArguments(source)[sourceArity - i - 1], elementTypes[targetArity - i - 1]); 23494 } 23495 return; 23496 } 23497 if (isArrayType(target)) { 23498 inferFromIndexTypes(source, target); 23499 return; 23500 } 23501 } 23502 inferFromProperties(source, target); 23503 inferFromSignatures(source, target, SignatureKind.Call); 23504 inferFromSignatures(source, target, SignatureKind.Construct); 23505 inferFromIndexTypes(source, target); 23506 } 23507 } 23508 23509 function inferFromProperties(source: Type, target: Type) { 23510 const properties = getPropertiesOfObjectType(target); 23511 for (const targetProp of properties) { 23512 const sourceProp = getPropertyOfType(source, targetProp.escapedName); 23513 if (sourceProp && !some(sourceProp.declarations, hasSkipDirectInferenceFlag)) { 23514 inferFromTypes(getTypeOfSymbol(sourceProp), getTypeOfSymbol(targetProp)); 23515 } 23516 } 23517 } 23518 23519 function inferFromSignatures(source: Type, target: Type, kind: SignatureKind) { 23520 const sourceSignatures = getSignaturesOfType(source, kind); 23521 const targetSignatures = getSignaturesOfType(target, kind); 23522 const sourceLen = sourceSignatures.length; 23523 const targetLen = targetSignatures.length; 23524 const len = sourceLen < targetLen ? sourceLen : targetLen; 23525 for (let i = 0; i < len; i++) { 23526 inferFromSignature(getBaseSignature(sourceSignatures[sourceLen - len + i]), getErasedSignature(targetSignatures[targetLen - len + i])); 23527 } 23528 } 23529 23530 function inferFromSignature(source: Signature, target: Signature) { 23531 const saveBivariant = bivariant; 23532 const kind = target.declaration ? target.declaration.kind : SyntaxKind.Unknown; 23533 // Once we descend into a bivariant signature we remain bivariant for all nested inferences 23534 bivariant = bivariant || kind === SyntaxKind.MethodDeclaration || kind === SyntaxKind.MethodSignature || kind === SyntaxKind.Constructor; 23535 applyToParameterTypes(source, target, inferFromContravariantTypesIfStrictFunctionTypes); 23536 bivariant = saveBivariant; 23537 applyToReturnTypes(source, target, inferFromTypes); 23538 } 23539 23540 function inferFromIndexTypes(source: Type, target: Type) { 23541 // Inferences across mapped type index signatures are pretty much the same a inferences to homomorphic variables 23542 const priority = (getObjectFlags(source) & getObjectFlags(target) & ObjectFlags.Mapped) ? InferencePriority.HomomorphicMappedType : 0; 23543 const indexInfos = getIndexInfosOfType(target); 23544 if (isObjectTypeWithInferableIndex(source)) { 23545 for (const targetInfo of indexInfos) { 23546 const propTypes: Type[] = []; 23547 for (const prop of getPropertiesOfType(source)) { 23548 if (isApplicableIndexType(getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique), targetInfo.keyType)) { 23549 const propType = getTypeOfSymbol(prop); 23550 propTypes.push(prop.flags & SymbolFlags.Optional ? removeMissingOrUndefinedType(propType) : propType); 23551 } 23552 } 23553 for (const info of getIndexInfosOfType(source)) { 23554 if (isApplicableIndexType(info.keyType, targetInfo.keyType)) { 23555 propTypes.push(info.type); 23556 } 23557 } 23558 if (propTypes.length) { 23559 inferWithPriority(getUnionType(propTypes), targetInfo.type, priority); 23560 } 23561 } 23562 } 23563 for (const targetInfo of indexInfos) { 23564 const sourceInfo = getApplicableIndexInfo(source, targetInfo.keyType); 23565 if (sourceInfo) { 23566 inferWithPriority(sourceInfo.type, targetInfo.type, priority); 23567 } 23568 } 23569 } 23570 } 23571 23572 function isTypeOrBaseIdenticalTo(s: Type, t: Type) { 23573 return exactOptionalPropertyTypes && t === missingType ? s === t : 23574 (isTypeIdenticalTo(s, t) || !!(t.flags & TypeFlags.String && s.flags & TypeFlags.StringLiteral || t.flags & TypeFlags.Number && s.flags & TypeFlags.NumberLiteral)); 23575 } 23576 23577 function isTypeCloselyMatchedBy(s: Type, t: Type) { 23578 return !!(s.flags & TypeFlags.Object && t.flags & TypeFlags.Object && s.symbol && s.symbol === t.symbol || 23579 s.aliasSymbol && s.aliasTypeArguments && s.aliasSymbol === t.aliasSymbol); 23580 } 23581 23582 function hasPrimitiveConstraint(type: TypeParameter): boolean { 23583 const constraint = getConstraintOfTypeParameter(type); 23584 return !!constraint && maybeTypeOfKind(constraint.flags & TypeFlags.Conditional ? getDefaultConstraintOfConditionalType(constraint as ConditionalType) : constraint, TypeFlags.Primitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping); 23585 } 23586 23587 function isObjectLiteralType(type: Type) { 23588 return !!(getObjectFlags(type) & ObjectFlags.ObjectLiteral); 23589 } 23590 23591 function isObjectOrArrayLiteralType(type: Type) { 23592 return !!(getObjectFlags(type) & (ObjectFlags.ObjectLiteral | ObjectFlags.ArrayLiteral)); 23593 } 23594 23595 function unionObjectAndArrayLiteralCandidates(candidates: Type[]): Type[] { 23596 if (candidates.length > 1) { 23597 const objectLiterals = filter(candidates, isObjectOrArrayLiteralType); 23598 if (objectLiterals.length) { 23599 const literalsType = getUnionType(objectLiterals, UnionReduction.Subtype); 23600 return concatenate(filter(candidates, t => !isObjectOrArrayLiteralType(t)), [literalsType]); 23601 } 23602 } 23603 return candidates; 23604 } 23605 23606 function getContravariantInference(inference: InferenceInfo) { 23607 return inference.priority! & InferencePriority.PriorityImpliesCombination ? getIntersectionType(inference.contraCandidates!) : getCommonSubtype(inference.contraCandidates!); 23608 } 23609 23610 function getCovariantInference(inference: InferenceInfo, signature: Signature) { 23611 // Extract all object and array literal types and replace them with a single widened and normalized type. 23612 const candidates = unionObjectAndArrayLiteralCandidates(inference.candidates!); 23613 // We widen inferred literal types if 23614 // all inferences were made to top-level occurrences of the type parameter, and 23615 // the type parameter has no constraint or its constraint includes no primitive or literal types, and 23616 // the type parameter was fixed during inference or does not occur at top-level in the return type. 23617 const primitiveConstraint = hasPrimitiveConstraint(inference.typeParameter); 23618 const widenLiteralTypes = !primitiveConstraint && inference.topLevel && 23619 (inference.isFixed || !isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), inference.typeParameter)); 23620 const baseCandidates = primitiveConstraint ? sameMap(candidates, getRegularTypeOfLiteralType) : 23621 widenLiteralTypes ? sameMap(candidates, getWidenedLiteralType) : 23622 candidates; 23623 // If all inferences were made from a position that implies a combined result, infer a union type. 23624 // Otherwise, infer a common supertype. 23625 const unwidenedType = inference.priority! & InferencePriority.PriorityImpliesCombination ? 23626 getUnionType(baseCandidates, UnionReduction.Subtype) : 23627 getCommonSupertype(baseCandidates); 23628 return getWidenedType(unwidenedType); 23629 } 23630 23631 function getInferredType(context: InferenceContext, index: number): Type { 23632 const inference = context.inferences[index]; 23633 if (!inference.inferredType) { 23634 let inferredType: Type | undefined; 23635 const signature = context.signature; 23636 if (signature) { 23637 const inferredCovariantType = inference.candidates ? getCovariantInference(inference, signature) : undefined; 23638 if (inference.contraCandidates) { 23639 // If we have both co- and contra-variant inferences, we prefer the contra-variant inference 23640 // unless the co-variant inference is a subtype of some contra-variant inference and not 'never'. 23641 inferredType = inferredCovariantType && !(inferredCovariantType.flags & TypeFlags.Never) && 23642 some(inference.contraCandidates, t => isTypeSubtypeOf(inferredCovariantType, t)) ? 23643 inferredCovariantType : getContravariantInference(inference); 23644 } 23645 else if (inferredCovariantType) { 23646 inferredType = inferredCovariantType; 23647 } 23648 else if (context.flags & InferenceFlags.NoDefault) { 23649 // We use silentNeverType as the wildcard that signals no inferences. 23650 inferredType = silentNeverType; 23651 } 23652 else { 23653 // Infer either the default or the empty object type when no inferences were 23654 // made. It is important to remember that in this case, inference still 23655 // succeeds, meaning there is no error for not having inference candidates. An 23656 // inference error only occurs when there are *conflicting* candidates, i.e. 23657 // candidates with no common supertype. 23658 const defaultType = getDefaultFromTypeParameter(inference.typeParameter); 23659 if (defaultType) { 23660 // Instantiate the default type. Any forward reference to a type 23661 // parameter should be instantiated to the empty object type. 23662 inferredType = instantiateType(defaultType, mergeTypeMappers(createBackreferenceMapper(context, index), context.nonFixingMapper)); 23663 } 23664 } 23665 } 23666 else { 23667 inferredType = getTypeFromInference(inference); 23668 } 23669 23670 inference.inferredType = inferredType || getDefaultTypeArgumentType(!!(context.flags & InferenceFlags.AnyDefault)); 23671 23672 const constraint = getConstraintOfTypeParameter(inference.typeParameter); 23673 if (constraint) { 23674 const instantiatedConstraint = instantiateType(constraint, context.nonFixingMapper); 23675 if (!inferredType || !context.compareTypes(inferredType, getTypeWithThisArgument(instantiatedConstraint, inferredType))) { 23676 inference.inferredType = inferredType = instantiatedConstraint; 23677 } 23678 } 23679 } 23680 23681 return inference.inferredType; 23682 } 23683 23684 function getDefaultTypeArgumentType(isInJavaScriptFile: boolean): Type { 23685 return isInJavaScriptFile ? anyType : unknownType; 23686 } 23687 23688 function getInferredTypes(context: InferenceContext): Type[] { 23689 const result: Type[] = []; 23690 for (let i = 0; i < context.inferences.length; i++) { 23691 result.push(getInferredType(context, i)); 23692 } 23693 return result; 23694 } 23695 23696 // EXPRESSION TYPE CHECKING 23697 23698 function getCannotFindNameDiagnosticForName(node: Identifier): DiagnosticMessage { 23699 switch (node.escapedText) { 23700 case "document": 23701 case "console": 23702 return Diagnostics.Cannot_find_name_0_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_include_dom; 23703 case "$": 23704 return compilerOptions.types 23705 ? Diagnostics.Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_jQuery_Try_npm_i_save_dev_types_Slashjquery_and_then_add_jquery_to_the_types_field_in_your_tsconfig 23706 : Diagnostics.Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_jQuery_Try_npm_i_save_dev_types_Slashjquery; 23707 case "describe": 23708 case "suite": 23709 case "it": 23710 case "test": 23711 return compilerOptions.types 23712 ? Diagnostics.Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_a_test_runner_Try_npm_i_save_dev_types_Slashjest_or_npm_i_save_dev_types_Slashmocha_and_then_add_jest_or_mocha_to_the_types_field_in_your_tsconfig 23713 : Diagnostics.Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_a_test_runner_Try_npm_i_save_dev_types_Slashjest_or_npm_i_save_dev_types_Slashmocha; 23714 case "process": 23715 case "require": 23716 case "Buffer": 23717 case "module": 23718 return compilerOptions.types 23719 ? Diagnostics.Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_node_Try_npm_i_save_dev_types_Slashnode_and_then_add_node_to_the_types_field_in_your_tsconfig 23720 : Diagnostics.Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_node_Try_npm_i_save_dev_types_Slashnode; 23721 case "Map": 23722 case "Set": 23723 case "Promise": 23724 case "Symbol": 23725 case "WeakMap": 23726 case "WeakSet": 23727 case "Iterator": 23728 case "AsyncIterator": 23729 case "SharedArrayBuffer": 23730 case "Atomics": 23731 case "AsyncIterable": 23732 case "AsyncIterableIterator": 23733 case "AsyncGenerator": 23734 case "AsyncGeneratorFunction": 23735 case "BigInt": 23736 case "Reflect": 23737 case "BigInt64Array": 23738 case "BigUint64Array": 23739 return Diagnostics.Cannot_find_name_0_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_1_or_later; 23740 case "await": 23741 if (isCallExpression(node.parent)) { 23742 return Diagnostics.Cannot_find_name_0_Did_you_mean_to_write_this_in_an_async_function; 23743 } 23744 // falls through 23745 default: 23746 if (node.parent.kind === SyntaxKind.ShorthandPropertyAssignment) { 23747 return Diagnostics.No_value_exists_in_scope_for_the_shorthand_property_0_Either_declare_one_or_provide_an_initializer; 23748 } 23749 else { 23750 return Diagnostics.Cannot_find_name_0; 23751 } 23752 } 23753 } 23754 23755 function getResolvedSymbol(node: Identifier): Symbol { 23756 const links = getNodeLinks(node); 23757 if (!links.resolvedSymbol) { 23758 links.resolvedSymbol = !nodeIsMissing(node) && 23759 resolveName( 23760 node, 23761 node.escapedText, 23762 SymbolFlags.Value | SymbolFlags.ExportValue, 23763 getCannotFindNameDiagnosticForName(node), 23764 node, 23765 !isWriteOnlyAccess(node), 23766 /*excludeGlobals*/ false) || unknownSymbol; 23767 } 23768 return links.resolvedSymbol; 23769 } 23770 23771 function isInTypeQuery(node: Node): boolean { 23772 // TypeScript 1.0 spec (April 2014): 3.6.3 23773 // A type query consists of the keyword typeof followed by an expression. 23774 // The expression is restricted to a single identifier or a sequence of identifiers separated by periods 23775 return !!findAncestor( 23776 node, 23777 n => n.kind === SyntaxKind.TypeQuery ? true : n.kind === SyntaxKind.Identifier || n.kind === SyntaxKind.QualifiedName ? false : "quit"); 23778 } 23779 23780 // Return the flow cache key for a "dotted name" (i.e. a sequence of identifiers 23781 // separated by dots). The key consists of the id of the symbol referenced by the 23782 // leftmost identifier followed by zero or more property names separated by dots. 23783 // The result is undefined if the reference isn't a dotted name. 23784 function getFlowCacheKey(node: Node, declaredType: Type, initialType: Type, flowContainer: Node | undefined): string | undefined { 23785 switch (node.kind) { 23786 case SyntaxKind.Identifier: 23787 if (!isThisInTypeQuery(node)) { 23788 const symbol = getResolvedSymbol(node as Identifier); 23789 return symbol !== unknownSymbol ? `${flowContainer ? getNodeId(flowContainer) : "-1"}|${getTypeId(declaredType)}|${getTypeId(initialType)}|${getSymbolId(symbol)}` : undefined; 23790 } 23791 // falls through 23792 case SyntaxKind.ThisKeyword: 23793 return `0|${flowContainer ? getNodeId(flowContainer) : "-1"}|${getTypeId(declaredType)}|${getTypeId(initialType)}`; 23794 case SyntaxKind.NonNullExpression: 23795 case SyntaxKind.ParenthesizedExpression: 23796 return getFlowCacheKey((node as NonNullExpression | ParenthesizedExpression).expression, declaredType, initialType, flowContainer); 23797 case SyntaxKind.QualifiedName: 23798 const left = getFlowCacheKey((node as QualifiedName).left, declaredType, initialType, flowContainer); 23799 return left && left + "." + (node as QualifiedName).right.escapedText; 23800 case SyntaxKind.PropertyAccessExpression: 23801 case SyntaxKind.ElementAccessExpression: 23802 const propName = getAccessedPropertyName(node as AccessExpression); 23803 if (propName !== undefined) { 23804 const key = getFlowCacheKey((node as AccessExpression).expression, declaredType, initialType, flowContainer); 23805 return key && key + "." + propName; 23806 } 23807 break; 23808 case SyntaxKind.ObjectBindingPattern: 23809 case SyntaxKind.ArrayBindingPattern: 23810 case SyntaxKind.FunctionDeclaration: 23811 case SyntaxKind.FunctionExpression: 23812 case SyntaxKind.ArrowFunction: 23813 case SyntaxKind.MethodDeclaration: 23814 // Handle pseudo-references originating in getNarrowedTypeOfSymbol. 23815 return `${getNodeId(node)}#${getTypeId(declaredType)}`; 23816 } 23817 return undefined; 23818 } 23819 23820 function isMatchingReference(source: Node, target: Node): boolean { 23821 switch (target.kind) { 23822 case SyntaxKind.ParenthesizedExpression: 23823 case SyntaxKind.NonNullExpression: 23824 return isMatchingReference(source, (target as NonNullExpression | ParenthesizedExpression).expression); 23825 case SyntaxKind.BinaryExpression: 23826 return (isAssignmentExpression(target) && isMatchingReference(source, target.left)) || 23827 (isBinaryExpression(target) && target.operatorToken.kind === SyntaxKind.CommaToken && isMatchingReference(source, target.right)); 23828 } 23829 switch (source.kind) { 23830 case SyntaxKind.MetaProperty: 23831 return target.kind === SyntaxKind.MetaProperty 23832 && (source as MetaProperty).keywordToken === (target as MetaProperty).keywordToken 23833 && (source as MetaProperty).name.escapedText === (target as MetaProperty).name.escapedText; 23834 case SyntaxKind.Identifier: 23835 case SyntaxKind.PrivateIdentifier: 23836 return isThisInTypeQuery(source) ? 23837 target.kind === SyntaxKind.ThisKeyword : 23838 target.kind === SyntaxKind.Identifier && getResolvedSymbol(source as Identifier) === getResolvedSymbol(target as Identifier) || 23839 (target.kind === SyntaxKind.VariableDeclaration || target.kind === SyntaxKind.BindingElement) && 23840 getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(source as Identifier)) === getSymbolOfNode(target); 23841 case SyntaxKind.ThisKeyword: 23842 return target.kind === SyntaxKind.ThisKeyword; 23843 case SyntaxKind.SuperKeyword: 23844 return target.kind === SyntaxKind.SuperKeyword; 23845 case SyntaxKind.NonNullExpression: 23846 case SyntaxKind.ParenthesizedExpression: 23847 return isMatchingReference((source as NonNullExpression | ParenthesizedExpression).expression, target); 23848 case SyntaxKind.PropertyAccessExpression: 23849 case SyntaxKind.ElementAccessExpression: 23850 const sourcePropertyName = getAccessedPropertyName(source as AccessExpression); 23851 const targetPropertyName = isAccessExpression(target) ? getAccessedPropertyName(target) : undefined; 23852 return sourcePropertyName !== undefined && targetPropertyName !== undefined && targetPropertyName === sourcePropertyName && 23853 isMatchingReference((source as AccessExpression).expression, (target as AccessExpression).expression); 23854 case SyntaxKind.QualifiedName: 23855 return isAccessExpression(target) && 23856 (source as QualifiedName).right.escapedText === getAccessedPropertyName(target) && 23857 isMatchingReference((source as QualifiedName).left, target.expression); 23858 case SyntaxKind.BinaryExpression: 23859 return (isBinaryExpression(source) && source.operatorToken.kind === SyntaxKind.CommaToken && isMatchingReference(source.right, target)); 23860 } 23861 return false; 23862 } 23863 23864 function getAccessedPropertyName(access: AccessExpression | BindingElement | ParameterDeclaration): __String | undefined { 23865 if (isPropertyAccessExpression(access)) { 23866 return access.name.escapedText; 23867 } 23868 if (isElementAccessExpression(access)) { 23869 return tryGetElementAccessExpressionName(access); 23870 } 23871 if (isBindingElement(access)) { 23872 const name = getDestructuringPropertyName(access); 23873 return name ? escapeLeadingUnderscores(name) : undefined; 23874 } 23875 if (isParameter(access)) { 23876 return ("" + access.parent.parameters.indexOf(access)) as __String; 23877 } 23878 return undefined; 23879 } 23880 23881 function tryGetNameFromType(type: Type) { 23882 return type.flags & TypeFlags.UniqueESSymbol ? (type as UniqueESSymbolType).escapedName : 23883 type.flags & TypeFlags.StringOrNumberLiteral ? escapeLeadingUnderscores("" + (type as StringLiteralType | NumberLiteralType).value) : undefined; 23884 } 23885 23886 function tryGetElementAccessExpressionName(node: ElementAccessExpression) { 23887 if (isStringOrNumericLiteralLike(node.argumentExpression)) { 23888 return escapeLeadingUnderscores(node.argumentExpression.text); 23889 } 23890 if (isEntityNameExpression(node.argumentExpression)) { 23891 const symbol = resolveEntityName(node.argumentExpression, SymbolFlags.Value, /*ignoreErrors*/ true); 23892 if (!symbol || !(isConstVariable(symbol) || (symbol.flags & SymbolFlags.EnumMember))) return undefined; 23893 23894 const declaration = symbol.valueDeclaration; 23895 if (declaration === undefined) return undefined; 23896 23897 const type = tryGetTypeFromEffectiveTypeNode(declaration); 23898 if (type) { 23899 const name = tryGetNameFromType(type); 23900 if (name !== undefined) { 23901 return name; 23902 } 23903 } 23904 23905 if (hasOnlyExpressionInitializer(declaration) && isBlockScopedNameDeclaredBeforeUse(declaration, node.argumentExpression)) { 23906 const initializer = getEffectiveInitializer(declaration); 23907 if (initializer) { 23908 return tryGetNameFromType(getTypeOfExpression(initializer)); 23909 } 23910 if (isEnumMember(declaration)) { 23911 return getTextOfPropertyName(declaration.name); 23912 } 23913 } 23914 } 23915 return undefined; 23916 } 23917 23918 function containsMatchingReference(source: Node, target: Node) { 23919 while (isAccessExpression(source)) { 23920 source = source.expression; 23921 if (isMatchingReference(source, target)) { 23922 return true; 23923 } 23924 } 23925 return false; 23926 } 23927 23928 function optionalChainContainsReference(source: Node, target: Node) { 23929 while (isOptionalChain(source)) { 23930 source = source.expression; 23931 if (isMatchingReference(source, target)) { 23932 return true; 23933 } 23934 } 23935 return false; 23936 } 23937 23938 function isDiscriminantProperty(type: Type | undefined, name: __String) { 23939 if (type && type.flags & TypeFlags.Union) { 23940 const prop = getUnionOrIntersectionProperty(type as UnionType, name); 23941 if (prop && getCheckFlags(prop) & CheckFlags.SyntheticProperty) { 23942 if ((prop as TransientSymbol).isDiscriminantProperty === undefined) { 23943 (prop as TransientSymbol).isDiscriminantProperty = 23944 ((prop as TransientSymbol).checkFlags & CheckFlags.Discriminant) === CheckFlags.Discriminant && 23945 !isGenericType(getTypeOfSymbol(prop)); 23946 } 23947 return !!(prop as TransientSymbol).isDiscriminantProperty; 23948 } 23949 } 23950 return false; 23951 } 23952 23953 function findDiscriminantProperties(sourceProperties: Symbol[], target: Type): Symbol[] | undefined { 23954 let result: Symbol[] | undefined; 23955 for (const sourceProperty of sourceProperties) { 23956 if (isDiscriminantProperty(target, sourceProperty.escapedName)) { 23957 if (result) { 23958 result.push(sourceProperty); 23959 continue; 23960 } 23961 result = [sourceProperty]; 23962 } 23963 } 23964 return result; 23965 } 23966 23967 // Given a set of constituent types and a property name, create and return a map keyed by the literal 23968 // types of the property by that name in each constituent type. No map is returned if some key property 23969 // has a non-literal type or if less than 10 or less than 50% of the constituents have a unique key. 23970 // Entries with duplicate keys have unknownType as the value. 23971 function mapTypesByKeyProperty(types: Type[], name: __String) { 23972 const map = new Map<TypeId, Type>(); 23973 let count = 0; 23974 for (const type of types) { 23975 if (type.flags & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.InstantiableNonPrimitive)) { 23976 const discriminant = getTypeOfPropertyOfType(type, name); 23977 if (discriminant) { 23978 if (!isLiteralType(discriminant)) { 23979 return undefined; 23980 } 23981 let duplicate = false; 23982 forEachType(discriminant, t => { 23983 const id = getTypeId(getRegularTypeOfLiteralType(t)); 23984 const existing = map.get(id); 23985 if (!existing) { 23986 map.set(id, type); 23987 } 23988 else if (existing !== unknownType) { 23989 map.set(id, unknownType); 23990 duplicate = true; 23991 } 23992 }); 23993 if (!duplicate) count++; 23994 } 23995 } 23996 } 23997 return count >= 10 && count * 2 >= types.length ? map : undefined; 23998 } 23999 24000 // Return the name of a discriminant property for which it was possible and feasible to construct a map of 24001 // constituent types keyed by the literal types of the property by that name in each constituent type. 24002 function getKeyPropertyName(unionType: UnionType): __String | undefined { 24003 const types = unionType.types; 24004 // We only construct maps for unions with many non-primitive constituents. 24005 if (types.length < 10 || getObjectFlags(unionType) & ObjectFlags.PrimitiveUnion || 24006 countWhere(types, t => !!(t.flags & (TypeFlags.Object | TypeFlags.InstantiableNonPrimitive))) < 10) { 24007 return undefined; 24008 } 24009 if (unionType.keyPropertyName === undefined) { 24010 // The candidate key property name is the name of the first property with a unit type in one of the 24011 // constituent types. 24012 const keyPropertyName = forEach(types, t => 24013 t.flags & (TypeFlags.Object | TypeFlags.InstantiableNonPrimitive) ? 24014 forEach(getPropertiesOfType(t), p => isUnitType(getTypeOfSymbol(p)) ? p.escapedName : undefined) : 24015 undefined); 24016 const mapByKeyProperty = keyPropertyName && mapTypesByKeyProperty(types, keyPropertyName); 24017 unionType.keyPropertyName = mapByKeyProperty ? keyPropertyName : "" as __String; 24018 unionType.constituentMap = mapByKeyProperty; 24019 } 24020 return (unionType.keyPropertyName as string).length ? unionType.keyPropertyName : undefined; 24021 } 24022 24023 // Given a union type for which getKeyPropertyName returned a non-undefined result, return the constituent 24024 // that corresponds to the given key type for that property name. 24025 function getConstituentTypeForKeyType(unionType: UnionType, keyType: Type) { 24026 const result = unionType.constituentMap?.get(getTypeId(getRegularTypeOfLiteralType(keyType))); 24027 return result !== unknownType ? result : undefined; 24028 } 24029 24030 function getMatchingUnionConstituentForType(unionType: UnionType, type: Type) { 24031 const keyPropertyName = getKeyPropertyName(unionType); 24032 const propType = keyPropertyName && getTypeOfPropertyOfType(type, keyPropertyName); 24033 return propType && getConstituentTypeForKeyType(unionType, propType); 24034 } 24035 24036 function getMatchingUnionConstituentForObjectLiteral(unionType: UnionType, node: ObjectLiteralExpression) { 24037 const keyPropertyName = getKeyPropertyName(unionType); 24038 const propNode = keyPropertyName && find(node.properties, p => p.symbol && p.kind === SyntaxKind.PropertyAssignment && 24039 p.symbol.escapedName === keyPropertyName && isPossiblyDiscriminantValue(p.initializer)); 24040 const propType = propNode && getContextFreeTypeOfExpression((propNode as PropertyAssignment).initializer); 24041 return propType && getConstituentTypeForKeyType(unionType, propType); 24042 } 24043 24044 function isOrContainsMatchingReference(source: Node, target: Node) { 24045 return isMatchingReference(source, target) || containsMatchingReference(source, target); 24046 } 24047 24048 function hasMatchingArgument(expression: CallExpression | NewExpression, reference: Node) { 24049 if (expression.arguments) { 24050 for (const argument of expression.arguments) { 24051 if (isOrContainsMatchingReference(reference, argument)) { 24052 return true; 24053 } 24054 } 24055 } 24056 if (expression.expression.kind === SyntaxKind.PropertyAccessExpression && 24057 isOrContainsMatchingReference(reference, (expression.expression as PropertyAccessExpression).expression)) { 24058 return true; 24059 } 24060 return false; 24061 } 24062 24063 function getFlowNodeId(flow: FlowNode): number { 24064 if (!flow.id || flow.id < 0) { 24065 flow.id = nextFlowId; 24066 nextFlowId++; 24067 } 24068 return flow.id; 24069 } 24070 24071 function typeMaybeAssignableTo(source: Type, target: Type) { 24072 if (!(source.flags & TypeFlags.Union)) { 24073 return isTypeAssignableTo(source, target); 24074 } 24075 for (const t of (source as UnionType).types) { 24076 if (isTypeAssignableTo(t, target)) { 24077 return true; 24078 } 24079 } 24080 return false; 24081 } 24082 24083 // Remove those constituent types of declaredType to which no constituent type of assignedType is assignable. 24084 // For example, when a variable of type number | string | boolean is assigned a value of type number | boolean, 24085 // we remove type string. 24086 function getAssignmentReducedType(declaredType: UnionType, assignedType: Type) { 24087 if (declaredType === assignedType) { 24088 return declaredType; 24089 } 24090 if (assignedType.flags & TypeFlags.Never) { 24091 return assignedType; 24092 } 24093 const key = `A${getTypeId(declaredType)},${getTypeId(assignedType)}`; 24094 return getCachedType(key) ?? setCachedType(key, getAssignmentReducedTypeWorker(declaredType, assignedType)); 24095 } 24096 24097 function getAssignmentReducedTypeWorker(declaredType: UnionType, assignedType: Type) { 24098 const filteredType = filterType(declaredType, t => typeMaybeAssignableTo(assignedType, t)); 24099 // Ensure that we narrow to fresh types if the assignment is a fresh boolean literal type. 24100 const reducedType = assignedType.flags & TypeFlags.BooleanLiteral && isFreshLiteralType(assignedType) ? mapType(filteredType, getFreshTypeOfLiteralType) : filteredType; 24101 // Our crude heuristic produces an invalid result in some cases: see GH#26130. 24102 // For now, when that happens, we give up and don't narrow at all. (This also 24103 // means we'll never narrow for erroneous assignments where the assigned type 24104 // is not assignable to the declared type.) 24105 return isTypeAssignableTo(assignedType, reducedType) ? reducedType : declaredType; 24106 } 24107 24108 function isFunctionObjectType(type: ObjectType): boolean { 24109 // We do a quick check for a "bind" property before performing the more expensive subtype 24110 // check. This gives us a quicker out in the common case where an object type is not a function. 24111 const resolved = resolveStructuredTypeMembers(type); 24112 return !!(resolved.callSignatures.length || resolved.constructSignatures.length || 24113 resolved.members.get("bind" as __String) && isTypeSubtypeOf(type, globalFunctionType)); 24114 } 24115 24116 function getTypeFacts(type: Type): TypeFacts { 24117 if (type.flags & (TypeFlags.Intersection | TypeFlags.Instantiable)) { 24118 type = getBaseConstraintOfType(type) || unknownType; 24119 } 24120 const flags = type.flags; 24121 if (flags & (TypeFlags.String | TypeFlags.StringMapping)) { 24122 return strictNullChecks ? TypeFacts.StringStrictFacts : TypeFacts.StringFacts; 24123 } 24124 if (flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral)) { 24125 const isEmpty = flags & TypeFlags.StringLiteral && (type as StringLiteralType).value === ""; 24126 return strictNullChecks ? 24127 isEmpty ? TypeFacts.EmptyStringStrictFacts : TypeFacts.NonEmptyStringStrictFacts : 24128 isEmpty ? TypeFacts.EmptyStringFacts : TypeFacts.NonEmptyStringFacts; 24129 } 24130 if (flags & (TypeFlags.Number | TypeFlags.Enum)) { 24131 return strictNullChecks ? TypeFacts.NumberStrictFacts : TypeFacts.NumberFacts; 24132 } 24133 if (flags & TypeFlags.NumberLiteral) { 24134 const isZero = (type as NumberLiteralType).value === 0; 24135 return strictNullChecks ? 24136 isZero ? TypeFacts.ZeroNumberStrictFacts : TypeFacts.NonZeroNumberStrictFacts : 24137 isZero ? TypeFacts.ZeroNumberFacts : TypeFacts.NonZeroNumberFacts; 24138 } 24139 if (flags & TypeFlags.BigInt) { 24140 return strictNullChecks ? TypeFacts.BigIntStrictFacts : TypeFacts.BigIntFacts; 24141 } 24142 if (flags & TypeFlags.BigIntLiteral) { 24143 const isZero = isZeroBigInt(type as BigIntLiteralType); 24144 return strictNullChecks ? 24145 isZero ? TypeFacts.ZeroBigIntStrictFacts : TypeFacts.NonZeroBigIntStrictFacts : 24146 isZero ? TypeFacts.ZeroBigIntFacts : TypeFacts.NonZeroBigIntFacts; 24147 } 24148 if (flags & TypeFlags.Boolean) { 24149 return strictNullChecks ? TypeFacts.BooleanStrictFacts : TypeFacts.BooleanFacts; 24150 } 24151 if (flags & TypeFlags.BooleanLike) { 24152 return strictNullChecks ? 24153 (type === falseType || type === regularFalseType) ? TypeFacts.FalseStrictFacts : TypeFacts.TrueStrictFacts : 24154 (type === falseType || type === regularFalseType) ? TypeFacts.FalseFacts : TypeFacts.TrueFacts; 24155 } 24156 if (flags & TypeFlags.Object) { 24157 return getObjectFlags(type) & ObjectFlags.Anonymous && isEmptyObjectType(type as ObjectType) ? 24158 strictNullChecks ? TypeFacts.EmptyObjectStrictFacts : TypeFacts.EmptyObjectFacts : 24159 isFunctionObjectType(type as ObjectType) ? 24160 strictNullChecks ? TypeFacts.FunctionStrictFacts : TypeFacts.FunctionFacts : 24161 strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts; 24162 } 24163 if (flags & TypeFlags.Void) { 24164 return TypeFacts.VoidFacts; 24165 } 24166 if (flags & TypeFlags.Undefined) { 24167 return TypeFacts.UndefinedFacts; 24168 } 24169 if (flags & TypeFlags.Null) { 24170 return TypeFacts.NullFacts; 24171 } 24172 if (flags & TypeFlags.ESSymbolLike) { 24173 return strictNullChecks ? TypeFacts.SymbolStrictFacts : TypeFacts.SymbolFacts; 24174 } 24175 if (flags & TypeFlags.NonPrimitive) { 24176 return strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts; 24177 } 24178 if (flags & TypeFlags.Never) { 24179 return TypeFacts.None; 24180 } 24181 if (flags & TypeFlags.Union) { 24182 return reduceLeft((type as UnionType).types, (facts, t) => facts | getTypeFacts(t), TypeFacts.None); 24183 } 24184 if (flags & TypeFlags.Intersection) { 24185 return getIntersectionTypeFacts(type as IntersectionType); 24186 } 24187 return TypeFacts.UnknownFacts; 24188 } 24189 24190 function getIntersectionTypeFacts(type: IntersectionType): TypeFacts { 24191 // When an intersection contains a primitive type we ignore object type constituents as they are 24192 // presumably type tags. For example, in string & { __kind__: "name" } we ignore the object type. 24193 const ignoreObjects = maybeTypeOfKind(type, TypeFlags.Primitive); 24194 // When computing the type facts of an intersection type, certain type facts are computed as `and` 24195 // and others are computed as `or`. 24196 let oredFacts = TypeFacts.None; 24197 let andedFacts = TypeFacts.All; 24198 for (const t of type.types) { 24199 if (!(ignoreObjects && t.flags & TypeFlags.Object)) { 24200 const f = getTypeFacts(t); 24201 oredFacts |= f; 24202 andedFacts &= f; 24203 } 24204 } 24205 return oredFacts & TypeFacts.OrFactsMask | andedFacts & TypeFacts.AndFactsMask; 24206 } 24207 24208 function getTypeWithFacts(type: Type, include: TypeFacts) { 24209 return filterType(type, t => (getTypeFacts(t) & include) !== 0); 24210 } 24211 24212 // This function is similar to getTypeWithFacts, except that in strictNullChecks mode it replaces type 24213 // unknown with the union {} | null | undefined (and reduces that accordingly), and it intersects remaining 24214 // instantiable types with {}, {} | null, or {} | undefined in order to remove null and/or undefined. 24215 function getAdjustedTypeWithFacts(type: Type, facts: TypeFacts) { 24216 const reduced = recombineUnknownType(getTypeWithFacts(strictNullChecks && type.flags & TypeFlags.Unknown ? unknownUnionType : type, facts)); 24217 if (strictNullChecks) { 24218 switch (facts) { 24219 case TypeFacts.NEUndefined: 24220 return mapType(reduced, t => getTypeFacts(t) & TypeFacts.EQUndefined ? getIntersectionType([t, getTypeFacts(t) & TypeFacts.EQNull && !maybeTypeOfKind(reduced, TypeFlags.Null) ? getUnionType([emptyObjectType, nullType]) : emptyObjectType]): t); 24221 case TypeFacts.NENull: 24222 return mapType(reduced, t => getTypeFacts(t) & TypeFacts.EQNull ? getIntersectionType([t, getTypeFacts(t) & TypeFacts.EQUndefined && !maybeTypeOfKind(reduced, TypeFlags.Undefined) ? getUnionType([emptyObjectType, undefinedType]) : emptyObjectType]): t); 24223 case TypeFacts.NEUndefinedOrNull: 24224 case TypeFacts.Truthy: 24225 return mapType(reduced, t => getTypeFacts(t) & TypeFacts.EQUndefinedOrNull ? getGlobalNonNullableTypeInstantiation(t): t); 24226 } 24227 } 24228 return reduced; 24229 } 24230 24231 function recombineUnknownType(type: Type) { 24232 return type === unknownUnionType ? unknownType : type; 24233 } 24234 24235 function getTypeWithDefault(type: Type, defaultExpression: Expression) { 24236 return defaultExpression ? 24237 getUnionType([getNonUndefinedType(type), getTypeOfExpression(defaultExpression)]) : 24238 type; 24239 } 24240 24241 function getTypeOfDestructuredProperty(type: Type, name: PropertyName) { 24242 const nameType = getLiteralTypeFromPropertyName(name); 24243 if (!isTypeUsableAsPropertyName(nameType)) return errorType; 24244 const text = getPropertyNameFromType(nameType); 24245 return getTypeOfPropertyOfType(type, text) || includeUndefinedInIndexSignature(getApplicableIndexInfoForName(type, text)?.type) || errorType; 24246 } 24247 24248 function getTypeOfDestructuredArrayElement(type: Type, index: number) { 24249 return everyType(type, isTupleLikeType) && getTupleElementType(type, index) || 24250 includeUndefinedInIndexSignature(checkIteratedTypeOrElementType(IterationUse.Destructuring, type, undefinedType, /*errorNode*/ undefined)) || 24251 errorType; 24252 } 24253 24254 function includeUndefinedInIndexSignature(type: Type | undefined): Type | undefined { 24255 if (!type) return type; 24256 return compilerOptions.noUncheckedIndexedAccess ? 24257 getUnionType([type, undefinedType]) : 24258 type; 24259 } 24260 24261 function getTypeOfDestructuredSpreadExpression(type: Type) { 24262 return createArrayType(checkIteratedTypeOrElementType(IterationUse.Destructuring, type, undefinedType, /*errorNode*/ undefined) || errorType); 24263 } 24264 24265 function getAssignedTypeOfBinaryExpression(node: BinaryExpression): Type { 24266 const isDestructuringDefaultAssignment = 24267 node.parent.kind === SyntaxKind.ArrayLiteralExpression && isDestructuringAssignmentTarget(node.parent) || 24268 node.parent.kind === SyntaxKind.PropertyAssignment && isDestructuringAssignmentTarget(node.parent.parent); 24269 return isDestructuringDefaultAssignment ? 24270 getTypeWithDefault(getAssignedType(node), node.right) : 24271 getTypeOfExpression(node.right); 24272 } 24273 24274 function isDestructuringAssignmentTarget(parent: Node) { 24275 return parent.parent.kind === SyntaxKind.BinaryExpression && (parent.parent as BinaryExpression).left === parent || 24276 parent.parent.kind === SyntaxKind.ForOfStatement && (parent.parent as ForOfStatement).initializer === parent; 24277 } 24278 24279 function getAssignedTypeOfArrayLiteralElement(node: ArrayLiteralExpression, element: Expression): Type { 24280 return getTypeOfDestructuredArrayElement(getAssignedType(node), node.elements.indexOf(element)); 24281 } 24282 24283 function getAssignedTypeOfSpreadExpression(node: SpreadElement): Type { 24284 return getTypeOfDestructuredSpreadExpression(getAssignedType(node.parent as ArrayLiteralExpression)); 24285 } 24286 24287 function getAssignedTypeOfPropertyAssignment(node: PropertyAssignment | ShorthandPropertyAssignment): Type { 24288 return getTypeOfDestructuredProperty(getAssignedType(node.parent), node.name); 24289 } 24290 24291 function getAssignedTypeOfShorthandPropertyAssignment(node: ShorthandPropertyAssignment): Type { 24292 return getTypeWithDefault(getAssignedTypeOfPropertyAssignment(node), node.objectAssignmentInitializer!); 24293 } 24294 24295 function getAssignedType(node: Expression): Type { 24296 const { parent } = node; 24297 switch (parent.kind) { 24298 case SyntaxKind.ForInStatement: 24299 return stringType; 24300 case SyntaxKind.ForOfStatement: 24301 return checkRightHandSideOfForOf(parent as ForOfStatement) || errorType; 24302 case SyntaxKind.BinaryExpression: 24303 return getAssignedTypeOfBinaryExpression(parent as BinaryExpression); 24304 case SyntaxKind.DeleteExpression: 24305 return undefinedType; 24306 case SyntaxKind.ArrayLiteralExpression: 24307 return getAssignedTypeOfArrayLiteralElement(parent as ArrayLiteralExpression, node); 24308 case SyntaxKind.SpreadElement: 24309 return getAssignedTypeOfSpreadExpression(parent as SpreadElement); 24310 case SyntaxKind.PropertyAssignment: 24311 return getAssignedTypeOfPropertyAssignment(parent as PropertyAssignment); 24312 case SyntaxKind.ShorthandPropertyAssignment: 24313 return getAssignedTypeOfShorthandPropertyAssignment(parent as ShorthandPropertyAssignment); 24314 } 24315 return errorType; 24316 } 24317 24318 function getInitialTypeOfBindingElement(node: BindingElement): Type { 24319 const pattern = node.parent; 24320 const parentType = getInitialType(pattern.parent as VariableDeclaration | BindingElement); 24321 const type = pattern.kind === SyntaxKind.ObjectBindingPattern ? 24322 getTypeOfDestructuredProperty(parentType, node.propertyName || node.name as Identifier) : 24323 !node.dotDotDotToken ? 24324 getTypeOfDestructuredArrayElement(parentType, pattern.elements.indexOf(node)) : 24325 getTypeOfDestructuredSpreadExpression(parentType); 24326 return getTypeWithDefault(type, node.initializer!); 24327 } 24328 24329 function getTypeOfInitializer(node: Expression) { 24330 // Return the cached type if one is available. If the type of the variable was inferred 24331 // from its initializer, we'll already have cached the type. Otherwise we compute it now 24332 // without caching such that transient types are reflected. 24333 const links = getNodeLinks(node); 24334 return links.resolvedType || getTypeOfExpression(node); 24335 } 24336 24337 function getInitialTypeOfVariableDeclaration(node: VariableDeclaration) { 24338 if (node.initializer) { 24339 return getTypeOfInitializer(node.initializer); 24340 } 24341 if (node.parent.parent.kind === SyntaxKind.ForInStatement) { 24342 return stringType; 24343 } 24344 if (node.parent.parent.kind === SyntaxKind.ForOfStatement) { 24345 return checkRightHandSideOfForOf(node.parent.parent) || errorType; 24346 } 24347 return errorType; 24348 } 24349 24350 function getInitialType(node: VariableDeclaration | BindingElement) { 24351 return node.kind === SyntaxKind.VariableDeclaration ? 24352 getInitialTypeOfVariableDeclaration(node) : 24353 getInitialTypeOfBindingElement(node); 24354 } 24355 24356 function isEmptyArrayAssignment(node: VariableDeclaration | BindingElement | Expression) { 24357 return node.kind === SyntaxKind.VariableDeclaration && (node as VariableDeclaration).initializer && 24358 isEmptyArrayLiteral((node as VariableDeclaration).initializer!) || 24359 node.kind !== SyntaxKind.BindingElement && node.parent.kind === SyntaxKind.BinaryExpression && 24360 isEmptyArrayLiteral((node.parent as BinaryExpression).right); 24361 } 24362 24363 function getReferenceCandidate(node: Expression): Expression { 24364 switch (node.kind) { 24365 case SyntaxKind.ParenthesizedExpression: 24366 return getReferenceCandidate((node as ParenthesizedExpression).expression); 24367 case SyntaxKind.BinaryExpression: 24368 switch ((node as BinaryExpression).operatorToken.kind) { 24369 case SyntaxKind.EqualsToken: 24370 case SyntaxKind.BarBarEqualsToken: 24371 case SyntaxKind.AmpersandAmpersandEqualsToken: 24372 case SyntaxKind.QuestionQuestionEqualsToken: 24373 return getReferenceCandidate((node as BinaryExpression).left); 24374 case SyntaxKind.CommaToken: 24375 return getReferenceCandidate((node as BinaryExpression).right); 24376 } 24377 } 24378 return node; 24379 } 24380 24381 function getReferenceRoot(node: Node): Node { 24382 const { parent } = node; 24383 return parent.kind === SyntaxKind.ParenthesizedExpression || 24384 parent.kind === SyntaxKind.BinaryExpression && (parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken && (parent as BinaryExpression).left === node || 24385 parent.kind === SyntaxKind.BinaryExpression && (parent as BinaryExpression).operatorToken.kind === SyntaxKind.CommaToken && (parent as BinaryExpression).right === node ? 24386 getReferenceRoot(parent) : node; 24387 } 24388 24389 function getTypeOfSwitchClause(clause: CaseClause | DefaultClause) { 24390 if (clause.kind === SyntaxKind.CaseClause) { 24391 return getRegularTypeOfLiteralType(getTypeOfExpression(clause.expression)); 24392 } 24393 return neverType; 24394 } 24395 24396 function getSwitchClauseTypes(switchStatement: SwitchStatement): Type[] { 24397 const links = getNodeLinks(switchStatement); 24398 if (!links.switchTypes) { 24399 links.switchTypes = []; 24400 for (const clause of switchStatement.caseBlock.clauses) { 24401 links.switchTypes.push(getTypeOfSwitchClause(clause)); 24402 } 24403 } 24404 return links.switchTypes; 24405 } 24406 24407 // Get the type names from all cases in a switch on `typeof`. The default clause and/or duplicate type names are 24408 // represented as undefined. Return undefined if one or more case clause expressions are not string literals. 24409 function getSwitchClauseTypeOfWitnesses(switchStatement: SwitchStatement): (string | undefined)[] | undefined { 24410 if (some(switchStatement.caseBlock.clauses, clause => clause.kind === SyntaxKind.CaseClause && !isStringLiteralLike(clause.expression))) { 24411 return undefined; 24412 } 24413 const witnesses: (string | undefined)[] = []; 24414 for (const clause of switchStatement.caseBlock.clauses) { 24415 const text = clause.kind === SyntaxKind.CaseClause ? (clause.expression as StringLiteralLike).text : undefined; 24416 witnesses.push(text && !contains(witnesses, text) ? text : undefined); 24417 } 24418 return witnesses; 24419 } 24420 24421 function eachTypeContainedIn(source: Type, types: Type[]) { 24422 return source.flags & TypeFlags.Union ? !forEach((source as UnionType).types, t => !contains(types, t)) : contains(types, source); 24423 } 24424 24425 function isTypeSubsetOf(source: Type, target: Type) { 24426 return source === target || target.flags & TypeFlags.Union && isTypeSubsetOfUnion(source, target as UnionType); 24427 } 24428 24429 function isTypeSubsetOfUnion(source: Type, target: UnionType) { 24430 if (source.flags & TypeFlags.Union) { 24431 for (const t of (source as UnionType).types) { 24432 if (!containsType(target.types, t)) { 24433 return false; 24434 } 24435 } 24436 return true; 24437 } 24438 if (source.flags & TypeFlags.EnumLiteral && getBaseTypeOfEnumLiteralType(source as LiteralType) === target) { 24439 return true; 24440 } 24441 return containsType(target.types, source); 24442 } 24443 24444 function forEachType<T>(type: Type, f: (t: Type) => T | undefined): T | undefined { 24445 return type.flags & TypeFlags.Union ? forEach((type as UnionType).types, f) : f(type); 24446 } 24447 24448 function someType(type: Type, f: (t: Type) => boolean): boolean { 24449 return type.flags & TypeFlags.Union ? some((type as UnionType).types, f) : f(type); 24450 } 24451 24452 function everyType(type: Type, f: (t: Type) => boolean): boolean { 24453 return type.flags & TypeFlags.Union ? every((type as UnionType).types, f) : f(type); 24454 } 24455 24456 function everyContainedType(type: Type, f: (t: Type) => boolean): boolean { 24457 return type.flags & TypeFlags.UnionOrIntersection ? every((type as UnionOrIntersectionType).types, f) : f(type); 24458 } 24459 24460 function filterType(type: Type, f: (t: Type) => boolean): Type { 24461 if (type.flags & TypeFlags.Union) { 24462 const types = (type as UnionType).types; 24463 const filtered = filter(types, f); 24464 if (filtered === types) { 24465 return type; 24466 } 24467 const origin = (type as UnionType).origin; 24468 let newOrigin: Type | undefined; 24469 if (origin && origin.flags & TypeFlags.Union) { 24470 // If the origin type is a (denormalized) union type, filter its non-union constituents. If that ends 24471 // up removing a smaller number of types than in the normalized constituent set (meaning some of the 24472 // filtered types are within nested unions in the origin), then we can't construct a new origin type. 24473 // Otherwise, if we have exactly one type left in the origin set, return that as the filtered type. 24474 // Otherwise, construct a new filtered origin type. 24475 const originTypes = (origin as UnionType).types; 24476 const originFiltered = filter(originTypes, t => !!(t.flags & TypeFlags.Union) || f(t)); 24477 if (originTypes.length - originFiltered.length === types.length - filtered.length) { 24478 if (originFiltered.length === 1) { 24479 return originFiltered[0]; 24480 } 24481 newOrigin = createOriginUnionOrIntersectionType(TypeFlags.Union, originFiltered); 24482 } 24483 } 24484 return getUnionTypeFromSortedList(filtered, (type as UnionType).objectFlags, /*aliasSymbol*/ undefined, /*aliasTypeArguments*/ undefined, newOrigin); 24485 } 24486 return type.flags & TypeFlags.Never || f(type) ? type : neverType; 24487 } 24488 24489 function removeType(type: Type, targetType: Type) { 24490 return filterType(type, t => t !== targetType); 24491 } 24492 24493 function countTypes(type: Type) { 24494 return type.flags & TypeFlags.Union ? (type as UnionType).types.length : 1; 24495 } 24496 24497 // Apply a mapping function to a type and return the resulting type. If the source type 24498 // is a union type, the mapping function is applied to each constituent type and a union 24499 // of the resulting types is returned. 24500 function mapType(type: Type, mapper: (t: Type) => Type, noReductions?: boolean): Type; 24501 function mapType(type: Type, mapper: (t: Type) => Type | undefined, noReductions?: boolean): Type | undefined; 24502 function mapType(type: Type, mapper: (t: Type) => Type | undefined, noReductions?: boolean): Type | undefined { 24503 if (type.flags & TypeFlags.Never) { 24504 return type; 24505 } 24506 if (!(type.flags & TypeFlags.Union)) { 24507 return mapper(type); 24508 } 24509 const origin = (type as UnionType).origin; 24510 const types = origin && origin.flags & TypeFlags.Union ? (origin as UnionType).types : (type as UnionType).types; 24511 let mappedTypes: Type[] | undefined; 24512 let changed = false; 24513 for (const t of types) { 24514 const mapped = t.flags & TypeFlags.Union ? mapType(t, mapper, noReductions) : mapper(t); 24515 changed ||= t !== mapped; 24516 if (mapped) { 24517 if (!mappedTypes) { 24518 mappedTypes = [mapped]; 24519 } 24520 else { 24521 mappedTypes.push(mapped); 24522 } 24523 } 24524 } 24525 return changed ? mappedTypes && getUnionType(mappedTypes, noReductions ? UnionReduction.None : UnionReduction.Literal) : type; 24526 } 24527 24528 function mapTypeWithAlias(type: Type, mapper: (t: Type) => Type, aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined) { 24529 return type.flags & TypeFlags.Union && aliasSymbol ? 24530 getUnionType(map((type as UnionType).types, mapper), UnionReduction.Literal, aliasSymbol, aliasTypeArguments) : 24531 mapType(type, mapper); 24532 } 24533 24534 function extractTypesOfKind(type: Type, kind: TypeFlags) { 24535 return filterType(type, t => (t.flags & kind) !== 0); 24536 } 24537 24538 // Return a new type in which occurrences of the string, number and bigint primitives and placeholder template 24539 // literal types in typeWithPrimitives have been replaced with occurrences of compatible and more specific types 24540 // from typeWithLiterals. This is essentially a limited form of intersection between the two types. We avoid a 24541 // true intersection because it is more costly and, when applied to union types, generates a large number of 24542 // types we don't actually care about. 24543 function replacePrimitivesWithLiterals(typeWithPrimitives: Type, typeWithLiterals: Type) { 24544 if (maybeTypeOfKind(typeWithPrimitives, TypeFlags.String | TypeFlags.TemplateLiteral | TypeFlags.Number | TypeFlags.BigInt) && 24545 maybeTypeOfKind(typeWithLiterals, TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping | TypeFlags.NumberLiteral | TypeFlags.BigIntLiteral)) { 24546 return mapType(typeWithPrimitives, t => 24547 t.flags & TypeFlags.String ? extractTypesOfKind(typeWithLiterals, TypeFlags.String | TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) : 24548 isPatternLiteralType(t) && !maybeTypeOfKind(typeWithLiterals, TypeFlags.String | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) ? extractTypesOfKind(typeWithLiterals, TypeFlags.StringLiteral) : 24549 t.flags & TypeFlags.Number ? extractTypesOfKind(typeWithLiterals, TypeFlags.Number | TypeFlags.NumberLiteral) : 24550 t.flags & TypeFlags.BigInt ? extractTypesOfKind(typeWithLiterals, TypeFlags.BigInt | TypeFlags.BigIntLiteral) : t); 24551 } 24552 return typeWithPrimitives; 24553 } 24554 24555 function isIncomplete(flowType: FlowType) { 24556 return flowType.flags === 0; 24557 } 24558 24559 function getTypeFromFlowType(flowType: FlowType) { 24560 return flowType.flags === 0 ? (flowType as IncompleteType).type : flowType as Type; 24561 } 24562 24563 function createFlowType(type: Type, incomplete: boolean): FlowType { 24564 return incomplete ? { flags: 0, type: type.flags & TypeFlags.Never ? silentNeverType : type } : type; 24565 } 24566 24567 // An evolving array type tracks the element types that have so far been seen in an 24568 // 'x.push(value)' or 'x[n] = value' operation along the control flow graph. Evolving 24569 // array types are ultimately converted into manifest array types (using getFinalArrayType) 24570 // and never escape the getFlowTypeOfReference function. 24571 function createEvolvingArrayType(elementType: Type): EvolvingArrayType { 24572 const result = createObjectType(ObjectFlags.EvolvingArray) as EvolvingArrayType; 24573 result.elementType = elementType; 24574 return result; 24575 } 24576 24577 function getEvolvingArrayType(elementType: Type): EvolvingArrayType { 24578 return evolvingArrayTypes[elementType.id] || (evolvingArrayTypes[elementType.id] = createEvolvingArrayType(elementType)); 24579 } 24580 24581 // When adding evolving array element types we do not perform subtype reduction. Instead, 24582 // we defer subtype reduction until the evolving array type is finalized into a manifest 24583 // array type. 24584 function addEvolvingArrayElementType(evolvingArrayType: EvolvingArrayType, node: Expression): EvolvingArrayType { 24585 const elementType = getRegularTypeOfObjectLiteral(getBaseTypeOfLiteralType(getContextFreeTypeOfExpression(node))); 24586 return isTypeSubsetOf(elementType, evolvingArrayType.elementType) ? evolvingArrayType : getEvolvingArrayType(getUnionType([evolvingArrayType.elementType, elementType])); 24587 } 24588 24589 function createFinalArrayType(elementType: Type) { 24590 return elementType.flags & TypeFlags.Never ? 24591 autoArrayType : 24592 createArrayType(elementType.flags & TypeFlags.Union ? 24593 getUnionType((elementType as UnionType).types, UnionReduction.Subtype) : 24594 elementType); 24595 } 24596 24597 // We perform subtype reduction upon obtaining the final array type from an evolving array type. 24598 function getFinalArrayType(evolvingArrayType: EvolvingArrayType): Type { 24599 return evolvingArrayType.finalArrayType || (evolvingArrayType.finalArrayType = createFinalArrayType(evolvingArrayType.elementType)); 24600 } 24601 24602 function finalizeEvolvingArrayType(type: Type): Type { 24603 return getObjectFlags(type) & ObjectFlags.EvolvingArray ? getFinalArrayType(type as EvolvingArrayType) : type; 24604 } 24605 24606 function getElementTypeOfEvolvingArrayType(type: Type) { 24607 return getObjectFlags(type) & ObjectFlags.EvolvingArray ? (type as EvolvingArrayType).elementType : neverType; 24608 } 24609 24610 function isEvolvingArrayTypeList(types: Type[]) { 24611 let hasEvolvingArrayType = false; 24612 for (const t of types) { 24613 if (!(t.flags & TypeFlags.Never)) { 24614 if (!(getObjectFlags(t) & ObjectFlags.EvolvingArray)) { 24615 return false; 24616 } 24617 hasEvolvingArrayType = true; 24618 } 24619 } 24620 return hasEvolvingArrayType; 24621 } 24622 24623 // Return true if the given node is 'x' in an 'x.length', x.push(value)', 'x.unshift(value)' or 24624 // 'x[n] = value' operation, where 'n' is an expression of type any, undefined, or a number-like type. 24625 function isEvolvingArrayOperationTarget(node: Node) { 24626 const root = getReferenceRoot(node); 24627 const parent = root.parent; 24628 const isLengthPushOrUnshift = isPropertyAccessExpression(parent) && ( 24629 parent.name.escapedText === "length" || 24630 parent.parent.kind === SyntaxKind.CallExpression 24631 && isIdentifier(parent.name) 24632 && isPushOrUnshiftIdentifier(parent.name)); 24633 const isElementAssignment = parent.kind === SyntaxKind.ElementAccessExpression && 24634 (parent as ElementAccessExpression).expression === root && 24635 parent.parent.kind === SyntaxKind.BinaryExpression && 24636 (parent.parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken && 24637 (parent.parent as BinaryExpression).left === parent && 24638 !isAssignmentTarget(parent.parent) && 24639 isTypeAssignableToKind(getTypeOfExpression((parent as ElementAccessExpression).argumentExpression), TypeFlags.NumberLike); 24640 return isLengthPushOrUnshift || isElementAssignment; 24641 } 24642 24643 function isDeclarationWithExplicitTypeAnnotation(node: Declaration) { 24644 return (isVariableDeclaration(node) || isPropertyDeclaration(node) || isPropertySignature(node) || isParameter(node)) && 24645 !!(getEffectiveTypeAnnotationNode(node) || 24646 isInJSFile(node) && hasInitializer(node) && node.initializer && isFunctionExpressionOrArrowFunction(node.initializer) && getEffectiveReturnTypeNode(node.initializer)); 24647 } 24648 24649 function getExplicitTypeOfSymbol(symbol: Symbol, diagnostic?: Diagnostic) { 24650 symbol = resolveSymbol(symbol); 24651 if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.ValueModule)) { 24652 return getTypeOfSymbol(symbol); 24653 } 24654 if (symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property)) { 24655 if (getCheckFlags(symbol) & CheckFlags.Mapped) { 24656 const origin = (symbol as MappedSymbol).syntheticOrigin; 24657 if (origin && getExplicitTypeOfSymbol(origin)) { 24658 return getTypeOfSymbol(symbol); 24659 } 24660 } 24661 const declaration = symbol.valueDeclaration; 24662 if (declaration) { 24663 if (isDeclarationWithExplicitTypeAnnotation(declaration)) { 24664 return getTypeOfSymbol(symbol); 24665 } 24666 if (isVariableDeclaration(declaration) && declaration.parent.parent.kind === SyntaxKind.ForOfStatement) { 24667 const statement = declaration.parent.parent; 24668 const expressionType = getTypeOfDottedName(statement.expression, /*diagnostic*/ undefined); 24669 if (expressionType) { 24670 const use = statement.awaitModifier ? IterationUse.ForAwaitOf : IterationUse.ForOf; 24671 return checkIteratedTypeOrElementType(use, expressionType, undefinedType, /*errorNode*/ undefined); 24672 } 24673 } 24674 if (diagnostic) { 24675 addRelatedInfo(diagnostic, createDiagnosticForNode(declaration, Diagnostics._0_needs_an_explicit_type_annotation, symbolToString(symbol))); 24676 } 24677 } 24678 } 24679 } 24680 24681 // We require the dotted function name in an assertion expression to be comprised of identifiers 24682 // that reference function, method, class or value module symbols; or variable, property or 24683 // parameter symbols with declarations that have explicit type annotations. Such references are 24684 // resolvable with no possibility of triggering circularities in control flow analysis. 24685 function getTypeOfDottedName(node: Expression, diagnostic: Diagnostic | undefined): Type | undefined { 24686 if (!(node.flags & NodeFlags.InWithStatement)) { 24687 switch (node.kind) { 24688 case SyntaxKind.Identifier: 24689 const symbol = getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(node as Identifier)); 24690 return getExplicitTypeOfSymbol(symbol, diagnostic); 24691 case SyntaxKind.ThisKeyword: 24692 return getExplicitThisType(node); 24693 case SyntaxKind.SuperKeyword: 24694 return checkSuperExpression(node); 24695 case SyntaxKind.PropertyAccessExpression: { 24696 const type = getTypeOfDottedName((node as PropertyAccessExpression).expression, diagnostic); 24697 if (type) { 24698 const name = (node as PropertyAccessExpression).name; 24699 let prop: Symbol | undefined; 24700 if (isPrivateIdentifier(name)) { 24701 if (!type.symbol) { 24702 return undefined; 24703 } 24704 prop = getPropertyOfType(type, getSymbolNameForPrivateIdentifier(type.symbol, name.escapedText)); 24705 } 24706 else { 24707 prop = getPropertyOfType(type, name.escapedText); 24708 } 24709 return prop && getExplicitTypeOfSymbol(prop, diagnostic); 24710 } 24711 return undefined; 24712 } 24713 case SyntaxKind.ParenthesizedExpression: 24714 return getTypeOfDottedName((node as ParenthesizedExpression).expression, diagnostic); 24715 } 24716 } 24717 } 24718 24719 function getEffectsSignature(node: CallExpression) { 24720 const links = getNodeLinks(node); 24721 let signature = links.effectsSignature; 24722 if (signature === undefined) { 24723 // A call expression parented by an expression statement is a potential assertion. Other call 24724 // expressions are potential type predicate function calls. In order to avoid triggering 24725 // circularities in control flow analysis, we use getTypeOfDottedName when resolving the call 24726 // target expression of an assertion. 24727 let funcType: Type | undefined; 24728 if (node.parent.kind === SyntaxKind.ExpressionStatement) { 24729 funcType = getTypeOfDottedName(node.expression, /*diagnostic*/ undefined); 24730 } 24731 else if (node.expression.kind !== SyntaxKind.SuperKeyword) { 24732 if (isOptionalChain(node)) { 24733 funcType = checkNonNullType( 24734 getOptionalExpressionType(checkExpression(node.expression), node.expression), 24735 node.expression 24736 ); 24737 } 24738 else { 24739 funcType = checkNonNullExpression(node.expression); 24740 } 24741 } 24742 const signatures = getSignaturesOfType(funcType && getApparentType(funcType) || unknownType, SignatureKind.Call); 24743 const candidate = signatures.length === 1 && !signatures[0].typeParameters ? signatures[0] : 24744 some(signatures, hasTypePredicateOrNeverReturnType) ? getResolvedSignature(node) : 24745 undefined; 24746 signature = links.effectsSignature = candidate && hasTypePredicateOrNeverReturnType(candidate) ? candidate : unknownSignature; 24747 } 24748 return signature === unknownSignature ? undefined : signature; 24749 } 24750 24751 function hasTypePredicateOrNeverReturnType(signature: Signature) { 24752 return !!(getTypePredicateOfSignature(signature) || 24753 signature.declaration && (getReturnTypeFromAnnotation(signature.declaration) || unknownType).flags & TypeFlags.Never); 24754 } 24755 24756 function getTypePredicateArgument(predicate: TypePredicate, callExpression: CallExpression) { 24757 if (predicate.kind === TypePredicateKind.Identifier || predicate.kind === TypePredicateKind.AssertsIdentifier) { 24758 return callExpression.arguments[predicate.parameterIndex]; 24759 } 24760 const invokedExpression = skipParentheses(callExpression.expression); 24761 return isAccessExpression(invokedExpression) ? skipParentheses(invokedExpression.expression) : undefined; 24762 } 24763 24764 function reportFlowControlError(node: Node) { 24765 const block = findAncestor(node, isFunctionOrModuleBlock) as Block | ModuleBlock | SourceFile; 24766 const sourceFile = getSourceFileOfNode(node); 24767 const span = getSpanOfTokenAtPosition(sourceFile, block.statements.pos); 24768 diagnostics.add(createFileDiagnostic(sourceFile, span.start, span.length, Diagnostics.The_containing_function_or_module_body_is_too_large_for_control_flow_analysis)); 24769 } 24770 24771 function isReachableFlowNode(flow: FlowNode) { 24772 const result = isReachableFlowNodeWorker(flow, /*noCacheCheck*/ false); 24773 lastFlowNode = flow; 24774 lastFlowNodeReachable = result; 24775 return result; 24776 } 24777 24778 function isFalseExpression(expr: Expression): boolean { 24779 const node = skipParentheses(expr, /*excludeJSDocTypeAssertions*/ true); 24780 return node.kind === SyntaxKind.FalseKeyword || node.kind === SyntaxKind.BinaryExpression && ( 24781 (node as BinaryExpression).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken && (isFalseExpression((node as BinaryExpression).left) || isFalseExpression((node as BinaryExpression).right)) || 24782 (node as BinaryExpression).operatorToken.kind === SyntaxKind.BarBarToken && isFalseExpression((node as BinaryExpression).left) && isFalseExpression((node as BinaryExpression).right)); 24783 } 24784 24785 function isReachableFlowNodeWorker(flow: FlowNode, noCacheCheck: boolean): boolean { 24786 while (true) { 24787 if (flow === lastFlowNode) { 24788 return lastFlowNodeReachable; 24789 } 24790 const flags = flow.flags; 24791 if (flags & FlowFlags.Shared) { 24792 if (!noCacheCheck) { 24793 const id = getFlowNodeId(flow); 24794 const reachable = flowNodeReachable[id]; 24795 return reachable !== undefined ? reachable : (flowNodeReachable[id] = isReachableFlowNodeWorker(flow, /*noCacheCheck*/ true)); 24796 } 24797 noCacheCheck = false; 24798 } 24799 if (flags & (FlowFlags.Assignment | FlowFlags.Condition | FlowFlags.ArrayMutation)) { 24800 flow = (flow as FlowAssignment | FlowCondition | FlowArrayMutation).antecedent; 24801 } 24802 else if (flags & FlowFlags.Call) { 24803 const signature = getEffectsSignature((flow as FlowCall).node); 24804 if (signature) { 24805 const predicate = getTypePredicateOfSignature(signature); 24806 if (predicate && predicate.kind === TypePredicateKind.AssertsIdentifier && !predicate.type) { 24807 const predicateArgument = (flow as FlowCall).node.arguments[predicate.parameterIndex]; 24808 if (predicateArgument && isFalseExpression(predicateArgument)) { 24809 return false; 24810 } 24811 } 24812 if (getReturnTypeOfSignature(signature).flags & TypeFlags.Never) { 24813 return false; 24814 } 24815 } 24816 flow = (flow as FlowCall).antecedent; 24817 } 24818 else if (flags & FlowFlags.BranchLabel) { 24819 // A branching point is reachable if any branch is reachable. 24820 return some((flow as FlowLabel).antecedents, f => isReachableFlowNodeWorker(f, /*noCacheCheck*/ false)); 24821 } 24822 else if (flags & FlowFlags.LoopLabel) { 24823 const antecedents = (flow as FlowLabel).antecedents; 24824 if (antecedents === undefined || antecedents.length === 0) { 24825 return false; 24826 } 24827 // A loop is reachable if the control flow path that leads to the top is reachable. 24828 flow = antecedents[0]; 24829 } 24830 else if (flags & FlowFlags.SwitchClause) { 24831 // The control flow path representing an unmatched value in a switch statement with 24832 // no default clause is unreachable if the switch statement is exhaustive. 24833 if ((flow as FlowSwitchClause).clauseStart === (flow as FlowSwitchClause).clauseEnd && isExhaustiveSwitchStatement((flow as FlowSwitchClause).switchStatement)) { 24834 return false; 24835 } 24836 flow = (flow as FlowSwitchClause).antecedent; 24837 } 24838 else if (flags & FlowFlags.ReduceLabel) { 24839 // Cache is unreliable once we start adjusting labels 24840 lastFlowNode = undefined; 24841 const target = (flow as FlowReduceLabel).target; 24842 const saveAntecedents = target.antecedents; 24843 target.antecedents = (flow as FlowReduceLabel).antecedents; 24844 const result = isReachableFlowNodeWorker((flow as FlowReduceLabel).antecedent, /*noCacheCheck*/ false); 24845 target.antecedents = saveAntecedents; 24846 return result; 24847 } 24848 else { 24849 return !(flags & FlowFlags.Unreachable); 24850 } 24851 } 24852 } 24853 24854 // Return true if the given flow node is preceded by a 'super(...)' call in every possible code path 24855 // leading to the node. 24856 function isPostSuperFlowNode(flow: FlowNode, noCacheCheck: boolean): boolean { 24857 while (true) { 24858 const flags = flow.flags; 24859 if (flags & FlowFlags.Shared) { 24860 if (!noCacheCheck) { 24861 const id = getFlowNodeId(flow); 24862 const postSuper = flowNodePostSuper[id]; 24863 return postSuper !== undefined ? postSuper : (flowNodePostSuper[id] = isPostSuperFlowNode(flow, /*noCacheCheck*/ true)); 24864 } 24865 noCacheCheck = false; 24866 } 24867 if (flags & (FlowFlags.Assignment | FlowFlags.Condition | FlowFlags.ArrayMutation | FlowFlags.SwitchClause)) { 24868 flow = (flow as FlowAssignment | FlowCondition | FlowArrayMutation | FlowSwitchClause).antecedent; 24869 } 24870 else if (flags & FlowFlags.Call) { 24871 if ((flow as FlowCall).node.expression.kind === SyntaxKind.SuperKeyword) { 24872 return true; 24873 } 24874 flow = (flow as FlowCall).antecedent; 24875 } 24876 else if (flags & FlowFlags.BranchLabel) { 24877 // A branching point is post-super if every branch is post-super. 24878 return every((flow as FlowLabel).antecedents, f => isPostSuperFlowNode(f, /*noCacheCheck*/ false)); 24879 } 24880 else if (flags & FlowFlags.LoopLabel) { 24881 // A loop is post-super if the control flow path that leads to the top is post-super. 24882 flow = (flow as FlowLabel).antecedents![0]; 24883 } 24884 else if (flags & FlowFlags.ReduceLabel) { 24885 const target = (flow as FlowReduceLabel).target; 24886 const saveAntecedents = target.antecedents; 24887 target.antecedents = (flow as FlowReduceLabel).antecedents; 24888 const result = isPostSuperFlowNode((flow as FlowReduceLabel).antecedent, /*noCacheCheck*/ false); 24889 target.antecedents = saveAntecedents; 24890 return result; 24891 } 24892 else { 24893 // Unreachable nodes are considered post-super to silence errors 24894 return !!(flags & FlowFlags.Unreachable); 24895 } 24896 } 24897 } 24898 24899 function isConstantReference(node: Node): boolean { 24900 switch (node.kind) { 24901 case SyntaxKind.Identifier: { 24902 const symbol = getResolvedSymbol(node as Identifier); 24903 return isConstVariable(symbol) || isParameterOrCatchClauseVariable(symbol) && !isSymbolAssigned(symbol); 24904 } 24905 case SyntaxKind.PropertyAccessExpression: 24906 case SyntaxKind.ElementAccessExpression: 24907 // The resolvedSymbol property is initialized by checkPropertyAccess or checkElementAccess before we get here. 24908 return isConstantReference((node as AccessExpression).expression) && isReadonlySymbol(getNodeLinks(node).resolvedSymbol || unknownSymbol); 24909 } 24910 return false; 24911 } 24912 24913 function getFlowTypeOfReference(reference: Node, declaredType: Type, initialType = declaredType, flowContainer?: Node, flowNode = reference.flowNode) { 24914 let key: string | undefined; 24915 let isKeySet = false; 24916 let flowDepth = 0; 24917 if (flowAnalysisDisabled) { 24918 return errorType; 24919 } 24920 if (!flowNode) { 24921 return declaredType; 24922 } 24923 flowInvocationCount++; 24924 const sharedFlowStart = sharedFlowCount; 24925 const evolvedType = getTypeFromFlowType(getTypeAtFlowNode(flowNode)); 24926 sharedFlowCount = sharedFlowStart; 24927 // When the reference is 'x' in an 'x.length', 'x.push(value)', 'x.unshift(value)' or x[n] = value' operation, 24928 // we give type 'any[]' to 'x' instead of using the type determined by control flow analysis such that operations 24929 // on empty arrays are possible without implicit any errors and new element types can be inferred without 24930 // type mismatch errors. 24931 const resultType = getObjectFlags(evolvedType) & ObjectFlags.EvolvingArray && isEvolvingArrayOperationTarget(reference) ? autoArrayType : finalizeEvolvingArrayType(evolvedType); 24932 if (resultType === unreachableNeverType || reference.parent && reference.parent.kind === SyntaxKind.NonNullExpression && !(resultType.flags & TypeFlags.Never) && getTypeWithFacts(resultType, TypeFacts.NEUndefinedOrNull).flags & TypeFlags.Never) { 24933 return declaredType; 24934 } 24935 // The non-null unknown type should never escape control flow analysis. 24936 return resultType === nonNullUnknownType ? unknownType : resultType; 24937 24938 function getOrSetCacheKey() { 24939 if (isKeySet) { 24940 return key; 24941 } 24942 isKeySet = true; 24943 return key = getFlowCacheKey(reference, declaredType, initialType, flowContainer); 24944 } 24945 24946 function getTypeAtFlowNode(flow: FlowNode): FlowType { 24947 if (flowDepth === getMaxFlowDepth(compilerOptions)) { 24948 // We have made the number of recursive invocations by user configuring, or default value 2000. 24949 // To avoid overflowing the call stack we report an error 24950 // and disable further control flow analysis in the containing function or module body. 24951 tracing?.instant(tracing.Phase.CheckTypes, "getTypeAtFlowNode_DepthLimit", { flowId: flow.id }); 24952 flowAnalysisDisabled = true; 24953 reportFlowControlError(reference); 24954 return errorType; 24955 } 24956 flowDepth++; 24957 let sharedFlow: FlowNode | undefined; 24958 while (true) { 24959 const flags = flow.flags; 24960 if (flags & FlowFlags.Shared) { 24961 // We cache results of flow type resolution for shared nodes that were previously visited in 24962 // the same getFlowTypeOfReference invocation. A node is considered shared when it is the 24963 // antecedent of more than one node. 24964 for (let i = sharedFlowStart; i < sharedFlowCount; i++) { 24965 if (sharedFlowNodes[i] === flow) { 24966 flowDepth--; 24967 return sharedFlowTypes[i]; 24968 } 24969 } 24970 sharedFlow = flow; 24971 } 24972 let type: FlowType | undefined; 24973 if (flags & FlowFlags.Assignment) { 24974 type = getTypeAtFlowAssignment(flow as FlowAssignment); 24975 if (!type) { 24976 flow = (flow as FlowAssignment).antecedent; 24977 continue; 24978 } 24979 } 24980 else if (flags & FlowFlags.Call) { 24981 type = getTypeAtFlowCall(flow as FlowCall); 24982 if (!type) { 24983 flow = (flow as FlowCall).antecedent; 24984 continue; 24985 } 24986 } 24987 else if (flags & FlowFlags.Condition) { 24988 type = getTypeAtFlowCondition(flow as FlowCondition); 24989 } 24990 else if (flags & FlowFlags.SwitchClause) { 24991 type = getTypeAtSwitchClause(flow as FlowSwitchClause); 24992 } 24993 else if (flags & FlowFlags.Label) { 24994 if ((flow as FlowLabel).antecedents!.length === 1) { 24995 flow = (flow as FlowLabel).antecedents![0]; 24996 continue; 24997 } 24998 type = flags & FlowFlags.BranchLabel ? 24999 getTypeAtFlowBranchLabel(flow as FlowLabel) : 25000 getTypeAtFlowLoopLabel(flow as FlowLabel); 25001 } 25002 else if (flags & FlowFlags.ArrayMutation) { 25003 type = getTypeAtFlowArrayMutation(flow as FlowArrayMutation); 25004 if (!type) { 25005 flow = (flow as FlowArrayMutation).antecedent; 25006 continue; 25007 } 25008 } 25009 else if (flags & FlowFlags.ReduceLabel) { 25010 const target = (flow as FlowReduceLabel).target; 25011 const saveAntecedents = target.antecedents; 25012 target.antecedents = (flow as FlowReduceLabel).antecedents; 25013 type = getTypeAtFlowNode((flow as FlowReduceLabel).antecedent); 25014 target.antecedents = saveAntecedents; 25015 } 25016 else if (flags & FlowFlags.Start) { 25017 // Check if we should continue with the control flow of the containing function. 25018 const container = (flow as FlowStart).node; 25019 if (container && container !== flowContainer && 25020 reference.kind !== SyntaxKind.PropertyAccessExpression && 25021 reference.kind !== SyntaxKind.ElementAccessExpression && 25022 reference.kind !== SyntaxKind.ThisKeyword) { 25023 flow = container.flowNode!; 25024 continue; 25025 } 25026 // At the top of the flow we have the initial type. 25027 type = initialType; 25028 } 25029 else { 25030 // Unreachable code errors are reported in the binding phase. Here we 25031 // simply return the non-auto declared type to reduce follow-on errors. 25032 type = convertAutoToAny(declaredType); 25033 } 25034 if (sharedFlow) { 25035 // Record visited node and the associated type in the cache. 25036 sharedFlowNodes[sharedFlowCount] = sharedFlow; 25037 sharedFlowTypes[sharedFlowCount] = type; 25038 sharedFlowCount++; 25039 } 25040 flowDepth--; 25041 return type; 25042 } 25043 } 25044 25045 function getInitialOrAssignedType(flow: FlowAssignment) { 25046 const node = flow.node; 25047 return getNarrowableTypeForReference(node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement ? 25048 getInitialType(node as VariableDeclaration | BindingElement) : 25049 getAssignedType(node), reference); 25050 } 25051 25052 function getTypeAtFlowAssignment(flow: FlowAssignment) { 25053 const node = flow.node; 25054 // Assignments only narrow the computed type if the declared type is a union type. Thus, we 25055 // only need to evaluate the assigned type if the declared type is a union type. 25056 if (isMatchingReference(reference, node)) { 25057 if (!isReachableFlowNode(flow)) { 25058 return unreachableNeverType; 25059 } 25060 if (getAssignmentTargetKind(node) === AssignmentKind.Compound) { 25061 const flowType = getTypeAtFlowNode(flow.antecedent); 25062 return createFlowType(getBaseTypeOfLiteralType(getTypeFromFlowType(flowType)), isIncomplete(flowType)); 25063 } 25064 if (declaredType === autoType || declaredType === autoArrayType) { 25065 if (isEmptyArrayAssignment(node)) { 25066 return getEvolvingArrayType(neverType); 25067 } 25068 const assignedType = getWidenedLiteralType(getInitialOrAssignedType(flow)); 25069 return isTypeAssignableTo(assignedType, declaredType) ? assignedType : anyArrayType; 25070 } 25071 if (declaredType.flags & TypeFlags.Union) { 25072 return getAssignmentReducedType(declaredType as UnionType, getInitialOrAssignedType(flow)); 25073 } 25074 return declaredType; 25075 } 25076 // We didn't have a direct match. However, if the reference is a dotted name, this 25077 // may be an assignment to a left hand part of the reference. For example, for a 25078 // reference 'x.y.z', we may be at an assignment to 'x.y' or 'x'. In that case, 25079 // return the declared type. 25080 if (containsMatchingReference(reference, node)) { 25081 if (!isReachableFlowNode(flow)) { 25082 return unreachableNeverType; 25083 } 25084 // A matching dotted name might also be an expando property on a function *expression*, 25085 // in which case we continue control flow analysis back to the function's declaration 25086 if (isVariableDeclaration(node) && (isInJSFile(node) || isVarConst(node))) { 25087 const init = getDeclaredExpandoInitializer(node); 25088 if (init && (init.kind === SyntaxKind.FunctionExpression || init.kind === SyntaxKind.ArrowFunction)) { 25089 return getTypeAtFlowNode(flow.antecedent); 25090 } 25091 } 25092 return declaredType; 25093 } 25094 // for (const _ in ref) acts as a nonnull on ref 25095 if (isVariableDeclaration(node) && node.parent.parent.kind === SyntaxKind.ForInStatement && isMatchingReference(reference, node.parent.parent.expression)) { 25096 return getNonNullableTypeIfNeeded(finalizeEvolvingArrayType(getTypeFromFlowType(getTypeAtFlowNode(flow.antecedent)))); 25097 } 25098 // Assignment doesn't affect reference 25099 return undefined; 25100 } 25101 25102 function narrowTypeByAssertion(type: Type, expr: Expression): Type { 25103 const node = skipParentheses(expr, /*excludeJSDocTypeAssertions*/ true); 25104 if (node.kind === SyntaxKind.FalseKeyword) { 25105 return unreachableNeverType; 25106 } 25107 if (node.kind === SyntaxKind.BinaryExpression) { 25108 if ((node as BinaryExpression).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) { 25109 return narrowTypeByAssertion(narrowTypeByAssertion(type, (node as BinaryExpression).left), (node as BinaryExpression).right); 25110 } 25111 if ((node as BinaryExpression).operatorToken.kind === SyntaxKind.BarBarToken) { 25112 return getUnionType([narrowTypeByAssertion(type, (node as BinaryExpression).left), narrowTypeByAssertion(type, (node as BinaryExpression).right)]); 25113 } 25114 } 25115 return narrowType(type, node, /*assumeTrue*/ true); 25116 } 25117 25118 function getTypeAtFlowCall(flow: FlowCall): FlowType | undefined { 25119 const signature = getEffectsSignature(flow.node); 25120 if (signature) { 25121 const predicate = getTypePredicateOfSignature(signature); 25122 if (predicate && (predicate.kind === TypePredicateKind.AssertsThis || predicate.kind === TypePredicateKind.AssertsIdentifier)) { 25123 const flowType = getTypeAtFlowNode(flow.antecedent); 25124 const type = finalizeEvolvingArrayType(getTypeFromFlowType(flowType)); 25125 const narrowedType = predicate.type ? narrowTypeByTypePredicate(type, predicate, flow.node, /*assumeTrue*/ true) : 25126 predicate.kind === TypePredicateKind.AssertsIdentifier && predicate.parameterIndex >= 0 && predicate.parameterIndex < flow.node.arguments.length ? narrowTypeByAssertion(type, flow.node.arguments[predicate.parameterIndex]) : 25127 type; 25128 return narrowedType === type ? flowType : createFlowType(narrowedType, isIncomplete(flowType)); 25129 } 25130 if (getReturnTypeOfSignature(signature).flags & TypeFlags.Never) { 25131 return unreachableNeverType; 25132 } 25133 } 25134 return undefined; 25135 } 25136 25137 function getTypeAtFlowArrayMutation(flow: FlowArrayMutation): FlowType | undefined { 25138 if (declaredType === autoType || declaredType === autoArrayType) { 25139 const node = flow.node; 25140 const expr = node.kind === SyntaxKind.CallExpression ? 25141 (node.expression as PropertyAccessExpression).expression : 25142 (node.left as ElementAccessExpression).expression; 25143 if (isMatchingReference(reference, getReferenceCandidate(expr))) { 25144 const flowType = getTypeAtFlowNode(flow.antecedent); 25145 const type = getTypeFromFlowType(flowType); 25146 if (getObjectFlags(type) & ObjectFlags.EvolvingArray) { 25147 let evolvedType = type as EvolvingArrayType; 25148 if (node.kind === SyntaxKind.CallExpression) { 25149 for (const arg of node.arguments) { 25150 evolvedType = addEvolvingArrayElementType(evolvedType, arg); 25151 } 25152 } 25153 else { 25154 // We must get the context free expression type so as to not recur in an uncached fashion on the LHS (which causes exponential blowup in compile time) 25155 const indexType = getContextFreeTypeOfExpression((node.left as ElementAccessExpression).argumentExpression); 25156 if (isTypeAssignableToKind(indexType, TypeFlags.NumberLike)) { 25157 evolvedType = addEvolvingArrayElementType(evolvedType, node.right); 25158 } 25159 } 25160 return evolvedType === type ? flowType : createFlowType(evolvedType, isIncomplete(flowType)); 25161 } 25162 return flowType; 25163 } 25164 } 25165 return undefined; 25166 } 25167 25168 function getTypeAtFlowCondition(flow: FlowCondition): FlowType { 25169 const flowType = getTypeAtFlowNode(flow.antecedent); 25170 const type = getTypeFromFlowType(flowType); 25171 if (type.flags & TypeFlags.Never) { 25172 return flowType; 25173 } 25174 // If we have an antecedent type (meaning we're reachable in some way), we first 25175 // attempt to narrow the antecedent type. If that produces the never type, and if 25176 // the antecedent type is incomplete (i.e. a transient type in a loop), then we 25177 // take the type guard as an indication that control *could* reach here once we 25178 // have the complete type. We proceed by switching to the silent never type which 25179 // doesn't report errors when operators are applied to it. Note that this is the 25180 // *only* place a silent never type is ever generated. 25181 const assumeTrue = (flow.flags & FlowFlags.TrueCondition) !== 0; 25182 const nonEvolvingType = finalizeEvolvingArrayType(type); 25183 const narrowedType = narrowType(nonEvolvingType, flow.node, assumeTrue); 25184 if (narrowedType === nonEvolvingType) { 25185 return flowType; 25186 } 25187 return createFlowType(narrowedType, isIncomplete(flowType)); 25188 } 25189 25190 function getTypeAtSwitchClause(flow: FlowSwitchClause): FlowType { 25191 const expr = flow.switchStatement.expression; 25192 const flowType = getTypeAtFlowNode(flow.antecedent); 25193 let type = getTypeFromFlowType(flowType); 25194 if (isMatchingReference(reference, expr)) { 25195 type = narrowTypeBySwitchOnDiscriminant(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd); 25196 } 25197 else if (expr.kind === SyntaxKind.TypeOfExpression && isMatchingReference(reference, (expr as TypeOfExpression).expression)) { 25198 type = narrowTypeBySwitchOnTypeOf(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd); 25199 } 25200 else { 25201 if (strictNullChecks) { 25202 if (optionalChainContainsReference(expr, reference)) { 25203 type = narrowTypeBySwitchOptionalChainContainment(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd, 25204 t => !(t.flags & (TypeFlags.Undefined | TypeFlags.Never))); 25205 } 25206 else if (expr.kind === SyntaxKind.TypeOfExpression && optionalChainContainsReference((expr as TypeOfExpression).expression, reference)) { 25207 type = narrowTypeBySwitchOptionalChainContainment(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd, 25208 t => !(t.flags & TypeFlags.Never || t.flags & TypeFlags.StringLiteral && (t as StringLiteralType).value === "undefined")); 25209 } 25210 } 25211 const access = getDiscriminantPropertyAccess(expr, type); 25212 if (access) { 25213 type = narrowTypeBySwitchOnDiscriminantProperty(type, access, flow.switchStatement, flow.clauseStart, flow.clauseEnd); 25214 } 25215 } 25216 return createFlowType(type, isIncomplete(flowType)); 25217 } 25218 25219 function getTypeAtFlowBranchLabel(flow: FlowLabel): FlowType { 25220 const antecedentTypes: Type[] = []; 25221 let subtypeReduction = false; 25222 let seenIncomplete = false; 25223 let bypassFlow: FlowSwitchClause | undefined; 25224 for (const antecedent of flow.antecedents!) { 25225 if (!bypassFlow && antecedent.flags & FlowFlags.SwitchClause && (antecedent as FlowSwitchClause).clauseStart === (antecedent as FlowSwitchClause).clauseEnd) { 25226 // The antecedent is the bypass branch of a potentially exhaustive switch statement. 25227 bypassFlow = antecedent as FlowSwitchClause; 25228 continue; 25229 } 25230 const flowType = getTypeAtFlowNode(antecedent); 25231 const type = getTypeFromFlowType(flowType); 25232 // If the type at a particular antecedent path is the declared type and the 25233 // reference is known to always be assigned (i.e. when declared and initial types 25234 // are the same), there is no reason to process more antecedents since the only 25235 // possible outcome is subtypes that will be removed in the final union type anyway. 25236 if (type === declaredType && declaredType === initialType) { 25237 return type; 25238 } 25239 pushIfUnique(antecedentTypes, type); 25240 // If an antecedent type is not a subset of the declared type, we need to perform 25241 // subtype reduction. This happens when a "foreign" type is injected into the control 25242 // flow using the instanceof operator or a user defined type predicate. 25243 if (!isTypeSubsetOf(type, declaredType)) { 25244 subtypeReduction = true; 25245 } 25246 if (isIncomplete(flowType)) { 25247 seenIncomplete = true; 25248 } 25249 } 25250 if (bypassFlow) { 25251 const flowType = getTypeAtFlowNode(bypassFlow); 25252 const type = getTypeFromFlowType(flowType); 25253 // If the bypass flow contributes a type we haven't seen yet and the switch statement 25254 // isn't exhaustive, process the bypass flow type. Since exhaustiveness checks increase 25255 // the risk of circularities, we only want to perform them when they make a difference. 25256 if (!contains(antecedentTypes, type) && !isExhaustiveSwitchStatement(bypassFlow.switchStatement)) { 25257 if (type === declaredType && declaredType === initialType) { 25258 return type; 25259 } 25260 antecedentTypes.push(type); 25261 if (!isTypeSubsetOf(type, declaredType)) { 25262 subtypeReduction = true; 25263 } 25264 if (isIncomplete(flowType)) { 25265 seenIncomplete = true; 25266 } 25267 } 25268 } 25269 return createFlowType(getUnionOrEvolvingArrayType(antecedentTypes, subtypeReduction ? UnionReduction.Subtype : UnionReduction.Literal), seenIncomplete); 25270 } 25271 25272 function getTypeAtFlowLoopLabel(flow: FlowLabel): FlowType { 25273 // If we have previously computed the control flow type for the reference at 25274 // this flow loop junction, return the cached type. 25275 const id = getFlowNodeId(flow); 25276 const cache = flowLoopCaches[id] || (flowLoopCaches[id] = new Map<string, Type>()); 25277 const key = getOrSetCacheKey(); 25278 if (!key) { 25279 // No cache key is generated when binding patterns are in unnarrowable situations 25280 return declaredType; 25281 } 25282 const cached = cache.get(key); 25283 if (cached) { 25284 return cached; 25285 } 25286 // If this flow loop junction and reference are already being processed, return 25287 // the union of the types computed for each branch so far, marked as incomplete. 25288 // It is possible to see an empty array in cases where loops are nested and the 25289 // back edge of the outer loop reaches an inner loop that is already being analyzed. 25290 // In such cases we restart the analysis of the inner loop, which will then see 25291 // a non-empty in-process array for the outer loop and eventually terminate because 25292 // the first antecedent of a loop junction is always the non-looping control flow 25293 // path that leads to the top. 25294 for (let i = flowLoopStart; i < flowLoopCount; i++) { 25295 if (flowLoopNodes[i] === flow && flowLoopKeys[i] === key && flowLoopTypes[i].length) { 25296 return createFlowType(getUnionOrEvolvingArrayType(flowLoopTypes[i], UnionReduction.Literal), /*incomplete*/ true); 25297 } 25298 } 25299 // Add the flow loop junction and reference to the in-process stack and analyze 25300 // each antecedent code path. 25301 const antecedentTypes: Type[] = []; 25302 let subtypeReduction = false; 25303 let firstAntecedentType: FlowType | undefined; 25304 for (const antecedent of flow.antecedents!) { 25305 let flowType; 25306 if (!firstAntecedentType) { 25307 // The first antecedent of a loop junction is always the non-looping control 25308 // flow path that leads to the top. 25309 flowType = firstAntecedentType = getTypeAtFlowNode(antecedent); 25310 } 25311 else { 25312 // All but the first antecedent are the looping control flow paths that lead 25313 // back to the loop junction. We track these on the flow loop stack. 25314 flowLoopNodes[flowLoopCount] = flow; 25315 flowLoopKeys[flowLoopCount] = key; 25316 flowLoopTypes[flowLoopCount] = antecedentTypes; 25317 flowLoopCount++; 25318 const saveFlowTypeCache = flowTypeCache; 25319 flowTypeCache = undefined; 25320 flowType = getTypeAtFlowNode(antecedent); 25321 flowTypeCache = saveFlowTypeCache; 25322 flowLoopCount--; 25323 // If we see a value appear in the cache it is a sign that control flow analysis 25324 // was restarted and completed by checkExpressionCached. We can simply pick up 25325 // the resulting type and bail out. 25326 const cached = cache.get(key); 25327 if (cached) { 25328 return cached; 25329 } 25330 } 25331 const type = getTypeFromFlowType(flowType); 25332 pushIfUnique(antecedentTypes, type); 25333 // If an antecedent type is not a subset of the declared type, we need to perform 25334 // subtype reduction. This happens when a "foreign" type is injected into the control 25335 // flow using the instanceof operator or a user defined type predicate. 25336 if (!isTypeSubsetOf(type, declaredType)) { 25337 subtypeReduction = true; 25338 } 25339 // If the type at a particular antecedent path is the declared type there is no 25340 // reason to process more antecedents since the only possible outcome is subtypes 25341 // that will be removed in the final union type anyway. 25342 if (type === declaredType) { 25343 break; 25344 } 25345 } 25346 // The result is incomplete if the first antecedent (the non-looping control flow path) 25347 // is incomplete. 25348 const result = getUnionOrEvolvingArrayType(antecedentTypes, subtypeReduction ? UnionReduction.Subtype : UnionReduction.Literal); 25349 if (isIncomplete(firstAntecedentType!)) { 25350 return createFlowType(result, /*incomplete*/ true); 25351 } 25352 cache.set(key, result); 25353 return result; 25354 } 25355 25356 // At flow control branch or loop junctions, if the type along every antecedent code path 25357 // is an evolving array type, we construct a combined evolving array type. Otherwise we 25358 // finalize all evolving array types. 25359 function getUnionOrEvolvingArrayType(types: Type[], subtypeReduction: UnionReduction) { 25360 if (isEvolvingArrayTypeList(types)) { 25361 return getEvolvingArrayType(getUnionType(map(types, getElementTypeOfEvolvingArrayType))); 25362 } 25363 const result = recombineUnknownType(getUnionType(sameMap(types, finalizeEvolvingArrayType), subtypeReduction)); 25364 if (result !== declaredType && result.flags & declaredType.flags & TypeFlags.Union && arraysEqual((result as UnionType).types, (declaredType as UnionType).types)) { 25365 return declaredType; 25366 } 25367 return result; 25368 } 25369 25370 function getCandidateDiscriminantPropertyAccess(expr: Expression) { 25371 if (isBindingPattern(reference) || isFunctionExpressionOrArrowFunction(reference) || isObjectLiteralMethod(reference)) { 25372 // When the reference is a binding pattern or function or arrow expression, we are narrowing a pesudo-reference in 25373 // getNarrowedTypeOfSymbol. An identifier for a destructuring variable declared in the same binding pattern or 25374 // parameter declared in the same parameter list is a candidate. 25375 if (isIdentifier(expr)) { 25376 const symbol = getResolvedSymbol(expr); 25377 const declaration = symbol.valueDeclaration; 25378 if (declaration && (isBindingElement(declaration) || isParameter(declaration)) && reference === declaration.parent && !declaration.initializer && !declaration.dotDotDotToken) { 25379 return declaration; 25380 } 25381 } 25382 } 25383 else if (isAccessExpression(expr)) { 25384 // An access expression is a candidate if the reference matches the left hand expression. 25385 if (isMatchingReference(reference, expr.expression)) { 25386 return expr; 25387 } 25388 } 25389 else if (isIdentifier(expr)) { 25390 const symbol = getResolvedSymbol(expr); 25391 if (isConstVariable(symbol)) { 25392 const declaration = symbol.valueDeclaration!; 25393 // Given 'const x = obj.kind', allow 'x' as an alias for 'obj.kind' 25394 if (isVariableDeclaration(declaration) && !declaration.type && declaration.initializer && isAccessExpression(declaration.initializer) && 25395 isMatchingReference(reference, declaration.initializer.expression)) { 25396 return declaration.initializer; 25397 } 25398 // Given 'const { kind: x } = obj', allow 'x' as an alias for 'obj.kind' 25399 if (isBindingElement(declaration) && !declaration.initializer) { 25400 const parent = declaration.parent.parent; 25401 if (isVariableDeclaration(parent) && !parent.type && parent.initializer && (isIdentifier(parent.initializer) || isAccessExpression(parent.initializer)) && 25402 isMatchingReference(reference, parent.initializer)) { 25403 return declaration; 25404 } 25405 } 25406 } 25407 } 25408 return undefined; 25409 } 25410 25411 function getDiscriminantPropertyAccess(expr: Expression, computedType: Type) { 25412 const type = declaredType.flags & TypeFlags.Union ? declaredType : computedType; 25413 if (type.flags & TypeFlags.Union) { 25414 const access = getCandidateDiscriminantPropertyAccess(expr); 25415 if (access) { 25416 const name = getAccessedPropertyName(access); 25417 if (name && isDiscriminantProperty(type, name)) { 25418 return access; 25419 } 25420 } 25421 } 25422 return undefined; 25423 } 25424 25425 function narrowTypeByDiscriminant(type: Type, access: AccessExpression | BindingElement | ParameterDeclaration, narrowType: (t: Type) => Type): Type { 25426 const propName = getAccessedPropertyName(access); 25427 if (propName === undefined) { 25428 return type; 25429 } 25430 const removeNullable = strictNullChecks && isOptionalChain(access) && maybeTypeOfKind(type, TypeFlags.Nullable); 25431 let propType = getTypeOfPropertyOfType(removeNullable ? getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type, propName); 25432 if (!propType) { 25433 return type; 25434 } 25435 propType = removeNullable ? getOptionalType(propType) : propType; 25436 const narrowedPropType = narrowType(propType); 25437 return filterType(type, t => { 25438 const discriminantType = getTypeOfPropertyOrIndexSignature(t, propName); 25439 return !(discriminantType.flags & TypeFlags.Never) && !(narrowedPropType.flags & TypeFlags.Never) && areTypesComparable(narrowedPropType, discriminantType); 25440 }); 25441 } 25442 25443 function narrowTypeByDiscriminantProperty(type: Type, access: AccessExpression | BindingElement | ParameterDeclaration, operator: SyntaxKind, value: Expression, assumeTrue: boolean) { 25444 if ((operator === SyntaxKind.EqualsEqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken) && type.flags & TypeFlags.Union) { 25445 const keyPropertyName = getKeyPropertyName(type as UnionType); 25446 if (keyPropertyName && keyPropertyName === getAccessedPropertyName(access)) { 25447 const candidate = getConstituentTypeForKeyType(type as UnionType, getTypeOfExpression(value)); 25448 if (candidate) { 25449 return operator === (assumeTrue ? SyntaxKind.EqualsEqualsEqualsToken : SyntaxKind.ExclamationEqualsEqualsToken) ? candidate : 25450 isUnitType(getTypeOfPropertyOfType(candidate, keyPropertyName) || unknownType) ? removeType(type, candidate) : 25451 type; 25452 } 25453 } 25454 } 25455 return narrowTypeByDiscriminant(type, access, t => narrowTypeByEquality(t, operator, value, assumeTrue)); 25456 } 25457 25458 function narrowTypeBySwitchOnDiscriminantProperty(type: Type, access: AccessExpression | BindingElement | ParameterDeclaration, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number) { 25459 if (clauseStart < clauseEnd && type.flags & TypeFlags.Union && getKeyPropertyName(type as UnionType) === getAccessedPropertyName(access)) { 25460 const clauseTypes = getSwitchClauseTypes(switchStatement).slice(clauseStart, clauseEnd); 25461 const candidate = getUnionType(map(clauseTypes, t => getConstituentTypeForKeyType(type as UnionType, t) || unknownType)); 25462 if (candidate !== unknownType) { 25463 return candidate; 25464 } 25465 } 25466 return narrowTypeByDiscriminant(type, access, t => narrowTypeBySwitchOnDiscriminant(t, switchStatement, clauseStart, clauseEnd)); 25467 } 25468 25469 function narrowTypeByTruthiness(type: Type, expr: Expression, assumeTrue: boolean): Type { 25470 if (isMatchingReference(reference, expr)) { 25471 return getAdjustedTypeWithFacts(type, assumeTrue ? TypeFacts.Truthy : TypeFacts.Falsy); 25472 } 25473 if (strictNullChecks && assumeTrue && optionalChainContainsReference(expr, reference)) { 25474 type = getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); 25475 } 25476 const access = getDiscriminantPropertyAccess(expr, type); 25477 if (access) { 25478 return narrowTypeByDiscriminant(type, access, t => getTypeWithFacts(t, assumeTrue ? TypeFacts.Truthy : TypeFacts.Falsy)); 25479 } 25480 return type; 25481 } 25482 25483 function isTypePresencePossible(type: Type, propName: __String, assumeTrue: boolean) { 25484 const prop = getPropertyOfType(type, propName); 25485 return prop ? 25486 !!(prop.flags & SymbolFlags.Optional) || assumeTrue : 25487 !!getApplicableIndexInfoForName(type, propName) || !assumeTrue; 25488 } 25489 25490 function narrowTypeByInKeyword(type: Type, nameType: StringLiteralType | NumberLiteralType | UniqueESSymbolType, assumeTrue: boolean) { 25491 const name = getPropertyNameFromType(nameType); 25492 const isKnownProperty = someType(type, t => isTypePresencePossible(t, name, /*assumeTrue*/ true)); 25493 if (isKnownProperty) { 25494 // If the check is for a known property (i.e. a property declared in some constituent of 25495 // the target type), we filter the target type by presence of absence of the property. 25496 return filterType(type, t => isTypePresencePossible(t, name, assumeTrue)); 25497 } 25498 if (assumeTrue) { 25499 // If the check is for an unknown property, we intersect the target type with `Record<X, unknown>`, 25500 // where X is the name of the property. 25501 const recordSymbol = getGlobalRecordSymbol(); 25502 if (recordSymbol) { 25503 return getIntersectionType([type, getTypeAliasInstantiation(recordSymbol, [nameType, unknownType])]); 25504 } 25505 } 25506 return type; 25507 } 25508 25509 function narrowTypeByBinaryExpression(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type { 25510 switch (expr.operatorToken.kind) { 25511 case SyntaxKind.EqualsToken: 25512 case SyntaxKind.BarBarEqualsToken: 25513 case SyntaxKind.AmpersandAmpersandEqualsToken: 25514 case SyntaxKind.QuestionQuestionEqualsToken: 25515 return narrowTypeByTruthiness(narrowType(type, expr.right, assumeTrue), expr.left, assumeTrue); 25516 case SyntaxKind.EqualsEqualsToken: 25517 case SyntaxKind.ExclamationEqualsToken: 25518 case SyntaxKind.EqualsEqualsEqualsToken: 25519 case SyntaxKind.ExclamationEqualsEqualsToken: 25520 const operator = expr.operatorToken.kind; 25521 const left = getReferenceCandidate(expr.left); 25522 const right = getReferenceCandidate(expr.right); 25523 if (left.kind === SyntaxKind.TypeOfExpression && isStringLiteralLike(right)) { 25524 return narrowTypeByTypeof(type, left as TypeOfExpression, operator, right, assumeTrue); 25525 } 25526 if (right.kind === SyntaxKind.TypeOfExpression && isStringLiteralLike(left)) { 25527 return narrowTypeByTypeof(type, right as TypeOfExpression, operator, left, assumeTrue); 25528 } 25529 if (isMatchingReference(reference, left)) { 25530 return narrowTypeByEquality(type, operator, right, assumeTrue); 25531 } 25532 if (isMatchingReference(reference, right)) { 25533 return narrowTypeByEquality(type, operator, left, assumeTrue); 25534 } 25535 if (strictNullChecks) { 25536 if (optionalChainContainsReference(left, reference)) { 25537 type = narrowTypeByOptionalChainContainment(type, operator, right, assumeTrue); 25538 } 25539 else if (optionalChainContainsReference(right, reference)) { 25540 type = narrowTypeByOptionalChainContainment(type, operator, left, assumeTrue); 25541 } 25542 } 25543 const leftAccess = getDiscriminantPropertyAccess(left, type); 25544 if (leftAccess) { 25545 return narrowTypeByDiscriminantProperty(type, leftAccess, operator, right, assumeTrue); 25546 } 25547 const rightAccess = getDiscriminantPropertyAccess(right, type); 25548 if (rightAccess) { 25549 return narrowTypeByDiscriminantProperty(type, rightAccess, operator, left, assumeTrue); 25550 } 25551 if (isMatchingConstructorReference(left)) { 25552 return narrowTypeByConstructor(type, operator, right, assumeTrue); 25553 } 25554 if (isMatchingConstructorReference(right)) { 25555 return narrowTypeByConstructor(type, operator, left, assumeTrue); 25556 } 25557 break; 25558 case SyntaxKind.InstanceOfKeyword: 25559 return narrowTypeByInstanceof(type, expr, assumeTrue); 25560 case SyntaxKind.InKeyword: 25561 if (isPrivateIdentifier(expr.left)) { 25562 return narrowTypeByPrivateIdentifierInInExpression(type, expr, assumeTrue); 25563 } 25564 const target = getReferenceCandidate(expr.right); 25565 const leftType = getTypeOfExpression(expr.left); 25566 if (leftType.flags & TypeFlags.StringOrNumberLiteralOrUnique) { 25567 if (containsMissingType(type) && isAccessExpression(reference) && isMatchingReference(reference.expression, target) && 25568 getAccessedPropertyName(reference) === getPropertyNameFromType(leftType as StringLiteralType | NumberLiteralType | UniqueESSymbolType)) { 25569 return getTypeWithFacts(type, assumeTrue ? TypeFacts.NEUndefined : TypeFacts.EQUndefined); 25570 } 25571 if (isMatchingReference(reference, target)) { 25572 return narrowTypeByInKeyword(type, leftType as StringLiteralType | NumberLiteralType | UniqueESSymbolType, assumeTrue); 25573 } 25574 } 25575 break; 25576 case SyntaxKind.CommaToken: 25577 return narrowType(type, expr.right, assumeTrue); 25578 // Ordinarily we won't see && and || expressions in control flow analysis because the Binder breaks those 25579 // expressions down to individual conditional control flows. However, we may encounter them when analyzing 25580 // aliased conditional expressions. 25581 case SyntaxKind.AmpersandAmpersandToken: 25582 return assumeTrue ? 25583 narrowType(narrowType(type, expr.left, /*assumeTrue*/ true), expr.right, /*assumeTrue*/ true) : 25584 getUnionType([narrowType(type, expr.left, /*assumeTrue*/ false), narrowType(type, expr.right, /*assumeTrue*/ false)]); 25585 case SyntaxKind.BarBarToken: 25586 return assumeTrue ? 25587 getUnionType([narrowType(type, expr.left, /*assumeTrue*/ true), narrowType(type, expr.right, /*assumeTrue*/ true)]) : 25588 narrowType(narrowType(type, expr.left, /*assumeTrue*/ false), expr.right, /*assumeTrue*/ false); 25589 } 25590 return type; 25591 } 25592 25593 function narrowTypeByPrivateIdentifierInInExpression(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type { 25594 const target = getReferenceCandidate(expr.right); 25595 if (!isMatchingReference(reference, target)) { 25596 return type; 25597 } 25598 25599 Debug.assertNode(expr.left, isPrivateIdentifier); 25600 const symbol = getSymbolForPrivateIdentifierExpression(expr.left); 25601 if (symbol === undefined) { 25602 return type; 25603 } 25604 const classSymbol = symbol.parent!; 25605 const targetType = hasStaticModifier(Debug.checkDefined(symbol.valueDeclaration, "should always have a declaration")) 25606 ? getTypeOfSymbol(classSymbol) as InterfaceType 25607 : getDeclaredTypeOfSymbol(classSymbol); 25608 return getNarrowedType(type, targetType, assumeTrue, /*checkDerived*/ true); 25609 } 25610 25611 function narrowTypeByOptionalChainContainment(type: Type, operator: SyntaxKind, value: Expression, assumeTrue: boolean): Type { 25612 // We are in a branch of obj?.foo === value (or any one of the other equality operators). We narrow obj as follows: 25613 // When operator is === and type of value excludes undefined, null and undefined is removed from type of obj in true branch. 25614 // When operator is !== and type of value excludes undefined, null and undefined is removed from type of obj in false branch. 25615 // When operator is == and type of value excludes null and undefined, null and undefined is removed from type of obj in true branch. 25616 // When operator is != and type of value excludes null and undefined, null and undefined is removed from type of obj in false branch. 25617 // When operator is === and type of value is undefined, null and undefined is removed from type of obj in false branch. 25618 // When operator is !== and type of value is undefined, null and undefined is removed from type of obj in true branch. 25619 // When operator is == and type of value is null or undefined, null and undefined is removed from type of obj in false branch. 25620 // When operator is != and type of value is null or undefined, null and undefined is removed from type of obj in true branch. 25621 const equalsOperator = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.EqualsEqualsEqualsToken; 25622 const nullableFlags = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken ? TypeFlags.Nullable : TypeFlags.Undefined; 25623 const valueType = getTypeOfExpression(value); 25624 // Note that we include any and unknown in the exclusion test because their domain includes null and undefined. 25625 const removeNullable = equalsOperator !== assumeTrue && everyType(valueType, t => !!(t.flags & nullableFlags)) || 25626 equalsOperator === assumeTrue && everyType(valueType, t => !(t.flags & (TypeFlags.AnyOrUnknown | nullableFlags))); 25627 return removeNullable ? getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type; 25628 } 25629 25630 function narrowTypeByEquality(type: Type, operator: SyntaxKind, value: Expression, assumeTrue: boolean): Type { 25631 if (type.flags & TypeFlags.Any) { 25632 return type; 25633 } 25634 if (operator === SyntaxKind.ExclamationEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken) { 25635 assumeTrue = !assumeTrue; 25636 } 25637 const valueType = getTypeOfExpression(value); 25638 const doubleEquals = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken; 25639 if (valueType.flags & TypeFlags.Nullable) { 25640 if (!strictNullChecks) { 25641 return type; 25642 } 25643 const facts = doubleEquals ? 25644 assumeTrue ? TypeFacts.EQUndefinedOrNull : TypeFacts.NEUndefinedOrNull : 25645 valueType.flags & TypeFlags.Null ? 25646 assumeTrue ? TypeFacts.EQNull : TypeFacts.NENull : 25647 assumeTrue ? TypeFacts.EQUndefined : TypeFacts.NEUndefined; 25648 return getAdjustedTypeWithFacts(type, facts); 25649 } 25650 if (assumeTrue) { 25651 if (!doubleEquals && (type.flags & TypeFlags.Unknown || someType(type, isEmptyAnonymousObjectType))) { 25652 if (valueType.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive) || isEmptyAnonymousObjectType(valueType)) { 25653 return valueType; 25654 } 25655 if (valueType.flags & TypeFlags.Object) { 25656 return nonPrimitiveType; 25657 } 25658 } 25659 const filteredType = filterType(type, t => areTypesComparable(t, valueType) || doubleEquals && isCoercibleUnderDoubleEquals(t, valueType)); 25660 return replacePrimitivesWithLiterals(filteredType, valueType); 25661 } 25662 if (isUnitType(valueType)) { 25663 return filterType(type, t => !(isUnitLikeType(t) && areTypesComparable(t, valueType))); 25664 } 25665 return type; 25666 } 25667 25668 function narrowTypeByTypeof(type: Type, typeOfExpr: TypeOfExpression, operator: SyntaxKind, literal: LiteralExpression, assumeTrue: boolean): Type { 25669 // We have '==', '!=', '===', or !==' operator with 'typeof xxx' and string literal operands 25670 if (operator === SyntaxKind.ExclamationEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken) { 25671 assumeTrue = !assumeTrue; 25672 } 25673 const target = getReferenceCandidate(typeOfExpr.expression); 25674 if (!isMatchingReference(reference, target)) { 25675 const propertyAccess = getDiscriminantPropertyAccess(typeOfExpr.expression, type); 25676 if (propertyAccess) { 25677 return narrowTypeByDiscriminant(type, propertyAccess, t => narrowTypeByLiteralExpression(t, literal, assumeTrue)); 25678 } 25679 if (strictNullChecks && optionalChainContainsReference(target, reference) && assumeTrue === (literal.text !== "undefined")) { 25680 return getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); 25681 } 25682 return type; 25683 } 25684 return narrowTypeByLiteralExpression(type, literal, assumeTrue); 25685 } 25686 25687 function narrowTypeByLiteralExpression(type: Type, literal: LiteralExpression, assumeTrue: boolean) { 25688 return assumeTrue ? 25689 narrowTypeByTypeName(type, literal.text) : 25690 getTypeWithFacts(type, typeofNEFacts.get(literal.text) || TypeFacts.TypeofNEHostObject); 25691 } 25692 25693 function narrowTypeBySwitchOptionalChainContainment(type: Type, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number, clauseCheck: (type: Type) => boolean) { 25694 const everyClauseChecks = clauseStart !== clauseEnd && every(getSwitchClauseTypes(switchStatement).slice(clauseStart, clauseEnd), clauseCheck); 25695 return everyClauseChecks ? getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type; 25696 } 25697 25698 function narrowTypeBySwitchOnDiscriminant(type: Type, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number) { 25699 // We only narrow if all case expressions specify 25700 // values with unit types, except for the case where 25701 // `type` is unknown. In this instance we map object 25702 // types to the nonPrimitive type and narrow with that. 25703 const switchTypes = getSwitchClauseTypes(switchStatement); 25704 if (!switchTypes.length) { 25705 return type; 25706 } 25707 const clauseTypes = switchTypes.slice(clauseStart, clauseEnd); 25708 const hasDefaultClause = clauseStart === clauseEnd || contains(clauseTypes, neverType); 25709 if ((type.flags & TypeFlags.Unknown) && !hasDefaultClause) { 25710 let groundClauseTypes: Type[] | undefined; 25711 for (let i = 0; i < clauseTypes.length; i += 1) { 25712 const t = clauseTypes[i]; 25713 if (t.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive)) { 25714 if (groundClauseTypes !== undefined) { 25715 groundClauseTypes.push(t); 25716 } 25717 } 25718 else if (t.flags & TypeFlags.Object) { 25719 if (groundClauseTypes === undefined) { 25720 groundClauseTypes = clauseTypes.slice(0, i); 25721 } 25722 groundClauseTypes.push(nonPrimitiveType); 25723 } 25724 else { 25725 return type; 25726 } 25727 } 25728 return getUnionType(groundClauseTypes === undefined ? clauseTypes : groundClauseTypes); 25729 } 25730 const discriminantType = getUnionType(clauseTypes); 25731 const caseType = 25732 discriminantType.flags & TypeFlags.Never ? neverType : 25733 replacePrimitivesWithLiterals(filterType(type, t => areTypesComparable(discriminantType, t)), discriminantType); 25734 if (!hasDefaultClause) { 25735 return caseType; 25736 } 25737 const defaultType = filterType(type, t => !(isUnitLikeType(t) && contains(switchTypes, getRegularTypeOfLiteralType(extractUnitType(t))))); 25738 return caseType.flags & TypeFlags.Never ? defaultType : getUnionType([caseType, defaultType]); 25739 } 25740 25741 function narrowTypeByTypeName(type: Type, typeName: string) { 25742 switch (typeName) { 25743 case "string": return narrowTypeByTypeFacts(type, stringType, TypeFacts.TypeofEQString); 25744 case "number": return narrowTypeByTypeFacts(type, numberType, TypeFacts.TypeofEQNumber); 25745 case "bigint": return narrowTypeByTypeFacts(type, bigintType, TypeFacts.TypeofEQBigInt); 25746 case "boolean": return narrowTypeByTypeFacts(type, booleanType, TypeFacts.TypeofEQBoolean); 25747 case "symbol": return narrowTypeByTypeFacts(type, esSymbolType, TypeFacts.TypeofEQSymbol); 25748 case "object": return type.flags & TypeFlags.Any ? type : getUnionType([narrowTypeByTypeFacts(type, nonPrimitiveType, TypeFacts.TypeofEQObject), narrowTypeByTypeFacts(type, nullType, TypeFacts.EQNull)]); 25749 case "function": return type.flags & TypeFlags.Any ? type : narrowTypeByTypeFacts(type, globalFunctionType, TypeFacts.TypeofEQFunction); 25750 case "undefined": return narrowTypeByTypeFacts(type, undefinedType, TypeFacts.EQUndefined); 25751 } 25752 return narrowTypeByTypeFacts(type, nonPrimitiveType, TypeFacts.TypeofEQHostObject); 25753 } 25754 25755 function narrowTypeByTypeFacts(type: Type, impliedType: Type, facts: TypeFacts) { 25756 return mapType(type, t => 25757 // We first check if a constituent is a subtype of the implied type. If so, we either keep or eliminate 25758 // the constituent based on its type facts. We use the strict subtype relation because it treats `object` 25759 // as a subtype of `{}`, and we need the type facts check because function types are subtypes of `object`, 25760 // but are classified as "function" according to `typeof`. 25761 isTypeRelatedTo(t, impliedType, strictSubtypeRelation) ? getTypeFacts(t) & facts ? t : neverType : 25762 // We next check if the consituent is a supertype of the implied type. If so, we substitute the implied 25763 // type. This handles top types like `unknown` and `{}`, and supertypes like `{ toString(): string }`. 25764 isTypeSubtypeOf(impliedType, t) ? impliedType : 25765 // Neither the constituent nor the implied type is a subtype of the other, however their domains may still 25766 // overlap. For example, an unconstrained type parameter and type `string`. If the type facts indicate 25767 // possible overlap, we form an intersection. Otherwise, we eliminate the constituent. 25768 getTypeFacts(t) & facts ? getIntersectionType([t, impliedType]) : 25769 neverType); 25770 } 25771 25772 function narrowTypeBySwitchOnTypeOf(type: Type, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): Type { 25773 const witnesses = getSwitchClauseTypeOfWitnesses(switchStatement); 25774 if (!witnesses) { 25775 return type; 25776 } 25777 // Equal start and end denotes implicit fallthrough; undefined marks explicit default clause. 25778 const defaultIndex = findIndex(switchStatement.caseBlock.clauses, clause => clause.kind === SyntaxKind.DefaultClause); 25779 const hasDefaultClause = clauseStart === clauseEnd || (defaultIndex >= clauseStart && defaultIndex < clauseEnd); 25780 if (hasDefaultClause) { 25781 // In the default clause we filter constituents down to those that are not-equal to all handled cases. 25782 const notEqualFacts = getNotEqualFactsFromTypeofSwitch(clauseStart, clauseEnd, witnesses); 25783 return filterType(type, t => (getTypeFacts(t) & notEqualFacts) === notEqualFacts); 25784 } 25785 // In the non-default cause we create a union of the type narrowed by each of the listed cases. 25786 const clauseWitnesses = witnesses.slice(clauseStart, clauseEnd); 25787 return getUnionType(map(clauseWitnesses, text => text ? narrowTypeByTypeName(type, text) : neverType)); 25788 } 25789 25790 function isMatchingConstructorReference(expr: Expression) { 25791 return (isPropertyAccessExpression(expr) && idText(expr.name) === "constructor" || 25792 isElementAccessExpression(expr) && isStringLiteralLike(expr.argumentExpression) && expr.argumentExpression.text === "constructor") && 25793 isMatchingReference(reference, expr.expression); 25794 } 25795 25796 function narrowTypeByConstructor(type: Type, operator: SyntaxKind, identifier: Expression, assumeTrue: boolean): Type { 25797 // Do not narrow when checking inequality. 25798 if (assumeTrue ? (operator !== SyntaxKind.EqualsEqualsToken && operator !== SyntaxKind.EqualsEqualsEqualsToken) : (operator !== SyntaxKind.ExclamationEqualsToken && operator !== SyntaxKind.ExclamationEqualsEqualsToken)) { 25799 return type; 25800 } 25801 25802 // Get the type of the constructor identifier expression, if it is not a function then do not narrow. 25803 const identifierType = getTypeOfExpression(identifier); 25804 if (!isFunctionType(identifierType) && !isConstructorType(identifierType)) { 25805 return type; 25806 } 25807 25808 // Get the prototype property of the type identifier so we can find out its type. 25809 const prototypeProperty = getPropertyOfType(identifierType, "prototype" as __String); 25810 if (!prototypeProperty) { 25811 return type; 25812 } 25813 25814 // Get the type of the prototype, if it is undefined, or the global `Object` or `Function` types then do not narrow. 25815 const prototypeType = getTypeOfSymbol(prototypeProperty); 25816 const candidate = !isTypeAny(prototypeType) ? prototypeType : undefined; 25817 if (!candidate || candidate === globalObjectType || candidate === globalFunctionType) { 25818 return type; 25819 } 25820 25821 // If the type that is being narrowed is `any` then just return the `candidate` type since every type is a subtype of `any`. 25822 if (isTypeAny(type)) { 25823 return candidate; 25824 } 25825 25826 // Filter out types that are not considered to be "constructed by" the `candidate` type. 25827 return filterType(type, t => isConstructedBy(t, candidate)); 25828 25829 function isConstructedBy(source: Type, target: Type) { 25830 // If either the source or target type are a class type then we need to check that they are the same exact type. 25831 // This is because you may have a class `A` that defines some set of properties, and another class `B` 25832 // that defines the same set of properties as class `A`, in that case they are structurally the same 25833 // type, but when you do something like `instanceOfA.constructor === B` it will return false. 25834 if (source.flags & TypeFlags.Object && getObjectFlags(source) & ObjectFlags.Class || 25835 target.flags & TypeFlags.Object && getObjectFlags(target) & ObjectFlags.Class) { 25836 return source.symbol === target.symbol; 25837 } 25838 25839 // For all other types just check that the `source` type is a subtype of the `target` type. 25840 return isTypeSubtypeOf(source, target); 25841 } 25842 } 25843 25844 function narrowTypeByInstanceof(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type { 25845 const left = getReferenceCandidate(expr.left); 25846 if (!isMatchingReference(reference, left)) { 25847 if (assumeTrue && strictNullChecks && optionalChainContainsReference(left, reference)) { 25848 return getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); 25849 } 25850 return type; 25851 } 25852 25853 // Check that right operand is a function type with a prototype property 25854 const rightType = getTypeOfExpression(expr.right); 25855 if (!isTypeDerivedFrom(rightType, globalFunctionType)) { 25856 return type; 25857 } 25858 25859 let targetType: Type | undefined; 25860 const prototypeProperty = getPropertyOfType(rightType, "prototype" as __String); 25861 if (prototypeProperty) { 25862 // Target type is type of the prototype property 25863 const prototypePropertyType = getTypeOfSymbol(prototypeProperty); 25864 if (!isTypeAny(prototypePropertyType)) { 25865 targetType = prototypePropertyType; 25866 } 25867 } 25868 25869 // Don't narrow from 'any' if the target type is exactly 'Object' or 'Function' 25870 if (isTypeAny(type) && (targetType === globalObjectType || targetType === globalFunctionType)) { 25871 return type; 25872 } 25873 25874 if (!targetType) { 25875 const constructSignatures = getSignaturesOfType(rightType, SignatureKind.Construct); 25876 targetType = constructSignatures.length ? 25877 getUnionType(map(constructSignatures, signature => getReturnTypeOfSignature(getErasedSignature(signature)))) : 25878 emptyObjectType; 25879 } 25880 25881 // We can't narrow a union based off instanceof without negated types see #31576 for more info 25882 if (!assumeTrue && rightType.flags & TypeFlags.Union) { 25883 const nonConstructorTypeInUnion = find((rightType as UnionType).types, (t) => !isConstructorType(t)); 25884 if (!nonConstructorTypeInUnion) return type; 25885 } 25886 25887 return getNarrowedType(type, targetType, assumeTrue, /*checkDerived*/ true); 25888 } 25889 25890 function getNarrowedType(type: Type, candidate: Type, assumeTrue: boolean, checkDerived: boolean) { 25891 const key = type.flags & TypeFlags.Union ? `N${getTypeId(type)},${getTypeId(candidate)},${(assumeTrue ? 1 : 0) | (checkDerived ? 2 : 0)}` : undefined; 25892 return getCachedType(key) ?? setCachedType(key, getNarrowedTypeWorker(type, candidate, assumeTrue, checkDerived)); 25893 } 25894 25895 function getNarrowedTypeWorker(type: Type, candidate: Type, assumeTrue: boolean, checkDerived: boolean) { 25896 const isRelated = checkDerived ? isTypeDerivedFrom : isTypeSubtypeOf; 25897 if (!assumeTrue) { 25898 return filterType(type, t => !isRelated(t, candidate)); 25899 } 25900 if (type.flags & TypeFlags.AnyOrUnknown) { 25901 return candidate; 25902 } 25903 // We first attempt to filter the current type, narrowing constituents as appropriate and removing 25904 // constituents that are unrelated to the candidate. 25905 const keyPropertyName = type.flags & TypeFlags.Union ? getKeyPropertyName(type as UnionType) : undefined; 25906 const narrowedType = mapType(candidate, c => { 25907 // If a discriminant property is available, use that to reduce the type. 25908 const discriminant = keyPropertyName && getTypeOfPropertyOfType(c, keyPropertyName); 25909 const matching = discriminant && getConstituentTypeForKeyType(type as UnionType, discriminant); 25910 // For each constituent t in the current type, if t and and c are directly related, pick the most 25911 // specific of the two. When t and c are related in both directions, we prefer c for type predicates 25912 // because that is the asserted type, but t for `instanceof` because generics aren't reflected in 25913 // prototype object types. 25914 const directlyRelated = mapType(matching || type, checkDerived ? 25915 t => isTypeDerivedFrom(t, c) ? t : isTypeDerivedFrom(c, t) ? c : neverType : 25916 t => isTypeSubtypeOf(c, t) ? c : isTypeSubtypeOf(t, c) ? t : neverType); 25917 // If no constituents are directly related, create intersections for any generic constituents that 25918 // are related by constraint. 25919 return directlyRelated.flags & TypeFlags.Never ? 25920 mapType(type, t => maybeTypeOfKind(t, TypeFlags.Instantiable) && isRelated(c, getBaseConstraintOfType(t) || unknownType) ? getIntersectionType([t, c]) : neverType) : 25921 directlyRelated; 25922 }); 25923 // If filtering produced a non-empty type, return that. Otherwise, pick the most specific of the two 25924 // based on assignability, or as a last resort produce an intersection. 25925 return !(narrowedType.flags & TypeFlags.Never) ? narrowedType : 25926 isTypeSubtypeOf(candidate, type) ? candidate : 25927 isTypeAssignableTo(type, candidate) ? type : 25928 isTypeAssignableTo(candidate, type) ? candidate : 25929 getIntersectionType([type, candidate]); 25930 } 25931 25932 function narrowTypeByCallExpression(type: Type, callExpression: CallExpression, assumeTrue: boolean): Type { 25933 if (hasMatchingArgument(callExpression, reference)) { 25934 const signature = assumeTrue || !isCallChain(callExpression) ? getEffectsSignature(callExpression) : undefined; 25935 const predicate = signature && getTypePredicateOfSignature(signature); 25936 if (predicate && (predicate.kind === TypePredicateKind.This || predicate.kind === TypePredicateKind.Identifier)) { 25937 return narrowTypeByTypePredicate(type, predicate, callExpression, assumeTrue); 25938 } 25939 } 25940 if (containsMissingType(type) && isAccessExpression(reference) && isPropertyAccessExpression(callExpression.expression)) { 25941 const callAccess = callExpression.expression; 25942 if (isMatchingReference(reference.expression, getReferenceCandidate(callAccess.expression)) && 25943 isIdentifier(callAccess.name) && callAccess.name.escapedText === "hasOwnProperty" && callExpression.arguments.length === 1) { 25944 const argument = callExpression.arguments[0]; 25945 if (isStringLiteralLike(argument) && getAccessedPropertyName(reference) === escapeLeadingUnderscores(argument.text)) { 25946 return getTypeWithFacts(type, assumeTrue ? TypeFacts.NEUndefined : TypeFacts.EQUndefined); 25947 } 25948 } 25949 } 25950 return type; 25951 } 25952 25953 function narrowTypeByTypePredicate(type: Type, predicate: TypePredicate, callExpression: CallExpression, assumeTrue: boolean): Type { 25954 // Don't narrow from 'any' if the predicate type is exactly 'Object' or 'Function' 25955 if (predicate.type && !(isTypeAny(type) && (predicate.type === globalObjectType || predicate.type === globalFunctionType))) { 25956 const predicateArgument = getTypePredicateArgument(predicate, callExpression); 25957 if (predicateArgument) { 25958 if (isMatchingReference(reference, predicateArgument)) { 25959 return getNarrowedType(type, predicate.type, assumeTrue, /*checkDerived*/ false); 25960 } 25961 if (strictNullChecks && assumeTrue && optionalChainContainsReference(predicateArgument, reference) && 25962 !(getTypeFacts(predicate.type) & TypeFacts.EQUndefined)) { 25963 type = getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); 25964 } 25965 const access = getDiscriminantPropertyAccess(predicateArgument, type); 25966 if (access) { 25967 return narrowTypeByDiscriminant(type, access, t => getNarrowedType(t, predicate.type!, assumeTrue, /*checkDerived*/ false)); 25968 } 25969 } 25970 } 25971 return type; 25972 } 25973 25974 // Narrow the given type based on the given expression having the assumed boolean value. The returned type 25975 // will be a subtype or the same type as the argument. 25976 function narrowType(type: Type, expr: Expression, assumeTrue: boolean): Type { 25977 // for `a?.b`, we emulate a synthetic `a !== null && a !== undefined` condition for `a` 25978 if (isExpressionOfOptionalChainRoot(expr) || 25979 isBinaryExpression(expr.parent) && expr.parent.operatorToken.kind === SyntaxKind.QuestionQuestionToken && expr.parent.left === expr) { 25980 return narrowTypeByOptionality(type, expr, assumeTrue); 25981 } 25982 switch (expr.kind) { 25983 case SyntaxKind.Identifier: 25984 // When narrowing a reference to a const variable, non-assigned parameter, or readonly property, we inline 25985 // up to five levels of aliased conditional expressions that are themselves declared as const variables. 25986 if (!isMatchingReference(reference, expr) && inlineLevel < 5) { 25987 const symbol = getResolvedSymbol(expr as Identifier); 25988 if (isConstVariable(symbol)) { 25989 const declaration = symbol.valueDeclaration; 25990 if (declaration && isVariableDeclaration(declaration) && !declaration.type && declaration.initializer && isConstantReference(reference)) { 25991 inlineLevel++; 25992 const result = narrowType(type, declaration.initializer, assumeTrue); 25993 inlineLevel--; 25994 return result; 25995 } 25996 } 25997 } 25998 // falls through 25999 case SyntaxKind.ThisKeyword: 26000 case SyntaxKind.SuperKeyword: 26001 case SyntaxKind.PropertyAccessExpression: 26002 case SyntaxKind.ElementAccessExpression: 26003 return narrowTypeByTruthiness(type, expr, assumeTrue); 26004 case SyntaxKind.CallExpression: 26005 return narrowTypeByCallExpression(type, expr as CallExpression, assumeTrue); 26006 case SyntaxKind.ParenthesizedExpression: 26007 case SyntaxKind.NonNullExpression: 26008 return narrowType(type, (expr as ParenthesizedExpression | NonNullExpression).expression, assumeTrue); 26009 case SyntaxKind.BinaryExpression: 26010 return narrowTypeByBinaryExpression(type, expr as BinaryExpression, assumeTrue); 26011 case SyntaxKind.PrefixUnaryExpression: 26012 if ((expr as PrefixUnaryExpression).operator === SyntaxKind.ExclamationToken) { 26013 return narrowType(type, (expr as PrefixUnaryExpression).operand, !assumeTrue); 26014 } 26015 break; 26016 } 26017 return type; 26018 } 26019 26020 function narrowTypeByOptionality(type: Type, expr: Expression, assumePresent: boolean): Type { 26021 if (isMatchingReference(reference, expr)) { 26022 return getAdjustedTypeWithFacts(type, assumePresent ? TypeFacts.NEUndefinedOrNull : TypeFacts.EQUndefinedOrNull); 26023 } 26024 const access = getDiscriminantPropertyAccess(expr, type); 26025 if (access) { 26026 return narrowTypeByDiscriminant(type, access, t => getTypeWithFacts(t, assumePresent ? TypeFacts.NEUndefinedOrNull : TypeFacts.EQUndefinedOrNull)); 26027 } 26028 return type; 26029 } 26030 } 26031 26032 function getTypeOfSymbolAtLocation(symbol: Symbol, location: Node) { 26033 symbol = symbol.exportSymbol || symbol; 26034 26035 // If we have an identifier or a property access at the given location, if the location is 26036 // an dotted name expression, and if the location is not an assignment target, obtain the type 26037 // of the expression (which will reflect control flow analysis). If the expression indeed 26038 // resolved to the given symbol, return the narrowed type. 26039 if (location.kind === SyntaxKind.Identifier || location.kind === SyntaxKind.PrivateIdentifier) { 26040 if (isRightSideOfQualifiedNameOrPropertyAccess(location)) { 26041 location = location.parent; 26042 } 26043 if (isExpressionNode(location) && (!isAssignmentTarget(location) || isWriteAccess(location))) { 26044 const type = getTypeOfExpression(location as Expression); 26045 if (getExportSymbolOfValueSymbolIfExported(getNodeLinks(location).resolvedSymbol) === symbol) { 26046 return type; 26047 } 26048 } 26049 } 26050 if (isDeclarationName(location) && isSetAccessor(location.parent) && getAnnotatedAccessorTypeNode(location.parent)) { 26051 return getWriteTypeOfAccessors(location.parent.symbol); 26052 } 26053 // The location isn't a reference to the given symbol, meaning we're being asked 26054 // a hypothetical question of what type the symbol would have if there was a reference 26055 // to it at the given location. Since we have no control flow information for the 26056 // hypothetical reference (control flow information is created and attached by the 26057 // binder), we simply return the declared type of the symbol. 26058 return getNonMissingTypeOfSymbol(symbol); 26059 } 26060 26061 function getControlFlowContainer(node: Node): Node { 26062 return findAncestor(node.parent, node => 26063 isFunctionLike(node) && !getImmediatelyInvokedFunctionExpression(node) || 26064 node.kind === SyntaxKind.ModuleBlock || 26065 node.kind === SyntaxKind.SourceFile || 26066 node.kind === SyntaxKind.PropertyDeclaration || 26067 node.kind === SyntaxKind.AnnotationPropertyDeclaration)!; 26068 } 26069 26070 // Check if a parameter or catch variable is assigned anywhere 26071 function isSymbolAssigned(symbol: Symbol) { 26072 if (!symbol.valueDeclaration) { 26073 return false; 26074 } 26075 const parent = getRootDeclaration(symbol.valueDeclaration).parent; 26076 const links = getNodeLinks(parent); 26077 if (!(links.flags & NodeCheckFlags.AssignmentsMarked)) { 26078 links.flags |= NodeCheckFlags.AssignmentsMarked; 26079 if (!hasParentWithAssignmentsMarked(parent)) { 26080 markNodeAssignments(parent); 26081 } 26082 } 26083 return symbol.isAssigned || false; 26084 } 26085 26086 function hasParentWithAssignmentsMarked(node: Node) { 26087 return !!findAncestor(node.parent, node => 26088 (isFunctionLike(node) || isCatchClause(node)) && !!(getNodeLinks(node).flags & NodeCheckFlags.AssignmentsMarked)); 26089 } 26090 26091 function markNodeAssignments(node: Node) { 26092 if (node.kind === SyntaxKind.Identifier) { 26093 if (isAssignmentTarget(node)) { 26094 const symbol = getResolvedSymbol(node as Identifier); 26095 if (isParameterOrCatchClauseVariable(symbol)) { 26096 symbol.isAssigned = true; 26097 } 26098 } 26099 } 26100 else { 26101 forEachChild(node, markNodeAssignments); 26102 } 26103 } 26104 26105 function isConstVariable(symbol: Symbol) { 26106 return symbol.flags & SymbolFlags.Variable && (getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Const) !== 0; 26107 } 26108 26109 /** remove undefined from the annotated type of a parameter when there is an initializer (that doesn't include undefined) */ 26110 function removeOptionalityFromDeclaredType(declaredType: Type, declaration: VariableLikeDeclaration): Type { 26111 if (pushTypeResolution(declaration.symbol, TypeSystemPropertyName.DeclaredType)) { 26112 const annotationIncludesUndefined = strictNullChecks && 26113 declaration.kind === SyntaxKind.Parameter && 26114 declaration.initializer && 26115 getTypeFacts(declaredType) & TypeFacts.IsUndefined && 26116 !(getTypeFacts(checkExpression(declaration.initializer)) & TypeFacts.IsUndefined); 26117 popTypeResolution(); 26118 26119 return annotationIncludesUndefined ? getTypeWithFacts(declaredType, TypeFacts.NEUndefined) : declaredType; 26120 } 26121 else { 26122 reportCircularityError(declaration.symbol); 26123 return declaredType; 26124 } 26125 } 26126 26127 function isConstraintPosition(type: Type, node: Node) { 26128 const parent = node.parent; 26129 // In an element access obj[x], we consider obj to be in a constraint position, except when obj is of 26130 // a generic type without a nullable constraint and x is a generic type. This is because when both obj 26131 // and x are of generic types T and K, we want the resulting type to be T[K]. 26132 return parent.kind === SyntaxKind.PropertyAccessExpression || 26133 parent.kind === SyntaxKind.QualifiedName || 26134 parent.kind === SyntaxKind.CallExpression && (parent as CallExpression).expression === node || 26135 parent.kind === SyntaxKind.ElementAccessExpression && (parent as ElementAccessExpression).expression === node && 26136 !(someType(type, isGenericTypeWithoutNullableConstraint) && isGenericIndexType(getTypeOfExpression((parent as ElementAccessExpression).argumentExpression))); 26137 } 26138 26139 function isGenericTypeWithUnionConstraint(type: Type): boolean { 26140 return type.flags & TypeFlags.Intersection ? 26141 some((type as IntersectionType).types, isGenericTypeWithUnionConstraint) : 26142 !!(type.flags & TypeFlags.Instantiable && getBaseConstraintOrType(type).flags & (TypeFlags.Nullable | TypeFlags.Union)); 26143 } 26144 26145 function isGenericTypeWithoutNullableConstraint(type: Type): boolean { 26146 return type.flags & TypeFlags.Intersection ? 26147 some((type as IntersectionType).types, isGenericTypeWithoutNullableConstraint) : 26148 !!(type.flags & TypeFlags.Instantiable && !maybeTypeOfKind(getBaseConstraintOrType(type), TypeFlags.Nullable)); 26149 } 26150 26151 function hasContextualTypeWithNoGenericTypes(node: Node, checkMode: CheckMode | undefined) { 26152 // Computing the contextual type for a child of a JSX element involves resolving the type of the 26153 // element's tag name, so we exclude that here to avoid circularities. 26154 // If check mode has `CheckMode.RestBindingElement`, we skip binding pattern contextual types, 26155 // as we want the type of a rest element to be generic when possible. 26156 const contextualType = (isIdentifier(node) || isPropertyAccessExpression(node) || isElementAccessExpression(node)) && 26157 !((isJsxOpeningElement(node.parent) || isJsxSelfClosingElement(node.parent)) && node.parent.tagName === node) && 26158 (checkMode && checkMode & CheckMode.RestBindingElement ? 26159 getContextualType(node, ContextFlags.SkipBindingPatterns) 26160 : getContextualType(node, /*contextFlags*/ undefined)); 26161 return contextualType && !isGenericType(contextualType); 26162 } 26163 26164 function getNarrowableTypeForReference(type: Type, reference: Node, checkMode?: CheckMode) { 26165 // When the type of a reference is or contains an instantiable type with a union type constraint, and 26166 // when the reference is in a constraint position (where it is known we'll obtain the apparent type) or 26167 // has a contextual type containing no top-level instantiables (meaning constraints will determine 26168 // assignability), we substitute constraints for all instantiables in the type of the reference to give 26169 // control flow analysis an opportunity to narrow it further. For example, for a reference of a type 26170 // parameter type 'T extends string | undefined' with a contextual type 'string', we substitute 26171 // 'string | undefined' to give control flow analysis the opportunity to narrow to type 'string'. 26172 const substituteConstraints = !(checkMode && checkMode & CheckMode.Inferential) && 26173 someType(type, isGenericTypeWithUnionConstraint) && 26174 (isConstraintPosition(type, reference) || hasContextualTypeWithNoGenericTypes(reference, checkMode)); 26175 return substituteConstraints ? mapType(type, getBaseConstraintOrType) : type; 26176 } 26177 26178 function isExportOrExportExpression(location: Node) { 26179 return !!findAncestor(location, n => { 26180 const parent = n.parent; 26181 if (parent === undefined) { 26182 return "quit"; 26183 } 26184 if (isExportAssignment(parent)) { 26185 return parent.expression === n && isEntityNameExpression(n); 26186 } 26187 if (isExportSpecifier(parent)) { 26188 return parent.name === n || parent.propertyName === n; 26189 } 26190 return false; 26191 }); 26192 } 26193 26194 function markAliasReferenced(symbol: Symbol, location: Node) { 26195 if (isNonLocalAlias(symbol, /*excludes*/ SymbolFlags.Value) && !isInTypeQuery(location) && !getTypeOnlyAliasDeclaration(symbol, SymbolFlags.Value)) { 26196 const target = resolveAlias(symbol); 26197 if (getAllSymbolFlags(target) & (SymbolFlags.Value | SymbolFlags.ExportValue)) { 26198 // An alias resolving to a const enum cannot be elided if (1) 'isolatedModules' is enabled 26199 // (because the const enum value will not be inlined), or if (2) the alias is an export 26200 // of a const enum declaration that will be preserved. 26201 if (compilerOptions.isolatedModules || 26202 shouldPreserveConstEnums(compilerOptions) && isExportOrExportExpression(location) || 26203 !isConstEnumOrConstEnumOnlyModule(getExportSymbolOfValueSymbolIfExported(target)) 26204 ) { 26205 markAliasSymbolAsReferenced(symbol); 26206 } 26207 else { 26208 markConstEnumAliasAsReferenced(symbol); 26209 } 26210 } 26211 } 26212 } 26213 26214 function getNarrowedTypeOfSymbol(symbol: Symbol, location: Identifier) { 26215 const declaration = symbol.valueDeclaration; 26216 if (declaration) { 26217 // If we have a non-rest binding element with no initializer declared as a const variable or a const-like 26218 // parameter (a parameter for which there are no assignments in the function body), and if the parent type 26219 // for the destructuring is a union type, one or more of the binding elements may represent discriminant 26220 // properties, and we want the effects of conditional checks on such discriminants to affect the types of 26221 // other binding elements from the same destructuring. Consider: 26222 // 26223 // type Action = 26224 // | { kind: 'A', payload: number } 26225 // | { kind: 'B', payload: string }; 26226 // 26227 // function f({ kind, payload }: Action) { 26228 // if (kind === 'A') { 26229 // payload.toFixed(); 26230 // } 26231 // if (kind === 'B') { 26232 // payload.toUpperCase(); 26233 // } 26234 // } 26235 // 26236 // Above, we want the conditional checks on 'kind' to affect the type of 'payload'. To facilitate this, we use 26237 // the binding pattern AST instance for '{ kind, payload }' as a pseudo-reference and narrow this reference 26238 // as if it occurred in the specified location. We then recompute the narrowed binding element type by 26239 // destructuring from the narrowed parent type. 26240 if (isBindingElement(declaration) && !declaration.initializer && !declaration.dotDotDotToken && declaration.parent.elements.length >= 2) { 26241 const parent = declaration.parent.parent; 26242 if (parent.kind === SyntaxKind.VariableDeclaration && getCombinedNodeFlags(declaration) & NodeFlags.Const || parent.kind === SyntaxKind.Parameter) { 26243 const links = getNodeLinks(parent); 26244 if (!(links.flags & NodeCheckFlags.InCheckIdentifier)) { 26245 links.flags |= NodeCheckFlags.InCheckIdentifier; 26246 const parentType = getTypeForBindingElementParent(parent, CheckMode.Normal); 26247 const parentTypeConstraint = parentType && mapType(parentType, getBaseConstraintOrType); 26248 links.flags &= ~NodeCheckFlags.InCheckIdentifier; 26249 if (parentTypeConstraint && parentTypeConstraint.flags & TypeFlags.Union && !(parent.kind === SyntaxKind.Parameter && isSymbolAssigned(symbol))) { 26250 const pattern = declaration.parent; 26251 const narrowedType = getFlowTypeOfReference(pattern, parentTypeConstraint, parentTypeConstraint, /*flowContainer*/ undefined, location.flowNode); 26252 if (narrowedType.flags & TypeFlags.Never) { 26253 return neverType; 26254 } 26255 return getBindingElementTypeFromParentType(declaration, narrowedType); 26256 } 26257 } 26258 } 26259 } 26260 // If we have a const-like parameter with no type annotation or initializer, and if the parameter is contextually 26261 // typed by a signature with a single rest parameter of a union of tuple types, one or more of the parameters may 26262 // represent discriminant tuple elements, and we want the effects of conditional checks on such discriminants to 26263 // affect the types of other parameters in the same parameter list. Consider: 26264 // 26265 // type Action = [kind: 'A', payload: number] | [kind: 'B', payload: string]; 26266 // 26267 // const f: (...args: Action) => void = (kind, payload) => { 26268 // if (kind === 'A') { 26269 // payload.toFixed(); 26270 // } 26271 // if (kind === 'B') { 26272 // payload.toUpperCase(); 26273 // } 26274 // } 26275 // 26276 // Above, we want the conditional checks on 'kind' to affect the type of 'payload'. To facilitate this, we use 26277 // the arrow function AST node for '(kind, payload) => ...' as a pseudo-reference and narrow this reference as 26278 // if it occurred in the specified location. We then recompute the narrowed parameter type by indexing into the 26279 // narrowed tuple type. 26280 if (isParameter(declaration) && !declaration.type && !declaration.initializer && !declaration.dotDotDotToken) { 26281 const func = declaration.parent; 26282 if (func.parameters.length >= 2 && isContextSensitiveFunctionOrObjectLiteralMethod(func)) { 26283 const contextualSignature = getContextualSignature(func); 26284 if (contextualSignature && contextualSignature.parameters.length === 1 && signatureHasRestParameter(contextualSignature)) { 26285 const restType = getReducedApparentType(getTypeOfSymbol(contextualSignature.parameters[0])); 26286 if (restType.flags & TypeFlags.Union && everyType(restType, isTupleType) && !isSymbolAssigned(symbol)) { 26287 const narrowedType = getFlowTypeOfReference(func, restType, restType, /*flowContainer*/ undefined, location.flowNode); 26288 const index = func.parameters.indexOf(declaration) - (getThisParameter(func) ? 1 : 0); 26289 return getIndexedAccessType(narrowedType, getNumberLiteralType(index)); 26290 } 26291 } 26292 } 26293 } 26294 } 26295 return getTypeOfSymbol(symbol); 26296 } 26297 26298 function checkIdentifier(node: Identifier, checkMode: CheckMode | undefined): Type { 26299 if (isThisInTypeQuery(node)) { 26300 return checkThisExpression(node); 26301 } 26302 26303 const symbol = getResolvedSymbol(node); 26304 if (symbol === unknownSymbol) { 26305 return errorType; 26306 } 26307 26308 // As noted in ECMAScript 6 language spec, arrow functions never have an arguments objects. 26309 // Although in down-level emit of arrow function, we emit it using function expression which means that 26310 // arguments objects will be bound to the inner object; emitting arrow function natively in ES6, arguments objects 26311 // will be bound to non-arrow function that contain this arrow function. This results in inconsistent behavior. 26312 // To avoid that we will give an error to users if they use arguments objects in arrow function so that they 26313 // can explicitly bound arguments objects 26314 if (symbol === argumentsSymbol) { 26315 if (isInPropertyInitializerOrClassStaticBlock(node)) { 26316 error(node, Diagnostics.arguments_cannot_be_referenced_in_property_initializers); 26317 return errorType; 26318 } 26319 26320 const container = getContainingFunction(node)!; 26321 if (languageVersion < ScriptTarget.ES2015) { 26322 if (container.kind === SyntaxKind.ArrowFunction) { 26323 error(node, Diagnostics.The_arguments_object_cannot_be_referenced_in_an_arrow_function_in_ES3_and_ES5_Consider_using_a_standard_function_expression); 26324 } 26325 else if (hasSyntacticModifier(container, ModifierFlags.Async)) { 26326 error(node, Diagnostics.The_arguments_object_cannot_be_referenced_in_an_async_function_or_method_in_ES3_and_ES5_Consider_using_a_standard_function_or_method); 26327 } 26328 } 26329 26330 getNodeLinks(container).flags |= NodeCheckFlags.CaptureArguments; 26331 checkIdentifierJsDoc(node, symbol); 26332 return getTypeOfSymbol(symbol); 26333 } 26334 26335 if (shouldMarkIdentifierAliasReferenced(node)) { 26336 markAliasReferenced(symbol, node); 26337 } 26338 26339 const localOrExportSymbol = getExportSymbolOfValueSymbolIfExported(symbol); 26340 const targetSymbol = checkDeprecatedAliasedSymbol(localOrExportSymbol, node); 26341 checkIdentifierJsDoc(node, targetSymbol); 26342 if (isDeprecatedSymbol(targetSymbol) && isUncalledFunctionReference(node, targetSymbol) && targetSymbol.declarations) { 26343 addDeprecatedSuggestion(node, targetSymbol.declarations, node.escapedText as string); 26344 } 26345 26346 let declaration = localOrExportSymbol.valueDeclaration; 26347 if (declaration && localOrExportSymbol.flags & SymbolFlags.Class) { 26348 // Due to the emit for class decorators, any reference to the class from inside of the class body 26349 // must instead be rewritten to point to a temporary variable to avoid issues with the double-bind 26350 // behavior of class names in ES6. 26351 if (declaration.kind === SyntaxKind.ClassDeclaration 26352 && nodeIsDecorated(declaration as ClassDeclaration)) { 26353 let container = getContainingClass(node); 26354 while (container !== undefined) { 26355 if (container === declaration && container.name !== node) { 26356 getNodeLinks(declaration).flags |= NodeCheckFlags.ClassWithConstructorReference; 26357 getNodeLinks(node).flags |= NodeCheckFlags.ConstructorReferenceInClass; 26358 break; 26359 } 26360 26361 container = getContainingClass(container); 26362 } 26363 } 26364 else if (declaration.kind === SyntaxKind.ClassExpression) { 26365 // When we emit a class expression with static members that contain a reference 26366 // to the constructor in the initializer, we will need to substitute that 26367 // binding with an alias as the class name is not in scope. 26368 let container = getThisContainer(node, /*includeArrowFunctions*/ false); 26369 while (container.kind !== SyntaxKind.SourceFile) { 26370 if (container.parent === declaration) { 26371 if (isPropertyDeclaration(container) && isStatic(container) || isClassStaticBlockDeclaration(container)) { 26372 getNodeLinks(declaration).flags |= NodeCheckFlags.ClassWithConstructorReference; 26373 getNodeLinks(node).flags |= NodeCheckFlags.ConstructorReferenceInClass; 26374 } 26375 break; 26376 } 26377 26378 container = getThisContainer(container, /*includeArrowFunctions*/ false); 26379 } 26380 } 26381 } 26382 26383 checkNestedBlockScopedBinding(node, symbol); 26384 26385 let type = getNarrowedTypeOfSymbol(localOrExportSymbol, node); 26386 const assignmentKind = getAssignmentTargetKind(node); 26387 26388 if ((localOrExportSymbol.flags & SymbolFlags.Annotation) && 26389 !findAncestor(node, isAnnotationDeclaration) && 26390 !findAncestor(node, isAnnotation) && 26391 !findAncestor(node, isDecorator) && 26392 !findAncestor(node, isImportDeclaration) && 26393 !findAncestor(node, isExportDeclaration) && 26394 !findAncestor(node, isExportAssignment)) { 26395 error(node, Diagnostics.Annotation_cannot_be_used_as_type_or_variable_or_function_or_method); 26396 return errorType; 26397 } 26398 26399 if (assignmentKind) { 26400 if (!(localOrExportSymbol.flags & SymbolFlags.Variable) && 26401 !(isInJSFile(node) && localOrExportSymbol.flags & SymbolFlags.ValueModule)) { 26402 const assignmentError = localOrExportSymbol.flags & SymbolFlags.Enum ? Diagnostics.Cannot_assign_to_0_because_it_is_an_enum 26403 : localOrExportSymbol.flags & SymbolFlags.Class ? Diagnostics.Cannot_assign_to_0_because_it_is_a_class 26404 : localOrExportSymbol.flags & SymbolFlags.Module ? Diagnostics.Cannot_assign_to_0_because_it_is_a_namespace 26405 : localOrExportSymbol.flags & SymbolFlags.Function ? Diagnostics.Cannot_assign_to_0_because_it_is_a_function 26406 : localOrExportSymbol.flags & SymbolFlags.Alias ? Diagnostics.Cannot_assign_to_0_because_it_is_an_import 26407 : Diagnostics.Cannot_assign_to_0_because_it_is_not_a_variable; 26408 26409 error(node, assignmentError, symbolToString(symbol)); 26410 return errorType; 26411 } 26412 if (isReadonlySymbol(localOrExportSymbol)) { 26413 if (localOrExportSymbol.flags & SymbolFlags.Variable) { 26414 error(node, Diagnostics.Cannot_assign_to_0_because_it_is_a_constant, symbolToString(symbol)); 26415 } 26416 else { 26417 error(node, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, symbolToString(symbol)); 26418 } 26419 return errorType; 26420 } 26421 } 26422 26423 const isAlias = localOrExportSymbol.flags & SymbolFlags.Alias; 26424 26425 // We only narrow variables and parameters occurring in a non-assignment position. For all other 26426 // entities we simply return the declared type. 26427 if (localOrExportSymbol.flags & SymbolFlags.Variable) { 26428 if (assignmentKind === AssignmentKind.Definite) { 26429 return type; 26430 } 26431 } 26432 else if (isAlias) { 26433 declaration = getDeclarationOfAliasSymbol(symbol); 26434 } 26435 else { 26436 return type; 26437 } 26438 26439 if (!declaration) { 26440 return type; 26441 } 26442 26443 type = getNarrowableTypeForReference(type, node, checkMode); 26444 26445 // The declaration container is the innermost function that encloses the declaration of the variable 26446 // or parameter. The flow container is the innermost function starting with which we analyze the control 26447 // flow graph to determine the control flow based type. 26448 const isParameter = getRootDeclaration(declaration).kind === SyntaxKind.Parameter; 26449 const declarationContainer = getControlFlowContainer(declaration); 26450 let flowContainer = getControlFlowContainer(node); 26451 const isOuterVariable = flowContainer !== declarationContainer; 26452 const isSpreadDestructuringAssignmentTarget = node.parent && node.parent.parent && isSpreadAssignment(node.parent) && isDestructuringAssignmentTarget(node.parent.parent); 26453 const isModuleExports = symbol.flags & SymbolFlags.ModuleExports; 26454 // When the control flow originates in a function expression or arrow function and we are referencing 26455 // a const variable or parameter from an outer function, we extend the origin of the control flow 26456 // analysis to include the immediately enclosing function. 26457 while (flowContainer !== declarationContainer && (flowContainer.kind === SyntaxKind.FunctionExpression || 26458 flowContainer.kind === SyntaxKind.ArrowFunction || isObjectLiteralOrClassExpressionMethodOrAccessor(flowContainer)) && 26459 (isConstVariable(localOrExportSymbol) && type !== autoArrayType || isParameter && !isSymbolAssigned(localOrExportSymbol))) { 26460 flowContainer = getControlFlowContainer(flowContainer); 26461 } 26462 // We only look for uninitialized variables in strict null checking mode, and only when we can analyze 26463 // the entire control flow graph from the variable's declaration (i.e. when the flow container and 26464 // declaration container are the same). 26465 const assumeInitialized = isParameter || isAlias || isOuterVariable || isSpreadDestructuringAssignmentTarget || isModuleExports || isSameScopedBindingElement(node, declaration) || 26466 type !== autoType && type !== autoArrayType && (!strictNullChecks || (type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Void)) !== 0 || 26467 isInTypeQuery(node) || node.parent.kind === SyntaxKind.ExportSpecifier) || 26468 node.parent.kind === SyntaxKind.NonNullExpression || 26469 declaration.kind === SyntaxKind.VariableDeclaration && (declaration as VariableDeclaration).exclamationToken || 26470 declaration.flags & NodeFlags.Ambient; 26471 const initialType = assumeInitialized ? (isParameter ? removeOptionalityFromDeclaredType(type, declaration as VariableLikeDeclaration) : type) : 26472 type === autoType || type === autoArrayType ? undefinedType : 26473 getOptionalType(type); 26474 const flowType = getFlowTypeOfReference(node, type, initialType, flowContainer); 26475 // A variable is considered uninitialized when it is possible to analyze the entire control flow graph 26476 // from declaration to use, and when the variable's declared type doesn't include undefined but the 26477 // control flow based type does include undefined. 26478 if (!isEvolvingArrayOperationTarget(node) && (type === autoType || type === autoArrayType)) { 26479 if (flowType === autoType || flowType === autoArrayType) { 26480 if (noImplicitAny) { 26481 error(getNameOfDeclaration(declaration), Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined, symbolToString(symbol), typeToString(flowType)); 26482 error(node, Diagnostics.Variable_0_implicitly_has_an_1_type, symbolToString(symbol), typeToString(flowType)); 26483 } 26484 return convertAutoToAny(flowType); 26485 } 26486 } 26487 else if (!assumeInitialized && !containsUndefinedType(type) && containsUndefinedType(flowType)) { 26488 error(node, Diagnostics.Variable_0_is_used_before_being_assigned, symbolToString(symbol)); 26489 // Return the declared type to reduce follow-on errors 26490 return type; 26491 } 26492 return assignmentKind ? getBaseTypeOfLiteralType(flowType) : flowType; 26493 } 26494 26495 function isSameScopedBindingElement(node: Identifier, declaration: Declaration) { 26496 if (isBindingElement(declaration)) { 26497 const bindingElement = findAncestor(node, isBindingElement); 26498 return bindingElement && getRootDeclaration(bindingElement) === getRootDeclaration(declaration); 26499 } 26500 } 26501 26502 function shouldMarkIdentifierAliasReferenced(node: Identifier): boolean { 26503 const parent = node.parent; 26504 if (parent) { 26505 // A property access expression LHS? checkPropertyAccessExpression will handle that. 26506 if (isPropertyAccessExpression(parent) && parent.expression === node) { 26507 return false; 26508 } 26509 // Next two check for an identifier inside a type only export. 26510 if (isExportSpecifier(parent) && parent.isTypeOnly) { 26511 return false; 26512 } 26513 const greatGrandparent = parent.parent?.parent; 26514 if (greatGrandparent && isExportDeclaration(greatGrandparent) && greatGrandparent.isTypeOnly) { 26515 return false; 26516 } 26517 } 26518 return true; 26519 } 26520 26521 function isInsideFunctionOrInstancePropertyInitializer(node: Node, threshold: Node): boolean { 26522 return !!findAncestor(node, n => n === threshold ? "quit" : isFunctionLike(n) || ( 26523 n.parent && isPropertyDeclaration(n.parent) && !hasStaticModifier(n.parent) && n.parent.initializer === n 26524 )); 26525 } 26526 26527 function getPartOfForStatementContainingNode(node: Node, container: ForStatement) { 26528 return findAncestor(node, n => n === container ? "quit" : n === container.initializer || n === container.condition || n === container.incrementor || n === container.statement); 26529 } 26530 26531 function getEnclosingIterationStatement(node: Node): Node | undefined { 26532 return findAncestor(node, n => (!n || nodeStartsNewLexicalEnvironment(n)) ? "quit" : isIterationStatement(n, /*lookInLabeledStatements*/ false)); 26533 } 26534 26535 function checkNestedBlockScopedBinding(node: Identifier, symbol: Symbol): void { 26536 if (languageVersion >= ScriptTarget.ES2015 || 26537 (symbol.flags & (SymbolFlags.BlockScopedVariable | SymbolFlags.Class)) === 0 || 26538 !symbol.valueDeclaration || 26539 isSourceFile(symbol.valueDeclaration) || 26540 symbol.valueDeclaration.parent.kind === SyntaxKind.CatchClause) { 26541 return; 26542 } 26543 26544 // 1. walk from the use site up to the declaration and check 26545 // if there is anything function like between declaration and use-site (is binding/class is captured in function). 26546 // 2. walk from the declaration up to the boundary of lexical environment and check 26547 // if there is an iteration statement in between declaration and boundary (is binding/class declared inside iteration statement) 26548 26549 const container = getEnclosingBlockScopeContainer(symbol.valueDeclaration); 26550 const isCaptured = isInsideFunctionOrInstancePropertyInitializer(node, container); 26551 26552 const enclosingIterationStatement = getEnclosingIterationStatement(container); 26553 if (enclosingIterationStatement) { 26554 if (isCaptured) { 26555 // mark iteration statement as containing block-scoped binding captured in some function 26556 let capturesBlockScopeBindingInLoopBody = true; 26557 if (isForStatement(container)) { 26558 const varDeclList = getAncestor(symbol.valueDeclaration, SyntaxKind.VariableDeclarationList); 26559 if (varDeclList && varDeclList.parent === container) { 26560 const part = getPartOfForStatementContainingNode(node.parent, container); 26561 if (part) { 26562 const links = getNodeLinks(part); 26563 links.flags |= NodeCheckFlags.ContainsCapturedBlockScopeBinding; 26564 26565 const capturedBindings = links.capturedBlockScopeBindings || (links.capturedBlockScopeBindings = []); 26566 pushIfUnique(capturedBindings, symbol); 26567 26568 if (part === container.initializer) { 26569 capturesBlockScopeBindingInLoopBody = false; // Initializer is outside of loop body 26570 } 26571 } 26572 } 26573 } 26574 if (capturesBlockScopeBindingInLoopBody) { 26575 getNodeLinks(enclosingIterationStatement).flags |= NodeCheckFlags.LoopWithCapturedBlockScopedBinding; 26576 } 26577 } 26578 26579 // mark variables that are declared in loop initializer and reassigned inside the body of ForStatement. 26580 // if body of ForStatement will be converted to function then we'll need a extra machinery to propagate reassigned values back. 26581 if (isForStatement(container)) { 26582 const varDeclList = getAncestor(symbol.valueDeclaration, SyntaxKind.VariableDeclarationList); 26583 if (varDeclList && varDeclList.parent === container && isAssignedInBodyOfForStatement(node, container)) { 26584 getNodeLinks(symbol.valueDeclaration).flags |= NodeCheckFlags.NeedsLoopOutParameter; 26585 } 26586 } 26587 26588 // set 'declared inside loop' bit on the block-scoped binding 26589 getNodeLinks(symbol.valueDeclaration).flags |= NodeCheckFlags.BlockScopedBindingInLoop; 26590 } 26591 26592 if (isCaptured) { 26593 getNodeLinks(symbol.valueDeclaration).flags |= NodeCheckFlags.CapturedBlockScopedBinding; 26594 } 26595 } 26596 26597 function isBindingCapturedByNode(node: Node, decl: VariableDeclaration | BindingElement) { 26598 const links = getNodeLinks(node); 26599 return !!links && contains(links.capturedBlockScopeBindings, getSymbolOfNode(decl)); 26600 } 26601 26602 function isAssignedInBodyOfForStatement(node: Identifier, container: ForStatement): boolean { 26603 // skip parenthesized nodes 26604 let current: Node = node; 26605 while (current.parent.kind === SyntaxKind.ParenthesizedExpression) { 26606 current = current.parent; 26607 } 26608 26609 // check if node is used as LHS in some assignment expression 26610 let isAssigned = false; 26611 if (isAssignmentTarget(current)) { 26612 isAssigned = true; 26613 } 26614 else if ((current.parent.kind === SyntaxKind.PrefixUnaryExpression || current.parent.kind === SyntaxKind.PostfixUnaryExpression)) { 26615 const expr = current.parent as PrefixUnaryExpression | PostfixUnaryExpression; 26616 isAssigned = expr.operator === SyntaxKind.PlusPlusToken || expr.operator === SyntaxKind.MinusMinusToken; 26617 } 26618 26619 if (!isAssigned) { 26620 return false; 26621 } 26622 26623 // at this point we know that node is the target of assignment 26624 // now check that modification happens inside the statement part of the ForStatement 26625 return !!findAncestor(current, n => n === container ? "quit" : n === container.statement); 26626 } 26627 26628 function captureLexicalThis(node: Node, container: Node): void { 26629 getNodeLinks(node).flags |= NodeCheckFlags.LexicalThis; 26630 if (container.kind === SyntaxKind.PropertyDeclaration || container.kind === SyntaxKind.Constructor) { 26631 const classNode = container.parent; 26632 getNodeLinks(classNode).flags |= NodeCheckFlags.CaptureThis; 26633 } 26634 else { 26635 getNodeLinks(container).flags |= NodeCheckFlags.CaptureThis; 26636 } 26637 } 26638 26639 function findFirstSuperCall(node: Node): SuperCall | undefined { 26640 return isSuperCall(node) ? node : 26641 isFunctionLike(node) ? undefined : 26642 forEachChild(node, findFirstSuperCall); 26643 } 26644 26645 /** 26646 * Check if the given class-declaration extends null then return true. 26647 * Otherwise, return false 26648 * @param classDecl a class declaration to check if it extends null 26649 */ 26650 function classDeclarationExtendsNull(classDecl: ClassDeclaration): boolean { 26651 const classSymbol = getSymbolOfNode(classDecl); 26652 const classInstanceType = getDeclaredTypeOfSymbol(classSymbol) as InterfaceType; 26653 const baseConstructorType = getBaseConstructorTypeOfClass(classInstanceType); 26654 26655 return baseConstructorType === nullWideningType; 26656 } 26657 26658 function checkThisBeforeSuper(node: Node, container: Node, diagnosticMessage: DiagnosticMessage) { 26659 const containingClassDecl = container.parent as ClassDeclaration; 26660 const baseTypeNode = getClassExtendsHeritageElement(containingClassDecl); 26661 26662 // If a containing class does not have extends clause or the class extends null 26663 // skip checking whether super statement is called before "this" accessing. 26664 if (baseTypeNode && !classDeclarationExtendsNull(containingClassDecl)) { 26665 if (node.flowNode && !isPostSuperFlowNode(node.flowNode, /*noCacheCheck*/ false)) { 26666 error(node, diagnosticMessage); 26667 } 26668 } 26669 } 26670 26671 function checkThisInStaticClassFieldInitializerInDecoratedClass(thisExpression: Node, container: Node) { 26672 if (isPropertyDeclaration(container) && hasStaticModifier(container) && 26673 container.initializer && textRangeContainsPositionInclusive(container.initializer, thisExpression.pos) && hasDecorators(container.parent)) { 26674 error(thisExpression, Diagnostics.Cannot_use_this_in_a_static_property_initializer_of_a_decorated_class); 26675 } 26676 } 26677 26678 function checkThisExpression(node: Node): Type { 26679 const isNodeInTypeQuery = isInTypeQuery(node); 26680 // Stop at the first arrow function so that we can 26681 // tell whether 'this' needs to be captured. 26682 let container = getThisContainer(node, /* includeArrowFunctions */ true); 26683 let capturedByArrowFunction = false; 26684 26685 if (container.kind === SyntaxKind.Constructor) { 26686 checkThisBeforeSuper(node, container, Diagnostics.super_must_be_called_before_accessing_this_in_the_constructor_of_a_derived_class); 26687 } 26688 26689 // Now skip arrow functions to get the "real" owner of 'this'. 26690 if (container.kind === SyntaxKind.ArrowFunction) { 26691 container = getThisContainer(container, /* includeArrowFunctions */ false); 26692 capturedByArrowFunction = true; 26693 } 26694 26695 checkThisInStaticClassFieldInitializerInDecoratedClass(node, container); 26696 switch (container.kind) { 26697 case SyntaxKind.ModuleDeclaration: 26698 error(node, Diagnostics.this_cannot_be_referenced_in_a_module_or_namespace_body); 26699 // do not return here so in case if lexical this is captured - it will be reflected in flags on NodeLinks 26700 break; 26701 case SyntaxKind.EnumDeclaration: 26702 error(node, Diagnostics.this_cannot_be_referenced_in_current_location); 26703 // do not return here so in case if lexical this is captured - it will be reflected in flags on NodeLinks 26704 break; 26705 case SyntaxKind.Constructor: 26706 if (isInConstructorArgumentInitializer(node, container)) { 26707 error(node, Diagnostics.this_cannot_be_referenced_in_constructor_arguments); 26708 // do not return here so in case if lexical this is captured - it will be reflected in flags on NodeLinks 26709 } 26710 break; 26711 case SyntaxKind.ComputedPropertyName: 26712 error(node, Diagnostics.this_cannot_be_referenced_in_a_computed_property_name); 26713 break; 26714 } 26715 26716 // When targeting es6, mark that we'll need to capture `this` in its lexically bound scope. 26717 if (!isNodeInTypeQuery && capturedByArrowFunction && languageVersion < ScriptTarget.ES2015) { 26718 captureLexicalThis(node, container); 26719 } 26720 26721 const type = tryGetThisTypeAt(node, /*includeGlobalThis*/ true, container); 26722 if (noImplicitThis) { 26723 const globalThisType = getTypeOfSymbol(globalThisSymbol); 26724 if (type === globalThisType && capturedByArrowFunction) { 26725 error(node, Diagnostics.The_containing_arrow_function_captures_the_global_value_of_this); 26726 } 26727 else if (!type) { 26728 // With noImplicitThis, functions may not reference 'this' if it has type 'any' 26729 const diag = error(node, Diagnostics.this_implicitly_has_type_any_because_it_does_not_have_a_type_annotation); 26730 if (!isSourceFile(container)) { 26731 const outsideThis = tryGetThisTypeAt(container); 26732 if (outsideThis && outsideThis !== globalThisType) { 26733 addRelatedInfo(diag, createDiagnosticForNode(container, Diagnostics.An_outer_value_of_this_is_shadowed_by_this_container)); 26734 } 26735 } 26736 } 26737 } 26738 return type || anyType; 26739 } 26740 26741 function tryGetThisTypeAt(node: Node, includeGlobalThis = true, container = getThisContainer(node, /*includeArrowFunctions*/ false)): Type | undefined { 26742 const isInJS = isInJSFile(node); 26743 if (isFunctionLike(container) && 26744 (!isInParameterInitializerBeforeContainingFunction(node) || getThisParameter(container))) { 26745 let thisType = getThisTypeOfDeclaration(container) || isInJS && getTypeForThisExpressionFromJSDoc(container); 26746 // Note: a parameter initializer should refer to class-this unless function-this is explicitly annotated. 26747 // If this is a function in a JS file, it might be a class method. 26748 if (!thisType) { 26749 const className = getClassNameFromPrototypeMethod(container); 26750 if (isInJS && className) { 26751 const classSymbol = checkExpression(className).symbol; 26752 if (classSymbol && classSymbol.members && (classSymbol.flags & SymbolFlags.Function)) { 26753 thisType = (getDeclaredTypeOfSymbol(classSymbol) as InterfaceType).thisType; 26754 } 26755 } 26756 else if (isJSConstructor(container)) { 26757 thisType = (getDeclaredTypeOfSymbol(getMergedSymbol(container.symbol)) as InterfaceType).thisType; 26758 } 26759 thisType ||= getContextualThisParameterType(container); 26760 } 26761 26762 if (thisType) { 26763 return getFlowTypeOfReference(node, thisType); 26764 } 26765 } 26766 26767 if (isClassLike(container.parent)) { 26768 const symbol = getSymbolOfNode(container.parent); 26769 const type = isStatic(container) ? getTypeOfSymbol(symbol) : (getDeclaredTypeOfSymbol(symbol) as InterfaceType).thisType!; 26770 return getFlowTypeOfReference(node, type); 26771 } 26772 26773 if (isSourceFile(container)) { 26774 // look up in the source file's locals or exports 26775 if (container.commonJsModuleIndicator) { 26776 const fileSymbol = getSymbolOfNode(container); 26777 return fileSymbol && getTypeOfSymbol(fileSymbol); 26778 } 26779 else if (container.externalModuleIndicator) { 26780 // TODO: Maybe issue a better error than 'object is possibly undefined' 26781 return undefinedType; 26782 } 26783 else if (includeGlobalThis) { 26784 return getTypeOfSymbol(globalThisSymbol); 26785 } 26786 } 26787 } 26788 26789 function getExplicitThisType(node: Expression) { 26790 const container = getThisContainer(node, /*includeArrowFunctions*/ false); 26791 if (isFunctionLike(container)) { 26792 const signature = getSignatureFromDeclaration(container); 26793 if (signature.thisParameter) { 26794 return getExplicitTypeOfSymbol(signature.thisParameter); 26795 } 26796 } 26797 if (isClassLike(container.parent)) { 26798 const symbol = getSymbolOfNode(container.parent); 26799 return isStatic(container) ? getTypeOfSymbol(symbol) : (getDeclaredTypeOfSymbol(symbol) as InterfaceType).thisType!; 26800 } 26801 } 26802 26803 function getClassNameFromPrototypeMethod(container: Node) { 26804 // Check if it's the RHS of a x.prototype.y = function [name]() { .... } 26805 if (container.kind === SyntaxKind.FunctionExpression && 26806 isBinaryExpression(container.parent) && 26807 getAssignmentDeclarationKind(container.parent) === AssignmentDeclarationKind.PrototypeProperty) { 26808 // Get the 'x' of 'x.prototype.y = container' 26809 return ((container.parent // x.prototype.y = container 26810 .left as PropertyAccessExpression) // x.prototype.y 26811 .expression as PropertyAccessExpression) // x.prototype 26812 .expression; // x 26813 } 26814 // x.prototype = { method() { } } 26815 else if (container.kind === SyntaxKind.MethodDeclaration && 26816 container.parent.kind === SyntaxKind.ObjectLiteralExpression && 26817 isBinaryExpression(container.parent.parent) && 26818 getAssignmentDeclarationKind(container.parent.parent) === AssignmentDeclarationKind.Prototype) { 26819 return (container.parent.parent.left as PropertyAccessExpression).expression; 26820 } 26821 // x.prototype = { method: function() { } } 26822 else if (container.kind === SyntaxKind.FunctionExpression && 26823 container.parent.kind === SyntaxKind.PropertyAssignment && 26824 container.parent.parent.kind === SyntaxKind.ObjectLiteralExpression && 26825 isBinaryExpression(container.parent.parent.parent) && 26826 getAssignmentDeclarationKind(container.parent.parent.parent) === AssignmentDeclarationKind.Prototype) { 26827 return (container.parent.parent.parent.left as PropertyAccessExpression).expression; 26828 } 26829 // Object.defineProperty(x, "method", { value: function() { } }); 26830 // Object.defineProperty(x, "method", { set: (x: () => void) => void }); 26831 // Object.defineProperty(x, "method", { get: () => function() { }) }); 26832 else if (container.kind === SyntaxKind.FunctionExpression && 26833 isPropertyAssignment(container.parent) && 26834 isIdentifier(container.parent.name) && 26835 (container.parent.name.escapedText === "value" || container.parent.name.escapedText === "get" || container.parent.name.escapedText === "set") && 26836 isObjectLiteralExpression(container.parent.parent) && 26837 isCallExpression(container.parent.parent.parent) && 26838 container.parent.parent.parent.arguments[2] === container.parent.parent && 26839 getAssignmentDeclarationKind(container.parent.parent.parent) === AssignmentDeclarationKind.ObjectDefinePrototypeProperty) { 26840 return (container.parent.parent.parent.arguments[0] as PropertyAccessExpression).expression; 26841 } 26842 // Object.defineProperty(x, "method", { value() { } }); 26843 // Object.defineProperty(x, "method", { set(x: () => void) {} }); 26844 // Object.defineProperty(x, "method", { get() { return () => {} } }); 26845 else if (isMethodDeclaration(container) && 26846 isIdentifier(container.name) && 26847 (container.name.escapedText === "value" || container.name.escapedText === "get" || container.name.escapedText === "set") && 26848 isObjectLiteralExpression(container.parent) && 26849 isCallExpression(container.parent.parent) && 26850 container.parent.parent.arguments[2] === container.parent && 26851 getAssignmentDeclarationKind(container.parent.parent) === AssignmentDeclarationKind.ObjectDefinePrototypeProperty) { 26852 return (container.parent.parent.arguments[0] as PropertyAccessExpression).expression; 26853 } 26854 } 26855 26856 function getTypeForThisExpressionFromJSDoc(node: Node) { 26857 const jsdocType = getJSDocType(node); 26858 if (jsdocType && jsdocType.kind === SyntaxKind.JSDocFunctionType) { 26859 const jsDocFunctionType = jsdocType as JSDocFunctionType; 26860 if (jsDocFunctionType.parameters.length > 0 && 26861 jsDocFunctionType.parameters[0].name && 26862 (jsDocFunctionType.parameters[0].name as Identifier).escapedText === InternalSymbolName.This) { 26863 return getTypeFromTypeNode(jsDocFunctionType.parameters[0].type!); 26864 } 26865 } 26866 const thisTag = getJSDocThisTag(node); 26867 if (thisTag && thisTag.typeExpression) { 26868 return getTypeFromTypeNode(thisTag.typeExpression); 26869 } 26870 } 26871 26872 function isInConstructorArgumentInitializer(node: Node, constructorDecl: Node): boolean { 26873 return !!findAncestor(node, n => isFunctionLikeDeclaration(n) ? "quit" : n.kind === SyntaxKind.Parameter && n.parent === constructorDecl); 26874 } 26875 26876 function checkSuperExpression(node: Node): Type { 26877 const isCallExpression = node.parent.kind === SyntaxKind.CallExpression && (node.parent as CallExpression).expression === node; 26878 26879 const immediateContainer = getSuperContainer(node, /*stopOnFunctions*/ true); 26880 let container = immediateContainer; 26881 let needToCaptureLexicalThis = false; 26882 let inAsyncFunction = false; 26883 26884 // adjust the container reference in case if super is used inside arrow functions with arbitrarily deep nesting 26885 if (!isCallExpression) { 26886 while (container && container.kind === SyntaxKind.ArrowFunction) { 26887 if (hasSyntacticModifier(container, ModifierFlags.Async)) inAsyncFunction = true; 26888 container = getSuperContainer(container, /*stopOnFunctions*/ true); 26889 needToCaptureLexicalThis = languageVersion < ScriptTarget.ES2015; 26890 } 26891 if (container && hasSyntacticModifier(container, ModifierFlags.Async)) inAsyncFunction = true; 26892 } 26893 26894 const canUseSuperExpression = isLegalUsageOfSuperExpression(container); 26895 let nodeCheckFlag: NodeCheckFlags = 0; 26896 26897 if (!canUseSuperExpression) { 26898 // issue more specific error if super is used in computed property name 26899 // class A { foo() { return "1" }} 26900 // class B { 26901 // [super.foo()]() {} 26902 // } 26903 const current = findAncestor(node, n => n === container ? "quit" : n.kind === SyntaxKind.ComputedPropertyName); 26904 if (current && current.kind === SyntaxKind.ComputedPropertyName) { 26905 error(node, Diagnostics.super_cannot_be_referenced_in_a_computed_property_name); 26906 } 26907 else if (isCallExpression) { 26908 error(node, Diagnostics.Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors); 26909 } 26910 else if (!container || !container.parent || !(isClassLike(container.parent) || container.parent.kind === SyntaxKind.ObjectLiteralExpression)) { 26911 error(node, Diagnostics.super_can_only_be_referenced_in_members_of_derived_classes_or_object_literal_expressions); 26912 } 26913 else { 26914 error(node, Diagnostics.super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class); 26915 } 26916 return errorType; 26917 } 26918 26919 if (!isCallExpression && immediateContainer.kind === SyntaxKind.Constructor) { 26920 checkThisBeforeSuper(node, container, Diagnostics.super_must_be_called_before_accessing_a_property_of_super_in_the_constructor_of_a_derived_class); 26921 } 26922 26923 if (isStatic(container) || isCallExpression) { 26924 nodeCheckFlag = NodeCheckFlags.SuperStatic; 26925 if (!isCallExpression && 26926 languageVersion >= ScriptTarget.ES2015 && languageVersion <= ScriptTarget.ES2021 && 26927 (isPropertyDeclaration(container) || isClassStaticBlockDeclaration(container))) { 26928 // for `super.x` or `super[x]` in a static initializer, mark all enclosing 26929 // block scope containers so that we can report potential collisions with 26930 // `Reflect`. 26931 forEachEnclosingBlockScopeContainer(node.parent, current => { 26932 if (!isSourceFile(current) || isExternalOrCommonJsModule(current)) { 26933 getNodeLinks(current).flags |= NodeCheckFlags.ContainsSuperPropertyInStaticInitializer; 26934 } 26935 }); 26936 } 26937 } 26938 else { 26939 nodeCheckFlag = NodeCheckFlags.SuperInstance; 26940 } 26941 26942 getNodeLinks(node).flags |= nodeCheckFlag; 26943 26944 // Due to how we emit async functions, we need to specialize the emit for an async method that contains a `super` reference. 26945 // This is due to the fact that we emit the body of an async function inside of a generator function. As generator 26946 // functions cannot reference `super`, we emit a helper inside of the method body, but outside of the generator. This helper 26947 // uses an arrow function, which is permitted to reference `super`. 26948 // 26949 // There are two primary ways we can access `super` from within an async method. The first is getting the value of a property 26950 // or indexed access on super, either as part of a right-hand-side expression or call expression. The second is when setting the value 26951 // of a property or indexed access, either as part of an assignment expression or destructuring assignment. 26952 // 26953 // The simplest case is reading a value, in which case we will emit something like the following: 26954 // 26955 // // ts 26956 // ... 26957 // async asyncMethod() { 26958 // let x = await super.asyncMethod(); 26959 // return x; 26960 // } 26961 // ... 26962 // 26963 // // js 26964 // ... 26965 // asyncMethod() { 26966 // const _super = Object.create(null, { 26967 // asyncMethod: { get: () => super.asyncMethod }, 26968 // }); 26969 // return __awaiter(this, arguments, Promise, function *() { 26970 // let x = yield _super.asyncMethod.call(this); 26971 // return x; 26972 // }); 26973 // } 26974 // ... 26975 // 26976 // The more complex case is when we wish to assign a value, especially as part of a destructuring assignment. As both cases 26977 // are legal in ES6, but also likely less frequent, we only emit setters if there is an assignment: 26978 // 26979 // // ts 26980 // ... 26981 // async asyncMethod(ar: Promise<any[]>) { 26982 // [super.a, super.b] = await ar; 26983 // } 26984 // ... 26985 // 26986 // // js 26987 // ... 26988 // asyncMethod(ar) { 26989 // const _super = Object.create(null, { 26990 // a: { get: () => super.a, set: (v) => super.a = v }, 26991 // b: { get: () => super.b, set: (v) => super.b = v } 26992 // }; 26993 // return __awaiter(this, arguments, Promise, function *() { 26994 // [_super.a, _super.b] = yield ar; 26995 // }); 26996 // } 26997 // ... 26998 // 26999 // Creating an object that has getter and setters instead of just an accessor function is required for destructuring assignments 27000 // as a call expression cannot be used as the target of a destructuring assignment while a property access can. 27001 // 27002 // For element access expressions (`super[x]`), we emit a generic helper that forwards the element access in both situations. 27003 if (container.kind === SyntaxKind.MethodDeclaration && inAsyncFunction) { 27004 if (isSuperProperty(node.parent) && isAssignmentTarget(node.parent)) { 27005 getNodeLinks(container).flags |= NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync; 27006 } 27007 else { 27008 getNodeLinks(container).flags |= NodeCheckFlags.MethodWithSuperPropertyAccessInAsync; 27009 } 27010 } 27011 27012 if (needToCaptureLexicalThis) { 27013 // call expressions are allowed only in constructors so they should always capture correct 'this' 27014 // super property access expressions can also appear in arrow functions - 27015 // in this case they should also use correct lexical this 27016 captureLexicalThis(node.parent, container); 27017 } 27018 27019 if (container.parent.kind === SyntaxKind.ObjectLiteralExpression) { 27020 if (languageVersion < ScriptTarget.ES2015) { 27021 error(node, Diagnostics.super_is_only_allowed_in_members_of_object_literal_expressions_when_option_target_is_ES2015_or_higher); 27022 return errorType; 27023 } 27024 else { 27025 // for object literal assume that type of 'super' is 'any' 27026 return anyType; 27027 } 27028 } 27029 27030 // at this point the only legal case for parent is ClassLikeDeclaration 27031 const classLikeDeclaration = container.parent as ClassLikeDeclaration; 27032 if (!getClassExtendsHeritageElement(classLikeDeclaration)) { 27033 error(node, Diagnostics.super_can_only_be_referenced_in_a_derived_class); 27034 return errorType; 27035 } 27036 27037 const classType = getDeclaredTypeOfSymbol(getSymbolOfNode(classLikeDeclaration)) as InterfaceType; 27038 const baseClassType = classType && getBaseTypes(classType)[0]; 27039 if (!baseClassType) { 27040 return errorType; 27041 } 27042 27043 if (container.kind === SyntaxKind.Constructor && isInConstructorArgumentInitializer(node, container)) { 27044 // issue custom error message for super property access in constructor arguments (to be aligned with old compiler) 27045 error(node, Diagnostics.super_cannot_be_referenced_in_constructor_arguments); 27046 return errorType; 27047 } 27048 27049 return nodeCheckFlag === NodeCheckFlags.SuperStatic 27050 ? getBaseConstructorTypeOfClass(classType) 27051 : getTypeWithThisArgument(baseClassType, classType.thisType); 27052 27053 function isLegalUsageOfSuperExpression(container: Node): boolean { 27054 if (!container) { 27055 return false; 27056 } 27057 27058 if (isCallExpression) { 27059 // TS 1.0 SPEC (April 2014): 4.8.1 27060 // Super calls are only permitted in constructors of derived classes 27061 return container.kind === SyntaxKind.Constructor; 27062 } 27063 else { 27064 // TS 1.0 SPEC (April 2014) 27065 // 'super' property access is allowed 27066 // - In a constructor, instance member function, instance member accessor, or instance member variable initializer where this references a derived class instance 27067 // - In a static member function or static member accessor 27068 27069 // topmost container must be something that is directly nested in the class declaration\object literal expression 27070 if (isClassLike(container.parent) || container.parent.kind === SyntaxKind.ObjectLiteralExpression) { 27071 if (isStatic(container)) { 27072 return container.kind === SyntaxKind.MethodDeclaration || 27073 container.kind === SyntaxKind.MethodSignature || 27074 container.kind === SyntaxKind.GetAccessor || 27075 container.kind === SyntaxKind.SetAccessor || 27076 container.kind === SyntaxKind.PropertyDeclaration || 27077 container.kind === SyntaxKind.ClassStaticBlockDeclaration; 27078 } 27079 else { 27080 return container.kind === SyntaxKind.MethodDeclaration || 27081 container.kind === SyntaxKind.MethodSignature || 27082 container.kind === SyntaxKind.GetAccessor || 27083 container.kind === SyntaxKind.SetAccessor || 27084 container.kind === SyntaxKind.PropertyDeclaration || 27085 container.kind === SyntaxKind.PropertySignature || 27086 container.kind === SyntaxKind.Constructor; 27087 } 27088 } 27089 } 27090 27091 return false; 27092 } 27093 } 27094 27095 function getContainingObjectLiteral(func: SignatureDeclaration): ObjectLiteralExpression | undefined { 27096 return (func.kind === SyntaxKind.MethodDeclaration || 27097 func.kind === SyntaxKind.GetAccessor || 27098 func.kind === SyntaxKind.SetAccessor) && func.parent.kind === SyntaxKind.ObjectLiteralExpression ? func.parent : 27099 func.kind === SyntaxKind.FunctionExpression && func.parent.kind === SyntaxKind.PropertyAssignment ? func.parent.parent as ObjectLiteralExpression : 27100 undefined; 27101 } 27102 27103 function getThisTypeArgument(type: Type): Type | undefined { 27104 return getObjectFlags(type) & ObjectFlags.Reference && (type as TypeReference).target === globalThisType ? getTypeArguments(type as TypeReference)[0] : undefined; 27105 } 27106 27107 function getThisTypeFromContextualType(type: Type): Type | undefined { 27108 return mapType(type, t => { 27109 return t.flags & TypeFlags.Intersection ? forEach((t as IntersectionType).types, getThisTypeArgument) : getThisTypeArgument(t); 27110 }); 27111 } 27112 27113 function getContextualThisParameterType(func: SignatureDeclaration): Type | undefined { 27114 if (func.kind === SyntaxKind.ArrowFunction) { 27115 return undefined; 27116 } 27117 if (isContextSensitiveFunctionOrObjectLiteralMethod(func)) { 27118 const contextualSignature = getContextualSignature(func); 27119 if (contextualSignature) { 27120 const thisParameter = contextualSignature.thisParameter; 27121 if (thisParameter) { 27122 return getTypeOfSymbol(thisParameter); 27123 } 27124 } 27125 } 27126 const inJs = isInJSFile(func); 27127 if (noImplicitThis || inJs) { 27128 const containingLiteral = getContainingObjectLiteral(func); 27129 if (containingLiteral) { 27130 // We have an object literal method. Check if the containing object literal has a contextual type 27131 // that includes a ThisType<T>. If so, T is the contextual type for 'this'. We continue looking in 27132 // any directly enclosing object literals. 27133 const contextualType = getApparentTypeOfContextualType(containingLiteral, /*contextFlags*/ undefined); 27134 let literal = containingLiteral; 27135 let type = contextualType; 27136 while (type) { 27137 const thisType = getThisTypeFromContextualType(type); 27138 if (thisType) { 27139 return instantiateType(thisType, getMapperFromContext(getInferenceContext(containingLiteral))); 27140 } 27141 if (literal.parent.kind !== SyntaxKind.PropertyAssignment) { 27142 break; 27143 } 27144 literal = literal.parent.parent as ObjectLiteralExpression; 27145 type = getApparentTypeOfContextualType(literal, /*contextFlags*/ undefined); 27146 } 27147 // There was no contextual ThisType<T> for the containing object literal, so the contextual type 27148 // for 'this' is the non-null form of the contextual type for the containing object literal or 27149 // the type of the object literal itself. 27150 return getWidenedType(contextualType ? getNonNullableType(contextualType) : checkExpressionCached(containingLiteral)); 27151 } 27152 // In an assignment of the form 'obj.xxx = function(...)' or 'obj[xxx] = function(...)', the 27153 // contextual type for 'this' is 'obj'. 27154 const parent = walkUpParenthesizedExpressions(func.parent); 27155 if (parent.kind === SyntaxKind.BinaryExpression && (parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken) { 27156 const target = (parent as BinaryExpression).left; 27157 if (isAccessExpression(target)) { 27158 const { expression } = target; 27159 // Don't contextually type `this` as `exports` in `exports.Point = function(x, y) { this.x = x; this.y = y; }` 27160 if (inJs && isIdentifier(expression)) { 27161 const sourceFile = getSourceFileOfNode(parent); 27162 if (sourceFile.commonJsModuleIndicator && getResolvedSymbol(expression) === sourceFile.symbol) { 27163 return undefined; 27164 } 27165 } 27166 27167 return getWidenedType(checkExpressionCached(expression)); 27168 } 27169 } 27170 } 27171 return undefined; 27172 } 27173 27174 // Return contextual type of parameter or undefined if no contextual type is available 27175 function getContextuallyTypedParameterType(parameter: ParameterDeclaration): Type | undefined { 27176 const func = parameter.parent; 27177 if (!isContextSensitiveFunctionOrObjectLiteralMethod(func)) { 27178 return undefined; 27179 } 27180 const iife = getImmediatelyInvokedFunctionExpression(func); 27181 if (iife && iife.arguments) { 27182 const args = getEffectiveCallArguments(iife); 27183 const indexOfParameter = func.parameters.indexOf(parameter); 27184 if (parameter.dotDotDotToken) { 27185 return getSpreadArgumentType(args, indexOfParameter, args.length, anyType, /*context*/ undefined, CheckMode.Normal); 27186 } 27187 const links = getNodeLinks(iife); 27188 const cached = links.resolvedSignature; 27189 links.resolvedSignature = anySignature; 27190 const type = indexOfParameter < args.length ? 27191 getWidenedLiteralType(checkExpression(args[indexOfParameter])) : 27192 parameter.initializer ? undefined : undefinedWideningType; 27193 links.resolvedSignature = cached; 27194 return type; 27195 } 27196 const contextualSignature = getContextualSignature(func); 27197 if (contextualSignature) { 27198 const index = func.parameters.indexOf(parameter) - (getThisParameter(func) ? 1 : 0); 27199 return parameter.dotDotDotToken && lastOrUndefined(func.parameters) === parameter ? 27200 getRestTypeAtPosition(contextualSignature, index) : 27201 tryGetTypeAtPosition(contextualSignature, index); 27202 } 27203 } 27204 27205 function getContextualTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration, contextFlags: ContextFlags | undefined): Type | undefined { 27206 const typeNode = getEffectiveTypeAnnotationNode(declaration); 27207 if (typeNode) { 27208 return getTypeFromTypeNode(typeNode); 27209 } 27210 switch (declaration.kind) { 27211 case SyntaxKind.Parameter: 27212 return getContextuallyTypedParameterType(declaration); 27213 case SyntaxKind.BindingElement: 27214 return getContextualTypeForBindingElement(declaration, contextFlags); 27215 case SyntaxKind.PropertyDeclaration: 27216 if (isStatic(declaration)) { 27217 return getContextualTypeForStaticPropertyDeclaration(declaration, contextFlags); 27218 } 27219 // By default, do nothing and return undefined - only the above cases have context implied by a parent 27220 } 27221 } 27222 27223 function getContextualTypeForBindingElement(declaration: BindingElement, contextFlags: ContextFlags | undefined): Type | undefined { 27224 const parent = declaration.parent.parent; 27225 const name = declaration.propertyName || declaration.name; 27226 const parentType = getContextualTypeForVariableLikeDeclaration(parent, contextFlags) || 27227 parent.kind !== SyntaxKind.BindingElement && parent.initializer && checkDeclarationInitializer(parent, declaration.dotDotDotToken ? CheckMode.RestBindingElement : CheckMode.Normal); 27228 if (!parentType || isBindingPattern(name) || isComputedNonLiteralName(name)) return undefined; 27229 if (parent.name.kind === SyntaxKind.ArrayBindingPattern) { 27230 const index = indexOfNode(declaration.parent.elements, declaration); 27231 if (index < 0) return undefined; 27232 return getContextualTypeForElementExpression(parentType, index); 27233 } 27234 const nameType = getLiteralTypeFromPropertyName(name); 27235 if (isTypeUsableAsPropertyName(nameType)) { 27236 const text = getPropertyNameFromType(nameType); 27237 return getTypeOfPropertyOfType(parentType, text); 27238 } 27239 } 27240 27241 function getContextualTypeForStaticPropertyDeclaration(declaration: PropertyDeclaration, contextFlags: ContextFlags | undefined): Type | undefined { 27242 const parentType = isExpression(declaration.parent) && getContextualType(declaration.parent, contextFlags); 27243 if (!parentType) return undefined; 27244 return getTypeOfPropertyOfContextualType(parentType, getSymbolOfNode(declaration).escapedName); 27245 } 27246 27247 // In a variable, parameter or property declaration with a type annotation, 27248 // the contextual type of an initializer expression is the type of the variable, parameter or property. 27249 // Otherwise, in a parameter declaration of a contextually typed function expression, 27250 // the contextual type of an initializer expression is the contextual type of the parameter. 27251 // Otherwise, in a variable or parameter declaration with a binding pattern name, 27252 // the contextual type of an initializer expression is the type implied by the binding pattern. 27253 // Otherwise, in a binding pattern inside a variable or parameter declaration, 27254 // the contextual type of an initializer expression is the type annotation of the containing declaration, if present. 27255 function getContextualTypeForInitializerExpression(node: Expression, contextFlags: ContextFlags | undefined): Type | undefined { 27256 const declaration = node.parent as VariableLikeDeclaration; 27257 if (hasInitializer(declaration) && node === declaration.initializer) { 27258 const result = getContextualTypeForVariableLikeDeclaration(declaration, contextFlags); 27259 if (result) { 27260 return result; 27261 } 27262 if (!(contextFlags! & ContextFlags.SkipBindingPatterns) && isBindingPattern(declaration.name) && declaration.name.elements.length > 0) { 27263 return getTypeFromBindingPattern(declaration.name, /*includePatternInType*/ true, /*reportErrors*/ false); 27264 } 27265 } 27266 return undefined; 27267 } 27268 27269 function getContextualTypeForReturnExpression(node: Expression, contextFlags: ContextFlags | undefined): Type | undefined { 27270 const func = getContainingFunction(node); 27271 if (func) { 27272 let contextualReturnType = getContextualReturnType(func, contextFlags); 27273 if (contextualReturnType) { 27274 const functionFlags = getFunctionFlags(func); 27275 if (functionFlags & FunctionFlags.Generator) { // Generator or AsyncGenerator function 27276 const isAsyncGenerator = (functionFlags & FunctionFlags.Async) !== 0; 27277 if (contextualReturnType.flags & TypeFlags.Union) { 27278 contextualReturnType = filterType(contextualReturnType, type => !!getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, type, isAsyncGenerator)); 27279 } 27280 const iterationReturnType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, contextualReturnType, (functionFlags & FunctionFlags.Async) !== 0); 27281 if (!iterationReturnType) { 27282 return undefined; 27283 } 27284 contextualReturnType = iterationReturnType; 27285 // falls through to unwrap Promise for AsyncGenerators 27286 } 27287 27288 if (functionFlags & FunctionFlags.Async) { // Async function or AsyncGenerator function 27289 // Get the awaited type without the `Awaited<T>` alias 27290 const contextualAwaitedType = mapType(contextualReturnType, getAwaitedTypeNoAlias); 27291 return contextualAwaitedType && getUnionType([contextualAwaitedType, createPromiseLikeType(contextualAwaitedType)]); 27292 } 27293 27294 return contextualReturnType; // Regular function or Generator function 27295 } 27296 } 27297 return undefined; 27298 } 27299 27300 function getContextualTypeForAwaitOperand(node: AwaitExpression, contextFlags: ContextFlags | undefined): Type | undefined { 27301 const contextualType = getContextualType(node, contextFlags); 27302 if (contextualType) { 27303 const contextualAwaitedType = getAwaitedTypeNoAlias(contextualType); 27304 return contextualAwaitedType && getUnionType([contextualAwaitedType, createPromiseLikeType(contextualAwaitedType)]); 27305 } 27306 return undefined; 27307 } 27308 27309 function getContextualTypeForYieldOperand(node: YieldExpression, contextFlags: ContextFlags | undefined): Type | undefined { 27310 const func = getContainingFunction(node); 27311 if (func) { 27312 const functionFlags = getFunctionFlags(func); 27313 let contextualReturnType = getContextualReturnType(func, contextFlags); 27314 if (contextualReturnType) { 27315 const isAsyncGenerator = (functionFlags & FunctionFlags.Async) !== 0; 27316 if (!node.asteriskToken && contextualReturnType.flags & TypeFlags.Union) { 27317 contextualReturnType = filterType(contextualReturnType, type => !!getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, type, isAsyncGenerator)); 27318 } 27319 return node.asteriskToken 27320 ? contextualReturnType 27321 : getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Yield, contextualReturnType, isAsyncGenerator); 27322 } 27323 } 27324 27325 return undefined; 27326 } 27327 27328 function isInParameterInitializerBeforeContainingFunction(node: Node) { 27329 let inBindingInitializer = false; 27330 while (node.parent && !isFunctionLike(node.parent)) { 27331 if (isParameter(node.parent) && (inBindingInitializer || node.parent.initializer === node)) { 27332 return true; 27333 } 27334 if (isBindingElement(node.parent) && node.parent.initializer === node) { 27335 inBindingInitializer = true; 27336 } 27337 27338 node = node.parent; 27339 } 27340 27341 return false; 27342 } 27343 27344 function getContextualIterationType(kind: IterationTypeKind, functionDecl: SignatureDeclaration): Type | undefined { 27345 const isAsync = !!(getFunctionFlags(functionDecl) & FunctionFlags.Async); 27346 const contextualReturnType = getContextualReturnType(functionDecl, /*contextFlags*/ undefined); 27347 if (contextualReturnType) { 27348 return getIterationTypeOfGeneratorFunctionReturnType(kind, contextualReturnType, isAsync) 27349 || undefined; 27350 } 27351 27352 return undefined; 27353 } 27354 27355 function getContextualReturnType(functionDecl: SignatureDeclaration, contextFlags: ContextFlags | undefined): Type | undefined { 27356 // If the containing function has a return type annotation, is a constructor, or is a get accessor whose 27357 // corresponding set accessor has a type annotation, return statements in the function are contextually typed 27358 const returnType = getReturnTypeFromAnnotation(functionDecl); 27359 if (returnType) { 27360 return returnType; 27361 } 27362 // Otherwise, if the containing function is contextually typed by a function type with exactly one call signature 27363 // and that call signature is non-generic, return statements are contextually typed by the return type of the signature 27364 const signature = getContextualSignatureForFunctionLikeDeclaration(functionDecl as FunctionExpression); 27365 if (signature && !isResolvingReturnTypeOfSignature(signature)) { 27366 return getReturnTypeOfSignature(signature); 27367 } 27368 const iife = getImmediatelyInvokedFunctionExpression(functionDecl); 27369 if (iife) { 27370 return getContextualType(iife, contextFlags); 27371 } 27372 return undefined; 27373 } 27374 27375 // In a typed function call, an argument or substitution expression is contextually typed by the type of the corresponding parameter. 27376 function getContextualTypeForArgument(callTarget: CallLikeExpression, arg: Expression): Type | undefined { 27377 const args = getEffectiveCallArguments(callTarget); 27378 const argIndex = args.indexOf(arg); // -1 for e.g. the expression of a CallExpression, or the tag of a TaggedTemplateExpression 27379 return argIndex === -1 ? undefined : getContextualTypeForArgumentAtIndex(callTarget, argIndex); 27380 } 27381 27382 function getContextualTypeForArgumentAtIndex(callTarget: CallLikeExpression, argIndex: number): Type { 27383 if (isImportCall(callTarget)) { 27384 return argIndex === 0 ? stringType : 27385 argIndex === 1 ? getGlobalImportCallOptionsType(/*reportErrors*/ false) : 27386 anyType; 27387 } 27388 27389 // If we're already in the process of resolving the given signature, don't resolve again as 27390 // that could cause infinite recursion. Instead, return anySignature. 27391 const signature = getNodeLinks(callTarget).resolvedSignature === resolvingSignature ? resolvingSignature : getResolvedSignature(callTarget); 27392 27393 if (isJsxOpeningLikeElement(callTarget) && argIndex === 0) { 27394 return getEffectiveFirstArgumentForJsxSignature(signature, callTarget); 27395 } 27396 const restIndex = signature.parameters.length - 1; 27397 return signatureHasRestParameter(signature) && argIndex >= restIndex ? 27398 getIndexedAccessType(getTypeOfSymbol(signature.parameters[restIndex]), getNumberLiteralType(argIndex - restIndex), AccessFlags.Contextual) : 27399 getTypeAtPosition(signature, argIndex); 27400 } 27401 27402 function getContextualTypeForSubstitutionExpression(template: TemplateExpression, substitutionExpression: Expression) { 27403 if (template.parent.kind === SyntaxKind.TaggedTemplateExpression) { 27404 return getContextualTypeForArgument(template.parent as TaggedTemplateExpression, substitutionExpression); 27405 } 27406 27407 return undefined; 27408 } 27409 27410 function getContextualTypeForBinaryOperand(node: Expression, contextFlags: ContextFlags | undefined): Type | undefined { 27411 const binaryExpression = node.parent as BinaryExpression; 27412 const { left, operatorToken, right } = binaryExpression; 27413 switch (operatorToken.kind) { 27414 case SyntaxKind.EqualsToken: 27415 case SyntaxKind.AmpersandAmpersandEqualsToken: 27416 case SyntaxKind.BarBarEqualsToken: 27417 case SyntaxKind.QuestionQuestionEqualsToken: 27418 return node === right ? getContextualTypeForAssignmentDeclaration(binaryExpression) : undefined; 27419 case SyntaxKind.BarBarToken: 27420 case SyntaxKind.QuestionQuestionToken: 27421 // When an || expression has a contextual type, the operands are contextually typed by that type, except 27422 // when that type originates in a binding pattern, the right operand is contextually typed by the type of 27423 // the left operand. When an || expression has no contextual type, the right operand is contextually typed 27424 // by the type of the left operand, except for the special case of Javascript declarations of the form 27425 // `namespace.prop = namespace.prop || {}`. 27426 const type = getContextualType(binaryExpression, contextFlags); 27427 return node === right && (type && type.pattern || !type && !isDefaultedExpandoInitializer(binaryExpression)) ? 27428 getTypeOfExpression(left) : type; 27429 case SyntaxKind.AmpersandAmpersandToken: 27430 case SyntaxKind.CommaToken: 27431 return node === right ? getContextualType(binaryExpression, contextFlags) : undefined; 27432 default: 27433 return undefined; 27434 } 27435 } 27436 27437 /** 27438 * Try to find a resolved symbol for an expression without also resolving its type, as 27439 * getSymbolAtLocation would (as that could be reentrant into contextual typing) 27440 */ 27441 function getSymbolForExpression(e: Expression) { 27442 if (e.symbol) { 27443 return e.symbol; 27444 } 27445 if (isIdentifier(e)) { 27446 return getResolvedSymbol(e); 27447 } 27448 if (isPropertyAccessExpression(e)) { 27449 const lhsType = getTypeOfExpression(e.expression); 27450 return isPrivateIdentifier(e.name) ? tryGetPrivateIdentifierPropertyOfType(lhsType, e.name) : getPropertyOfType(lhsType, e.name.escapedText); 27451 } 27452 if (isElementAccessExpression(e)) { 27453 const propType = checkExpressionCached(e.argumentExpression); 27454 if (!isTypeUsableAsPropertyName(propType)) { 27455 return undefined; 27456 } 27457 const lhsType = getTypeOfExpression(e.expression); 27458 return getPropertyOfType(lhsType, getPropertyNameFromType(propType)); 27459 } 27460 return undefined; 27461 27462 function tryGetPrivateIdentifierPropertyOfType(type: Type, id: PrivateIdentifier) { 27463 const lexicallyScopedSymbol = lookupSymbolForPrivateIdentifierDeclaration(id.escapedText, id); 27464 return lexicallyScopedSymbol && getPrivateIdentifierPropertyOfType(type, lexicallyScopedSymbol); 27465 } 27466 } 27467 27468 // In an assignment expression, the right operand is contextually typed by the type of the left operand. 27469 // Don't do this for assignment declarations unless there is a type tag on the assignment, to avoid circularity from checking the right operand. 27470 function getContextualTypeForAssignmentDeclaration(binaryExpression: BinaryExpression): Type | undefined { 27471 const kind = getAssignmentDeclarationKind(binaryExpression); 27472 switch (kind) { 27473 case AssignmentDeclarationKind.None: 27474 case AssignmentDeclarationKind.ThisProperty: 27475 const lhsSymbol = getSymbolForExpression(binaryExpression.left); 27476 const decl = lhsSymbol && lhsSymbol.valueDeclaration; 27477 // Unannotated, uninitialized property declarations have a type implied by their usage in the constructor. 27478 // We avoid calling back into `getTypeOfExpression` and reentering contextual typing to avoid a bogus circularity error in that case. 27479 if (decl && (isPropertyDeclaration(decl) || isPropertySignature(decl))) { 27480 const overallAnnotation = getEffectiveTypeAnnotationNode(decl); 27481 return (overallAnnotation && instantiateType(getTypeFromTypeNode(overallAnnotation), getSymbolLinks(lhsSymbol).mapper)) || 27482 (isPropertyDeclaration(decl) ? decl.initializer && getTypeOfExpression(binaryExpression.left) : undefined); 27483 } 27484 if (kind === AssignmentDeclarationKind.None) { 27485 return getTypeOfExpression(binaryExpression.left); 27486 } 27487 return getContextualTypeForThisPropertyAssignment(binaryExpression); 27488 case AssignmentDeclarationKind.Property: 27489 if (isPossiblyAliasedThisProperty(binaryExpression, kind)) { 27490 return getContextualTypeForThisPropertyAssignment(binaryExpression); 27491 } 27492 // If `binaryExpression.left` was assigned a symbol, then this is a new declaration; otherwise it is an assignment to an existing declaration. 27493 // See `bindStaticPropertyAssignment` in `binder.ts`. 27494 else if (!binaryExpression.left.symbol) { 27495 return getTypeOfExpression(binaryExpression.left); 27496 } 27497 else { 27498 const decl = binaryExpression.left.symbol.valueDeclaration; 27499 if (!decl) { 27500 return undefined; 27501 } 27502 const lhs = cast(binaryExpression.left, isAccessExpression); 27503 const overallAnnotation = getEffectiveTypeAnnotationNode(decl); 27504 if (overallAnnotation) { 27505 return getTypeFromTypeNode(overallAnnotation); 27506 } 27507 else if (isIdentifier(lhs.expression)) { 27508 const id = lhs.expression; 27509 const parentSymbol = resolveName(id, id.escapedText, SymbolFlags.Value, undefined, id.escapedText, /*isUse*/ true); 27510 if (parentSymbol) { 27511 const annotated = parentSymbol.valueDeclaration && getEffectiveTypeAnnotationNode(parentSymbol.valueDeclaration); 27512 if (annotated) { 27513 const nameStr = getElementOrPropertyAccessName(lhs); 27514 if (nameStr !== undefined) { 27515 return getTypeOfPropertyOfContextualType(getTypeFromTypeNode(annotated), nameStr); 27516 } 27517 } 27518 return undefined; 27519 } 27520 } 27521 return isInJSFile(decl) ? undefined : getTypeOfExpression(binaryExpression.left); 27522 } 27523 case AssignmentDeclarationKind.ExportsProperty: 27524 case AssignmentDeclarationKind.Prototype: 27525 case AssignmentDeclarationKind.PrototypeProperty: 27526 case AssignmentDeclarationKind.ModuleExports: 27527 let valueDeclaration: Declaration | undefined; 27528 if (kind !== AssignmentDeclarationKind.ModuleExports) { 27529 valueDeclaration = binaryExpression.left.symbol?.valueDeclaration; 27530 } 27531 valueDeclaration ||= binaryExpression.symbol?.valueDeclaration; 27532 const annotated = valueDeclaration && getEffectiveTypeAnnotationNode(valueDeclaration); 27533 return annotated ? getTypeFromTypeNode(annotated) : undefined; 27534 case AssignmentDeclarationKind.ObjectDefinePropertyValue: 27535 case AssignmentDeclarationKind.ObjectDefinePropertyExports: 27536 case AssignmentDeclarationKind.ObjectDefinePrototypeProperty: 27537 return Debug.fail("Does not apply"); 27538 default: 27539 return Debug.assertNever(kind); 27540 } 27541 } 27542 27543 function isPossiblyAliasedThisProperty(declaration: BinaryExpression, kind = getAssignmentDeclarationKind(declaration)) { 27544 if (kind === AssignmentDeclarationKind.ThisProperty) { 27545 return true; 27546 } 27547 if (!isInJSFile(declaration) || kind !== AssignmentDeclarationKind.Property || !isIdentifier((declaration.left as AccessExpression).expression)) { 27548 return false; 27549 } 27550 const name = ((declaration.left as AccessExpression).expression as Identifier).escapedText; 27551 const symbol = resolveName(declaration.left, name, SymbolFlags.Value, undefined, undefined, /*isUse*/ true, /*excludeGlobals*/ true); 27552 return isThisInitializedDeclaration(symbol?.valueDeclaration); 27553 } 27554 27555 function getContextualTypeForThisPropertyAssignment(binaryExpression: BinaryExpression): Type | undefined { 27556 if (!binaryExpression.symbol) return getTypeOfExpression(binaryExpression.left); 27557 if (binaryExpression.symbol.valueDeclaration) { 27558 const annotated = getEffectiveTypeAnnotationNode(binaryExpression.symbol.valueDeclaration); 27559 if (annotated) { 27560 const type = getTypeFromTypeNode(annotated); 27561 if (type) { 27562 return type; 27563 } 27564 } 27565 } 27566 const thisAccess = cast(binaryExpression.left, isAccessExpression); 27567 if (!isObjectLiteralMethod(getThisContainer(thisAccess.expression, /*includeArrowFunctions*/ false))) { 27568 return undefined; 27569 } 27570 const thisType = checkThisExpression(thisAccess.expression); 27571 const nameStr = getElementOrPropertyAccessName(thisAccess); 27572 return nameStr !== undefined && getTypeOfPropertyOfContextualType(thisType, nameStr) || undefined; 27573 27574 } 27575 27576 function isCircularMappedProperty(symbol: Symbol) { 27577 return !!(getCheckFlags(symbol) & CheckFlags.Mapped && !(symbol as MappedSymbol).type && findResolutionCycleStartIndex(symbol, TypeSystemPropertyName.Type) >= 0); 27578 } 27579 27580 function getTypeOfPropertyOfContextualType(type: Type, name: __String, nameType?: Type) { 27581 return mapType(type, t => { 27582 if (isGenericMappedType(t) && !t.declaration.nameType) { 27583 const constraint = getConstraintTypeFromMappedType(t); 27584 const constraintOfConstraint = getBaseConstraintOfType(constraint) || constraint; 27585 const propertyNameType = nameType || getStringLiteralType(unescapeLeadingUnderscores(name)); 27586 if (isTypeAssignableTo(propertyNameType, constraintOfConstraint)) { 27587 return substituteIndexedMappedType(t, propertyNameType); 27588 } 27589 } 27590 else if (t.flags & TypeFlags.StructuredType) { 27591 const prop = getPropertyOfType(t, name); 27592 if (prop) { 27593 return isCircularMappedProperty(prop) ? undefined : getTypeOfSymbol(prop); 27594 } 27595 if (isTupleType(t)) { 27596 const restType = getRestTypeOfTupleType(t); 27597 if (restType && isNumericLiteralName(name) && +name >= 0) { 27598 return restType; 27599 } 27600 } 27601 return findApplicableIndexInfo(getIndexInfosOfStructuredType(t), nameType || getStringLiteralType(unescapeLeadingUnderscores(name)))?.type; 27602 } 27603 return undefined; 27604 }, /*noReductions*/ true); 27605 } 27606 27607 // In an object literal contextually typed by a type T, the contextual type of a property assignment is the type of 27608 // the matching property in T, if one exists. Otherwise, it is the type of the numeric index signature in T, if one 27609 // exists. Otherwise, it is the type of the string index signature in T, if one exists. 27610 function getContextualTypeForObjectLiteralMethod(node: MethodDeclaration, contextFlags: ContextFlags | undefined): Type | undefined { 27611 Debug.assert(isObjectLiteralMethod(node)); 27612 if (node.flags & NodeFlags.InWithStatement) { 27613 // We cannot answer semantic questions within a with block, do not proceed any further 27614 return undefined; 27615 } 27616 return getContextualTypeForObjectLiteralElement(node, contextFlags); 27617 } 27618 27619 function getContextualTypeForObjectLiteralElement(element: ObjectLiteralElementLike, contextFlags: ContextFlags | undefined) { 27620 const objectLiteral = element.parent as ObjectLiteralExpression; 27621 const propertyAssignmentType = isPropertyAssignment(element) && getContextualTypeForVariableLikeDeclaration(element, contextFlags); 27622 if (propertyAssignmentType) { 27623 return propertyAssignmentType; 27624 } 27625 const type = getApparentTypeOfContextualType(objectLiteral, contextFlags); 27626 if (type) { 27627 if (hasBindableName(element)) { 27628 // For a (non-symbol) computed property, there is no reason to look up the name 27629 // in the type. It will just be "__computed", which does not appear in any 27630 // SymbolTable. 27631 const symbol = getSymbolOfNode(element); 27632 return getTypeOfPropertyOfContextualType(type, symbol.escapedName, getSymbolLinks(symbol).nameType); 27633 } 27634 if (element.name) { 27635 const nameType = getLiteralTypeFromPropertyName(element.name); 27636 // We avoid calling getApplicableIndexInfo here because it performs potentially expensive intersection reduction. 27637 return mapType(type, t => findApplicableIndexInfo(getIndexInfosOfStructuredType(t), nameType)?.type, /*noReductions*/ true); 27638 } 27639 } 27640 return undefined; 27641 } 27642 27643 // In an array literal contextually typed by a type T, the contextual type of an element expression at index N is 27644 // the type of the property with the numeric name N in T, if one exists. Otherwise, if T has a numeric index signature, 27645 // it is the type of the numeric index signature in T. Otherwise, in ES6 and higher, the contextual type is the iterated 27646 // type of T. 27647 function getContextualTypeForElementExpression(arrayContextualType: Type | undefined, index: number): Type | undefined { 27648 return arrayContextualType && ( 27649 getTypeOfPropertyOfContextualType(arrayContextualType, "" + index as __String) 27650 || mapType( 27651 arrayContextualType, 27652 t => getIteratedTypeOrElementType(IterationUse.Element, t, undefinedType, /*errorNode*/ undefined, /*checkAssignability*/ false), 27653 /*noReductions*/ true)); 27654 } 27655 27656 // In a contextually typed conditional expression, the true/false expressions are contextually typed by the same type. 27657 function getContextualTypeForConditionalOperand(node: Expression, contextFlags: ContextFlags | undefined): Type | undefined { 27658 const conditional = node.parent as ConditionalExpression; 27659 return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional, contextFlags) : undefined; 27660 } 27661 27662 function getContextualTypeForChildJsxExpression(node: JsxElement, child: JsxChild, contextFlags: ContextFlags | undefined) { 27663 const attributesType = getApparentTypeOfContextualType(node.openingElement.tagName, contextFlags); 27664 // JSX expression is in children of JSX Element, we will look for an "children" attribute (we get the name from JSX.ElementAttributesProperty) 27665 const jsxChildrenPropertyName = getJsxElementChildrenPropertyName(getJsxNamespaceAt(node)); 27666 if (!(attributesType && !isTypeAny(attributesType) && jsxChildrenPropertyName && jsxChildrenPropertyName !== "")) { 27667 return undefined; 27668 } 27669 const realChildren = getSemanticJsxChildren(node.children); 27670 const childIndex = realChildren.indexOf(child); 27671 const childFieldType = getTypeOfPropertyOfContextualType(attributesType, jsxChildrenPropertyName); 27672 return childFieldType && (realChildren.length === 1 ? childFieldType : mapType(childFieldType, t => { 27673 if (isArrayLikeType(t)) { 27674 return getIndexedAccessType(t, getNumberLiteralType(childIndex)); 27675 } 27676 else { 27677 return t; 27678 } 27679 }, /*noReductions*/ true)); 27680 } 27681 27682 function getContextualTypeForJsxExpression(node: JsxExpression, contextFlags: ContextFlags | undefined): Type | undefined { 27683 const exprParent = node.parent; 27684 return isJsxAttributeLike(exprParent) 27685 ? getContextualType(node, contextFlags) 27686 : isJsxElement(exprParent) 27687 ? getContextualTypeForChildJsxExpression(exprParent, node, contextFlags) 27688 : undefined; 27689 } 27690 27691 function getContextualTypeForJsxAttribute(attribute: JsxAttribute | JsxSpreadAttribute, contextFlags: ContextFlags | undefined): Type | undefined { 27692 // When we trying to resolve JsxOpeningLikeElement as a stateless function element, we will already give its attributes a contextual type 27693 // which is a type of the parameter of the signature we are trying out. 27694 // If there is no contextual type (e.g. we are trying to resolve stateful component), get attributes type from resolving element's tagName 27695 if (isJsxAttribute(attribute)) { 27696 const attributesType = getApparentTypeOfContextualType(attribute.parent, contextFlags); 27697 if (!attributesType || isTypeAny(attributesType)) { 27698 return undefined; 27699 } 27700 return getTypeOfPropertyOfContextualType(attributesType, attribute.name.escapedText); 27701 } 27702 else { 27703 return getContextualType(attribute.parent, contextFlags); 27704 } 27705 } 27706 27707 // Return true if the given expression is possibly a discriminant value. We limit the kinds of 27708 // expressions we check to those that don't depend on their contextual type in order not to cause 27709 // recursive (and possibly infinite) invocations of getContextualType. 27710 function isPossiblyDiscriminantValue(node: Expression): boolean { 27711 switch (node.kind) { 27712 case SyntaxKind.StringLiteral: 27713 case SyntaxKind.NumericLiteral: 27714 case SyntaxKind.BigIntLiteral: 27715 case SyntaxKind.NoSubstitutionTemplateLiteral: 27716 case SyntaxKind.TrueKeyword: 27717 case SyntaxKind.FalseKeyword: 27718 case SyntaxKind.NullKeyword: 27719 case SyntaxKind.Identifier: 27720 case SyntaxKind.UndefinedKeyword: 27721 return true; 27722 case SyntaxKind.PropertyAccessExpression: 27723 case SyntaxKind.ParenthesizedExpression: 27724 return isPossiblyDiscriminantValue((node as PropertyAccessExpression | ParenthesizedExpression).expression); 27725 case SyntaxKind.JsxExpression: 27726 return !(node as JsxExpression).expression || isPossiblyDiscriminantValue((node as JsxExpression).expression!); 27727 } 27728 return false; 27729 } 27730 27731 function discriminateContextualTypeByObjectMembers(node: ObjectLiteralExpression, contextualType: UnionType) { 27732 return getMatchingUnionConstituentForObjectLiteral(contextualType, node) || discriminateTypeByDiscriminableItems(contextualType, 27733 concatenate( 27734 map( 27735 filter(node.properties, p => !!p.symbol && p.kind === SyntaxKind.PropertyAssignment && isPossiblyDiscriminantValue(p.initializer) && isDiscriminantProperty(contextualType, p.symbol.escapedName)), 27736 prop => ([() => getContextFreeTypeOfExpression((prop as PropertyAssignment).initializer), prop.symbol.escapedName] as [() => Type, __String]) 27737 ), 27738 map( 27739 filter(getPropertiesOfType(contextualType), s => !!(s.flags & SymbolFlags.Optional) && !!node?.symbol?.members && !node.symbol.members.has(s.escapedName) && isDiscriminantProperty(contextualType, s.escapedName)), 27740 s => [() => undefinedType, s.escapedName] as [() => Type, __String] 27741 ) 27742 ), 27743 isTypeAssignableTo, 27744 contextualType 27745 ); 27746 } 27747 27748 function discriminateContextualTypeByJSXAttributes(node: JsxAttributes, contextualType: UnionType) { 27749 return discriminateTypeByDiscriminableItems(contextualType, 27750 concatenate( 27751 map( 27752 filter(node.properties, p => !!p.symbol && p.kind === SyntaxKind.JsxAttribute && isDiscriminantProperty(contextualType, p.symbol.escapedName) && (!p.initializer || isPossiblyDiscriminantValue(p.initializer))), 27753 prop => ([!(prop as JsxAttribute).initializer ? (() => trueType) : (() => getContextFreeTypeOfExpression((prop as JsxAttribute).initializer!)), prop.symbol.escapedName] as [() => Type, __String]) 27754 ), 27755 map( 27756 filter(getPropertiesOfType(contextualType), s => !!(s.flags & SymbolFlags.Optional) && !!node?.symbol?.members && !node.symbol.members.has(s.escapedName) && isDiscriminantProperty(contextualType, s.escapedName)), 27757 s => [() => undefinedType, s.escapedName] as [() => Type, __String] 27758 ) 27759 ), 27760 isTypeAssignableTo, 27761 contextualType 27762 ); 27763 } 27764 27765 // Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily 27766 // be "pushed" onto a node using the contextualType property. 27767 function getApparentTypeOfContextualType(node: Expression | MethodDeclaration, contextFlags: ContextFlags | undefined): Type | undefined { 27768 const contextualType = isObjectLiteralMethod(node) ? 27769 getContextualTypeForObjectLiteralMethod(node, contextFlags) : 27770 getContextualType(node, contextFlags); 27771 const instantiatedType = instantiateContextualType(contextualType, node, contextFlags); 27772 if (instantiatedType && !(contextFlags && contextFlags & ContextFlags.NoConstraints && instantiatedType.flags & TypeFlags.TypeVariable)) { 27773 const apparentType = mapType(instantiatedType, getApparentType, /*noReductions*/ true); 27774 return apparentType.flags & TypeFlags.Union && isObjectLiteralExpression(node) ? discriminateContextualTypeByObjectMembers(node, apparentType as UnionType) : 27775 apparentType.flags & TypeFlags.Union && isJsxAttributes(node) ? discriminateContextualTypeByJSXAttributes(node, apparentType as UnionType) : 27776 apparentType; 27777 } 27778 } 27779 27780 // If the given contextual type contains instantiable types and if a mapper representing 27781 // return type inferences is available, instantiate those types using that mapper. 27782 function instantiateContextualType(contextualType: Type | undefined, node: Node, contextFlags: ContextFlags | undefined): Type | undefined { 27783 if (contextualType && maybeTypeOfKind(contextualType, TypeFlags.Instantiable)) { 27784 const inferenceContext = getInferenceContext(node); 27785 // If no inferences have been made, and none of the type parameters for which we are inferring 27786 // specify default types, nothing is gained from instantiating as type parameters would just be 27787 // replaced with their constraints similar to the apparent type. 27788 if (inferenceContext && contextFlags! & ContextFlags.Signature && some(inferenceContext.inferences, hasInferenceCandidatesOrDefault)) { 27789 // For contextual signatures we incorporate all inferences made so far, e.g. from return 27790 // types as well as arguments to the left in a function call. 27791 return instantiateInstantiableTypes(contextualType, inferenceContext.nonFixingMapper); 27792 } 27793 if (inferenceContext?.returnMapper) { 27794 // For other purposes (e.g. determining whether to produce literal types) we only 27795 // incorporate inferences made from the return type in a function call. We remove 27796 // the 'boolean' type from the contextual type such that contextually typed boolean 27797 // literals actually end up widening to 'boolean' (see #48363). 27798 const type = instantiateInstantiableTypes(contextualType, inferenceContext.returnMapper); 27799 return type.flags & TypeFlags.Union && containsType((type as UnionType).types, regularFalseType) && containsType((type as UnionType).types, regularTrueType) ? 27800 filterType(type, t => t !== regularFalseType && t !== regularTrueType) : 27801 type; 27802 } 27803 } 27804 return contextualType; 27805 } 27806 27807 // This function is similar to instantiateType, except that (a) it only instantiates types that 27808 // are classified as instantiable (i.e. it doesn't instantiate object types), and (b) it performs 27809 // no reductions on instantiated union types. 27810 function instantiateInstantiableTypes(type: Type, mapper: TypeMapper): Type { 27811 if (type.flags & TypeFlags.Instantiable) { 27812 return instantiateType(type, mapper); 27813 } 27814 if (type.flags & TypeFlags.Union) { 27815 return getUnionType(map((type as UnionType).types, t => instantiateInstantiableTypes(t, mapper)), UnionReduction.None); 27816 } 27817 if (type.flags & TypeFlags.Intersection) { 27818 return getIntersectionType(map((type as IntersectionType).types, t => instantiateInstantiableTypes(t, mapper))); 27819 } 27820 return type; 27821 } 27822 27823 /** 27824 * Whoa! Do you really want to use this function? 27825 * 27826 * Unless you're trying to get the *non-apparent* type for a 27827 * value-literal type or you're authoring relevant portions of this algorithm, 27828 * you probably meant to use 'getApparentTypeOfContextualType'. 27829 * Otherwise this may not be very useful. 27830 * 27831 * In cases where you *are* working on this function, you should understand 27832 * when it is appropriate to use 'getContextualType' and 'getApparentTypeOfContextualType'. 27833 * 27834 * - Use 'getContextualType' when you are simply going to propagate the result to the expression. 27835 * - Use 'getApparentTypeOfContextualType' when you're going to need the members of the type. 27836 * 27837 * @param node the expression whose contextual type will be returned. 27838 * @returns the contextual type of an expression. 27839 */ 27840 function getContextualType(node: Expression, contextFlags: ContextFlags | undefined): Type | undefined { 27841 if (node.flags & NodeFlags.InWithStatement) { 27842 // We cannot answer semantic questions within a with block, do not proceed any further 27843 return undefined; 27844 } 27845 if (node.contextualType) { 27846 return node.contextualType; 27847 } 27848 const { parent } = node; 27849 switch (parent.kind) { 27850 case SyntaxKind.VariableDeclaration: 27851 case SyntaxKind.Parameter: 27852 case SyntaxKind.PropertyDeclaration: 27853 case SyntaxKind.PropertySignature: 27854 case SyntaxKind.BindingElement: 27855 return getContextualTypeForInitializerExpression(node, contextFlags); 27856 case SyntaxKind.ArrowFunction: 27857 case SyntaxKind.ReturnStatement: 27858 return getContextualTypeForReturnExpression(node, contextFlags); 27859 case SyntaxKind.YieldExpression: 27860 return getContextualTypeForYieldOperand(parent as YieldExpression, contextFlags); 27861 case SyntaxKind.AwaitExpression: 27862 return getContextualTypeForAwaitOperand(parent as AwaitExpression, contextFlags); 27863 case SyntaxKind.CallExpression: 27864 case SyntaxKind.EtsComponentExpression: 27865 if (isInEtsFile(parent) && (<CallExpression | EtsComponentExpression>parent).expression.kind === SyntaxKind.ImportKeyword) { 27866 return stringType; 27867 } 27868 /* falls through */ 27869 case SyntaxKind.NewExpression: 27870 return getContextualTypeForArgument(parent as CallExpression | NewExpression | EtsComponentExpression, node); 27871 case SyntaxKind.TypeAssertionExpression: 27872 case SyntaxKind.AsExpression: 27873 return isConstTypeReference((parent as AssertionExpression).type) ? tryFindWhenConstTypeReference(parent as AssertionExpression) : getTypeFromTypeNode((parent as AssertionExpression).type); 27874 case SyntaxKind.BinaryExpression: 27875 return getContextualTypeForBinaryOperand(node, contextFlags); 27876 case SyntaxKind.PropertyAssignment: 27877 case SyntaxKind.ShorthandPropertyAssignment: 27878 return getContextualTypeForObjectLiteralElement(parent as PropertyAssignment | ShorthandPropertyAssignment, contextFlags); 27879 case SyntaxKind.SpreadAssignment: 27880 return getContextualType(parent.parent as ObjectLiteralExpression, contextFlags); 27881 case SyntaxKind.ArrayLiteralExpression: { 27882 const arrayLiteral = parent as ArrayLiteralExpression; 27883 const type = getApparentTypeOfContextualType(arrayLiteral, contextFlags); 27884 return getContextualTypeForElementExpression(type, indexOfNode(arrayLiteral.elements, node)); 27885 } 27886 case SyntaxKind.ConditionalExpression: 27887 return getContextualTypeForConditionalOperand(node, contextFlags); 27888 case SyntaxKind.TemplateSpan: 27889 Debug.assert(parent.parent.kind === SyntaxKind.TemplateExpression); 27890 return getContextualTypeForSubstitutionExpression(parent.parent as TemplateExpression, node); 27891 case SyntaxKind.ParenthesizedExpression: { 27892 // Like in `checkParenthesizedExpression`, an `/** @type {xyz} */` comment before a parenthesized expression acts as a type cast. 27893 const tag = isInJSFile(parent) ? getJSDocTypeTag(parent) : undefined; 27894 return !tag ? getContextualType(parent as ParenthesizedExpression, contextFlags) : 27895 isJSDocTypeTag(tag) && isConstTypeReference(tag.typeExpression.type) ? tryFindWhenConstTypeReference(parent as ParenthesizedExpression) : 27896 getTypeFromTypeNode(tag.typeExpression.type); 27897 } 27898 case SyntaxKind.NonNullExpression: 27899 return getContextualType(parent as NonNullExpression, contextFlags); 27900 case SyntaxKind.SatisfiesExpression: 27901 return getTypeFromTypeNode((parent as SatisfiesExpression).type); 27902 case SyntaxKind.ExportAssignment: 27903 return tryGetTypeFromEffectiveTypeNode(parent as ExportAssignment); 27904 case SyntaxKind.JsxExpression: 27905 return getContextualTypeForJsxExpression(parent as JsxExpression, contextFlags); 27906 case SyntaxKind.JsxAttribute: 27907 case SyntaxKind.JsxSpreadAttribute: 27908 return getContextualTypeForJsxAttribute(parent as JsxAttribute | JsxSpreadAttribute, contextFlags); 27909 case SyntaxKind.JsxOpeningElement: 27910 case SyntaxKind.JsxSelfClosingElement: 27911 return getContextualJsxElementAttributesType(parent as JsxOpeningLikeElement, contextFlags); 27912 } 27913 return undefined; 27914 27915 function tryFindWhenConstTypeReference(node: Expression) { 27916 return getContextualType(node, contextFlags); 27917 } 27918 } 27919 27920 function getInferenceContext(node: Node) { 27921 const ancestor = findAncestor(node, n => !!n.inferenceContext); 27922 return ancestor && ancestor.inferenceContext!; 27923 } 27924 27925 function getContextualJsxElementAttributesType(node: JsxOpeningLikeElement, contextFlags: ContextFlags | undefined) { 27926 if (isJsxOpeningElement(node) && node.parent.contextualType && contextFlags !== ContextFlags.Completions) { 27927 // Contextually applied type is moved from attributes up to the outer jsx attributes so when walking up from the children they get hit 27928 // _However_ to hit them from the _attributes_ we must look for them here; otherwise we'll used the declared type 27929 // (as below) instead! 27930 return node.parent.contextualType; 27931 } 27932 return getContextualTypeForArgumentAtIndex(node, 0); 27933 } 27934 27935 function getEffectiveFirstArgumentForJsxSignature(signature: Signature, node: JsxOpeningLikeElement) { 27936 return getJsxReferenceKind(node) !== JsxReferenceKind.Component 27937 ? getJsxPropsTypeFromCallSignature(signature, node) 27938 : getJsxPropsTypeFromClassType(signature, node); 27939 } 27940 27941 function getJsxPropsTypeFromCallSignature(sig: Signature, context: JsxOpeningLikeElement) { 27942 let propsType = getTypeOfFirstParameterOfSignatureWithFallback(sig, unknownType); 27943 propsType = getJsxManagedAttributesFromLocatedAttributes(context, getJsxNamespaceAt(context), propsType); 27944 const intrinsicAttribs = getJsxType(JsxNames.IntrinsicAttributes, context); 27945 if (!isErrorType(intrinsicAttribs)) { 27946 propsType = intersectTypes(intrinsicAttribs, propsType); 27947 } 27948 return propsType; 27949 } 27950 27951 function getJsxPropsTypeForSignatureFromMember(sig: Signature, forcedLookupLocation: __String) { 27952 if (sig.compositeSignatures) { 27953 // JSX Elements using the legacy `props`-field based lookup (eg, react class components) need to treat the `props` member as an input 27954 // instead of an output position when resolving the signature. We need to go back to the input signatures of the composite signature, 27955 // get the type of `props` on each return type individually, and then _intersect them_, rather than union them (as would normally occur 27956 // for a union signature). It's an unfortunate quirk of looking in the output of the signature for the type we want to use for the input. 27957 // The default behavior of `getTypeOfFirstParameterOfSignatureWithFallback` when no `props` member name is defined is much more sane. 27958 const results: Type[] = []; 27959 for (const signature of sig.compositeSignatures) { 27960 const instance = getReturnTypeOfSignature(signature); 27961 if (isTypeAny(instance)) { 27962 return instance; 27963 } 27964 const propType = getTypeOfPropertyOfType(instance, forcedLookupLocation); 27965 if (!propType) { 27966 return; 27967 } 27968 results.push(propType); 27969 } 27970 return getIntersectionType(results); // Same result for both union and intersection signatures 27971 } 27972 const instanceType = getReturnTypeOfSignature(sig); 27973 return isTypeAny(instanceType) ? instanceType : getTypeOfPropertyOfType(instanceType, forcedLookupLocation); 27974 } 27975 27976 function getStaticTypeOfReferencedJsxConstructor(context: JsxOpeningLikeElement) { 27977 if (isJsxIntrinsicIdentifier(context.tagName)) { 27978 const result = getIntrinsicAttributesTypeFromJsxOpeningLikeElement(context); 27979 const fakeSignature = createSignatureForJSXIntrinsic(context, result); 27980 return getOrCreateTypeFromSignature(fakeSignature); 27981 } 27982 const tagType = checkExpressionCached(context.tagName); 27983 if (tagType.flags & TypeFlags.StringLiteral) { 27984 const result = getIntrinsicAttributesTypeFromStringLiteralType(tagType as StringLiteralType, context); 27985 if (!result) { 27986 return errorType; 27987 } 27988 const fakeSignature = createSignatureForJSXIntrinsic(context, result); 27989 return getOrCreateTypeFromSignature(fakeSignature); 27990 } 27991 return tagType; 27992 } 27993 27994 function getJsxManagedAttributesFromLocatedAttributes(context: JsxOpeningLikeElement, ns: Symbol, attributesType: Type) { 27995 const managedSym = getJsxLibraryManagedAttributes(ns); 27996 if (managedSym) { 27997 const declaredManagedType = getDeclaredTypeOfSymbol(managedSym); // fetches interface type, or initializes symbol links type parmaeters 27998 const ctorType = getStaticTypeOfReferencedJsxConstructor(context); 27999 if (managedSym.flags & SymbolFlags.TypeAlias) { 28000 const params = getSymbolLinks(managedSym).typeParameters; 28001 if (length(params) >= 2) { 28002 const args = fillMissingTypeArguments([ctorType, attributesType], params, 2, isInJSFile(context)); 28003 return getTypeAliasInstantiation(managedSym, args); 28004 } 28005 } 28006 if (length((declaredManagedType as GenericType).typeParameters) >= 2) { 28007 const args = fillMissingTypeArguments([ctorType, attributesType], (declaredManagedType as GenericType).typeParameters, 2, isInJSFile(context)); 28008 return createTypeReference((declaredManagedType as GenericType), args); 28009 } 28010 } 28011 return attributesType; 28012 } 28013 28014 function getJsxPropsTypeFromClassType(sig: Signature, context: JsxOpeningLikeElement) { 28015 const ns = getJsxNamespaceAt(context); 28016 const forcedLookupLocation = getJsxElementPropertiesName(ns); 28017 let attributesType = forcedLookupLocation === undefined 28018 // If there is no type ElementAttributesProperty, return the type of the first parameter of the signature, which should be the props type 28019 ? getTypeOfFirstParameterOfSignatureWithFallback(sig, unknownType) 28020 : forcedLookupLocation === "" 28021 // If there is no e.g. 'props' member in ElementAttributesProperty, use the element class type instead 28022 ? getReturnTypeOfSignature(sig) 28023 // Otherwise get the type of the property on the signature return type 28024 : getJsxPropsTypeForSignatureFromMember(sig, forcedLookupLocation); 28025 28026 if (!attributesType) { 28027 // There is no property named 'props' on this instance type 28028 if (!!forcedLookupLocation && !!length(context.attributes.properties)) { 28029 error(context, Diagnostics.JSX_element_class_does_not_support_attributes_because_it_does_not_have_a_0_property, unescapeLeadingUnderscores(forcedLookupLocation)); 28030 } 28031 return unknownType; 28032 } 28033 28034 attributesType = getJsxManagedAttributesFromLocatedAttributes(context, ns, attributesType); 28035 28036 if (isTypeAny(attributesType)) { 28037 // Props is of type 'any' or unknown 28038 return attributesType; 28039 } 28040 else { 28041 // Normal case -- add in IntrinsicClassElements<T> and IntrinsicElements 28042 let apparentAttributesType = attributesType; 28043 const intrinsicClassAttribs = getJsxType(JsxNames.IntrinsicClassAttributes, context); 28044 if (!isErrorType(intrinsicClassAttribs)) { 28045 const typeParams = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(intrinsicClassAttribs.symbol); 28046 const hostClassType = getReturnTypeOfSignature(sig); 28047 let libraryManagedAttributeType: Type; 28048 if (typeParams) { 28049 // apply JSX.IntrinsicClassElements<hostClassType, ...> 28050 const inferredArgs = fillMissingTypeArguments([hostClassType], typeParams, getMinTypeArgumentCount(typeParams), isInJSFile(context)); 28051 libraryManagedAttributeType = instantiateType(intrinsicClassAttribs, createTypeMapper(typeParams, inferredArgs)); 28052 } 28053 // or JSX.IntrinsicClassElements has no generics. 28054 else libraryManagedAttributeType = intrinsicClassAttribs; 28055 apparentAttributesType = intersectTypes(libraryManagedAttributeType, apparentAttributesType); 28056 } 28057 28058 const intrinsicAttribs = getJsxType(JsxNames.IntrinsicAttributes, context); 28059 if (!isErrorType(intrinsicAttribs)) { 28060 apparentAttributesType = intersectTypes(intrinsicAttribs, apparentAttributesType); 28061 } 28062 28063 return apparentAttributesType; 28064 } 28065 } 28066 28067 function getIntersectedSignatures(signatures: readonly Signature[]) { 28068 return getStrictOptionValue(compilerOptions, "noImplicitAny") 28069 ? reduceLeft( 28070 signatures, 28071 (left, right) => 28072 left === right || !left ? left 28073 : compareTypeParametersIdentical(left.typeParameters, right.typeParameters) ? combineSignaturesOfIntersectionMembers(left, right) 28074 : undefined) 28075 : undefined; 28076 } 28077 28078 function combineIntersectionThisParam(left: Symbol | undefined, right: Symbol | undefined, mapper: TypeMapper | undefined): Symbol | undefined { 28079 if (!left || !right) { 28080 return left || right; 28081 } 28082 // A signature `this` type might be a read or a write position... It's very possible that it should be invariant 28083 // and we should refuse to merge signatures if there are `this` types and they do not match. However, so as to be 28084 // pessimistic when contextual typing, for now, we'll union the `this` types. 28085 const thisType = getUnionType([getTypeOfSymbol(left), instantiateType(getTypeOfSymbol(right), mapper)]); 28086 return createSymbolWithType(left, thisType); 28087 } 28088 28089 function combineIntersectionParameters(left: Signature, right: Signature, mapper: TypeMapper | undefined) { 28090 const leftCount = getParameterCount(left); 28091 const rightCount = getParameterCount(right); 28092 const longest = leftCount >= rightCount ? left : right; 28093 const shorter = longest === left ? right : left; 28094 const longestCount = longest === left ? leftCount : rightCount; 28095 const eitherHasEffectiveRest = (hasEffectiveRestParameter(left) || hasEffectiveRestParameter(right)); 28096 const needsExtraRestElement = eitherHasEffectiveRest && !hasEffectiveRestParameter(longest); 28097 const params = new Array<Symbol>(longestCount + (needsExtraRestElement ? 1 : 0)); 28098 for (let i = 0; i < longestCount; i++) { 28099 let longestParamType = tryGetTypeAtPosition(longest, i)!; 28100 if (longest === right) { 28101 longestParamType = instantiateType(longestParamType, mapper); 28102 } 28103 let shorterParamType = tryGetTypeAtPosition(shorter, i) || unknownType; 28104 if (shorter === right) { 28105 shorterParamType = instantiateType(shorterParamType, mapper); 28106 } 28107 const unionParamType = getUnionType([longestParamType, shorterParamType]); 28108 const isRestParam = eitherHasEffectiveRest && !needsExtraRestElement && i === (longestCount - 1); 28109 const isOptional = i >= getMinArgumentCount(longest) && i >= getMinArgumentCount(shorter); 28110 const leftName = i >= leftCount ? undefined : getParameterNameAtPosition(left, i); 28111 const rightName = i >= rightCount ? undefined : getParameterNameAtPosition(right, i); 28112 28113 const paramName = leftName === rightName ? leftName : 28114 !leftName ? rightName : 28115 !rightName ? leftName : 28116 undefined; 28117 const paramSymbol = createSymbol( 28118 SymbolFlags.FunctionScopedVariable | (isOptional && !isRestParam ? SymbolFlags.Optional : 0), 28119 paramName || `arg${i}` as __String 28120 ); 28121 paramSymbol.type = isRestParam ? createArrayType(unionParamType) : unionParamType; 28122 params[i] = paramSymbol; 28123 } 28124 if (needsExtraRestElement) { 28125 const restParamSymbol = createSymbol(SymbolFlags.FunctionScopedVariable, "args" as __String); 28126 restParamSymbol.type = createArrayType(getTypeAtPosition(shorter, longestCount)); 28127 if (shorter === right) { 28128 restParamSymbol.type = instantiateType(restParamSymbol.type, mapper); 28129 } 28130 params[longestCount] = restParamSymbol; 28131 } 28132 return params; 28133 } 28134 28135 function combineSignaturesOfIntersectionMembers(left: Signature, right: Signature): Signature { 28136 const typeParams = left.typeParameters || right.typeParameters; 28137 let paramMapper: TypeMapper | undefined; 28138 if (left.typeParameters && right.typeParameters) { 28139 paramMapper = createTypeMapper(right.typeParameters, left.typeParameters); 28140 // We just use the type parameter defaults from the first signature 28141 } 28142 const declaration = left.declaration; 28143 const params = combineIntersectionParameters(left, right, paramMapper); 28144 const thisParam = combineIntersectionThisParam(left.thisParameter, right.thisParameter, paramMapper); 28145 const minArgCount = Math.max(left.minArgumentCount, right.minArgumentCount); 28146 const result = createSignature( 28147 declaration, 28148 typeParams, 28149 thisParam, 28150 params, 28151 /*resolvedReturnType*/ undefined, 28152 /*resolvedTypePredicate*/ undefined, 28153 minArgCount, 28154 (left.flags | right.flags) & SignatureFlags.PropagatingFlags 28155 ); 28156 result.compositeKind = TypeFlags.Intersection; 28157 result.compositeSignatures = concatenate(left.compositeKind === TypeFlags.Intersection && left.compositeSignatures || [left], [right]); 28158 if (paramMapper) { 28159 result.mapper = left.compositeKind === TypeFlags.Intersection && left.mapper && left.compositeSignatures ? combineTypeMappers(left.mapper, paramMapper) : paramMapper; 28160 } 28161 return result; 28162 } 28163 28164 // If the given type is an object or union type with a single signature, and if that signature has at 28165 // least as many parameters as the given function, return the signature. Otherwise return undefined. 28166 function getContextualCallSignature(type: Type, node: SignatureDeclaration): Signature | undefined { 28167 const signatures = getSignaturesOfType(type, SignatureKind.Call); 28168 const applicableByArity = filter(signatures, s => !isAritySmaller(s, node)); 28169 return applicableByArity.length === 1 ? applicableByArity[0] : getIntersectedSignatures(applicableByArity); 28170 } 28171 28172 /** If the contextual signature has fewer parameters than the function expression, do not use it */ 28173 function isAritySmaller(signature: Signature, target: SignatureDeclaration) { 28174 let targetParameterCount = 0; 28175 for (; targetParameterCount < target.parameters.length; targetParameterCount++) { 28176 const param = target.parameters[targetParameterCount]; 28177 if (param.initializer || param.questionToken || param.dotDotDotToken || isJSDocOptionalParameter(param)) { 28178 break; 28179 } 28180 } 28181 if (target.parameters.length && parameterIsThisKeyword(target.parameters[0])) { 28182 targetParameterCount--; 28183 } 28184 return !hasEffectiveRestParameter(signature) && getParameterCount(signature) < targetParameterCount; 28185 } 28186 28187 function getContextualSignatureForFunctionLikeDeclaration(node: FunctionLikeDeclaration): Signature | undefined { 28188 // Only function expressions, arrow functions, and object literal methods are contextually typed. 28189 return isFunctionExpressionOrArrowFunction(node) || isObjectLiteralMethod(node) 28190 ? getContextualSignature(node as FunctionExpression) 28191 : undefined; 28192 } 28193 28194 // Return the contextual signature for a given expression node. A contextual type provides a 28195 // contextual signature if it has a single call signature and if that call signature is non-generic. 28196 // If the contextual type is a union type, get the signature from each type possible and if they are 28197 // all identical ignoring their return type, the result is same signature but with return type as 28198 // union type of return types from these signatures 28199 function getContextualSignature(node: FunctionExpression | ArrowFunction | MethodDeclaration): Signature | undefined { 28200 Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); 28201 const typeTagSignature = getSignatureOfTypeTag(node); 28202 if (typeTagSignature) { 28203 return typeTagSignature; 28204 } 28205 const type = getApparentTypeOfContextualType(node, ContextFlags.Signature); 28206 if (!type) { 28207 return undefined; 28208 } 28209 if (!(type.flags & TypeFlags.Union)) { 28210 return getContextualCallSignature(type, node); 28211 } 28212 let signatureList: Signature[] | undefined; 28213 const types = (type as UnionType).types; 28214 for (const current of types) { 28215 const signature = getContextualCallSignature(current, node); 28216 if (signature) { 28217 if (!signatureList) { 28218 // This signature will contribute to contextual union signature 28219 signatureList = [signature]; 28220 } 28221 else if (!compareSignaturesIdentical(signatureList[0], signature, /*partialMatch*/ false, /*ignoreThisTypes*/ true, /*ignoreReturnTypes*/ true, compareTypesIdentical)) { 28222 // Signatures aren't identical, do not use 28223 return undefined; 28224 } 28225 else { 28226 // Use this signature for contextual union signature 28227 signatureList.push(signature); 28228 } 28229 } 28230 } 28231 // Result is union of signatures collected (return type is union of return types of this signature set) 28232 if (signatureList) { 28233 return signatureList.length === 1 ? signatureList[0] : createUnionSignature(signatureList[0], signatureList); 28234 } 28235 } 28236 28237 function checkSpreadExpression(node: SpreadElement, checkMode?: CheckMode): Type { 28238 if (languageVersion < ScriptTarget.ES2015) { 28239 checkExternalEmitHelpers(node, compilerOptions.downlevelIteration ? ExternalEmitHelpers.SpreadIncludes : ExternalEmitHelpers.SpreadArray); 28240 } 28241 28242 const arrayOrIterableType = checkExpression(node.expression, checkMode); 28243 return checkIteratedTypeOrElementType(IterationUse.Spread, arrayOrIterableType, undefinedType, node.expression); 28244 } 28245 28246 function checkSyntheticExpression(node: SyntheticExpression): Type { 28247 return node.isSpread ? getIndexedAccessType(node.type, numberType) : node.type; 28248 } 28249 28250 function hasDefaultValue(node: BindingElement | Expression): boolean { 28251 return (node.kind === SyntaxKind.BindingElement && !!(node as BindingElement).initializer) || 28252 (node.kind === SyntaxKind.BinaryExpression && (node as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken); 28253 } 28254 28255 function checkArrayLiteral(node: ArrayLiteralExpression, checkMode: CheckMode | undefined, forceTuple: boolean | undefined): Type { 28256 const elements = node.elements; 28257 const elementCount = elements.length; 28258 const elementTypes: Type[] = []; 28259 const elementFlags: ElementFlags[] = []; 28260 const contextualType = getApparentTypeOfContextualType(node, /*contextFlags*/ undefined); 28261 const inDestructuringPattern = isAssignmentTarget(node); 28262 const inConstContext = isConstContext(node); 28263 let hasOmittedExpression = false; 28264 for (let i = 0; i < elementCount; i++) { 28265 const e = elements[i]; 28266 if (e.kind === SyntaxKind.SpreadElement) { 28267 if (languageVersion < ScriptTarget.ES2015) { 28268 checkExternalEmitHelpers(e, compilerOptions.downlevelIteration ? ExternalEmitHelpers.SpreadIncludes : ExternalEmitHelpers.SpreadArray); 28269 } 28270 const spreadType = checkExpression((e as SpreadElement).expression, checkMode, forceTuple); 28271 if (isArrayLikeType(spreadType)) { 28272 elementTypes.push(spreadType); 28273 elementFlags.push(ElementFlags.Variadic); 28274 } 28275 else if (inDestructuringPattern) { 28276 // Given the following situation: 28277 // var c: {}; 28278 // [...c] = ["", 0]; 28279 // 28280 // c is represented in the tree as a spread element in an array literal. 28281 // But c really functions as a rest element, and its purpose is to provide 28282 // a contextual type for the right hand side of the assignment. Therefore, 28283 // instead of calling checkExpression on "...c", which will give an error 28284 // if c is not iterable/array-like, we need to act as if we are trying to 28285 // get the contextual element type from it. So we do something similar to 28286 // getContextualTypeForElementExpression, which will crucially not error 28287 // if there is no index type / iterated type. 28288 const restElementType = getIndexTypeOfType(spreadType, numberType) || 28289 getIteratedTypeOrElementType(IterationUse.Destructuring, spreadType, undefinedType, /*errorNode*/ undefined, /*checkAssignability*/ false) || 28290 unknownType; 28291 elementTypes.push(restElementType); 28292 elementFlags.push(ElementFlags.Rest); 28293 } 28294 else { 28295 elementTypes.push(checkIteratedTypeOrElementType(IterationUse.Spread, spreadType, undefinedType, (e as SpreadElement).expression)); 28296 elementFlags.push(ElementFlags.Rest); 28297 } 28298 } 28299 else if (exactOptionalPropertyTypes && e.kind === SyntaxKind.OmittedExpression) { 28300 hasOmittedExpression = true; 28301 elementTypes.push(missingType); 28302 elementFlags.push(ElementFlags.Optional); 28303 } 28304 else { 28305 const elementContextualType = getContextualTypeForElementExpression(contextualType, elementTypes.length); 28306 const type = checkExpressionForMutableLocation(e, checkMode, elementContextualType, forceTuple); 28307 elementTypes.push(addOptionality(type, /*isProperty*/ true, hasOmittedExpression)); 28308 elementFlags.push(hasOmittedExpression ? ElementFlags.Optional : ElementFlags.Required); 28309 if (contextualType && someType(contextualType, isTupleLikeType) && checkMode && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && isContextSensitive(e)) { 28310 const inferenceContext = getInferenceContext(node); 28311 Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context 28312 addIntraExpressionInferenceSite(inferenceContext, e, type); 28313 } 28314 } 28315 } 28316 if (inDestructuringPattern) { 28317 return createTupleType(elementTypes, elementFlags); 28318 } 28319 if (forceTuple || inConstContext || contextualType && someType(contextualType, isTupleLikeType)) { 28320 return createArrayLiteralType(createTupleType(elementTypes, elementFlags, /*readonly*/ inConstContext)); 28321 } 28322 return createArrayLiteralType(createArrayType(elementTypes.length ? 28323 getUnionType(sameMap(elementTypes, (t, i) => elementFlags[i] & ElementFlags.Variadic ? getIndexedAccessTypeOrUndefined(t, numberType) || anyType : t), UnionReduction.Subtype) : 28324 strictNullChecks ? implicitNeverType : undefinedWideningType, inConstContext)); 28325 } 28326 28327 function createArrayLiteralType(type: Type) { 28328 if (!(getObjectFlags(type) & ObjectFlags.Reference)) { 28329 return type; 28330 } 28331 let literalType = (type as TypeReference).literalType; 28332 if (!literalType) { 28333 literalType = (type as TypeReference).literalType = cloneTypeReference(type as TypeReference); 28334 literalType.objectFlags |= ObjectFlags.ArrayLiteral | ObjectFlags.ContainsObjectOrArrayLiteral; 28335 } 28336 return literalType; 28337 } 28338 28339 function isNumericName(name: DeclarationName): boolean { 28340 switch (name.kind) { 28341 case SyntaxKind.ComputedPropertyName: 28342 return isNumericComputedName(name); 28343 case SyntaxKind.Identifier: 28344 return isNumericLiteralName(name.escapedText); 28345 case SyntaxKind.NumericLiteral: 28346 case SyntaxKind.StringLiteral: 28347 return isNumericLiteralName(name.text); 28348 default: 28349 return false; 28350 } 28351 } 28352 28353 function isNumericComputedName(name: ComputedPropertyName): boolean { 28354 // It seems odd to consider an expression of type Any to result in a numeric name, 28355 // but this behavior is consistent with checkIndexedAccess 28356 return isTypeAssignableToKind(checkComputedPropertyName(name), TypeFlags.NumberLike); 28357 } 28358 28359 function checkComputedPropertyName(node: ComputedPropertyName): Type { 28360 const links = getNodeLinks(node.expression); 28361 if (!links.resolvedType) { 28362 if ((isTypeLiteralNode(node.parent.parent) || isClassLike(node.parent.parent) || isInterfaceDeclaration(node.parent.parent)) 28363 && isBinaryExpression(node.expression) && node.expression.operatorToken.kind === SyntaxKind.InKeyword 28364 && node.parent.kind !== SyntaxKind.GetAccessor && node.parent.kind !== SyntaxKind.SetAccessor) { 28365 return links.resolvedType = errorType; 28366 } 28367 links.resolvedType = checkExpression(node.expression); 28368 // The computed property name of a non-static class field within a loop must be stored in a block-scoped binding. 28369 // (It needs to be bound at class evaluation time.) 28370 if (isPropertyDeclaration(node.parent) && !hasStaticModifier(node.parent) && isClassExpression(node.parent.parent)) { 28371 const container = getEnclosingBlockScopeContainer(node.parent.parent); 28372 const enclosingIterationStatement = getEnclosingIterationStatement(container); 28373 if (enclosingIterationStatement) { 28374 // The computed field name will use a block scoped binding which can be unique for each iteration of the loop. 28375 getNodeLinks(enclosingIterationStatement).flags |= NodeCheckFlags.LoopWithCapturedBlockScopedBinding; 28376 // The generated variable which stores the computed field name must be block-scoped. 28377 getNodeLinks(node).flags |= NodeCheckFlags.BlockScopedBindingInLoop; 28378 // The generated variable which stores the class must be block-scoped. 28379 getNodeLinks(node.parent.parent).flags |= NodeCheckFlags.BlockScopedBindingInLoop; 28380 } 28381 } 28382 // This will allow types number, string, symbol or any. It will also allow enums, the unknown 28383 // type, and any union of these types (like string | number). 28384 if (links.resolvedType.flags & TypeFlags.Nullable || 28385 !isTypeAssignableToKind(links.resolvedType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbolLike) && 28386 !isTypeAssignableTo(links.resolvedType, stringNumberSymbolType)) { 28387 error(node, Diagnostics.A_computed_property_name_must_be_of_type_string_number_symbol_or_any); 28388 } 28389 } 28390 28391 return links.resolvedType; 28392 } 28393 28394 function isSymbolWithNumericName(symbol: Symbol) { 28395 const firstDecl = symbol.declarations?.[0]; 28396 return isNumericLiteralName(symbol.escapedName) || (firstDecl && isNamedDeclaration(firstDecl) && isNumericName(firstDecl.name)); 28397 } 28398 28399 function isSymbolWithSymbolName(symbol: Symbol) { 28400 const firstDecl = symbol.declarations?.[0]; 28401 return isKnownSymbol(symbol) || (firstDecl && isNamedDeclaration(firstDecl) && isComputedPropertyName(firstDecl.name) && 28402 isTypeAssignableToKind(checkComputedPropertyName(firstDecl.name), TypeFlags.ESSymbol)); 28403 } 28404 28405 function getObjectLiteralIndexInfo(node: ObjectLiteralExpression, offset: number, properties: Symbol[], keyType: Type): IndexInfo { 28406 const propTypes: Type[] = []; 28407 for (let i = offset; i < properties.length; i++) { 28408 const prop = properties[i]; 28409 if (keyType === stringType && !isSymbolWithSymbolName(prop) || 28410 keyType === numberType && isSymbolWithNumericName(prop) || 28411 keyType === esSymbolType && isSymbolWithSymbolName(prop)) { 28412 propTypes.push(getTypeOfSymbol(properties[i])); 28413 } 28414 } 28415 const unionType = propTypes.length ? getUnionType(propTypes, UnionReduction.Subtype) : undefinedType; 28416 return createIndexInfo(keyType, unionType, isConstContext(node)); 28417 } 28418 28419 function getImmediateAliasedSymbol(symbol: Symbol): Symbol | undefined { 28420 Debug.assert((symbol.flags & SymbolFlags.Alias) !== 0, "Should only get Alias here."); 28421 const links = getSymbolLinks(symbol); 28422 if (!links.immediateTarget) { 28423 const node = getDeclarationOfAliasSymbol(symbol); 28424 if (!node) return Debug.fail(); 28425 links.immediateTarget = getTargetOfAliasDeclaration(node, /*dontRecursivelyResolve*/ true); 28426 } 28427 28428 return links.immediateTarget; 28429 } 28430 28431 function checkObjectLiteral(node: ObjectLiteralExpression, checkMode?: CheckMode): Type { 28432 const inDestructuringPattern = isAssignmentTarget(node); 28433 // Grammar checking 28434 checkGrammarObjectLiteralExpression(node, inDestructuringPattern); 28435 28436 const allPropertiesTable = strictNullChecks ? createSymbolTable() : undefined; 28437 let propertiesTable = createSymbolTable(); 28438 let propertiesArray: Symbol[] = []; 28439 let spread: Type = emptyObjectType; 28440 28441 const contextualType = getApparentTypeOfContextualType(node, /*contextFlags*/ undefined); 28442 const contextualTypeHasPattern = contextualType && contextualType.pattern && 28443 (contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression); 28444 const inConstContext = isConstContext(node); 28445 const checkFlags = inConstContext ? CheckFlags.Readonly : 0; 28446 const isInJavascript = isInJSFile(node) && !isInJsonFile(node); 28447 const enumTag = getJSDocEnumTag(node); 28448 const isJSObjectLiteral = !contextualType && isInJavascript && !enumTag; 28449 let objectFlags: ObjectFlags = freshObjectLiteralFlag; 28450 let patternWithComputedProperties = false; 28451 let hasComputedStringProperty = false; 28452 let hasComputedNumberProperty = false; 28453 let hasComputedSymbolProperty = false; 28454 28455 // Spreads may cause an early bail; ensure computed names are always checked (this is cached) 28456 // As otherwise they may not be checked until exports for the type at this position are retrieved, 28457 // which may never occur. 28458 for (const elem of node.properties) { 28459 if (elem.name && isComputedPropertyName(elem.name)) { 28460 checkComputedPropertyName(elem.name); 28461 } 28462 } 28463 28464 let offset = 0; 28465 for (const memberDecl of node.properties) { 28466 let member = getSymbolOfNode(memberDecl); 28467 const computedNameType = memberDecl.name && memberDecl.name.kind === SyntaxKind.ComputedPropertyName ? 28468 checkComputedPropertyName(memberDecl.name) : undefined; 28469 if (memberDecl.kind === SyntaxKind.PropertyAssignment || 28470 memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment || 28471 isObjectLiteralMethod(memberDecl)) { 28472 let type = memberDecl.kind === SyntaxKind.PropertyAssignment ? checkPropertyAssignment(memberDecl, checkMode) : 28473 // avoid resolving the left side of the ShorthandPropertyAssignment outside of the destructuring 28474 // for error recovery purposes. For example, if a user wrote `{ a = 100 }` instead of `{ a: 100 }`. 28475 // we don't want to say "could not find 'a'". 28476 memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment ? checkExpressionForMutableLocation(!inDestructuringPattern && memberDecl.objectAssignmentInitializer ? memberDecl.objectAssignmentInitializer : memberDecl.name, checkMode) : 28477 checkObjectLiteralMethod(memberDecl, checkMode); 28478 if (isInJavascript) { 28479 const jsDocType = getTypeForDeclarationFromJSDocComment(memberDecl); 28480 if (jsDocType) { 28481 checkTypeAssignableTo(type, jsDocType, memberDecl); 28482 type = jsDocType; 28483 } 28484 else if (enumTag && enumTag.typeExpression) { 28485 checkTypeAssignableTo(type, getTypeFromTypeNode(enumTag.typeExpression), memberDecl); 28486 } 28487 } 28488 objectFlags |= getObjectFlags(type) & ObjectFlags.PropagatingFlags; 28489 const nameType = computedNameType && isTypeUsableAsPropertyName(computedNameType) ? computedNameType : undefined; 28490 const prop = nameType ? 28491 createSymbol(SymbolFlags.Property | member.flags, getPropertyNameFromType(nameType), checkFlags | CheckFlags.Late) : 28492 createSymbol(SymbolFlags.Property | member.flags, member.escapedName, checkFlags); 28493 if (nameType) { 28494 prop.nameType = nameType; 28495 } 28496 28497 if (inDestructuringPattern) { 28498 // If object literal is an assignment pattern and if the assignment pattern specifies a default value 28499 // for the property, make the property optional. 28500 const isOptional = 28501 (memberDecl.kind === SyntaxKind.PropertyAssignment && hasDefaultValue(memberDecl.initializer)) || 28502 (memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment && memberDecl.objectAssignmentInitializer); 28503 if (isOptional) { 28504 prop.flags |= SymbolFlags.Optional; 28505 } 28506 } 28507 else if (contextualTypeHasPattern && !(getObjectFlags(contextualType) & ObjectFlags.ObjectLiteralPatternWithComputedProperties)) { 28508 // If object literal is contextually typed by the implied type of a binding pattern, and if the 28509 // binding pattern specifies a default value for the property, make the property optional. 28510 const impliedProp = getPropertyOfType(contextualType, member.escapedName); 28511 if (impliedProp) { 28512 prop.flags |= impliedProp.flags & SymbolFlags.Optional; 28513 } 28514 28515 else if (!compilerOptions.suppressExcessPropertyErrors && !getIndexInfoOfType(contextualType, stringType)) { 28516 error(memberDecl.name, Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1, 28517 symbolToString(member), typeToString(contextualType)); 28518 } 28519 } 28520 28521 prop.declarations = member.declarations; 28522 prop.parent = member.parent; 28523 if (member.valueDeclaration) { 28524 prop.valueDeclaration = member.valueDeclaration; 28525 } 28526 28527 prop.type = type; 28528 prop.target = member; 28529 member = prop; 28530 allPropertiesTable?.set(prop.escapedName, prop); 28531 28532 if (contextualType && checkMode && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && 28533 (memberDecl.kind === SyntaxKind.PropertyAssignment || memberDecl.kind === SyntaxKind.MethodDeclaration) && isContextSensitive(memberDecl)) { 28534 const inferenceContext = getInferenceContext(node); 28535 Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context 28536 const inferenceNode = memberDecl.kind === SyntaxKind.PropertyAssignment ? memberDecl.initializer : memberDecl; 28537 addIntraExpressionInferenceSite(inferenceContext, inferenceNode, type); 28538 } 28539 if (type.symbol && (type.symbol.flags & SymbolFlags.Annotation)) { 28540 error(memberDecl, Diagnostics.Annotation_cannot_be_used_as_a_value); 28541 } 28542 } 28543 else if (memberDecl.kind === SyntaxKind.SpreadAssignment) { 28544 if (languageVersion < ScriptTarget.ES2015) { 28545 checkExternalEmitHelpers(memberDecl, ExternalEmitHelpers.Assign); 28546 } 28547 if (propertiesArray.length > 0) { 28548 spread = getSpreadType(spread, createObjectLiteralType(), node.symbol, objectFlags, inConstContext); 28549 propertiesArray = []; 28550 propertiesTable = createSymbolTable(); 28551 hasComputedStringProperty = false; 28552 hasComputedNumberProperty = false; 28553 hasComputedSymbolProperty = false; 28554 } 28555 const type = getReducedType(checkExpression(memberDecl.expression)); 28556 if (isValidSpreadType(type)) { 28557 const mergedType = tryMergeUnionOfObjectTypeAndEmptyObject(type, inConstContext); 28558 if (allPropertiesTable) { 28559 checkSpreadPropOverrides(mergedType, allPropertiesTable, memberDecl); 28560 } 28561 offset = propertiesArray.length; 28562 if (isErrorType(spread)) { 28563 continue; 28564 } 28565 spread = getSpreadType(spread, mergedType, node.symbol, objectFlags, inConstContext); 28566 } 28567 else { 28568 error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types); 28569 spread = errorType; 28570 } 28571 continue; 28572 } 28573 else { 28574 // TypeScript 1.0 spec (April 2014) 28575 // A get accessor declaration is processed in the same manner as 28576 // an ordinary function declaration(section 6.1) with no parameters. 28577 // A set accessor declaration is processed in the same manner 28578 // as an ordinary function declaration with a single parameter and a Void return type. 28579 Debug.assert(memberDecl.kind === SyntaxKind.GetAccessor || memberDecl.kind === SyntaxKind.SetAccessor); 28580 checkNodeDeferred(memberDecl); 28581 } 28582 28583 if (computedNameType && !(computedNameType.flags & TypeFlags.StringOrNumberLiteralOrUnique)) { 28584 if (isTypeAssignableTo(computedNameType, stringNumberSymbolType)) { 28585 if (isTypeAssignableTo(computedNameType, numberType)) { 28586 hasComputedNumberProperty = true; 28587 } 28588 else if (isTypeAssignableTo(computedNameType, esSymbolType)) { 28589 hasComputedSymbolProperty = true; 28590 } 28591 else { 28592 hasComputedStringProperty = true; 28593 } 28594 if (inDestructuringPattern) { 28595 patternWithComputedProperties = true; 28596 } 28597 } 28598 } 28599 else { 28600 propertiesTable.set(member.escapedName, member); 28601 } 28602 propertiesArray.push(member); 28603 } 28604 28605 // If object literal is contextually typed by the implied type of a binding pattern, augment the result 28606 // type with those properties for which the binding pattern specifies a default value. 28607 // If the object literal is spread into another object literal, skip this step and let the top-level object 28608 // literal handle it instead. Note that this might require full traversal to the root pattern's parent 28609 // as it's the guaranteed to be the common ancestor of the pattern node and the current object node. 28610 // It's not possible to check if the immediate parent node is a spread assignment 28611 // since the type flows in non-obvious ways through conditional expressions, IIFEs and more. 28612 if (contextualTypeHasPattern) { 28613 const rootPatternParent = findAncestor(contextualType.pattern!.parent, n => 28614 n.kind === SyntaxKind.VariableDeclaration || 28615 n.kind === SyntaxKind.BinaryExpression || 28616 n.kind === SyntaxKind.Parameter 28617 ); 28618 const spreadOrOutsideRootObject = findAncestor(node, n => 28619 n === rootPatternParent || 28620 n.kind === SyntaxKind.SpreadAssignment 28621 )!; 28622 28623 if (spreadOrOutsideRootObject.kind !== SyntaxKind.SpreadAssignment) { 28624 for (const prop of getPropertiesOfType(contextualType)) { 28625 if (!propertiesTable.get(prop.escapedName) && !getPropertyOfType(spread, prop.escapedName)) { 28626 if (!(prop.flags & SymbolFlags.Optional)) { 28627 error(prop.valueDeclaration || (prop as TransientSymbol).bindingElement, 28628 Diagnostics.Initializer_provides_no_value_for_this_binding_element_and_the_binding_element_has_no_default_value); 28629 } 28630 propertiesTable.set(prop.escapedName, prop); 28631 propertiesArray.push(prop); 28632 } 28633 } 28634 } 28635 } 28636 28637 if (isErrorType(spread)) { 28638 return errorType; 28639 } 28640 28641 if (spread !== emptyObjectType) { 28642 if (propertiesArray.length > 0) { 28643 spread = getSpreadType(spread, createObjectLiteralType(), node.symbol, objectFlags, inConstContext); 28644 propertiesArray = []; 28645 propertiesTable = createSymbolTable(); 28646 hasComputedStringProperty = false; 28647 hasComputedNumberProperty = false; 28648 } 28649 // remap the raw emptyObjectType fed in at the top into a fresh empty object literal type, unique to this use site 28650 return mapType(spread, t => t === emptyObjectType ? createObjectLiteralType() : t); 28651 } 28652 28653 return createObjectLiteralType(); 28654 28655 function createObjectLiteralType() { 28656 const indexInfos = []; 28657 if (hasComputedStringProperty) indexInfos.push(getObjectLiteralIndexInfo(node, offset, propertiesArray, stringType)); 28658 if (hasComputedNumberProperty) indexInfos.push(getObjectLiteralIndexInfo(node, offset, propertiesArray, numberType)); 28659 if (hasComputedSymbolProperty) indexInfos.push(getObjectLiteralIndexInfo(node, offset, propertiesArray, esSymbolType)); 28660 const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, indexInfos); 28661 result.objectFlags |= objectFlags | ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral; 28662 if (isJSObjectLiteral) { 28663 result.objectFlags |= ObjectFlags.JSLiteral; 28664 } 28665 if (patternWithComputedProperties) { 28666 result.objectFlags |= ObjectFlags.ObjectLiteralPatternWithComputedProperties; 28667 } 28668 if (inDestructuringPattern) { 28669 result.pattern = node; 28670 } 28671 return result; 28672 } 28673 } 28674 28675 function isValidSpreadType(type: Type): boolean { 28676 const t = removeDefinitelyFalsyTypes(mapType(type, getBaseConstraintOrType)); 28677 return !!(t.flags & (TypeFlags.Any | TypeFlags.NonPrimitive | TypeFlags.Object | TypeFlags.InstantiableNonPrimitive) || 28678 t.flags & TypeFlags.UnionOrIntersection && every((t as UnionOrIntersectionType).types, isValidSpreadType)); 28679 } 28680 28681 function checkJsxSelfClosingElementDeferred(node: JsxSelfClosingElement) { 28682 checkJsxOpeningLikeElementOrOpeningFragment(node); 28683 } 28684 28685 function checkJsxSelfClosingElement(node: JsxSelfClosingElement, _checkMode: CheckMode | undefined): Type { 28686 checkNodeDeferred(node); 28687 return getJsxElementTypeAt(node) || anyType; 28688 } 28689 28690 function checkJsxElementDeferred(node: JsxElement) { 28691 // Check attributes 28692 checkJsxOpeningLikeElementOrOpeningFragment(node.openingElement); 28693 28694 // Perform resolution on the closing tag so that rename/go to definition/etc work 28695 if (isJsxIntrinsicIdentifier(node.closingElement.tagName)) { 28696 getIntrinsicTagSymbol(node.closingElement); 28697 } 28698 else { 28699 checkExpression(node.closingElement.tagName); 28700 } 28701 28702 checkJsxChildren(node); 28703 } 28704 28705 function checkJsxElement(node: JsxElement, _checkMode: CheckMode | undefined): Type { 28706 checkNodeDeferred(node); 28707 28708 return getJsxElementTypeAt(node) || anyType; 28709 } 28710 28711 function checkJsxFragment(node: JsxFragment): Type { 28712 checkJsxOpeningLikeElementOrOpeningFragment(node.openingFragment); 28713 28714 // by default, jsx:'react' will use jsxFactory = React.createElement and jsxFragmentFactory = React.Fragment 28715 // if jsxFactory compiler option is provided, ensure jsxFragmentFactory compiler option or @jsxFrag pragma is provided too 28716 const nodeSourceFile = getSourceFileOfNode(node); 28717 if (getJSXTransformEnabled(compilerOptions) && (compilerOptions.jsxFactory || nodeSourceFile.pragmas.has("jsx")) 28718 && !compilerOptions.jsxFragmentFactory && !nodeSourceFile.pragmas.has("jsxfrag")) { 28719 error(node, compilerOptions.jsxFactory 28720 ? Diagnostics.The_jsxFragmentFactory_compiler_option_must_be_provided_to_use_JSX_fragments_with_the_jsxFactory_compiler_option 28721 : Diagnostics.An_jsxFrag_pragma_is_required_when_using_an_jsx_pragma_with_JSX_fragments); 28722 } 28723 28724 checkJsxChildren(node); 28725 return getJsxElementTypeAt(node) || anyType; 28726 } 28727 28728 function isHyphenatedJsxName(name: string | __String) { 28729 return stringContains(name as string, "-"); 28730 } 28731 28732 /** 28733 * Returns true iff React would emit this tag name as a string rather than an identifier or qualified name 28734 */ 28735 function isJsxIntrinsicIdentifier(tagName: JsxTagNameExpression): boolean { 28736 return tagName.kind === SyntaxKind.Identifier && isIntrinsicJsxName(tagName.escapedText); 28737 } 28738 28739 function checkJsxAttribute(node: JsxAttribute, checkMode?: CheckMode) { 28740 return node.initializer 28741 ? checkExpressionForMutableLocation(node.initializer, checkMode) 28742 : trueType; // <Elem attr /> is sugar for <Elem attr={true} /> 28743 } 28744 28745 /** 28746 * Get attributes type of the JSX opening-like element. The result is from resolving "attributes" property of the opening-like element. 28747 * 28748 * @param openingLikeElement a JSX opening-like element 28749 * @param filter a function to remove attributes that will not participate in checking whether attributes are assignable 28750 * @return an anonymous type (similar to the one returned by checkObjectLiteral) in which its properties are attributes property. 28751 * @remarks Because this function calls getSpreadType, it needs to use the same checks as checkObjectLiteral, 28752 * which also calls getSpreadType. 28753 */ 28754 function createJsxAttributesTypeFromAttributesProperty(openingLikeElement: JsxOpeningLikeElement, checkMode: CheckMode | undefined) { 28755 const attributes = openingLikeElement.attributes; 28756 const attributesType = getContextualType(attributes, ContextFlags.None); 28757 const allAttributesTable = strictNullChecks ? createSymbolTable() : undefined; 28758 let attributesTable = createSymbolTable(); 28759 let spread: Type = emptyJsxObjectType; 28760 let hasSpreadAnyType = false; 28761 let typeToIntersect: Type | undefined; 28762 let explicitlySpecifyChildrenAttribute = false; 28763 let objectFlags: ObjectFlags = ObjectFlags.JsxAttributes; 28764 const jsxChildrenPropertyName = getJsxElementChildrenPropertyName(getJsxNamespaceAt(openingLikeElement)); 28765 28766 for (const attributeDecl of attributes.properties) { 28767 const member = attributeDecl.symbol; 28768 if (isJsxAttribute(attributeDecl)) { 28769 const exprType = checkJsxAttribute(attributeDecl, checkMode); 28770 objectFlags |= getObjectFlags(exprType) & ObjectFlags.PropagatingFlags; 28771 28772 const attributeSymbol = createSymbol(SymbolFlags.Property | member.flags, member.escapedName); 28773 attributeSymbol.declarations = member.declarations; 28774 attributeSymbol.parent = member.parent; 28775 if (member.valueDeclaration) { 28776 attributeSymbol.valueDeclaration = member.valueDeclaration; 28777 } 28778 attributeSymbol.type = exprType; 28779 attributeSymbol.target = member; 28780 attributesTable.set(attributeSymbol.escapedName, attributeSymbol); 28781 allAttributesTable?.set(attributeSymbol.escapedName, attributeSymbol); 28782 if (attributeDecl.name.escapedText === jsxChildrenPropertyName) { 28783 explicitlySpecifyChildrenAttribute = true; 28784 } 28785 if (attributesType) { 28786 const prop = getPropertyOfType(attributesType, member.escapedName); 28787 if (prop && prop.declarations && isDeprecatedSymbol(prop)) { 28788 addDeprecatedSuggestion(attributeDecl.name, prop.declarations, attributeDecl.name.escapedText as string); 28789 } 28790 } 28791 } 28792 else { 28793 Debug.assert(attributeDecl.kind === SyntaxKind.JsxSpreadAttribute); 28794 if (attributesTable.size > 0) { 28795 spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, objectFlags, /*readonly*/ false); 28796 attributesTable = createSymbolTable(); 28797 } 28798 const exprType = getReducedType(checkExpressionCached(attributeDecl.expression, checkMode)); 28799 if (isTypeAny(exprType)) { 28800 hasSpreadAnyType = true; 28801 } 28802 if (isValidSpreadType(exprType)) { 28803 spread = getSpreadType(spread, exprType, attributes.symbol, objectFlags, /*readonly*/ false); 28804 if (allAttributesTable) { 28805 checkSpreadPropOverrides(exprType, allAttributesTable, attributeDecl); 28806 } 28807 } 28808 else { 28809 error(attributeDecl.expression, Diagnostics.Spread_types_may_only_be_created_from_object_types); 28810 typeToIntersect = typeToIntersect ? getIntersectionType([typeToIntersect, exprType]) : exprType; 28811 } 28812 } 28813 } 28814 28815 if (!hasSpreadAnyType) { 28816 if (attributesTable.size > 0) { 28817 spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, objectFlags, /*readonly*/ false); 28818 } 28819 } 28820 28821 // Handle children attribute 28822 const parent = openingLikeElement.parent.kind === SyntaxKind.JsxElement ? openingLikeElement.parent as JsxElement : undefined; 28823 // We have to check that openingElement of the parent is the one we are visiting as this may not be true for selfClosingElement 28824 if (parent && parent.openingElement === openingLikeElement && parent.children.length > 0) { 28825 const childrenTypes: Type[] = checkJsxChildren(parent, checkMode); 28826 28827 if (!hasSpreadAnyType && jsxChildrenPropertyName && jsxChildrenPropertyName !== "") { 28828 // Error if there is a attribute named "children" explicitly specified and children element. 28829 // This is because children element will overwrite the value from attributes. 28830 // Note: we will not warn "children" attribute overwritten if "children" attribute is specified in object spread. 28831 if (explicitlySpecifyChildrenAttribute) { 28832 error(attributes, Diagnostics._0_are_specified_twice_The_attribute_named_0_will_be_overwritten, unescapeLeadingUnderscores(jsxChildrenPropertyName)); 28833 } 28834 28835 const contextualType = getApparentTypeOfContextualType(openingLikeElement.attributes, /*contextFlags*/ undefined); 28836 const childrenContextualType = contextualType && getTypeOfPropertyOfContextualType(contextualType, jsxChildrenPropertyName); 28837 // If there are children in the body of JSX element, create dummy attribute "children" with the union of children types so that it will pass the attribute checking process 28838 const childrenPropSymbol = createSymbol(SymbolFlags.Property, jsxChildrenPropertyName); 28839 childrenPropSymbol.type = childrenTypes.length === 1 ? childrenTypes[0] : 28840 childrenContextualType && someType(childrenContextualType, isTupleLikeType) ? createTupleType(childrenTypes) : 28841 createArrayType(getUnionType(childrenTypes)); 28842 // Fake up a property declaration for the children 28843 childrenPropSymbol.valueDeclaration = factory.createPropertySignature(/*modifiers*/ undefined, unescapeLeadingUnderscores(jsxChildrenPropertyName), /*questionToken*/ undefined, /*type*/ undefined); 28844 setParent(childrenPropSymbol.valueDeclaration, attributes); 28845 childrenPropSymbol.valueDeclaration.symbol = childrenPropSymbol; 28846 const childPropMap = createSymbolTable(); 28847 childPropMap.set(jsxChildrenPropertyName, childrenPropSymbol); 28848 spread = getSpreadType(spread, createAnonymousType(attributes.symbol, childPropMap, emptyArray, emptyArray, emptyArray), 28849 attributes.symbol, objectFlags, /*readonly*/ false); 28850 28851 } 28852 } 28853 28854 if (hasSpreadAnyType) { 28855 return anyType; 28856 } 28857 if (typeToIntersect && spread !== emptyJsxObjectType) { 28858 return getIntersectionType([typeToIntersect, spread]); 28859 } 28860 return typeToIntersect || (spread === emptyJsxObjectType ? createJsxAttributesType() : spread); 28861 28862 /** 28863 * Create anonymous type from given attributes symbol table. 28864 * @param symbol a symbol of JsxAttributes containing attributes corresponding to attributesTable 28865 * @param attributesTable a symbol table of attributes property 28866 */ 28867 function createJsxAttributesType() { 28868 objectFlags |= freshObjectLiteralFlag; 28869 const result = createAnonymousType(attributes.symbol, attributesTable, emptyArray, emptyArray, emptyArray); 28870 result.objectFlags |= objectFlags | ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral; 28871 return result; 28872 } 28873 } 28874 28875 function checkJsxChildren(node: JsxElement | JsxFragment, checkMode?: CheckMode) { 28876 const childrenTypes: Type[] = []; 28877 for (const child of node.children) { 28878 // In React, JSX text that contains only whitespaces will be ignored so we don't want to type-check that 28879 // because then type of children property will have constituent of string type. 28880 if (child.kind === SyntaxKind.JsxText) { 28881 if (!child.containsOnlyTriviaWhiteSpaces) { 28882 childrenTypes.push(stringType); 28883 } 28884 } 28885 else if (child.kind === SyntaxKind.JsxExpression && !child.expression) { 28886 continue; // empty jsx expressions don't *really* count as present children 28887 } 28888 else { 28889 childrenTypes.push(checkExpressionForMutableLocation(child, checkMode)); 28890 } 28891 } 28892 return childrenTypes; 28893 } 28894 28895 function checkSpreadPropOverrides(type: Type, props: SymbolTable, spread: SpreadAssignment | JsxSpreadAttribute) { 28896 for (const right of getPropertiesOfType(type)) { 28897 if (!(right.flags & SymbolFlags.Optional)) { 28898 const left = props.get(right.escapedName); 28899 if (left) { 28900 const diagnostic = error(left.valueDeclaration, Diagnostics._0_is_specified_more_than_once_so_this_usage_will_be_overwritten, unescapeLeadingUnderscores(left.escapedName)); 28901 addRelatedInfo(diagnostic, createDiagnosticForNode(spread, Diagnostics.This_spread_always_overwrites_this_property)); 28902 } 28903 } 28904 } 28905 } 28906 28907 /** 28908 * Check attributes property of opening-like element. This function is called during chooseOverload to get call signature of a JSX opening-like element. 28909 * (See "checkApplicableSignatureForJsxOpeningLikeElement" for how the function is used) 28910 * @param node a JSXAttributes to be resolved of its type 28911 */ 28912 function checkJsxAttributes(node: JsxAttributes, checkMode: CheckMode | undefined) { 28913 return createJsxAttributesTypeFromAttributesProperty(node.parent, checkMode); 28914 } 28915 28916 function getJsxType(name: __String, location: Node | undefined) { 28917 const namespace = getJsxNamespaceAt(location); 28918 const exports = namespace && getExportsOfSymbol(namespace); 28919 const typeSymbol = exports && getSymbol(exports, name, SymbolFlags.Type); 28920 return typeSymbol ? getDeclaredTypeOfSymbol(typeSymbol) : errorType; 28921 } 28922 28923 /** 28924 * Looks up an intrinsic tag name and returns a symbol that either points to an intrinsic 28925 * property (in which case nodeLinks.jsxFlags will be IntrinsicNamedElement) or an intrinsic 28926 * string index signature (in which case nodeLinks.jsxFlags will be IntrinsicIndexedElement). 28927 * May also return unknownSymbol if both of these lookups fail. 28928 */ 28929 function getIntrinsicTagSymbol(node: JsxOpeningLikeElement | JsxClosingElement): Symbol { 28930 const links = getNodeLinks(node); 28931 if (!links.resolvedSymbol) { 28932 const intrinsicElementsType = getJsxType(JsxNames.IntrinsicElements, node); 28933 if (!isErrorType(intrinsicElementsType)) { 28934 // Property case 28935 if (!isIdentifier(node.tagName)) return Debug.fail(); 28936 const intrinsicProp = getPropertyOfType(intrinsicElementsType, node.tagName.escapedText); 28937 if (intrinsicProp) { 28938 links.jsxFlags |= JsxFlags.IntrinsicNamedElement; 28939 return links.resolvedSymbol = intrinsicProp; 28940 } 28941 28942 // Intrinsic string indexer case 28943 const indexSignatureType = getIndexTypeOfType(intrinsicElementsType, stringType); 28944 if (indexSignatureType) { 28945 links.jsxFlags |= JsxFlags.IntrinsicIndexedElement; 28946 return links.resolvedSymbol = intrinsicElementsType.symbol; 28947 } 28948 28949 // Wasn't found 28950 error(node, Diagnostics.Property_0_does_not_exist_on_type_1, idText(node.tagName), "JSX." + JsxNames.IntrinsicElements); 28951 return links.resolvedSymbol = unknownSymbol; 28952 } 28953 else { 28954 if (noImplicitAny) { 28955 error(node, Diagnostics.JSX_element_implicitly_has_type_any_because_no_interface_JSX_0_exists, unescapeLeadingUnderscores(JsxNames.IntrinsicElements)); 28956 } 28957 return links.resolvedSymbol = unknownSymbol; 28958 } 28959 } 28960 return links.resolvedSymbol; 28961 } 28962 28963 function getJsxNamespaceContainerForImplicitImport(location: Node | undefined): Symbol | undefined { 28964 const file = location && getSourceFileOfNode(location); 28965 const links = file && getNodeLinks(file); 28966 if (links && links.jsxImplicitImportContainer === false) { 28967 return undefined; 28968 } 28969 if (links && links.jsxImplicitImportContainer) { 28970 return links.jsxImplicitImportContainer; 28971 } 28972 const runtimeImportSpecifier = getJSXRuntimeImport(getJSXImplicitImportBase(compilerOptions, file), compilerOptions); 28973 if (!runtimeImportSpecifier) { 28974 return undefined; 28975 } 28976 const isClassic = getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Classic; 28977 const errorMessage = isClassic 28978 ? Diagnostics.Cannot_find_module_0_Did_you_mean_to_set_the_moduleResolution_option_to_node_or_to_add_aliases_to_the_paths_option 28979 : Diagnostics.Cannot_find_module_0_or_its_corresponding_type_declarations; 28980 const mod = resolveExternalModule(location!, runtimeImportSpecifier, errorMessage, location!); 28981 const result = mod && mod !== unknownSymbol ? getMergedSymbol(resolveSymbol(mod)) : undefined; 28982 if (links) { 28983 links.jsxImplicitImportContainer = result || false; 28984 } 28985 return result; 28986 } 28987 28988 function getJsxNamespaceAt(location: Node | undefined): Symbol { 28989 const links = location && getNodeLinks(location); 28990 if (links && links.jsxNamespace) { 28991 return links.jsxNamespace; 28992 } 28993 if (!links || links.jsxNamespace !== false) { 28994 let resolvedNamespace = getJsxNamespaceContainerForImplicitImport(location); 28995 28996 if (!resolvedNamespace || resolvedNamespace === unknownSymbol) { 28997 const namespaceName = getJsxNamespace(location); 28998 resolvedNamespace = resolveName(location, namespaceName, SymbolFlags.Namespace, /*diagnosticMessage*/ undefined, namespaceName, /*isUse*/ false); 28999 } 29000 29001 if (resolvedNamespace) { 29002 const candidate = resolveSymbol(getSymbol(getExportsOfSymbol(resolveSymbol(resolvedNamespace)), JsxNames.JSX, SymbolFlags.Namespace)); 29003 if (candidate && candidate !== unknownSymbol) { 29004 if (links) { 29005 links.jsxNamespace = candidate; 29006 } 29007 return candidate; 29008 } 29009 } 29010 if (links) { 29011 links.jsxNamespace = false; 29012 } 29013 } 29014 // JSX global fallback 29015 const s = resolveSymbol(getGlobalSymbol(JsxNames.JSX, SymbolFlags.Namespace, /*diagnosticMessage*/ undefined)); 29016 if (s === unknownSymbol) { 29017 return undefined!; // TODO: GH#18217 29018 } 29019 return s!; // TODO: GH#18217 29020 } 29021 29022 /** 29023 * Look into JSX namespace and then look for container with matching name as nameOfAttribPropContainer. 29024 * Get a single property from that container if existed. Report an error if there are more than one property. 29025 * 29026 * @param nameOfAttribPropContainer a string of value JsxNames.ElementAttributesPropertyNameContainer or JsxNames.ElementChildrenAttributeNameContainer 29027 * if other string is given or the container doesn't exist, return undefined. 29028 */ 29029 function getNameFromJsxElementAttributesContainer(nameOfAttribPropContainer: __String, jsxNamespace: Symbol): __String | undefined { 29030 // JSX.ElementAttributesProperty | JSX.ElementChildrenAttribute [symbol] 29031 const jsxElementAttribPropInterfaceSym = jsxNamespace && getSymbol(jsxNamespace.exports!, nameOfAttribPropContainer, SymbolFlags.Type); 29032 // JSX.ElementAttributesProperty | JSX.ElementChildrenAttribute [type] 29033 const jsxElementAttribPropInterfaceType = jsxElementAttribPropInterfaceSym && getDeclaredTypeOfSymbol(jsxElementAttribPropInterfaceSym); 29034 // The properties of JSX.ElementAttributesProperty | JSX.ElementChildrenAttribute 29035 const propertiesOfJsxElementAttribPropInterface = jsxElementAttribPropInterfaceType && getPropertiesOfType(jsxElementAttribPropInterfaceType); 29036 if (propertiesOfJsxElementAttribPropInterface) { 29037 // Element Attributes has zero properties, so the element attributes type will be the class instance type 29038 if (propertiesOfJsxElementAttribPropInterface.length === 0) { 29039 return "" as __String; 29040 } 29041 // Element Attributes has one property, so the element attributes type will be the type of the corresponding 29042 // property of the class instance type 29043 else if (propertiesOfJsxElementAttribPropInterface.length === 1) { 29044 return propertiesOfJsxElementAttribPropInterface[0].escapedName; 29045 } 29046 else if (propertiesOfJsxElementAttribPropInterface.length > 1 && jsxElementAttribPropInterfaceSym.declarations) { 29047 // More than one property on ElementAttributesProperty is an error 29048 error(jsxElementAttribPropInterfaceSym.declarations[0], Diagnostics.The_global_type_JSX_0_may_not_have_more_than_one_property, unescapeLeadingUnderscores(nameOfAttribPropContainer)); 29049 } 29050 } 29051 return undefined; 29052 } 29053 29054 function getJsxLibraryManagedAttributes(jsxNamespace: Symbol) { 29055 // JSX.LibraryManagedAttributes [symbol] 29056 return jsxNamespace && getSymbol(jsxNamespace.exports!, JsxNames.LibraryManagedAttributes, SymbolFlags.Type); 29057 } 29058 29059 /// e.g. "props" for React.d.ts, 29060 /// or 'undefined' if ElementAttributesProperty doesn't exist (which means all 29061 /// non-intrinsic elements' attributes type is 'any'), 29062 /// or '' if it has 0 properties (which means every 29063 /// non-intrinsic elements' attributes type is the element instance type) 29064 function getJsxElementPropertiesName(jsxNamespace: Symbol) { 29065 return getNameFromJsxElementAttributesContainer(JsxNames.ElementAttributesPropertyNameContainer, jsxNamespace); 29066 } 29067 29068 function getJsxElementChildrenPropertyName(jsxNamespace: Symbol): __String | undefined { 29069 return getNameFromJsxElementAttributesContainer(JsxNames.ElementChildrenAttributeNameContainer, jsxNamespace); 29070 } 29071 29072 function getUninstantiatedJsxSignaturesOfType(elementType: Type, caller: JsxOpeningLikeElement): readonly Signature[] { 29073 if (elementType.flags & TypeFlags.String) { 29074 return [anySignature]; 29075 } 29076 else if (elementType.flags & TypeFlags.StringLiteral) { 29077 const intrinsicType = getIntrinsicAttributesTypeFromStringLiteralType(elementType as StringLiteralType, caller); 29078 if (!intrinsicType) { 29079 error(caller, Diagnostics.Property_0_does_not_exist_on_type_1, (elementType as StringLiteralType).value, "JSX." + JsxNames.IntrinsicElements); 29080 return emptyArray; 29081 } 29082 else { 29083 const fakeSignature = createSignatureForJSXIntrinsic(caller, intrinsicType); 29084 return [fakeSignature]; 29085 } 29086 } 29087 const apparentElemType = getApparentType(elementType); 29088 // Resolve the signatures, preferring constructor 29089 let signatures = getSignaturesOfType(apparentElemType, SignatureKind.Construct); 29090 if (signatures.length === 0) { 29091 // No construct signatures, try call signatures 29092 signatures = getSignaturesOfType(apparentElemType, SignatureKind.Call); 29093 } 29094 if (signatures.length === 0 && apparentElemType.flags & TypeFlags.Union) { 29095 // If each member has some combination of new/call signatures; make a union signature list for those 29096 signatures = getUnionSignatures(map((apparentElemType as UnionType).types, t => getUninstantiatedJsxSignaturesOfType(t, caller))); 29097 } 29098 return signatures; 29099 } 29100 29101 function getIntrinsicAttributesTypeFromStringLiteralType(type: StringLiteralType, location: Node): Type | undefined { 29102 // If the elemType is a stringLiteral type, we can then provide a check to make sure that the string literal type is one of the Jsx intrinsic element type 29103 // For example: 29104 // var CustomTag: "h1" = "h1"; 29105 // <CustomTag> Hello World </CustomTag> 29106 const intrinsicElementsType = getJsxType(JsxNames.IntrinsicElements, location); 29107 if (!isErrorType(intrinsicElementsType)) { 29108 const stringLiteralTypeName = type.value; 29109 const intrinsicProp = getPropertyOfType(intrinsicElementsType, escapeLeadingUnderscores(stringLiteralTypeName)); 29110 if (intrinsicProp) { 29111 return getTypeOfSymbol(intrinsicProp); 29112 } 29113 const indexSignatureType = getIndexTypeOfType(intrinsicElementsType, stringType); 29114 if (indexSignatureType) { 29115 return indexSignatureType; 29116 } 29117 return undefined; 29118 } 29119 // If we need to report an error, we already done so here. So just return any to prevent any more error downstream 29120 return anyType; 29121 } 29122 29123 function checkJsxReturnAssignableToAppropriateBound(refKind: JsxReferenceKind, elemInstanceType: Type, openingLikeElement: JsxOpeningLikeElement) { 29124 if (refKind === JsxReferenceKind.Function) { 29125 const sfcReturnConstraint = getJsxStatelessElementTypeAt(openingLikeElement); 29126 if (sfcReturnConstraint) { 29127 checkTypeRelatedTo(elemInstanceType, sfcReturnConstraint, assignableRelation, openingLikeElement.tagName, Diagnostics.Its_return_type_0_is_not_a_valid_JSX_element, generateInitialErrorChain); 29128 } 29129 } 29130 else if (refKind === JsxReferenceKind.Component) { 29131 const classConstraint = getJsxElementClassTypeAt(openingLikeElement); 29132 if (classConstraint) { 29133 // Issue an error if this return type isn't assignable to JSX.ElementClass, failing that 29134 checkTypeRelatedTo(elemInstanceType, classConstraint, assignableRelation, openingLikeElement.tagName, Diagnostics.Its_instance_type_0_is_not_a_valid_JSX_element, generateInitialErrorChain); 29135 } 29136 } 29137 else { // Mixed 29138 const sfcReturnConstraint = getJsxStatelessElementTypeAt(openingLikeElement); 29139 const classConstraint = getJsxElementClassTypeAt(openingLikeElement); 29140 if (!sfcReturnConstraint || !classConstraint) { 29141 return; 29142 } 29143 const combined = getUnionType([sfcReturnConstraint, classConstraint]); 29144 checkTypeRelatedTo(elemInstanceType, combined, assignableRelation, openingLikeElement.tagName, Diagnostics.Its_element_type_0_is_not_a_valid_JSX_element, generateInitialErrorChain); 29145 } 29146 29147 function generateInitialErrorChain(): DiagnosticMessageChain { 29148 const componentName = getTextOfNode(openingLikeElement.tagName); 29149 return chainDiagnosticMessages(/* details */ undefined, Diagnostics._0_cannot_be_used_as_a_JSX_component, componentName); 29150 } 29151 } 29152 29153 /** 29154 * Get attributes type of the given intrinsic opening-like Jsx element by resolving the tag name. 29155 * The function is intended to be called from a function which has checked that the opening element is an intrinsic element. 29156 * @param node an intrinsic JSX opening-like element 29157 */ 29158 function getIntrinsicAttributesTypeFromJsxOpeningLikeElement(node: JsxOpeningLikeElement): Type { 29159 Debug.assert(isJsxIntrinsicIdentifier(node.tagName)); 29160 const links = getNodeLinks(node); 29161 if (!links.resolvedJsxElementAttributesType) { 29162 const symbol = getIntrinsicTagSymbol(node); 29163 if (links.jsxFlags & JsxFlags.IntrinsicNamedElement) { 29164 return links.resolvedJsxElementAttributesType = getTypeOfSymbol(symbol) || errorType; 29165 } 29166 else if (links.jsxFlags & JsxFlags.IntrinsicIndexedElement) { 29167 return links.resolvedJsxElementAttributesType = 29168 getIndexTypeOfType(getJsxType(JsxNames.IntrinsicElements, node), stringType) || errorType; 29169 } 29170 else { 29171 return links.resolvedJsxElementAttributesType = errorType; 29172 } 29173 } 29174 return links.resolvedJsxElementAttributesType; 29175 } 29176 29177 function getJsxElementClassTypeAt(location: Node): Type | undefined { 29178 const type = getJsxType(JsxNames.ElementClass, location); 29179 if (isErrorType(type)) return undefined; 29180 return type; 29181 } 29182 29183 function getJsxElementTypeAt(location: Node): Type { 29184 return getJsxType(JsxNames.Element, location); 29185 } 29186 29187 function getJsxStatelessElementTypeAt(location: Node): Type | undefined { 29188 const jsxElementType = getJsxElementTypeAt(location); 29189 if (jsxElementType) { 29190 return getUnionType([jsxElementType, nullType]); 29191 } 29192 } 29193 29194 /** 29195 * Returns all the properties of the Jsx.IntrinsicElements interface 29196 */ 29197 function getJsxIntrinsicTagNamesAt(location: Node): Symbol[] { 29198 const intrinsics = getJsxType(JsxNames.IntrinsicElements, location); 29199 return intrinsics ? getPropertiesOfType(intrinsics) : emptyArray; 29200 } 29201 29202 function checkJsxPreconditions(errorNode: Node) { 29203 // Preconditions for using JSX 29204 if ((compilerOptions.jsx || JsxEmit.None) === JsxEmit.None) { 29205 error(errorNode, Diagnostics.Cannot_use_JSX_unless_the_jsx_flag_is_provided); 29206 } 29207 29208 if (getJsxElementTypeAt(errorNode) === undefined) { 29209 if (noImplicitAny) { 29210 error(errorNode, Diagnostics.JSX_element_implicitly_has_type_any_because_the_global_type_JSX_Element_does_not_exist); 29211 } 29212 } 29213 } 29214 29215 function checkJsxOpeningLikeElementOrOpeningFragment(node: JsxOpeningLikeElement | JsxOpeningFragment) { 29216 const isNodeOpeningLikeElement = isJsxOpeningLikeElement(node); 29217 29218 if (isNodeOpeningLikeElement) { 29219 checkGrammarJsxElement(node); 29220 } 29221 29222 checkJsxPreconditions(node); 29223 29224 if (!getJsxNamespaceContainerForImplicitImport(node)) { 29225 // The reactNamespace/jsxFactory's root symbol should be marked as 'used' so we don't incorrectly elide its import. 29226 // And if there is no reactNamespace/jsxFactory's symbol in scope when targeting React emit, we should issue an error. 29227 const jsxFactoryRefErr = diagnostics && compilerOptions.jsx === JsxEmit.React ? Diagnostics.Cannot_find_name_0 : undefined; 29228 const jsxFactoryNamespace = getJsxNamespace(node); 29229 const jsxFactoryLocation = isNodeOpeningLikeElement ? node.tagName : node; 29230 29231 // allow null as jsxFragmentFactory 29232 let jsxFactorySym: Symbol | undefined; 29233 if (!(isJsxOpeningFragment(node) && jsxFactoryNamespace === "null")) { 29234 jsxFactorySym = resolveName(jsxFactoryLocation, jsxFactoryNamespace, SymbolFlags.Value, jsxFactoryRefErr, jsxFactoryNamespace, /*isUse*/ true); 29235 } 29236 29237 if (jsxFactorySym) { 29238 // Mark local symbol as referenced here because it might not have been marked 29239 // if jsx emit was not jsxFactory as there wont be error being emitted 29240 jsxFactorySym.isReferenced = SymbolFlags.All; 29241 29242 // If react/jsxFactory symbol is alias, mark it as refereced 29243 if (jsxFactorySym.flags & SymbolFlags.Alias && !getTypeOnlyAliasDeclaration(jsxFactorySym)) { 29244 markAliasSymbolAsReferenced(jsxFactorySym); 29245 } 29246 } 29247 29248 // For JsxFragment, mark jsx pragma as referenced via resolveName 29249 if (isJsxOpeningFragment(node)) { 29250 const file = getSourceFileOfNode(node); 29251 const localJsxNamespace = getLocalJsxNamespace(file); 29252 if (localJsxNamespace) { 29253 resolveName(jsxFactoryLocation, localJsxNamespace, SymbolFlags.Value, jsxFactoryRefErr, localJsxNamespace, /*isUse*/ true); 29254 } 29255 } 29256 } 29257 29258 if (isNodeOpeningLikeElement) { 29259 const jsxOpeningLikeNode = node ; 29260 const sig = getResolvedSignature(jsxOpeningLikeNode); 29261 checkDeprecatedSignature(sig, node); 29262 checkJsxReturnAssignableToAppropriateBound(getJsxReferenceKind(jsxOpeningLikeNode), getReturnTypeOfSignature(sig), jsxOpeningLikeNode); 29263 } 29264 } 29265 29266 /** 29267 * Check if a property with the given name is known anywhere in the given type. In an object type, a property 29268 * is considered known if 29269 * 1. the object type is empty and the check is for assignability, or 29270 * 2. if the object type has index signatures, or 29271 * 3. if the property is actually declared in the object type 29272 * (this means that 'toString', for example, is not usually a known property). 29273 * 4. In a union or intersection type, 29274 * a property is considered known if it is known in any constituent type. 29275 * @param targetType a type to search a given name in 29276 * @param name a property name to search 29277 * @param isComparingJsxAttributes a boolean flag indicating whether we are searching in JsxAttributesType 29278 */ 29279 function isKnownProperty(targetType: Type, name: __String, isComparingJsxAttributes: boolean): boolean { 29280 if (targetType.flags & TypeFlags.Object) { 29281 // For backwards compatibility a symbol-named property is satisfied by a string index signature. This 29282 // is incorrect and inconsistent with element access expressions, where it is an error, so eventually 29283 // we should remove this exception. 29284 if (getPropertyOfObjectType(targetType, name) || 29285 getApplicableIndexInfoForName(targetType, name) || 29286 isLateBoundName(name) && getIndexInfoOfType(targetType, stringType) || 29287 isComparingJsxAttributes && isHyphenatedJsxName(name)) { 29288 // For JSXAttributes, if the attribute has a hyphenated name, consider that the attribute to be known. 29289 return true; 29290 } 29291 } 29292 else if (targetType.flags & TypeFlags.UnionOrIntersection && isExcessPropertyCheckTarget(targetType)) { 29293 for (const t of (targetType as UnionOrIntersectionType).types) { 29294 if (isKnownProperty(t, name, isComparingJsxAttributes)) { 29295 return true; 29296 } 29297 } 29298 } 29299 return false; 29300 } 29301 29302 function isExcessPropertyCheckTarget(type: Type): boolean { 29303 return !!(type.flags & TypeFlags.Object && !(getObjectFlags(type) & ObjectFlags.ObjectLiteralPatternWithComputedProperties) || 29304 type.flags & TypeFlags.NonPrimitive || 29305 type.flags & TypeFlags.Union && some((type as UnionType).types, isExcessPropertyCheckTarget) || 29306 type.flags & TypeFlags.Intersection && every((type as IntersectionType).types, isExcessPropertyCheckTarget)); 29307 } 29308 29309 function checkJsxExpression(node: JsxExpression, checkMode?: CheckMode) { 29310 checkGrammarJsxExpression(node); 29311 if (node.expression) { 29312 const type = checkExpression(node.expression, checkMode); 29313 if (node.dotDotDotToken && type !== anyType && !isArrayType(type)) { 29314 error(node, Diagnostics.JSX_spread_child_must_be_an_array_type); 29315 } 29316 return type; 29317 } 29318 else { 29319 return errorType; 29320 } 29321 } 29322 29323 function getDeclarationNodeFlagsFromSymbol(s: Symbol): NodeFlags { 29324 return s.valueDeclaration ? getCombinedNodeFlags(s.valueDeclaration) : 0; 29325 } 29326 29327 /** 29328 * Return whether this symbol is a member of a prototype somewhere 29329 * Note that this is not tracked well within the compiler, so the answer may be incorrect. 29330 */ 29331 function isPrototypeProperty(symbol: Symbol) { 29332 if (symbol.flags & SymbolFlags.Method || getCheckFlags(symbol) & CheckFlags.SyntheticMethod) { 29333 return true; 29334 } 29335 if (isInJSFile(symbol.valueDeclaration)) { 29336 const parent = symbol.valueDeclaration!.parent; 29337 return parent && isBinaryExpression(parent) && 29338 getAssignmentDeclarationKind(parent) === AssignmentDeclarationKind.PrototypeProperty; 29339 } 29340 } 29341 29342 /** 29343 * Check whether the requested property access is valid. 29344 * Returns true if node is a valid property access, and false otherwise. 29345 * @param node The node to be checked. 29346 * @param isSuper True if the access is from `super.`. 29347 * @param type The type of the object whose property is being accessed. (Not the type of the property.) 29348 * @param prop The symbol for the property being accessed. 29349 */ 29350 function checkPropertyAccessibility( 29351 node: PropertyAccessExpression | QualifiedName | PropertyAccessExpression | VariableDeclaration | ParameterDeclaration | ImportTypeNode | PropertyAssignment | ShorthandPropertyAssignment | BindingElement, 29352 isSuper: boolean, writing: boolean, type: Type, prop: Symbol, reportError = true): boolean { 29353 29354 const errorNode = !reportError ? undefined : 29355 node.kind === SyntaxKind.QualifiedName ? node.right : 29356 node.kind === SyntaxKind.ImportType ? node : 29357 node.kind === SyntaxKind.BindingElement && node.propertyName ? node.propertyName : node.name; 29358 29359 return checkPropertyAccessibilityAtLocation(node, isSuper, writing, type, prop, errorNode); 29360 } 29361 29362 /** 29363 * Check whether the requested property can be accessed at the requested location. 29364 * Returns true if node is a valid property access, and false otherwise. 29365 * @param location The location node where we want to check if the property is accessible. 29366 * @param isSuper True if the access is from `super.`. 29367 * @param writing True if this is a write property access, false if it is a read property access. 29368 * @param containingType The type of the object whose property is being accessed. (Not the type of the property.) 29369 * @param prop The symbol for the property being accessed. 29370 * @param errorNode The node where we should report an invalid property access error, or undefined if we should not report errors. 29371 */ 29372 function checkPropertyAccessibilityAtLocation(location: Node, 29373 isSuper: boolean, writing: boolean, 29374 containingType: Type, prop: Symbol, errorNode?: Node): boolean { 29375 29376 const flags = getDeclarationModifierFlagsFromSymbol(prop, writing); 29377 29378 if (isSuper) { 29379 // TS 1.0 spec (April 2014): 4.8.2 29380 // - In a constructor, instance member function, instance member accessor, or 29381 // instance member variable initializer where this references a derived class instance, 29382 // a super property access is permitted and must specify a public instance member function of the base class. 29383 // - In a static member function or static member accessor 29384 // where this references the constructor function object of a derived class, 29385 // a super property access is permitted and must specify a public static member function of the base class. 29386 if (languageVersion < ScriptTarget.ES2015) { 29387 if (symbolHasNonMethodDeclaration(prop)) { 29388 if (errorNode) { 29389 error(errorNode, Diagnostics.Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword); 29390 } 29391 return false; 29392 } 29393 } 29394 if (flags & ModifierFlags.Abstract) { 29395 // A method cannot be accessed in a super property access if the method is abstract. 29396 // This error could mask a private property access error. But, a member 29397 // cannot simultaneously be private and abstract, so this will trigger an 29398 // additional error elsewhere. 29399 if (errorNode) { 29400 error(errorNode, 29401 Diagnostics.Abstract_method_0_in_class_1_cannot_be_accessed_via_super_expression, 29402 symbolToString(prop), 29403 typeToString(getDeclaringClass(prop)!)); 29404 } 29405 return false; 29406 } 29407 } 29408 29409 // Referencing abstract properties within their own constructors is not allowed 29410 if ((flags & ModifierFlags.Abstract) && symbolHasNonMethodDeclaration(prop) && 29411 (isThisProperty(location) || isThisInitializedObjectBindingExpression(location) || isObjectBindingPattern(location.parent) && isThisInitializedDeclaration(location.parent.parent))) { 29412 const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(getParentOfSymbol(prop)!); 29413 if (declaringClassDeclaration && isNodeUsedDuringClassInitialization(location)) { 29414 if (errorNode) { 29415 error(errorNode, 29416 Diagnostics.Abstract_property_0_in_class_1_cannot_be_accessed_in_the_constructor, 29417 symbolToString(prop), 29418 getTextOfIdentifierOrLiteral(declaringClassDeclaration.name!)); 29419 } 29420 return false; 29421 } 29422 } 29423 29424 // Public properties are otherwise accessible. 29425 if (!(flags & ModifierFlags.NonPublicAccessibilityModifier)) { 29426 return true; 29427 } 29428 29429 // Property is known to be private or protected at this point 29430 29431 // Private property is accessible if the property is within the declaring class 29432 if (flags & ModifierFlags.Private) { 29433 const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(getParentOfSymbol(prop)!)!; 29434 if (!isNodeWithinClass(location, declaringClassDeclaration)) { 29435 if (errorNode) { 29436 error(errorNode, 29437 Diagnostics.Property_0_is_private_and_only_accessible_within_class_1, 29438 symbolToString(prop), 29439 typeToString(getDeclaringClass(prop)!)); 29440 } 29441 return false; 29442 } 29443 return true; 29444 } 29445 29446 // Property is known to be protected at this point 29447 29448 // All protected properties of a supertype are accessible in a super access 29449 if (isSuper) { 29450 return true; 29451 } 29452 29453 // Find the first enclosing class that has the declaring classes of the protected constituents 29454 // of the property as base classes 29455 let enclosingClass = forEachEnclosingClass(location, enclosingDeclaration => { 29456 const enclosingClass = getDeclaredTypeOfSymbol(getSymbolOfNode(enclosingDeclaration)!) as InterfaceType; 29457 return isClassDerivedFromDeclaringClasses(enclosingClass, prop, writing); 29458 }); 29459 // A protected property is accessible if the property is within the declaring class or classes derived from it 29460 if (!enclosingClass) { 29461 // allow PropertyAccessibility if context is in function with this parameter 29462 // static member access is disallowed 29463 enclosingClass = getEnclosingClassFromThisParameter(location); 29464 enclosingClass = enclosingClass && isClassDerivedFromDeclaringClasses(enclosingClass, prop, writing); 29465 if (flags & ModifierFlags.Static || !enclosingClass) { 29466 if (errorNode) { 29467 error(errorNode, 29468 Diagnostics.Property_0_is_protected_and_only_accessible_within_class_1_and_its_subclasses, 29469 symbolToString(prop), 29470 typeToString(getDeclaringClass(prop) || containingType)); 29471 } 29472 return false; 29473 } 29474 } 29475 // No further restrictions for static properties 29476 if (flags & ModifierFlags.Static) { 29477 return true; 29478 } 29479 if (containingType.flags & TypeFlags.TypeParameter) { 29480 // get the original type -- represented as the type constraint of the 'this' type 29481 containingType = (containingType as TypeParameter).isThisType ? getConstraintOfTypeParameter(containingType as TypeParameter)! : getBaseConstraintOfType(containingType as TypeParameter)!; // TODO: GH#18217 Use a different variable that's allowed to be undefined 29482 } 29483 if (!containingType || !hasBaseType(containingType, enclosingClass)) { 29484 if (errorNode) { 29485 error(errorNode, 29486 Diagnostics.Property_0_is_protected_and_only_accessible_through_an_instance_of_class_1_This_is_an_instance_of_class_2, 29487 symbolToString(prop), typeToString(enclosingClass), typeToString(containingType)); 29488 } 29489 return false; 29490 } 29491 return true; 29492 } 29493 29494 function getEnclosingClassFromThisParameter(node: Node): InterfaceType | undefined { 29495 const thisParameter = getThisParameterFromNodeContext(node); 29496 let thisType = thisParameter?.type && getTypeFromTypeNode(thisParameter.type); 29497 if (thisType && thisType.flags & TypeFlags.TypeParameter) { 29498 thisType = getConstraintOfTypeParameter(thisType as TypeParameter); 29499 } 29500 if (thisType && getObjectFlags(thisType) & (ObjectFlags.ClassOrInterface | ObjectFlags.Reference)) { 29501 return getTargetType(thisType) as InterfaceType; 29502 } 29503 return undefined; 29504 } 29505 29506 function getThisParameterFromNodeContext(node: Node) { 29507 const thisContainer = getThisContainer(node, /* includeArrowFunctions */ false); 29508 return thisContainer && isFunctionLike(thisContainer) ? getThisParameter(thisContainer) : undefined; 29509 } 29510 29511 function symbolHasNonMethodDeclaration(symbol: Symbol) { 29512 return !!forEachProperty(symbol, prop => !(prop.flags & SymbolFlags.Method)); 29513 } 29514 29515 function checkNonNullExpression(node: Expression | QualifiedName, checkMode?: CheckMode) { 29516 return checkNonNullType(checkExpression(node, checkMode), node); 29517 } 29518 29519 function isNullableType(type: Type) { 29520 return !!(getTypeFacts(type) & TypeFacts.IsUndefinedOrNull); 29521 } 29522 29523 function getNonNullableTypeIfNeeded(type: Type) { 29524 return isNullableType(type) ? getNonNullableType(type) : type; 29525 } 29526 29527 function reportObjectPossiblyNullOrUndefinedError(node: Node, facts: TypeFacts) { 29528 const nodeText = isEntityNameExpression(node) ? entityNameToString(node) : undefined; 29529 if (node.kind === SyntaxKind.NullKeyword) { 29530 error(node, Diagnostics.The_value_0_cannot_be_used_here, "null"); 29531 return; 29532 } 29533 if (nodeText !== undefined && nodeText.length < 100) { 29534 if (isIdentifier(node) && nodeText === "undefined") { 29535 error(node, Diagnostics.The_value_0_cannot_be_used_here, "undefined"); 29536 return; 29537 } 29538 error(node, facts & TypeFacts.IsUndefined ? facts & TypeFacts.IsNull ? 29539 Diagnostics._0_is_possibly_null_or_undefined : 29540 Diagnostics._0_is_possibly_undefined : 29541 Diagnostics._0_is_possibly_null, 29542 nodeText 29543 ); 29544 } 29545 else { 29546 error(node, facts & TypeFacts.IsUndefined ? facts & TypeFacts.IsNull ? 29547 Diagnostics.Object_is_possibly_null_or_undefined : 29548 Diagnostics.Object_is_possibly_undefined : 29549 Diagnostics.Object_is_possibly_null 29550 ); 29551 } 29552 } 29553 29554 function reportCannotInvokePossiblyNullOrUndefinedError(node: Node, facts: TypeFacts) { 29555 error(node, facts & TypeFacts.IsUndefined ? facts & TypeFacts.IsNull ? 29556 Diagnostics.Cannot_invoke_an_object_which_is_possibly_null_or_undefined : 29557 Diagnostics.Cannot_invoke_an_object_which_is_possibly_undefined : 29558 Diagnostics.Cannot_invoke_an_object_which_is_possibly_null 29559 ); 29560 } 29561 29562 function checkNonNullTypeWithReporter( 29563 type: Type, 29564 node: Node, 29565 reportError: (node: Node, facts: TypeFacts) => void 29566 ): Type { 29567 if (strictNullChecks && type.flags & TypeFlags.Unknown) { 29568 if (isEntityNameExpression(node)) { 29569 const nodeText = entityNameToString(node); 29570 if (nodeText.length < 100) { 29571 error(node, Diagnostics._0_is_of_type_unknown, nodeText); 29572 return errorType; 29573 } 29574 } 29575 error(node, Diagnostics.Object_is_of_type_unknown); 29576 return errorType; 29577 } 29578 const facts = getTypeFacts(type); 29579 if (facts & TypeFacts.IsUndefinedOrNull) { 29580 reportError(node, facts); 29581 const t = getNonNullableType(type); 29582 return t.flags & (TypeFlags.Nullable | TypeFlags.Never) ? errorType : t; 29583 } 29584 return type; 29585 } 29586 29587 function checkNonNullType(type: Type, node: Node) { 29588 return checkNonNullTypeWithReporter(type, node, reportObjectPossiblyNullOrUndefinedError); 29589 } 29590 29591 function checkNonNullNonVoidType(type: Type, node: Node): Type { 29592 const nonNullType = checkNonNullType(type, node); 29593 if (nonNullType.flags & TypeFlags.Void) { 29594 if (isEntityNameExpression(node)) { 29595 const nodeText = entityNameToString(node); 29596 if (isIdentifier(node) && nodeText === "undefined") { 29597 error(node, Diagnostics.The_value_0_cannot_be_used_here, nodeText); 29598 return nonNullType; 29599 } 29600 if (nodeText.length < 100) { 29601 error(node, Diagnostics._0_is_possibly_undefined, nodeText); 29602 return nonNullType; 29603 } 29604 } 29605 error(node, Diagnostics.Object_is_possibly_undefined); 29606 } 29607 return nonNullType; 29608 } 29609 29610 29611 function checkPropertyAccessExpression(node: PropertyAccessExpression, checkMode: CheckMode | undefined) { 29612 if (checkMode !== CheckMode.SkipEtsComponentBody) { 29613 propertyAccessExpressionConditionCheck(node); 29614 } 29615 return node.flags & NodeFlags.OptionalChain ? checkPropertyAccessChain(node as PropertyAccessChain, checkMode) : 29616 checkPropertyAccessExpressionOrQualifiedName(node, node.expression, checkNonNullExpression(node.expression), node.name, checkMode); 29617 } 29618 29619 function checkPropertyAccessChain(node: PropertyAccessChain, checkMode: CheckMode | undefined) { 29620 const leftType = checkExpression(node.expression); 29621 const nonOptionalType = getOptionalExpressionType(leftType, node.expression); 29622 return propagateOptionalTypeMarker(checkPropertyAccessExpressionOrQualifiedName(node, node.expression, checkNonNullType(nonOptionalType, node.expression), node.name, checkMode), node, nonOptionalType !== leftType); 29623 } 29624 29625 function checkQualifiedName(node: QualifiedName, checkMode: CheckMode | undefined) { 29626 const leftType = isPartOfTypeQuery(node) && isThisIdentifier(node.left) ? checkNonNullType(checkThisExpression(node.left), node.left) : checkNonNullExpression(node.left); 29627 return checkPropertyAccessExpressionOrQualifiedName(node, node.left, leftType, node.right, checkMode); 29628 } 29629 29630 function isMethodAccessForCall(node: Node) { 29631 while (node.parent.kind === SyntaxKind.ParenthesizedExpression) { 29632 node = node.parent; 29633 } 29634 return isCallOrNewExpression(node.parent) && node.parent.expression === node; 29635 } 29636 29637 // Lookup the private identifier lexically. 29638 function lookupSymbolForPrivateIdentifierDeclaration(propName: __String, location: Node): Symbol | undefined { 29639 for (let containingClass = getContainingClass(location); !!containingClass; containingClass = getContainingClass(containingClass)) { 29640 const { symbol } = containingClass; 29641 const name = getSymbolNameForPrivateIdentifier(symbol, propName); 29642 const prop = (symbol.members && symbol.members.get(name)) || (symbol.exports && symbol.exports.get(name)); 29643 if (prop) { 29644 return prop; 29645 } 29646 } 29647 } 29648 29649 function checkGrammarPrivateIdentifierExpression(privId: PrivateIdentifier): boolean { 29650 if (!getContainingClass(privId)) { 29651 return grammarErrorOnNode(privId, Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies); 29652 } 29653 29654 if (!isForInStatement(privId.parent)) { 29655 if (!isExpressionNode(privId)) { 29656 return grammarErrorOnNode(privId, Diagnostics.Private_identifiers_are_only_allowed_in_class_bodies_and_may_only_be_used_as_part_of_a_class_member_declaration_property_access_or_on_the_left_hand_side_of_an_in_expression); 29657 } 29658 29659 const isInOperation = isBinaryExpression(privId.parent) && privId.parent.operatorToken.kind === SyntaxKind.InKeyword; 29660 if (!getSymbolForPrivateIdentifierExpression(privId) && !isInOperation) { 29661 return grammarErrorOnNode(privId, Diagnostics.Cannot_find_name_0, idText(privId)); 29662 } 29663 } 29664 29665 return false; 29666 } 29667 29668 function checkPrivateIdentifierExpression(privId: PrivateIdentifier): Type { 29669 checkGrammarPrivateIdentifierExpression(privId); 29670 const symbol = getSymbolForPrivateIdentifierExpression(privId); 29671 if (symbol) { 29672 markPropertyAsReferenced(symbol, /* nodeForCheckWriteOnly: */ undefined, /* isThisAccess: */ false); 29673 } 29674 return anyType; 29675 } 29676 29677 function getSymbolForPrivateIdentifierExpression(privId: PrivateIdentifier): Symbol | undefined { 29678 if (!isExpressionNode(privId)) { 29679 return undefined; 29680 } 29681 29682 const links = getNodeLinks(privId); 29683 if (links.resolvedSymbol === undefined) { 29684 links.resolvedSymbol = lookupSymbolForPrivateIdentifierDeclaration(privId.escapedText, privId); 29685 } 29686 return links.resolvedSymbol; 29687 } 29688 29689 function getPrivateIdentifierPropertyOfType(leftType: Type, lexicallyScopedIdentifier: Symbol): Symbol | undefined { 29690 return getPropertyOfType(leftType, lexicallyScopedIdentifier.escapedName); 29691 } 29692 29693 function checkPrivateIdentifierPropertyAccess(leftType: Type, right: PrivateIdentifier, lexicallyScopedIdentifier: Symbol | undefined): boolean { 29694 // Either the identifier could not be looked up in the lexical scope OR the lexically scoped identifier did not exist on the type. 29695 // Find a private identifier with the same description on the type. 29696 let propertyOnType: Symbol | undefined; 29697 const properties = getPropertiesOfType(leftType); 29698 if (properties) { 29699 forEach(properties, (symbol: Symbol) => { 29700 const decl = symbol.valueDeclaration; 29701 if (decl && isNamedDeclaration(decl) && isPrivateIdentifier(decl.name) && decl.name.escapedText === right.escapedText) { 29702 propertyOnType = symbol; 29703 return true; 29704 } 29705 }); 29706 } 29707 const diagName = diagnosticName(right); 29708 if (propertyOnType) { 29709 const typeValueDecl = Debug.checkDefined(propertyOnType.valueDeclaration); 29710 const typeClass = Debug.checkDefined(getContainingClass(typeValueDecl)); 29711 // We found a private identifier property with the same description. 29712 // Either: 29713 // - There is a lexically scoped private identifier AND it shadows the one we found on the type. 29714 // - It is an attempt to access the private identifier outside of the class. 29715 if (lexicallyScopedIdentifier?.valueDeclaration) { 29716 const lexicalValueDecl = lexicallyScopedIdentifier.valueDeclaration; 29717 const lexicalClass = getContainingClass(lexicalValueDecl); 29718 Debug.assert(!!lexicalClass); 29719 if (findAncestor(lexicalClass, n => typeClass === n)) { 29720 const diagnostic = error( 29721 right, 29722 Diagnostics.The_property_0_cannot_be_accessed_on_type_1_within_this_class_because_it_is_shadowed_by_another_private_identifier_with_the_same_spelling, 29723 diagName, 29724 typeToString(leftType) 29725 ); 29726 29727 addRelatedInfo( 29728 diagnostic, 29729 createDiagnosticForNode( 29730 lexicalValueDecl, 29731 Diagnostics.The_shadowing_declaration_of_0_is_defined_here, 29732 diagName 29733 ), 29734 createDiagnosticForNode( 29735 typeValueDecl, 29736 Diagnostics.The_declaration_of_0_that_you_probably_intended_to_use_is_defined_here, 29737 diagName 29738 ) 29739 ); 29740 return true; 29741 } 29742 } 29743 error( 29744 right, 29745 Diagnostics.Property_0_is_not_accessible_outside_class_1_because_it_has_a_private_identifier, 29746 diagName, 29747 diagnosticName(typeClass.name || anon) 29748 ); 29749 return true; 29750 } 29751 return false; 29752 } 29753 29754 function isThisPropertyAccessInConstructor(node: ElementAccessExpression | PropertyAccessExpression | QualifiedName, prop: Symbol) { 29755 return (isConstructorDeclaredProperty(prop) || isThisProperty(node) && isAutoTypedProperty(prop)) 29756 && getThisContainer(node, /*includeArrowFunctions*/ true) === getDeclaringConstructor(prop); 29757 } 29758 29759 function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, leftType: Type, right: Identifier | PrivateIdentifier, checkMode: CheckMode | undefined) { 29760 const parentSymbol = getNodeLinks(left).resolvedSymbol; 29761 const assignmentKind = getAssignmentTargetKind(node); 29762 const apparentType = getApparentType(assignmentKind !== AssignmentKind.None || isMethodAccessForCall(node) ? getWidenedType(leftType) : leftType); 29763 const isAnyLike = isTypeAny(apparentType) || apparentType === silentNeverType; 29764 let prop: Symbol | undefined; 29765 29766 if (isPropertyAccessExpression(node) && isConstEnumObjectType(leftType)) { 29767 checkConstEnumRelate(node, leftType.symbol); 29768 } 29769 29770 if (isPrivateIdentifier(right)) { 29771 if (languageVersion < ScriptTarget.ESNext) { 29772 if (assignmentKind !== AssignmentKind.None) { 29773 checkExternalEmitHelpers(node, ExternalEmitHelpers.ClassPrivateFieldSet); 29774 } 29775 if (assignmentKind !== AssignmentKind.Definite) { 29776 checkExternalEmitHelpers(node, ExternalEmitHelpers.ClassPrivateFieldGet); 29777 } 29778 } 29779 29780 const lexicallyScopedSymbol = lookupSymbolForPrivateIdentifierDeclaration(right.escapedText, right); 29781 if (assignmentKind && lexicallyScopedSymbol && lexicallyScopedSymbol.valueDeclaration && isMethodDeclaration(lexicallyScopedSymbol.valueDeclaration)) { 29782 grammarErrorOnNode(right, Diagnostics.Cannot_assign_to_private_method_0_Private_methods_are_not_writable, idText(right)); 29783 } 29784 29785 if (isAnyLike) { 29786 if (lexicallyScopedSymbol) { 29787 return isErrorType(apparentType) ? errorType : apparentType; 29788 } 29789 if (!getContainingClass(right)) { 29790 grammarErrorOnNode(right, Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies); 29791 return anyType; 29792 } 29793 } 29794 prop = lexicallyScopedSymbol ? getPrivateIdentifierPropertyOfType(leftType, lexicallyScopedSymbol) : undefined; 29795 // Check for private-identifier-specific shadowing and lexical-scoping errors. 29796 if (!prop && checkPrivateIdentifierPropertyAccess(leftType, right, lexicallyScopedSymbol)) { 29797 return errorType; 29798 } 29799 else { 29800 const isSetonlyAccessor = prop && prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor); 29801 if (isSetonlyAccessor && assignmentKind !== AssignmentKind.Definite) { 29802 error(node, Diagnostics.Private_accessor_was_defined_without_a_getter); 29803 } 29804 } 29805 } 29806 else { 29807 if (isAnyLike) { 29808 if (isIdentifier(left) && parentSymbol) { 29809 markAliasReferenced(parentSymbol, node); 29810 } 29811 return isErrorType(apparentType) ? errorType : apparentType; 29812 } 29813 prop = getPropertyOfType(apparentType, right.escapedText, /*skipObjectFunctionPropertyAugment*/ false, /*includeTypeOnlyMembers*/ node.kind === SyntaxKind.QualifiedName); 29814 if (!prop) { 29815 const etsComponentExpressionNode = getEtsComponentExpressionInnerCallExpressionNode(node) 29816 || getRootEtsComponentInnerCallExpressionNode(node); 29817 const locals = getSourceFileOfNode(node).locals; 29818 if (etsComponentExpressionNode && locals?.has(right.escapedText)) { 29819 const extraSymbol = locals?.get(right.escapedText); 29820 const decorators = getAllDecorators(extraSymbol?.valueDeclaration); 29821 const etsComponentName = etsComponentExpressionNode.expression.kind === SyntaxKind.Identifier ? (<Identifier>etsComponentExpressionNode.expression).escapedText : undefined; 29822 if (getEtsExtendDecoratorsComponentNames(decorators, compilerOptions).find(extendComponentName => extendComponentName === etsComponentName)) { 29823 prop = extraSymbol; 29824 } 29825 if (hasEtsStylesDecoratorNames(decorators, compilerOptions)) { 29826 prop = extraSymbol; 29827 } 29828 } 29829 const props = getContainingStruct(node)?.symbol.members; 29830 if (etsComponentExpressionNode && props?.has(right.escapedText)) { 29831 const stylesSymbol = props?.get(right.escapedText); 29832 const decorators = getAllDecorators(stylesSymbol?.valueDeclaration); 29833 if (hasEtsStylesDecoratorNames(decorators, compilerOptions)) { 29834 prop = stylesSymbol; 29835 } 29836 } 29837 } 29838 } 29839 // In `Foo.Bar.Baz`, 'Foo' is not referenced if 'Bar' is a const enum or a module containing only const enums. 29840 // `Foo` is also not referenced in `enum FooCopy { Bar = Foo.Bar }`, because the enum member value gets inlined 29841 // here even if `Foo` is not a const enum. 29842 // 29843 // The exceptions are: 29844 // 1. if 'isolatedModules' is enabled, because the const enum value will not be inlined, and 29845 // 2. if 'preserveConstEnums' is enabled and the expression is itself an export, e.g. `export = Foo.Bar.Baz`. 29846 if (isIdentifier(left) && parentSymbol && ( 29847 compilerOptions.isolatedModules || 29848 !(prop && (isConstEnumOrConstEnumOnlyModule(prop) || prop.flags & SymbolFlags.EnumMember && node.parent.kind === SyntaxKind.EnumMember)) || 29849 shouldPreserveConstEnums(compilerOptions) && isExportOrExportExpression(node) 29850 )) { 29851 markAliasReferenced(parentSymbol, node); 29852 } 29853 29854 let propType: Type; 29855 if (!prop) { 29856 const indexInfo = !isPrivateIdentifier(right) && (assignmentKind === AssignmentKind.None || !isGenericObjectType(leftType) || isThisTypeParameter(leftType)) ? 29857 getApplicableIndexInfoForName(apparentType, right.escapedText) : undefined; 29858 if (!(indexInfo && indexInfo.type)) { 29859 const isUncheckedJS = isUncheckedJSSuggestion(node, leftType.symbol, /*excludeClasses*/ true); 29860 if (!isUncheckedJS && isJSLiteralType(leftType)) { 29861 return anyType; 29862 } 29863 if (leftType.symbol === globalThisSymbol) { 29864 if (globalThisSymbol.exports!.has(right.escapedText) && (globalThisSymbol.exports!.get(right.escapedText)!.flags & SymbolFlags.BlockScoped)) { 29865 error(right, Diagnostics.Property_0_does_not_exist_on_type_1, unescapeLeadingUnderscores(right.escapedText), typeToString(leftType)); 29866 } 29867 else if (noImplicitAny) { 29868 error(right, Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature, typeToString(leftType)); 29869 } 29870 return anyType; 29871 } 29872 if (right.escapedText && !checkAndReportErrorForExtendingInterface(node)) { 29873 reportNonexistentProperty(right, isThisTypeParameter(leftType) ? apparentType : leftType, isUncheckedJS); 29874 } 29875 return errorType; 29876 } 29877 if (indexInfo.isReadonly && (isAssignmentTarget(node) || isDeleteTarget(node))) { 29878 error(node, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(apparentType)); 29879 } 29880 29881 propType = (compilerOptions.noUncheckedIndexedAccess && !isAssignmentTarget(node)) ? getUnionType([indexInfo.type, undefinedType]) : indexInfo.type; 29882 if (compilerOptions.noPropertyAccessFromIndexSignature && isPropertyAccessExpression(node)) { 29883 error(right, Diagnostics.Property_0_comes_from_an_index_signature_so_it_must_be_accessed_with_0, unescapeLeadingUnderscores(right.escapedText)); 29884 } 29885 if (indexInfo.declaration && getCombinedNodeFlags(indexInfo.declaration) & NodeFlags.Deprecated) { 29886 addDeprecatedSuggestion(right, [indexInfo.declaration], right.escapedText as string); 29887 } 29888 } 29889 else { 29890 if (isDeprecatedSymbol(prop) && isUncalledFunctionReference(node, prop) && prop.declarations) { 29891 addDeprecatedSuggestion(right, prop.declarations, right.escapedText as string); 29892 } 29893 checkPropertyNotUsedBeforeDeclaration(prop, node, right); 29894 markPropertyAsReferenced(prop, node, isSelfTypeAccess(left, parentSymbol)); 29895 getNodeLinks(node).resolvedSymbol = prop; 29896 const writing = isWriteAccess(node); 29897 checkPropertyAccessibility(node, left.kind === SyntaxKind.SuperKeyword, writing, apparentType, prop); 29898 if (isAssignmentToReadonlyEntity(node as Expression, prop, assignmentKind)) { 29899 error(right, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, idText(right)); 29900 return errorType; 29901 } 29902 29903 propType = isThisPropertyAccessInConstructor(node, prop) ? autoType : writing ? getWriteTypeOfSymbol(prop) : getTypeOfSymbol(prop); 29904 } 29905 29906 return getFlowTypeOfAccessExpression(node, prop, propType, right, checkMode); 29907 } 29908 29909 function checkConstEnumRelate(node: Node, originalSymbol: Symbol): void { 29910 const symbol = resolveSymbol(originalSymbol); 29911 let filePath = getSourceFileOfNode(node)?.resolvedPath; 29912 if (!symbol || !filePath) { return; } 29913 if (!constEnumRelate.has(filePath)) { 29914 constEnumRelate.set(filePath, new Map()); 29915 } 29916 symbol.declarations?.forEach(decl => { 29917 let file = getSourceFileOfNode(decl); 29918 if (!file || file.resolvedPath === filePath) { 29919 return; 29920 } 29921 constEnumRelate.get(filePath)?.set(file.resolvedPath, file.version); 29922 }); 29923 } 29924 29925 /** 29926 * Determines whether a did-you-mean error should be a suggestion in an unchecked JS file. 29927 * Only applies to unchecked JS files without checkJS, // @ts-check or // @ts-nocheck 29928 * It does not suggest when the suggestion: 29929 * - Is from a global file that is different from the reference file, or 29930 * - (optionally) Is a class, or is a this.x property access expression 29931 */ 29932 function isUncheckedJSSuggestion(node: Node | undefined, suggestion: Symbol | undefined, excludeClasses: boolean): boolean { 29933 const file = getSourceFileOfNode(node); 29934 if (file) { 29935 if (compilerOptions.checkJs === undefined && file.checkJsDirective === undefined && (file.scriptKind === ScriptKind.JS || file.scriptKind === ScriptKind.JSX)) { 29936 const declarationFile = forEach(suggestion?.declarations, getSourceFileOfNode); 29937 return !(file !== declarationFile && !!declarationFile && isGlobalSourceFile(declarationFile)) 29938 && !(excludeClasses && suggestion && suggestion.flags & SymbolFlags.Class) 29939 && !(!!node && excludeClasses && isPropertyAccessExpression(node) && node.expression.kind === SyntaxKind.ThisKeyword); 29940 } 29941 } 29942 return false; 29943 } 29944 29945 function getFlowTypeOfAccessExpression(node: ElementAccessExpression | PropertyAccessExpression | QualifiedName, prop: Symbol | undefined, propType: Type, errorNode: Node, checkMode: CheckMode | undefined) { 29946 // Only compute control flow type if this is a property access expression that isn't an 29947 // assignment target, and the referenced property was declared as a variable, property, 29948 // accessor, or optional method. 29949 const assignmentKind = getAssignmentTargetKind(node); 29950 if (assignmentKind === AssignmentKind.Definite) { 29951 return removeMissingType(propType, !!(prop && prop.flags & SymbolFlags.Optional)); 29952 } 29953 if (prop && 29954 !(prop.flags & (SymbolFlags.Variable | SymbolFlags.Property | SymbolFlags.Accessor)) 29955 && !(prop.flags & SymbolFlags.Method && propType.flags & TypeFlags.Union) 29956 && !isDuplicatedCommonJSExport(prop.declarations)) { 29957 return propType; 29958 } 29959 if (propType === autoType) { 29960 return getFlowTypeOfProperty(node, prop); 29961 } 29962 propType = getNarrowableTypeForReference(propType, node, checkMode); 29963 // If strict null checks and strict property initialization checks are enabled, if we have 29964 // a this.xxx property access, if the property is an instance property without an initializer, 29965 // and if we are in a constructor of the same class as the property declaration, assume that 29966 // the property is uninitialized at the top of the control flow. 29967 let assumeUninitialized = false; 29968 if (strictNullChecks && strictPropertyInitialization && isAccessExpression(node) && node.expression.kind === SyntaxKind.ThisKeyword) { 29969 const declaration = prop && prop.valueDeclaration; 29970 if (declaration && isPropertyWithoutInitializer(declaration)) { 29971 if (!isStatic(declaration)) { 29972 const flowContainer = getControlFlowContainer(node); 29973 if (flowContainer.kind === SyntaxKind.Constructor && flowContainer.parent === declaration.parent && !(declaration.flags & NodeFlags.Ambient)) { 29974 assumeUninitialized = true; 29975 } 29976 } 29977 } 29978 } 29979 else if (strictNullChecks && prop && prop.valueDeclaration && 29980 isPropertyAccessExpression(prop.valueDeclaration) && 29981 getAssignmentDeclarationPropertyAccessKind(prop.valueDeclaration) && 29982 getControlFlowContainer(node) === getControlFlowContainer(prop.valueDeclaration)) { 29983 assumeUninitialized = true; 29984 } 29985 const flowType = getFlowTypeOfReference(node, propType, assumeUninitialized ? getOptionalType(propType) : propType); 29986 if (assumeUninitialized && !containsUndefinedType(propType) && containsUndefinedType(flowType)) { 29987 error(errorNode, Diagnostics.Property_0_is_used_before_being_assigned, symbolToString(prop!)); // TODO: GH#18217 29988 // Return the declared type to reduce follow-on errors 29989 return propType; 29990 } 29991 return assignmentKind ? getBaseTypeOfLiteralType(flowType) : flowType; 29992 } 29993 29994 function checkPropertyNotUsedBeforeDeclaration(prop: Symbol, node: PropertyAccessExpression | QualifiedName, right: Identifier | PrivateIdentifier): void { 29995 const { valueDeclaration } = prop; 29996 if (!valueDeclaration || getSourceFileOfNode(node).isDeclarationFile) { 29997 return; 29998 } 29999 30000 let diagnosticMessage; 30001 const declarationName = idText(right); 30002 if (isInPropertyInitializerOrClassStaticBlock(node) 30003 && !isOptionalPropertyDeclaration(valueDeclaration) 30004 && !(isAccessExpression(node) && isAccessExpression(node.expression)) 30005 && !isBlockScopedNameDeclaredBeforeUse(valueDeclaration, right) 30006 && !(isMethodDeclaration(valueDeclaration) && getCombinedModifierFlags(valueDeclaration) & ModifierFlags.Static) 30007 && (compilerOptions.useDefineForClassFields || !isPropertyDeclaredInAncestorClass(prop))) { 30008 let needInitialization: boolean | undefined = false; 30009 let hasRequireDecorator: boolean = false; 30010 const decorators = getAllDecorators(prop?.valueDeclaration) 30011 if (decorators) { 30012 needInitialization = host.getCompilerOptions().ets?.propertyDecorators.some(property => { 30013 return decorators?.some(decorator => { 30014 if (isIdentifier(decorator.expression) 30015 && property.name === decorator.expression.escapedText.toString() 30016 && !property.needInitialization) { 30017 return true; 30018 } 30019 else { 30020 return false; 30021 } 30022 }); 30023 }); 30024 hasRequireDecorator = decorators.some(decorator => { 30025 return isIdentifier(decorator.expression) && 30026 decorator.expression.escapedText.toString() === REQUIRE_DECORATOR; 30027 }); 30028 } 30029 // In the following cases, property can be uninitialized: 30030 // 1. Property is decorated with property decorators which allow no initialization, such as `@Link`, `@Prop`, `@ObjectLink` and `@Consume`. 30031 // 2. Property is decorated with `@Require` and satisfied the following conditions: 30032 // a. Property has been declared before used. 30033 // b. Property is declared and used in the same struct. 30034 if (!needInitialization && 30035 !(hasRequireDecorator && checkStructPropertyPosition(valueDeclaration, node))) { 30036 diagnosticMessage = error(right, Diagnostics.Property_0_is_used_before_its_initialization, declarationName); 30037 } 30038 } 30039 else if (valueDeclaration.kind === SyntaxKind.ClassDeclaration && 30040 node.parent.kind !== SyntaxKind.TypeReference && 30041 !(valueDeclaration.flags & NodeFlags.Ambient) && 30042 !isBlockScopedNameDeclaredBeforeUse(valueDeclaration, right)) { 30043 diagnosticMessage = error(right, Diagnostics.Class_0_used_before_its_declaration, declarationName); 30044 } 30045 30046 if (diagnosticMessage) { 30047 addRelatedInfo(diagnosticMessage, 30048 createDiagnosticForNode(valueDeclaration, Diagnostics._0_is_declared_here, declarationName) 30049 ); 30050 } 30051 } 30052 30053 function isInPropertyInitializerOrClassStaticBlock(node: Node): boolean { 30054 return !!findAncestor(node, node => { 30055 switch (node.kind) { 30056 case SyntaxKind.PropertyDeclaration: 30057 return true; 30058 case SyntaxKind.PropertyAssignment: 30059 case SyntaxKind.MethodDeclaration: 30060 case SyntaxKind.GetAccessor: 30061 case SyntaxKind.SetAccessor: 30062 case SyntaxKind.SpreadAssignment: 30063 case SyntaxKind.ComputedPropertyName: 30064 case SyntaxKind.TemplateSpan: 30065 case SyntaxKind.JsxExpression: 30066 case SyntaxKind.JsxAttribute: 30067 case SyntaxKind.JsxAttributes: 30068 case SyntaxKind.JsxSpreadAttribute: 30069 case SyntaxKind.JsxOpeningElement: 30070 case SyntaxKind.ExpressionWithTypeArguments: 30071 case SyntaxKind.HeritageClause: 30072 return false; 30073 case SyntaxKind.ArrowFunction: 30074 case SyntaxKind.ExpressionStatement: 30075 return isBlock(node.parent) && isClassStaticBlockDeclaration(node.parent.parent) ? true : "quit"; 30076 default: 30077 return isExpressionNode(node) ? false : "quit"; 30078 } 30079 }); 30080 } 30081 30082 /** 30083 * It's possible that "prop.valueDeclaration" is a local declaration, but the property was also declared in a superclass. 30084 * In that case we won't consider it used before its declaration, because it gets its value from the superclass' declaration. 30085 */ 30086 function isPropertyDeclaredInAncestorClass(prop: Symbol): boolean { 30087 if (!(prop.parent!.flags & SymbolFlags.Class)) { 30088 return false; 30089 } 30090 let classType: InterfaceType | undefined = getTypeOfSymbol(prop.parent!) as InterfaceType; 30091 while (true) { 30092 classType = classType.symbol && getSuperClass(classType) as InterfaceType | undefined; 30093 if (!classType) { 30094 return false; 30095 } 30096 const superProperty = getPropertyOfType(classType, prop.escapedName); 30097 if (superProperty && superProperty.valueDeclaration) { 30098 return true; 30099 } 30100 } 30101 } 30102 30103 function getSuperClass(classType: InterfaceType): Type | undefined { 30104 const x = getBaseTypes(classType); 30105 if (x.length === 0) { 30106 return undefined; 30107 } 30108 return getIntersectionType(x); 30109 } 30110 30111 function reportNonexistentProperty(propNode: Identifier | PrivateIdentifier, containingType: Type, isUncheckedJS: boolean) { 30112 let errorInfo: DiagnosticMessageChain | undefined; 30113 let relatedInfo: Diagnostic | undefined; 30114 if (!isPrivateIdentifier(propNode) && containingType.flags & TypeFlags.Union && !(containingType.flags & TypeFlags.Primitive)) { 30115 for (const subtype of (containingType as UnionType).types) { 30116 if (!getPropertyOfType(subtype, propNode.escapedText) && !getApplicableIndexInfoForName(subtype, propNode.escapedText)) { 30117 errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(propNode), typeToString(subtype)); 30118 break; 30119 } 30120 } 30121 } 30122 if (typeHasStaticProperty(propNode.escapedText, containingType)) { 30123 const propName = declarationNameToString(propNode); 30124 const typeName = typeToString(containingType); 30125 errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_to_access_the_static_member_2_instead, propName, typeName, typeName + "." + propName); 30126 } 30127 else { 30128 const promisedType = getPromisedTypeOfPromise(containingType); 30129 if (promisedType && getPropertyOfType(promisedType, propNode.escapedText)) { 30130 errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(propNode), typeToString(containingType)); 30131 relatedInfo = createDiagnosticForNode(propNode, Diagnostics.Did_you_forget_to_use_await); 30132 } 30133 else { 30134 const missingProperty = declarationNameToString(propNode); 30135 const container = typeToString(containingType); 30136 const libSuggestion = getSuggestedLibForNonExistentProperty(missingProperty, containingType); 30137 if (libSuggestion !== undefined) { 30138 errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_2_or_later, missingProperty, container, libSuggestion); 30139 } 30140 else { 30141 const suggestion = getSuggestedSymbolForNonexistentProperty(propNode, containingType); 30142 if (suggestion !== undefined) { 30143 const suggestedName = symbolName(suggestion); 30144 const message = isUncheckedJS ? Diagnostics.Property_0_may_not_exist_on_type_1_Did_you_mean_2 : Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2; 30145 errorInfo = chainDiagnosticMessages(errorInfo, message, missingProperty, container, suggestedName); 30146 relatedInfo = suggestion.valueDeclaration && createDiagnosticForNode(suggestion.valueDeclaration, Diagnostics._0_is_declared_here, suggestedName); 30147 } 30148 else { 30149 const diagnostic = containerSeemsToBeEmptyDomElement(containingType) 30150 ? Diagnostics.Property_0_does_not_exist_on_type_1_Try_changing_the_lib_compiler_option_to_include_dom 30151 : Diagnostics.Property_0_does_not_exist_on_type_1; 30152 errorInfo = chainDiagnosticMessages(elaborateNeverIntersection(errorInfo, containingType), diagnostic, missingProperty, container); 30153 } 30154 } 30155 } 30156 } 30157 const resultDiagnostic = createDiagnosticForNodeFromMessageChain(propNode, errorInfo); 30158 if (relatedInfo) { 30159 addRelatedInfo(resultDiagnostic, relatedInfo); 30160 } 30161 addErrorOrSuggestion(!isUncheckedJS || errorInfo.code !== Diagnostics.Property_0_may_not_exist_on_type_1_Did_you_mean_2.code, resultDiagnostic); 30162 } 30163 30164 function containerSeemsToBeEmptyDomElement(containingType: Type) { 30165 return (compilerOptions.lib && !compilerOptions.lib.includes("dom")) && 30166 everyContainedType(containingType, type => type.symbol && /^(EventTarget|Node|((HTML[a-zA-Z]*)?Element))$/.test(unescapeLeadingUnderscores(type.symbol.escapedName))) && 30167 isEmptyObjectType(containingType); 30168 } 30169 30170 function typeHasStaticProperty(propName: __String, containingType: Type): boolean { 30171 const prop = containingType.symbol && getPropertyOfType(getTypeOfSymbol(containingType.symbol), propName); 30172 return prop !== undefined && !!prop.valueDeclaration && isStatic(prop.valueDeclaration); 30173 } 30174 30175 function getSuggestedLibForNonExistentName(name: __String | Identifier) { 30176 const missingName = diagnosticName(name); 30177 const allFeatures = getScriptTargetFeatures(); 30178 const libTargets = getOwnKeys(allFeatures); 30179 for (const libTarget of libTargets) { 30180 const containingTypes = getOwnKeys(allFeatures[libTarget]); 30181 if (containingTypes !== undefined && contains(containingTypes, missingName)) { 30182 return libTarget; 30183 } 30184 } 30185 } 30186 30187 function getSuggestedLibForNonExistentProperty(missingProperty: string, containingType: Type) { 30188 const container = getApparentType(containingType).symbol; 30189 if (!container) { 30190 return undefined; 30191 } 30192 const allFeatures = getScriptTargetFeatures(); 30193 const libTargets = getOwnKeys(allFeatures); 30194 for (const libTarget of libTargets) { 30195 const featuresOfLib = allFeatures[libTarget]; 30196 const featuresOfContainingType = featuresOfLib[symbolName(container)]; 30197 if (featuresOfContainingType !== undefined && contains(featuresOfContainingType, missingProperty)) { 30198 return libTarget; 30199 } 30200 } 30201 } 30202 30203 function getSuggestedSymbolForNonexistentClassMember(name: string, baseType: Type): Symbol | undefined { 30204 return getSpellingSuggestionForName(name, getPropertiesOfType(baseType), SymbolFlags.ClassMember); 30205 } 30206 30207 function getSuggestedSymbolForNonexistentProperty(name: Identifier | PrivateIdentifier | string, containingType: Type): Symbol | undefined { 30208 let props = getPropertiesOfType(containingType); 30209 if (typeof name !== "string") { 30210 const parent = name.parent; 30211 if (isPropertyAccessExpression(parent)) { 30212 props = filter(props, prop => isValidPropertyAccessForCompletions(parent, containingType, prop)); 30213 } 30214 name = idText(name); 30215 } 30216 return getSpellingSuggestionForName(name, props, SymbolFlags.Value); 30217 } 30218 30219 function getSuggestedSymbolForNonexistentJSXAttribute(name: Identifier | PrivateIdentifier | string, containingType: Type): Symbol | undefined { 30220 const strName = isString(name) ? name : idText(name); 30221 const properties = getPropertiesOfType(containingType); 30222 const jsxSpecific = strName === "for" ? find(properties, x => symbolName(x) === "htmlFor") 30223 : strName === "class" ? find(properties, x => symbolName(x) === "className") 30224 : undefined; 30225 return jsxSpecific ?? getSpellingSuggestionForName(strName, properties, SymbolFlags.Value); 30226 } 30227 30228 function getSuggestionForNonexistentProperty(name: Identifier | PrivateIdentifier | string, containingType: Type): string | undefined { 30229 const suggestion = getSuggestedSymbolForNonexistentProperty(name, containingType); 30230 return suggestion && symbolName(suggestion); 30231 } 30232 30233 function getSuggestedSymbolForNonexistentSymbol(location: Node | undefined, outerName: __String, meaning: SymbolFlags): Symbol | undefined { 30234 Debug.assert(outerName !== undefined, "outername should always be defined"); 30235 const result = resolveNameHelper(location, outerName, meaning, /*nameNotFoundMessage*/ undefined, outerName, /*isUse*/ false, /*excludeGlobals*/ false, /*getSpellingSuggestions*/ true, (symbols, name, meaning, node) => { 30236 Debug.assertEqual(outerName, name, "name should equal outerName"); 30237 const symbol = getSymbol(symbols, name, meaning, node); 30238 // Sometimes the symbol is found when location is a return type of a function: `typeof x` and `x` is declared in the body of the function 30239 // So the table *contains* `x` but `x` isn't actually in scope. 30240 // However, resolveNameHelper will continue and call this callback again, so we'll eventually get a correct suggestion. 30241 if (symbol) return symbol; 30242 let candidates: Symbol[]; 30243 if (symbols === globals) { 30244 const primitives = mapDefined( 30245 ["string", "number", "boolean", "object", "bigint", "symbol"], 30246 s => symbols.has((s.charAt(0).toUpperCase() + s.slice(1)) as __String) 30247 ? createSymbol(SymbolFlags.TypeAlias, s as __String) as Symbol 30248 : undefined); 30249 candidates = primitives.concat(arrayFrom(symbols.values())); 30250 } 30251 else { 30252 candidates = arrayFrom(symbols.values()); 30253 } 30254 return getSpellingSuggestionForName(unescapeLeadingUnderscores(name), candidates, meaning); 30255 }); 30256 return result; 30257 } 30258 30259 function getSuggestionForNonexistentSymbol(location: Node | undefined, outerName: __String, meaning: SymbolFlags): string | undefined { 30260 const symbolResult = getSuggestedSymbolForNonexistentSymbol(location, outerName, meaning); 30261 return symbolResult && symbolName(symbolResult); 30262 } 30263 30264 function getSuggestedSymbolForNonexistentModule(name: Identifier, targetModule: Symbol): Symbol | undefined { 30265 return targetModule.exports && getSpellingSuggestionForName(idText(name), getExportsOfModuleAsArray(targetModule), SymbolFlags.ModuleMember); 30266 } 30267 30268 function getSuggestionForNonexistentExport(name: Identifier, targetModule: Symbol): string | undefined { 30269 const suggestion = getSuggestedSymbolForNonexistentModule(name, targetModule); 30270 return suggestion && symbolName(suggestion); 30271 } 30272 30273 function getSuggestionForNonexistentIndexSignature(objectType: Type, expr: ElementAccessExpression, keyedType: Type): string | undefined { 30274 // check if object type has setter or getter 30275 function hasProp(name: "set" | "get") { 30276 const prop = getPropertyOfObjectType(objectType, name as __String); 30277 if (prop) { 30278 const s = getSingleCallSignature(getTypeOfSymbol(prop)); 30279 return !!s && getMinArgumentCount(s) >= 1 && isTypeAssignableTo(keyedType, getTypeAtPosition(s, 0)); 30280 } 30281 return false; 30282 } 30283 30284 const suggestedMethod = isAssignmentTarget(expr) ? "set" : "get"; 30285 if (!hasProp(suggestedMethod)) { 30286 return undefined; 30287 } 30288 30289 let suggestion = tryGetPropertyAccessOrIdentifierToString(expr.expression); 30290 if (suggestion === undefined) { 30291 suggestion = suggestedMethod; 30292 } 30293 else { 30294 suggestion += "." + suggestedMethod; 30295 } 30296 30297 return suggestion; 30298 } 30299 30300 function getSuggestedTypeForNonexistentStringLiteralType(source: StringLiteralType, target: UnionType): StringLiteralType | undefined { 30301 const candidates = target.types.filter((type): type is StringLiteralType => !!(type.flags & TypeFlags.StringLiteral)); 30302 return getSpellingSuggestion(source.value, candidates, type => type.value); 30303 } 30304 30305 /** 30306 * Given a name and a list of symbols whose names are *not* equal to the name, return a spelling suggestion if there is one that is close enough. 30307 * Names less than length 3 only check for case-insensitive equality, not levenshtein distance. 30308 * 30309 * If there is a candidate that's the same except for case, return that. 30310 * If there is a candidate that's within one edit of the name, return that. 30311 * Otherwise, return the candidate with the smallest Levenshtein distance, 30312 * except for candidates: 30313 * * With no name 30314 * * Whose meaning doesn't match the `meaning` parameter. 30315 * * Whose length differs from the target name by more than 0.34 of the length of the name. 30316 * * Whose levenshtein distance is more than 0.4 of the length of the name 30317 * (0.4 allows 1 substitution/transposition for every 5 characters, 30318 * and 1 insertion/deletion at 3 characters) 30319 */ 30320 function getSpellingSuggestionForName(name: string, symbols: Symbol[], meaning: SymbolFlags): Symbol | undefined { 30321 return getSpellingSuggestion(name, symbols, getCandidateName); 30322 30323 function getCandidateName(candidate: Symbol) { 30324 const candidateName = symbolName(candidate); 30325 if (startsWith(candidateName, "\"")) { 30326 return undefined; 30327 } 30328 30329 if (candidate.flags & meaning) { 30330 return candidateName; 30331 } 30332 30333 if (candidate.flags & SymbolFlags.Alias) { 30334 const alias = tryResolveAlias(candidate); 30335 if (alias && alias.flags & meaning) { 30336 return candidateName; 30337 } 30338 } 30339 30340 return undefined; 30341 } 30342 } 30343 30344 function markPropertyAsReferenced(prop: Symbol, nodeForCheckWriteOnly: Node | undefined, isSelfTypeAccess: boolean) { 30345 const valueDeclaration = prop && (prop.flags & SymbolFlags.ClassMember) && prop.valueDeclaration; 30346 if (!valueDeclaration) { 30347 return; 30348 } 30349 const hasPrivateModifier = hasEffectiveModifier(valueDeclaration, ModifierFlags.Private); 30350 const hasPrivateIdentifier = prop.valueDeclaration && isNamedDeclaration(prop.valueDeclaration) && isPrivateIdentifier(prop.valueDeclaration.name); 30351 if (!hasPrivateModifier && !hasPrivateIdentifier) { 30352 return; 30353 } 30354 if (nodeForCheckWriteOnly && isWriteOnlyAccess(nodeForCheckWriteOnly) && !(prop.flags & SymbolFlags.SetAccessor)) { 30355 return; 30356 } 30357 if (isSelfTypeAccess) { 30358 // Find any FunctionLikeDeclaration because those create a new 'this' binding. But this should only matter for methods (or getters/setters). 30359 const containingMethod = findAncestor(nodeForCheckWriteOnly, isFunctionLikeDeclaration); 30360 if (containingMethod && containingMethod.symbol === prop) { 30361 return; 30362 } 30363 } 30364 30365 (getCheckFlags(prop) & CheckFlags.Instantiated ? getSymbolLinks(prop).target : prop)!.isReferenced = SymbolFlags.All; 30366 } 30367 30368 function isSelfTypeAccess(name: Expression | QualifiedName, parent: Symbol | undefined) { 30369 return name.kind === SyntaxKind.ThisKeyword 30370 || !!parent && isEntityNameExpression(name) && parent === getResolvedSymbol(getFirstIdentifier(name)); 30371 } 30372 30373 function isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName | ImportTypeNode, propertyName: __String): boolean { 30374 switch (node.kind) { 30375 case SyntaxKind.PropertyAccessExpression: 30376 return isValidPropertyAccessWithType(node, node.expression.kind === SyntaxKind.SuperKeyword, propertyName, getWidenedType(checkExpression(node.expression))); 30377 case SyntaxKind.QualifiedName: 30378 return isValidPropertyAccessWithType(node, /*isSuper*/ false, propertyName, getWidenedType(checkExpression(node.left))); 30379 case SyntaxKind.ImportType: 30380 return isValidPropertyAccessWithType(node, /*isSuper*/ false, propertyName, getTypeFromTypeNode(node)); 30381 } 30382 } 30383 30384 /** 30385 * Checks if an existing property access is valid for completions purposes. 30386 * @param node a property access-like node where we want to check if we can access a property. 30387 * This node does not need to be an access of the property we are checking. 30388 * e.g. in completions, this node will often be an incomplete property access node, as in `foo.`. 30389 * Besides providing a location (i.e. scope) used to check property accessibility, we use this node for 30390 * computing whether this is a `super` property access. 30391 * @param type the type whose property we are checking. 30392 * @param property the accessed property's symbol. 30393 */ 30394 function isValidPropertyAccessForCompletions(node: PropertyAccessExpression | ImportTypeNode | QualifiedName, type: Type, property: Symbol): boolean { 30395 return isPropertyAccessible(node, 30396 node.kind === SyntaxKind.PropertyAccessExpression && node.expression.kind === SyntaxKind.SuperKeyword, 30397 /* isWrite */ false, 30398 type, 30399 property); 30400 // Previously we validated the 'this' type of methods but this adversely affected performance. See #31377 for more context. 30401 } 30402 30403 function isValidPropertyAccessWithType( 30404 node: PropertyAccessExpression | QualifiedName | ImportTypeNode, 30405 isSuper: boolean, 30406 propertyName: __String, 30407 type: Type): boolean { 30408 30409 // Short-circuiting for improved performance. 30410 if (isTypeAny(type)) { 30411 return true; 30412 } 30413 30414 const prop = getPropertyOfType(type, propertyName); 30415 return !!prop && isPropertyAccessible(node, isSuper, /* isWrite */ false, type, prop); 30416 } 30417 30418 /** 30419 * Checks if a property can be accessed in a location. 30420 * The location is given by the `node` parameter. 30421 * The node does not need to be a property access. 30422 * @param node location where to check property accessibility 30423 * @param isSuper whether to consider this a `super` property access, e.g. `super.foo`. 30424 * @param isWrite whether this is a write access, e.g. `++foo.x`. 30425 * @param containingType type where the property comes from. 30426 * @param property property symbol. 30427 */ 30428 function isPropertyAccessible( 30429 node: Node, 30430 isSuper: boolean, 30431 isWrite: boolean, 30432 containingType: Type, 30433 property: Symbol): boolean { 30434 30435 // Short-circuiting for improved performance. 30436 if (isTypeAny(containingType)) { 30437 return true; 30438 } 30439 30440 // A #private property access in an optional chain is an error dealt with by the parser. 30441 // The checker does not check for it, so we need to do our own check here. 30442 if (property.valueDeclaration && isPrivateIdentifierClassElementDeclaration(property.valueDeclaration)) { 30443 const declClass = getContainingClass(property.valueDeclaration); 30444 return !isOptionalChain(node) && !!findAncestor(node, parent => parent === declClass); 30445 } 30446 30447 return checkPropertyAccessibilityAtLocation(node, isSuper, isWrite, containingType, property); 30448 } 30449 30450 /** 30451 * Return the symbol of the for-in variable declared or referenced by the given for-in statement. 30452 */ 30453 function getForInVariableSymbol(node: ForInStatement): Symbol | undefined { 30454 const initializer = node.initializer; 30455 if (initializer.kind === SyntaxKind.VariableDeclarationList) { 30456 const variable = (initializer as VariableDeclarationList).declarations[0]; 30457 if (variable && !isBindingPattern(variable.name)) { 30458 return getSymbolOfNode(variable); 30459 } 30460 } 30461 else if (initializer.kind === SyntaxKind.Identifier) { 30462 return getResolvedSymbol(initializer as Identifier); 30463 } 30464 return undefined; 30465 } 30466 30467 /** 30468 * Return true if the given type is considered to have numeric property names. 30469 */ 30470 function hasNumericPropertyNames(type: Type) { 30471 return getIndexInfosOfType(type).length === 1 && !!getIndexInfoOfType(type, numberType); 30472 } 30473 30474 /** 30475 * Return true if given node is an expression consisting of an identifier (possibly parenthesized) 30476 * that references a for-in variable for an object with numeric property names. 30477 */ 30478 function isForInVariableForNumericPropertyNames(expr: Expression) { 30479 const e = skipParentheses(expr); 30480 if (e.kind === SyntaxKind.Identifier) { 30481 const symbol = getResolvedSymbol(e as Identifier); 30482 if (symbol.flags & SymbolFlags.Variable) { 30483 let child: Node = expr; 30484 let node = expr.parent; 30485 while (node) { 30486 if (node.kind === SyntaxKind.ForInStatement && 30487 child === (node as ForInStatement).statement && 30488 getForInVariableSymbol(node as ForInStatement) === symbol && 30489 hasNumericPropertyNames(getTypeOfExpression((node as ForInStatement).expression))) { 30490 return true; 30491 } 30492 child = node; 30493 node = node.parent; 30494 } 30495 } 30496 } 30497 return false; 30498 } 30499 30500 function checkIndexedAccess(node: ElementAccessExpression, checkMode: CheckMode | undefined): Type { 30501 return node.flags & NodeFlags.OptionalChain ? checkElementAccessChain(node as ElementAccessChain, checkMode) : 30502 checkElementAccessExpression(node, checkNonNullExpression(node.expression), checkMode); 30503 } 30504 30505 function checkElementAccessChain(node: ElementAccessChain, checkMode: CheckMode | undefined) { 30506 const exprType = checkExpression(node.expression); 30507 const nonOptionalType = getOptionalExpressionType(exprType, node.expression); 30508 return propagateOptionalTypeMarker(checkElementAccessExpression(node, checkNonNullType(nonOptionalType, node.expression), checkMode), node, nonOptionalType !== exprType); 30509 } 30510 30511 function checkElementAccessExpression(node: ElementAccessExpression, exprType: Type, checkMode: CheckMode | undefined): Type { 30512 const objectType = getAssignmentTargetKind(node) !== AssignmentKind.None || isMethodAccessForCall(node) ? getWidenedType(exprType) : exprType; 30513 const indexExpression = node.argumentExpression; 30514 const indexType = checkExpression(indexExpression); 30515 30516 if (isErrorType(objectType) || objectType === silentNeverType) { 30517 return objectType; 30518 } 30519 30520 if (isConstEnumObjectType(objectType) && !isStringLiteralLike(indexExpression)) { 30521 error(indexExpression, Diagnostics.A_const_enum_member_can_only_be_accessed_using_a_string_literal); 30522 return errorType; 30523 } 30524 30525 if (isConstEnumObjectType(objectType)) { 30526 checkConstEnumRelate(node, objectType.symbol); 30527 } 30528 30529 const effectiveIndexType = isForInVariableForNumericPropertyNames(indexExpression) ? numberType : indexType; 30530 const accessFlags = isAssignmentTarget(node) ? 30531 AccessFlags.Writing | (isGenericObjectType(objectType) && !isThisTypeParameter(objectType) ? AccessFlags.NoIndexSignatures : 0) : 30532 AccessFlags.ExpressionPosition; 30533 const indexedAccessType = getIndexedAccessTypeOrUndefined(objectType, effectiveIndexType, accessFlags, node) || errorType; 30534 return checkIndexedAccessIndexType(getFlowTypeOfAccessExpression(node, getNodeLinks(node).resolvedSymbol, indexedAccessType, indexExpression, checkMode), node); 30535 } 30536 30537 function callLikeExpressionMayHaveTypeArguments(node: CallLikeExpression): node is CallExpression | NewExpression | TaggedTemplateExpression | JsxOpeningElement { 30538 return isCallOrNewExpression(node) || isTaggedTemplateExpression(node) || isJsxOpeningLikeElement(node); 30539 } 30540 30541 function resolveUntypedCall(node: CallLikeExpression): Signature { 30542 if (callLikeExpressionMayHaveTypeArguments(node)) { 30543 // Check type arguments even though we will give an error that untyped calls may not accept type arguments. 30544 // This gets us diagnostics for the type arguments and marks them as referenced. 30545 forEach(node.typeArguments, checkSourceElement); 30546 } 30547 30548 if (node.kind === SyntaxKind.TaggedTemplateExpression) { 30549 checkExpression(node.template); 30550 } 30551 else if (isJsxOpeningLikeElement(node)) { 30552 checkExpression(node.attributes); 30553 } 30554 else if (node.kind !== SyntaxKind.Decorator) { 30555 forEach((node as CallExpression).arguments, argument => { 30556 checkExpression(argument); 30557 }); 30558 } 30559 return anySignature; 30560 } 30561 30562 function resolveErrorCall(node: CallLikeExpression): Signature { 30563 resolveUntypedCall(node); 30564 return unknownSignature; 30565 } 30566 30567 // Re-order candidate signatures into the result array. Assumes the result array to be empty. 30568 // The candidate list orders groups in reverse, but within a group signatures are kept in declaration order 30569 // A nit here is that we reorder only signatures that belong to the same symbol, 30570 // so order how inherited signatures are processed is still preserved. 30571 // interface A { (x: string): void } 30572 // interface B extends A { (x: 'foo'): string } 30573 // const b: B; 30574 // b('foo') // <- here overloads should be processed as [(x:'foo'): string, (x: string): void] 30575 function reorderCandidates(signatures: readonly Signature[], result: Signature[], callChainFlags: SignatureFlags): void { 30576 let lastParent: Node | undefined; 30577 let lastSymbol: Symbol | undefined; 30578 let cutoffIndex = 0; 30579 let index: number | undefined; 30580 let specializedIndex = -1; 30581 let spliceIndex: number; 30582 Debug.assert(!result.length); 30583 for (const signature of signatures) { 30584 const symbol = signature.declaration && getSymbolOfNode(signature.declaration); 30585 const parent = signature.declaration && signature.declaration.parent; 30586 if (!lastSymbol || symbol === lastSymbol) { 30587 if (lastParent && parent === lastParent) { 30588 index = index! + 1; 30589 } 30590 else { 30591 lastParent = parent; 30592 index = cutoffIndex; 30593 } 30594 } 30595 else { 30596 // current declaration belongs to a different symbol 30597 // set cutoffIndex so re-orderings in the future won't change result set from 0 to cutoffIndex 30598 index = cutoffIndex = result.length; 30599 lastParent = parent; 30600 } 30601 lastSymbol = symbol; 30602 30603 // specialized signatures always need to be placed before non-specialized signatures regardless 30604 // of the cutoff position; see GH#1133 30605 if (signatureHasLiteralTypes(signature)) { 30606 specializedIndex++; 30607 spliceIndex = specializedIndex; 30608 // The cutoff index always needs to be greater than or equal to the specialized signature index 30609 // in order to prevent non-specialized signatures from being added before a specialized 30610 // signature. 30611 cutoffIndex++; 30612 } 30613 else { 30614 spliceIndex = index; 30615 } 30616 30617 result.splice(spliceIndex, 0, callChainFlags ? getOptionalCallSignature(signature, callChainFlags) : signature); 30618 } 30619 } 30620 30621 function isSpreadArgument(arg: Expression | undefined): arg is Expression { 30622 return !!arg && (arg.kind === SyntaxKind.SpreadElement || arg.kind === SyntaxKind.SyntheticExpression && (arg as SyntheticExpression).isSpread); 30623 } 30624 30625 function getSpreadArgumentIndex(args: readonly Expression[]): number { 30626 return findIndex(args, isSpreadArgument); 30627 } 30628 30629 function acceptsVoid(t: Type): boolean { 30630 return !!(t.flags & TypeFlags.Void); 30631 } 30632 30633 function acceptsVoidUndefinedUnknownOrAny(t: Type): boolean { 30634 return !!(t.flags & (TypeFlags.Void | TypeFlags.Undefined | TypeFlags.Unknown | TypeFlags.Any)); 30635 } 30636 30637 function hasCorrectArity(node: CallLikeExpression, args: readonly Expression[], signature: Signature, signatureHelpTrailingComma = false) { 30638 let argCount: number; 30639 let callIsIncomplete = false; // In incomplete call we want to be lenient when we have too few arguments 30640 let effectiveParameterCount = getParameterCount(signature); 30641 let effectiveMinimumArguments = getMinArgumentCount(signature); 30642 30643 if (node.kind === SyntaxKind.TaggedTemplateExpression) { 30644 argCount = args.length; 30645 if (node.template.kind === SyntaxKind.TemplateExpression) { 30646 // If a tagged template expression lacks a tail literal, the call is incomplete. 30647 // Specifically, a template only can end in a TemplateTail or a Missing literal. 30648 const lastSpan = last(node.template.templateSpans); // we should always have at least one span. 30649 callIsIncomplete = nodeIsMissing(lastSpan.literal) || !!lastSpan.literal.isUnterminated; 30650 } 30651 else { 30652 // If the template didn't end in a backtick, or its beginning occurred right prior to EOF, 30653 // then this might actually turn out to be a TemplateHead in the future; 30654 // so we consider the call to be incomplete. 30655 const templateLiteral = node.template as LiteralExpression; 30656 Debug.assert(templateLiteral.kind === SyntaxKind.NoSubstitutionTemplateLiteral); 30657 callIsIncomplete = !!templateLiteral.isUnterminated; 30658 } 30659 } 30660 else if (node.kind === SyntaxKind.Decorator) { 30661 argCount = getDecoratorArgumentCount(node, signature); 30662 } 30663 else if (isJsxOpeningLikeElement(node)) { 30664 callIsIncomplete = node.attributes.end === node.end; 30665 if (callIsIncomplete) { 30666 return true; 30667 } 30668 argCount = effectiveMinimumArguments === 0 ? args.length : 1; 30669 effectiveParameterCount = args.length === 0 ? effectiveParameterCount : 1; // class may have argumentless ctor functions - still resolve ctor and compare vs props member type 30670 effectiveMinimumArguments = Math.min(effectiveMinimumArguments, 1); // sfc may specify context argument - handled by framework and not typechecked 30671 } 30672 else if (!node.arguments) { 30673 // This only happens when we have something of the form: 'new C' 30674 Debug.assert(node.kind === SyntaxKind.NewExpression); 30675 return getMinArgumentCount(signature) === 0; 30676 } 30677 else { 30678 argCount = signatureHelpTrailingComma ? args.length + 1 : args.length; 30679 30680 // If we are missing the close parenthesis, the call is incomplete. 30681 callIsIncomplete = node.arguments.end === node.end; 30682 30683 // If a spread argument is present, check that it corresponds to a rest parameter or at least that it's in the valid range. 30684 const spreadArgIndex = getSpreadArgumentIndex(args); 30685 if (spreadArgIndex >= 0) { 30686 return spreadArgIndex >= getMinArgumentCount(signature) && (hasEffectiveRestParameter(signature) || spreadArgIndex < getParameterCount(signature)); 30687 } 30688 } 30689 30690 // Too many arguments implies incorrect arity. 30691 if (!hasEffectiveRestParameter(signature) && argCount > effectiveParameterCount) { 30692 return false; 30693 } 30694 30695 // If the call is incomplete, we should skip the lower bound check. 30696 // JSX signatures can have extra parameters provided by the library which we don't check 30697 if (callIsIncomplete || argCount >= effectiveMinimumArguments) { 30698 return true; 30699 } 30700 for (let i = argCount; i < effectiveMinimumArguments; i++) { 30701 const type = getTypeAtPosition(signature, i); 30702 if (filterType(type, isInJSFile(node) && !strictNullChecks ? acceptsVoidUndefinedUnknownOrAny : acceptsVoid).flags & TypeFlags.Never) { 30703 return false; 30704 } 30705 } 30706 return true; 30707 } 30708 30709 function hasCorrectTypeArgumentArity(signature: Signature, typeArguments: NodeArray<TypeNode> | undefined, virtual?: boolean) { 30710 // If the user supplied type arguments, but the number of type arguments does not match 30711 // the declared number of type parameters, the call has an incorrect arity. 30712 const numTypeParameters = virtual ? 1 : length(signature.typeParameters); 30713 const minTypeArgumentCount = virtual ? 1 : getMinTypeArgumentCount(signature.typeParameters); 30714 return !some(typeArguments) || 30715 (typeArguments.length >= minTypeArgumentCount && typeArguments.length <= numTypeParameters); 30716 } 30717 30718 // If type has a single call signature and no other members, return that signature. Otherwise, return undefined. 30719 function getSingleCallSignature(type: Type): Signature | undefined { 30720 return getSingleSignature(type, SignatureKind.Call, /*allowMembers*/ false); 30721 } 30722 30723 function getSingleCallOrConstructSignature(type: Type): Signature | undefined { 30724 return getSingleSignature(type, SignatureKind.Call, /*allowMembers*/ false) || 30725 getSingleSignature(type, SignatureKind.Construct, /*allowMembers*/ false); 30726 } 30727 30728 function getSingleSignature(type: Type, kind: SignatureKind, allowMembers: boolean): Signature | undefined { 30729 if (type.flags & TypeFlags.Object) { 30730 const resolved = resolveStructuredTypeMembers(type as ObjectType); 30731 if (allowMembers || resolved.properties.length === 0 && resolved.indexInfos.length === 0) { 30732 if (kind === SignatureKind.Call && resolved.callSignatures.length === 1 && resolved.constructSignatures.length === 0) { 30733 return resolved.callSignatures[0]; 30734 } 30735 if (kind === SignatureKind.Construct && resolved.constructSignatures.length === 1 && resolved.callSignatures.length === 0) { 30736 return resolved.constructSignatures[0]; 30737 } 30738 } 30739 } 30740 return undefined; 30741 } 30742 30743 // Instantiate a generic signature in the context of a non-generic signature (section 3.8.5 in TypeScript spec) 30744 function instantiateSignatureInContextOf(signature: Signature, contextualSignature: Signature, inferenceContext?: InferenceContext, compareTypes?: TypeComparer): Signature { 30745 const context = createInferenceContext(signature.typeParameters!, signature, InferenceFlags.None, compareTypes); 30746 // We clone the inferenceContext to avoid fixing. For example, when the source signature is <T>(x: T) => T[] and 30747 // the contextual signature is (...args: A) => B, we want to infer the element type of A's constraint (say 'any') 30748 // for T but leave it possible to later infer '[any]' back to A. 30749 const restType = getEffectiveRestType(contextualSignature); 30750 const mapper = inferenceContext && (restType && restType.flags & TypeFlags.TypeParameter ? inferenceContext.nonFixingMapper : inferenceContext.mapper); 30751 const sourceSignature = mapper ? instantiateSignature(contextualSignature, mapper) : contextualSignature; 30752 applyToParameterTypes(sourceSignature, signature, (source, target) => { 30753 // Type parameters from outer context referenced by source type are fixed by instantiation of the source type 30754 inferTypes(context.inferences, source, target); 30755 }); 30756 if (!inferenceContext) { 30757 applyToReturnTypes(contextualSignature, signature, (source, target) => { 30758 inferTypes(context.inferences, source, target, InferencePriority.ReturnType); 30759 }); 30760 } 30761 return getSignatureInstantiation(signature, getInferredTypes(context), isInJSFile(contextualSignature.declaration)); 30762 } 30763 30764 function inferJsxTypeArguments(node: JsxOpeningLikeElement, signature: Signature, checkMode: CheckMode, context: InferenceContext): Type[] { 30765 const paramType = getEffectiveFirstArgumentForJsxSignature(signature, node); 30766 const checkAttrType = checkExpressionWithContextualType(node.attributes, paramType, context, checkMode); 30767 inferTypes(context.inferences, checkAttrType, paramType); 30768 return getInferredTypes(context); 30769 } 30770 30771 function getThisArgumentType(thisArgumentNode: LeftHandSideExpression | undefined) { 30772 if (!thisArgumentNode) { 30773 return voidType; 30774 } 30775 const thisArgumentType = checkExpression(thisArgumentNode); 30776 return isOptionalChainRoot(thisArgumentNode.parent) ? getNonNullableType(thisArgumentType) : 30777 isOptionalChain(thisArgumentNode.parent) ? removeOptionalTypeMarker(thisArgumentType) : 30778 thisArgumentType; 30779 } 30780 30781 function inferTypeArguments(node: CallLikeExpression, signature: Signature, args: readonly Expression[], checkMode: CheckMode, context: InferenceContext): Type[] { 30782 if (isJsxOpeningLikeElement(node)) { 30783 return inferJsxTypeArguments(node, signature, checkMode, context); 30784 } 30785 30786 // If a contextual type is available, infer from that type to the return type of the call expression. For 30787 // example, given a 'function wrap<T, U>(cb: (x: T) => U): (x: T) => U' and a call expression 30788 // 'let f: (x: string) => number = wrap(s => s.length)', we infer from the declared type of 'f' to the 30789 // return type of 'wrap'. 30790 if (node.kind !== SyntaxKind.Decorator) { 30791 const skipBindingPatterns = every(signature.typeParameters, p => !!getDefaultFromTypeParameter(p)); 30792 const contextualType = getContextualType(node, skipBindingPatterns ? ContextFlags.SkipBindingPatterns : ContextFlags.None); 30793 if (contextualType) { 30794 const inferenceTargetType = getReturnTypeOfSignature(signature); 30795 if (couldContainTypeVariables(inferenceTargetType)) { 30796 const outerContext = getInferenceContext(node); 30797 const isFromBindingPattern = !skipBindingPatterns && getContextualType(node, ContextFlags.SkipBindingPatterns) !== contextualType; 30798 // A return type inference from a binding pattern can be used in instantiating the contextual 30799 // type of an argument later in inference, but cannot stand on its own as the final return type. 30800 // It is incorporated into `context.returnMapper` which is used in `instantiateContextualType`, 30801 // but doesn't need to go into `context.inferences`. This allows a an array binding pattern to 30802 // produce a tuple for `T` in 30803 // declare function f<T>(cb: () => T): T; 30804 // const [e1, e2, e3] = f(() => [1, "hi", true]); 30805 // but does not produce any inference for `T` in 30806 // declare function f<T>(): T; 30807 // const [e1, e2, e3] = f(); 30808 if (!isFromBindingPattern) { 30809 // We clone the inference context to avoid disturbing a resolution in progress for an 30810 // outer call expression. Effectively we just want a snapshot of whatever has been 30811 // inferred for any outer call expression so far. 30812 const outerMapper = getMapperFromContext(cloneInferenceContext(outerContext, InferenceFlags.NoDefault)); 30813 const instantiatedType = instantiateType(contextualType, outerMapper); 30814 // If the contextual type is a generic function type with a single call signature, we 30815 // instantiate the type with its own type parameters and type arguments. This ensures that 30816 // the type parameters are not erased to type any during type inference such that they can 30817 // be inferred as actual types from the contextual type. For example: 30818 // declare function arrayMap<T, U>(f: (x: T) => U): (a: T[]) => U[]; 30819 // const boxElements: <A>(a: A[]) => { value: A }[] = arrayMap(value => ({ value })); 30820 // Above, the type of the 'value' parameter is inferred to be 'A'. 30821 const contextualSignature = getSingleCallSignature(instantiatedType); 30822 const inferenceSourceType = contextualSignature && contextualSignature.typeParameters ? 30823 getOrCreateTypeFromSignature(getSignatureInstantiationWithoutFillingInTypeArguments(contextualSignature, contextualSignature.typeParameters)) : 30824 instantiatedType; 30825 // Inferences made from return types have lower priority than all other inferences. 30826 inferTypes(context.inferences, inferenceSourceType, inferenceTargetType, InferencePriority.ReturnType); 30827 } 30828 // Create a type mapper for instantiating generic contextual types using the inferences made 30829 // from the return type. We need a separate inference pass here because (a) instantiation of 30830 // the source type uses the outer context's return mapper (which excludes inferences made from 30831 // outer arguments), and (b) we don't want any further inferences going into this context. 30832 const returnContext = createInferenceContext(signature.typeParameters!, signature, context.flags); 30833 const returnSourceType = instantiateType(contextualType, outerContext && outerContext.returnMapper); 30834 inferTypes(returnContext.inferences, returnSourceType, inferenceTargetType); 30835 context.returnMapper = some(returnContext.inferences, hasInferenceCandidates) ? getMapperFromContext(cloneInferredPartOfContext(returnContext)) : undefined; 30836 } 30837 } 30838 } 30839 30840 const restType = getNonArrayRestType(signature); 30841 const argCount = restType ? Math.min(getParameterCount(signature) - 1, args.length) : args.length; 30842 if (restType && restType.flags & TypeFlags.TypeParameter) { 30843 const info = find(context.inferences, info => info.typeParameter === restType); 30844 if (info) { 30845 info.impliedArity = findIndex(args, isSpreadArgument, argCount) < 0 ? args.length - argCount : undefined; 30846 } 30847 } 30848 30849 const thisType = getThisTypeOfSignature(signature); 30850 if (thisType && couldContainTypeVariables(thisType)) { 30851 const thisArgumentNode = getThisArgumentOfCall(node); 30852 inferTypes(context.inferences, getThisArgumentType(thisArgumentNode), thisType); 30853 } 30854 30855 for (let i = 0; i < argCount; i++) { 30856 const arg = args[i]; 30857 if (arg.kind !== SyntaxKind.OmittedExpression && !(checkMode & CheckMode.IsForStringLiteralArgumentCompletions && hasSkipDirectInferenceFlag(arg))) { 30858 const paramType = getTypeAtPosition(signature, i); 30859 if (couldContainTypeVariables(paramType)) { 30860 const argType = checkExpressionWithContextualType(arg, paramType, context, checkMode); 30861 inferTypes(context.inferences, argType, paramType); 30862 } 30863 } 30864 } 30865 30866 if (restType && couldContainTypeVariables(restType)) { 30867 const spreadType = getSpreadArgumentType(args, argCount, args.length, restType, context, checkMode); 30868 inferTypes(context.inferences, spreadType, restType); 30869 } 30870 30871 return getInferredTypes(context); 30872 } 30873 30874 function getMutableArrayOrTupleType(type: Type) { 30875 return type.flags & TypeFlags.Union ? mapType(type, getMutableArrayOrTupleType) : 30876 type.flags & TypeFlags.Any || isMutableArrayOrTuple(getBaseConstraintOfType(type) || type) ? type : 30877 isTupleType(type) ? createTupleType(getTypeArguments(type), type.target.elementFlags, /*readonly*/ false, type.target.labeledElementDeclarations) : 30878 createTupleType([type], [ElementFlags.Variadic]); 30879 } 30880 30881 function getSpreadArgumentType(args: readonly Expression[], index: number, argCount: number, restType: Type, context: InferenceContext | undefined, checkMode: CheckMode) { 30882 if (index >= argCount - 1) { 30883 const arg = args[argCount - 1]; 30884 if (isSpreadArgument(arg)) { 30885 // We are inferring from a spread expression in the last argument position, i.e. both the parameter 30886 // and the argument are ...x forms. 30887 return getMutableArrayOrTupleType(arg.kind === SyntaxKind.SyntheticExpression ? (arg as SyntheticExpression).type : 30888 checkExpressionWithContextualType((arg as SpreadElement).expression, restType, context, checkMode)); 30889 } 30890 } 30891 const types = []; 30892 const flags = []; 30893 const names = []; 30894 for (let i = index; i < argCount; i++) { 30895 const arg = args[i]; 30896 if (isSpreadArgument(arg)) { 30897 const spreadType = arg.kind === SyntaxKind.SyntheticExpression ? (arg as SyntheticExpression).type : checkExpression((arg as SpreadElement).expression); 30898 if (isArrayLikeType(spreadType)) { 30899 types.push(spreadType); 30900 flags.push(ElementFlags.Variadic); 30901 } 30902 else { 30903 types.push(checkIteratedTypeOrElementType(IterationUse.Spread, spreadType, undefinedType, arg.kind === SyntaxKind.SpreadElement ? (arg as SpreadElement).expression : arg)); 30904 flags.push(ElementFlags.Rest); 30905 } 30906 } 30907 else { 30908 const contextualType = getIndexedAccessType(restType, getNumberLiteralType(i - index), AccessFlags.Contextual); 30909 const argType = checkExpressionWithContextualType(arg, contextualType, context, checkMode); 30910 const hasPrimitiveContextualType = maybeTypeOfKind(contextualType, TypeFlags.Primitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping); 30911 types.push(hasPrimitiveContextualType ? getRegularTypeOfLiteralType(argType) : getWidenedLiteralType(argType)); 30912 flags.push(ElementFlags.Required); 30913 } 30914 if (arg.kind === SyntaxKind.SyntheticExpression && (arg as SyntheticExpression).tupleNameSource) { 30915 names.push((arg as SyntheticExpression).tupleNameSource!); 30916 } 30917 } 30918 return createTupleType(types, flags, /*readonly*/ false, length(names) === length(types) ? names : undefined); 30919 } 30920 30921 function checkTypeArguments(signature: Signature, typeArgumentNodes: readonly TypeNode[], reportErrors: boolean, headMessage?: DiagnosticMessage): Type[] | undefined { 30922 const isJavascript = isInJSFile(signature.declaration); 30923 const typeParameters = signature.typeParameters!; 30924 const typeArgumentTypes = fillMissingTypeArguments(map(typeArgumentNodes, getTypeFromTypeNode), typeParameters, getMinTypeArgumentCount(typeParameters), isJavascript); 30925 let mapper: TypeMapper | undefined; 30926 for (let i = 0; i < typeArgumentNodes.length; i++) { 30927 Debug.assert(typeParameters[i] !== undefined, "Should not call checkTypeArguments with too many type arguments"); 30928 const constraint = getConstraintOfTypeParameter(typeParameters[i]); 30929 if (constraint) { 30930 const errorInfo = reportErrors && headMessage ? (() => chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Type_0_does_not_satisfy_the_constraint_1)) : undefined; 30931 const typeArgumentHeadMessage = headMessage || Diagnostics.Type_0_does_not_satisfy_the_constraint_1; 30932 if (!mapper) { 30933 mapper = createTypeMapper(typeParameters, typeArgumentTypes); 30934 } 30935 const typeArgument = typeArgumentTypes[i]; 30936 if (!checkTypeAssignableTo( 30937 typeArgument, 30938 getTypeWithThisArgument(instantiateType(constraint, mapper), typeArgument), 30939 reportErrors ? typeArgumentNodes[i] : undefined, 30940 typeArgumentHeadMessage, 30941 errorInfo)) { 30942 return undefined; 30943 } 30944 } 30945 } 30946 return typeArgumentTypes; 30947 } 30948 30949 function getJsxReferenceKind(node: JsxOpeningLikeElement): JsxReferenceKind { 30950 if (isJsxIntrinsicIdentifier(node.tagName)) { 30951 return JsxReferenceKind.Mixed; 30952 } 30953 const tagType = getApparentType(checkExpression(node.tagName)); 30954 if (length(getSignaturesOfType(tagType, SignatureKind.Construct))) { 30955 return JsxReferenceKind.Component; 30956 } 30957 if (length(getSignaturesOfType(tagType, SignatureKind.Call))) { 30958 return JsxReferenceKind.Function; 30959 } 30960 return JsxReferenceKind.Mixed; 30961 } 30962 30963 /** 30964 * Check if the given signature can possibly be a signature called by the JSX opening-like element. 30965 * @param node a JSX opening-like element we are trying to figure its call signature 30966 * @param signature a candidate signature we are trying whether it is a call signature 30967 * @param relation a relationship to check parameter and argument type 30968 */ 30969 function checkApplicableSignatureForJsxOpeningLikeElement( 30970 node: JsxOpeningLikeElement, 30971 signature: Signature, 30972 relation: ESMap<string, RelationComparisonResult>, 30973 checkMode: CheckMode, 30974 reportErrors: boolean, 30975 containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, 30976 errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } 30977 ) { 30978 // Stateless function components can have maximum of three arguments: "props", "context", and "updater". 30979 // However "context" and "updater" are implicit and can't be specify by users. Only the first parameter, props, 30980 // can be specified by users through attributes property. 30981 const paramType = getEffectiveFirstArgumentForJsxSignature(signature, node); 30982 const attributesType = checkExpressionWithContextualType(node.attributes, paramType, /*inferenceContext*/ undefined, checkMode); 30983 return checkTagNameDoesNotExpectTooManyArguments() && checkTypeRelatedToAndOptionallyElaborate( 30984 attributesType, 30985 paramType, 30986 relation, 30987 reportErrors ? node.tagName : undefined, 30988 node.attributes, 30989 /*headMessage*/ undefined, 30990 containingMessageChain, 30991 errorOutputContainer); 30992 30993 function checkTagNameDoesNotExpectTooManyArguments(): boolean { 30994 if (getJsxNamespaceContainerForImplicitImport(node)) { 30995 return true; // factory is implicitly jsx/jsxdev - assume it fits the bill, since we don't strongly look for the jsx/jsxs/jsxDEV factory APIs anywhere else (at least not yet) 30996 } 30997 const tagType = isJsxOpeningElement(node) || isJsxSelfClosingElement(node) && !isJsxIntrinsicIdentifier(node.tagName) ? checkExpression(node.tagName) : undefined; 30998 if (!tagType) { 30999 return true; 31000 } 31001 const tagCallSignatures = getSignaturesOfType(tagType, SignatureKind.Call); 31002 if (!length(tagCallSignatures)) { 31003 return true; 31004 } 31005 const factory = getJsxFactoryEntity(node); 31006 if (!factory) { 31007 return true; 31008 } 31009 const factorySymbol = resolveEntityName(factory, SymbolFlags.Value, /*ignoreErrors*/ true, /*dontResolveAlias*/ false, node); 31010 if (!factorySymbol) { 31011 return true; 31012 } 31013 31014 const factoryType = getTypeOfSymbol(factorySymbol); 31015 const callSignatures = getSignaturesOfType(factoryType, SignatureKind.Call); 31016 if (!length(callSignatures)) { 31017 return true; 31018 } 31019 31020 let hasFirstParamSignatures = false; 31021 let maxParamCount = 0; 31022 // Check that _some_ first parameter expects a FC-like thing, and that some overload of the SFC expects an acceptable number of arguments 31023 for (const sig of callSignatures) { 31024 const firstparam = getTypeAtPosition(sig, 0); 31025 const signaturesOfParam = getSignaturesOfType(firstparam, SignatureKind.Call); 31026 if (!length(signaturesOfParam)) continue; 31027 for (const paramSig of signaturesOfParam) { 31028 hasFirstParamSignatures = true; 31029 if (hasEffectiveRestParameter(paramSig)) { 31030 return true; // some signature has a rest param, so function components can have an arbitrary number of arguments 31031 } 31032 const paramCount = getParameterCount(paramSig); 31033 if (paramCount > maxParamCount) { 31034 maxParamCount = paramCount; 31035 } 31036 } 31037 } 31038 if (!hasFirstParamSignatures) { 31039 // Not a single signature had a first parameter which expected a signature - for back compat, and 31040 // to guard against generic factories which won't have signatures directly, do not error 31041 return true; 31042 } 31043 let absoluteMinArgCount = Infinity; 31044 for (const tagSig of tagCallSignatures) { 31045 const tagRequiredArgCount = getMinArgumentCount(tagSig); 31046 if (tagRequiredArgCount < absoluteMinArgCount) { 31047 absoluteMinArgCount = tagRequiredArgCount; 31048 } 31049 } 31050 if (absoluteMinArgCount <= maxParamCount) { 31051 return true; // some signature accepts the number of arguments the function component provides 31052 } 31053 31054 if (reportErrors) { 31055 const diag = createDiagnosticForNode(node.tagName, Diagnostics.Tag_0_expects_at_least_1_arguments_but_the_JSX_factory_2_provides_at_most_3, entityNameToString(node.tagName), absoluteMinArgCount, entityNameToString(factory), maxParamCount); 31056 const tagNameDeclaration = getSymbolAtLocation(node.tagName)?.valueDeclaration; 31057 if (tagNameDeclaration) { 31058 addRelatedInfo(diag, createDiagnosticForNode(tagNameDeclaration, Diagnostics._0_is_declared_here, entityNameToString(node.tagName))); 31059 } 31060 if (errorOutputContainer && errorOutputContainer.skipLogging) { 31061 (errorOutputContainer.errors || (errorOutputContainer.errors = [])).push(diag); 31062 } 31063 if (!errorOutputContainer.skipLogging) { 31064 diagnostics.add(diag); 31065 } 31066 } 31067 return false; 31068 } 31069 } 31070 31071 function getSignatureApplicabilityError( 31072 node: CallLikeExpression, 31073 args: readonly Expression[], 31074 signature: Signature, 31075 relation: ESMap<string, RelationComparisonResult>, 31076 checkMode: CheckMode, 31077 reportErrors: boolean, 31078 containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, 31079 ): readonly Diagnostic[] | undefined { 31080 31081 const errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } = { errors: undefined, skipLogging: true }; 31082 if (isJsxOpeningLikeElement(node)) { 31083 if (!checkApplicableSignatureForJsxOpeningLikeElement(node, signature, relation, checkMode, reportErrors, containingMessageChain, errorOutputContainer)) { 31084 Debug.assert(!reportErrors || !!errorOutputContainer.errors, "jsx should have errors when reporting errors"); 31085 return errorOutputContainer.errors || emptyArray; 31086 } 31087 return undefined; 31088 } 31089 const thisType = getThisTypeOfSignature(signature); 31090 if (thisType && thisType !== voidType && node.kind !== SyntaxKind.NewExpression) { 31091 // If the called expression is not of the form `x.f` or `x["f"]`, then sourceType = voidType 31092 // If the signature's 'this' type is voidType, then the check is skipped -- anything is compatible. 31093 // If the expression is a new expression, then the check is skipped. 31094 const thisArgumentNode = getThisArgumentOfCall(node); 31095 const thisArgumentType = getThisArgumentType(thisArgumentNode); 31096 const errorNode = reportErrors ? (thisArgumentNode || node) : undefined; 31097 const headMessage = Diagnostics.The_this_context_of_type_0_is_not_assignable_to_method_s_this_of_type_1; 31098 if (!checkTypeRelatedTo(thisArgumentType, thisType, relation, errorNode, headMessage, containingMessageChain, errorOutputContainer)) { 31099 Debug.assert(!reportErrors || !!errorOutputContainer.errors, "this parameter should have errors when reporting errors"); 31100 return errorOutputContainer.errors || emptyArray; 31101 } 31102 } 31103 const headMessage = Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1; 31104 const restType = getNonArrayRestType(signature); 31105 const argCount = restType ? Math.min(getParameterCount(signature) - 1, args.length) : args.length; 31106 for (let i = 0; i < argCount; i++) { 31107 const arg = args[i]; 31108 if (arg.kind !== SyntaxKind.OmittedExpression) { 31109 const paramType = getTypeAtPosition(signature, i); 31110 const argType = checkExpressionWithContextualType(arg, paramType, /*inferenceContext*/ undefined, checkMode); 31111 // If one or more arguments are still excluded (as indicated by CheckMode.SkipContextSensitive), 31112 // we obtain the regular type of any object literal arguments because we may not have inferred complete 31113 // parameter types yet and therefore excess property checks may yield false positives (see #17041). 31114 const checkArgType = checkMode & CheckMode.SkipContextSensitive ? getRegularTypeOfObjectLiteral(argType) : argType; 31115 if (!checkTypeRelatedToAndOptionallyElaborate(checkArgType, paramType, relation, reportErrors ? arg : undefined, arg, headMessage, containingMessageChain, errorOutputContainer)) { 31116 Debug.assert(!reportErrors || !!errorOutputContainer.errors, "parameter should have errors when reporting errors"); 31117 maybeAddMissingAwaitInfo(arg, checkArgType, paramType); 31118 return errorOutputContainer.errors || emptyArray; 31119 } 31120 } 31121 } 31122 if (restType) { 31123 const spreadType = getSpreadArgumentType(args, argCount, args.length, restType, /*context*/ undefined, checkMode); 31124 const restArgCount = args.length - argCount; 31125 const errorNode = !reportErrors ? undefined : 31126 restArgCount === 0 ? node : 31127 restArgCount === 1 ? args[argCount] : 31128 setTextRangePosEnd(createSyntheticExpression(node, spreadType), args[argCount].pos, args[args.length - 1].end); 31129 if (!checkTypeRelatedTo(spreadType, restType, relation, errorNode, headMessage, /*containingMessageChain*/ undefined, errorOutputContainer)) { 31130 Debug.assert(!reportErrors || !!errorOutputContainer.errors, "rest parameter should have errors when reporting errors"); 31131 maybeAddMissingAwaitInfo(errorNode, spreadType, restType); 31132 return errorOutputContainer.errors || emptyArray; 31133 } 31134 } 31135 return undefined; 31136 31137 function maybeAddMissingAwaitInfo(errorNode: Node | undefined, source: Type, target: Type) { 31138 if (errorNode && reportErrors && errorOutputContainer.errors && errorOutputContainer.errors.length) { 31139 // Bail if target is Promise-like---something else is wrong 31140 if (getAwaitedTypeOfPromise(target)) { 31141 return; 31142 } 31143 const awaitedTypeOfSource = getAwaitedTypeOfPromise(source); 31144 if (awaitedTypeOfSource && isTypeRelatedTo(awaitedTypeOfSource, target, relation)) { 31145 addRelatedInfo(errorOutputContainer.errors[0], createDiagnosticForNode(errorNode, Diagnostics.Did_you_forget_to_use_await)); 31146 } 31147 } 31148 } 31149 } 31150 31151 /** 31152 * Returns the this argument in calls like x.f(...) and x[f](...). Undefined otherwise. 31153 */ 31154 function getThisArgumentOfCall(node: CallLikeExpression): LeftHandSideExpression | undefined { 31155 const expression = node.kind === SyntaxKind.CallExpression ? node.expression : 31156 node.kind === SyntaxKind.TaggedTemplateExpression ? node.tag : undefined; 31157 if (expression) { 31158 const callee = skipOuterExpressions(expression); 31159 if (isAccessExpression(callee)) { 31160 return callee.expression; 31161 } 31162 } 31163 } 31164 31165 function createSyntheticExpression(parent: Node, type: Type, isSpread?: boolean, tupleNameSource?: ParameterDeclaration | NamedTupleMember) { 31166 const result = parseNodeFactory.createSyntheticExpression(type, isSpread, tupleNameSource); 31167 setTextRange(result, parent); 31168 setParent(result, parent); 31169 return result; 31170 } 31171 31172 /** 31173 * Returns the effective arguments for an expression that works like a function invocation. 31174 */ 31175 function getEffectiveCallArguments(node: CallLikeExpression): readonly Expression[] { 31176 if (node.kind === SyntaxKind.TaggedTemplateExpression) { 31177 const template = node.template; 31178 const args: Expression[] = [createSyntheticExpression(template, getGlobalTemplateStringsArrayType())]; 31179 if (template.kind === SyntaxKind.TemplateExpression) { 31180 forEach(template.templateSpans, span => { 31181 args.push(span.expression); 31182 }); 31183 } 31184 return args; 31185 } 31186 if (node.kind === SyntaxKind.Decorator) { 31187 return getEffectiveDecoratorArguments(node); 31188 } 31189 if (isJsxOpeningLikeElement(node)) { 31190 return node.attributes.properties.length > 0 || (isJsxOpeningElement(node) && node.parent.children.length > 0) ? [node.attributes] : emptyArray; 31191 } 31192 const args = node.arguments || emptyArray; 31193 const spreadIndex = getSpreadArgumentIndex(args); 31194 if (spreadIndex >= 0) { 31195 // Create synthetic arguments from spreads of tuple types. 31196 const effectiveArgs = args.slice(0, spreadIndex); 31197 for (let i = spreadIndex; i < args.length; i++) { 31198 const arg = args[i]; 31199 // We can call checkExpressionCached because spread expressions never have a contextual type. 31200 const spreadType = arg.kind === SyntaxKind.SpreadElement && (flowLoopCount ? checkExpression((arg as SpreadElement).expression) : checkExpressionCached((arg as SpreadElement).expression)); 31201 if (spreadType && isTupleType(spreadType)) { 31202 forEach(getTypeArguments(spreadType), (t, i) => { 31203 const flags = spreadType.target.elementFlags[i]; 31204 const syntheticArg = createSyntheticExpression(arg, flags & ElementFlags.Rest ? createArrayType(t) : t, 31205 !!(flags & ElementFlags.Variable), spreadType.target.labeledElementDeclarations?.[i]); 31206 effectiveArgs.push(syntheticArg); 31207 }); 31208 } 31209 else { 31210 effectiveArgs.push(arg); 31211 } 31212 } 31213 return effectiveArgs; 31214 } 31215 return args; 31216 } 31217 31218 /** 31219 * Returns the synthetic argument list for a decorator invocation. 31220 */ 31221 function getEffectiveDecoratorArguments(node: Decorator): readonly Expression[] { 31222 const parent = node.parent; 31223 const expr = node.expression; 31224 switch (parent.kind) { 31225 case SyntaxKind.ClassDeclaration: 31226 case SyntaxKind.ClassExpression: 31227 case SyntaxKind.StructDeclaration: 31228 // For a class decorator, the `target` is the type of the class (e.g. the 31229 // "static" or "constructor" side of the class). 31230 return [ 31231 createSyntheticExpression(expr, getTypeOfSymbol(getSymbolOfNode(parent))) 31232 ]; 31233 case SyntaxKind.Parameter: 31234 // A parameter declaration decorator will have three arguments (see 31235 // `ParameterDecorator` in core.d.ts). 31236 const func = parent.parent as FunctionLikeDeclaration; 31237 return [ 31238 createSyntheticExpression(expr, parent.parent.kind === SyntaxKind.Constructor ? getTypeOfSymbol(getSymbolOfNode(func)) : errorType), 31239 createSyntheticExpression(expr, anyType), 31240 createSyntheticExpression(expr, numberType) 31241 ]; 31242 case SyntaxKind.PropertyDeclaration: 31243 case SyntaxKind.MethodDeclaration: 31244 case SyntaxKind.GetAccessor: 31245 case SyntaxKind.SetAccessor: 31246 // A method or accessor declaration decorator will have two or three arguments (see 31247 // `PropertyDecorator` and `MethodDecorator` in core.d.ts). If we are emitting decorators 31248 // for ES3, we will only pass two arguments. 31249 const hasPropDesc = languageVersion !== ScriptTarget.ES3 && (!isPropertyDeclaration(parent) || hasAccessorModifier(parent)); 31250 return [ 31251 createSyntheticExpression(expr, getParentTypeOfClassElement(parent as ClassElement)), 31252 createSyntheticExpression(expr, getClassElementPropertyKeyType(parent as ClassElement)), 31253 createSyntheticExpression(expr, hasPropDesc ? createTypedPropertyDescriptorType(getTypeOfNode(parent)) : anyType) 31254 ]; 31255 case SyntaxKind.FunctionDeclaration: 31256 if (isEtsFunctionDecorators(getNameOfDecorator(node), compilerOptions)) { 31257 const symbol = getSymbolOfNode(expr); 31258 return symbol 31259 ? [ 31260 createSyntheticExpression(expr, getTypeOfSymbol(symbol)) 31261 ] 31262 : []; 31263 } 31264 return Debug.fail(); 31265 } 31266 return Debug.fail(); 31267 } 31268 31269 /** 31270 * Returns the argument count for a decorator node that works like a function invocation. 31271 */ 31272 function getDecoratorArgumentCount(node: Decorator, signature: Signature) { 31273 switch (node.parent.kind) { 31274 case SyntaxKind.ClassDeclaration: 31275 case SyntaxKind.ClassExpression: 31276 case SyntaxKind.StructDeclaration: 31277 return 1; 31278 case SyntaxKind.PropertyDeclaration: 31279 return hasAccessorModifier(node.parent) ? 3 : 2; 31280 case SyntaxKind.MethodDeclaration: 31281 case SyntaxKind.GetAccessor: 31282 case SyntaxKind.SetAccessor: 31283 // For ES3 or decorators with only two parameters we supply only two arguments 31284 return languageVersion === ScriptTarget.ES3 || signature.parameters.length <= 2 ? 2 : 3; 31285 case SyntaxKind.Parameter: 31286 return 3; 31287 case SyntaxKind.FunctionDeclaration: 31288 if (isEtsFunctionDecorators(getNameOfDecorator(node), compilerOptions)) { 31289 return isCallExpression(node.expression) ? 1 : 0; 31290 } 31291 return Debug.fail(); 31292 default: 31293 return Debug.fail(); 31294 } 31295 } 31296 function getDiagnosticSpanForCallNode(node: CallExpression, doNotIncludeArguments?: boolean) { 31297 let start: number; 31298 let length: number; 31299 const sourceFile = getSourceFileOfNode(node); 31300 31301 if (isPropertyAccessExpression(node.expression)) { 31302 const nameSpan = getErrorSpanForNode(sourceFile, node.expression.name); 31303 start = nameSpan.start; 31304 length = doNotIncludeArguments ? nameSpan.length : node.end - start; 31305 } 31306 else { 31307 const expressionSpan = getErrorSpanForNode(sourceFile, node.expression); 31308 start = expressionSpan.start; 31309 length = doNotIncludeArguments ? expressionSpan.length : node.end - start; 31310 } 31311 return { start, length, sourceFile }; 31312 } 31313 function getDiagnosticForCallNode(node: CallLikeExpression, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): DiagnosticWithLocation { 31314 if (isCallExpression(node)) { 31315 const { sourceFile, start, length } = getDiagnosticSpanForCallNode(node); 31316 return createFileDiagnostic(sourceFile, start, length, message, arg0, arg1, arg2, arg3); 31317 } 31318 else { 31319 return createDiagnosticForNode(node, message, arg0, arg1, arg2, arg3); 31320 } 31321 } 31322 31323 function isPromiseResolveArityError(node: CallLikeExpression) { 31324 if (!isCallExpression(node) || !isIdentifier(node.expression)) return false; 31325 31326 const symbol = resolveName(node.expression, node.expression.escapedText, SymbolFlags.Value, undefined, undefined, false); 31327 const decl = symbol?.valueDeclaration; 31328 if (!decl || !isParameter(decl) || !isFunctionExpressionOrArrowFunction(decl.parent) || !isNewExpression(decl.parent.parent) || !isIdentifier(decl.parent.parent.expression)) { 31329 return false; 31330 } 31331 31332 const globalPromiseSymbol = getGlobalPromiseConstructorSymbol(/*reportErrors*/ false); 31333 if (!globalPromiseSymbol) return false; 31334 31335 const constructorSymbol = getSymbolAtLocation(decl.parent.parent.expression, /*ignoreErrors*/ true); 31336 return constructorSymbol === globalPromiseSymbol; 31337 } 31338 31339 function getArgumentArityError(node: CallLikeExpression, signatures: readonly Signature[], args: readonly Expression[]) { 31340 const spreadIndex = getSpreadArgumentIndex(args); 31341 if (spreadIndex > -1) { 31342 return createDiagnosticForNode(args[spreadIndex], Diagnostics.A_spread_argument_must_either_have_a_tuple_type_or_be_passed_to_a_rest_parameter); 31343 } 31344 let min = Number.POSITIVE_INFINITY; // smallest parameter count 31345 let max = Number.NEGATIVE_INFINITY; // largest parameter count 31346 let maxBelow = Number.NEGATIVE_INFINITY; // largest parameter count that is smaller than the number of arguments 31347 let minAbove = Number.POSITIVE_INFINITY; // smallest parameter count that is larger than the number of arguments 31348 31349 let closestSignature: Signature | undefined; 31350 for (const sig of signatures) { 31351 const minParameter = getMinArgumentCount(sig); 31352 const maxParameter = getParameterCount(sig); 31353 // smallest/largest parameter counts 31354 if (minParameter < min) { 31355 min = minParameter; 31356 closestSignature = sig; 31357 } 31358 max = Math.max(max, maxParameter); 31359 // shortest parameter count *longer than the call*/longest parameter count *shorter than the call* 31360 if (minParameter < args.length && minParameter > maxBelow) maxBelow = minParameter; 31361 if (args.length < maxParameter && maxParameter < minAbove) minAbove = maxParameter; 31362 } 31363 const hasRestParameter = some(signatures, hasEffectiveRestParameter); 31364 const parameterRange = hasRestParameter ? min 31365 : min < max ? min + "-" + max 31366 : min; 31367 const isVoidPromiseError = !hasRestParameter && parameterRange === 1 && args.length === 0 && isPromiseResolveArityError(node); 31368 if (isVoidPromiseError && isInJSFile(node)) { 31369 return getDiagnosticForCallNode(node, Diagnostics.Expected_1_argument_but_got_0_new_Promise_needs_a_JSDoc_hint_to_produce_a_resolve_that_can_be_called_without_arguments); 31370 } 31371 const error = hasRestParameter 31372 ? Diagnostics.Expected_at_least_0_arguments_but_got_1 31373 : isVoidPromiseError 31374 ? Diagnostics.Expected_0_arguments_but_got_1_Did_you_forget_to_include_void_in_your_type_argument_to_Promise 31375 : Diagnostics.Expected_0_arguments_but_got_1; 31376 if (min < args.length && args.length < max) { 31377 // between min and max, but with no matching overload 31378 return getDiagnosticForCallNode(node, Diagnostics.No_overload_expects_0_arguments_but_overloads_do_exist_that_expect_either_1_or_2_arguments, args.length, maxBelow, minAbove); 31379 } 31380 else if (args.length < min) { 31381 // too short: put the error span on the call expression, not any of the args 31382 const diagnostic = getDiagnosticForCallNode(node, error, parameterRange, args.length); 31383 const parameter = closestSignature?.declaration?.parameters[closestSignature.thisParameter ? args.length + 1 : args.length]; 31384 if (parameter) { 31385 const parameterError = createDiagnosticForNode( 31386 parameter, 31387 isBindingPattern(parameter.name) ? Diagnostics.An_argument_matching_this_binding_pattern_was_not_provided 31388 : isRestParameter(parameter) ? Diagnostics.Arguments_for_the_rest_parameter_0_were_not_provided 31389 : Diagnostics.An_argument_for_0_was_not_provided, 31390 !parameter.name ? args.length : !isBindingPattern(parameter.name) ? idText(getFirstIdentifier(parameter.name)) : undefined 31391 ); 31392 return addRelatedInfo(diagnostic, parameterError); 31393 } 31394 return diagnostic; 31395 } 31396 else { 31397 // too long; error goes on the excess parameters 31398 const errorSpan = factory.createNodeArray(args.slice(max)); 31399 const pos = first(errorSpan).pos; 31400 let end = last(errorSpan).end; 31401 if (end === pos) { 31402 end++; 31403 } 31404 setTextRangePosEnd(errorSpan, pos, end); 31405 return createDiagnosticForNodeArray(getSourceFileOfNode(node), errorSpan, error, parameterRange, args.length); 31406 } 31407 } 31408 31409 function getTypeArgumentArityError(node: Node, signatures: readonly Signature[], typeArguments: NodeArray<TypeNode>) { 31410 const argCount = typeArguments.length; 31411 // No overloads exist 31412 if (signatures.length === 1) { 31413 const sig = signatures[0]; 31414 const min = getMinTypeArgumentCount(sig.typeParameters); 31415 const max = length(sig.typeParameters); 31416 return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, min < max ? min + "-" + max : min , argCount); 31417 } 31418 // Overloads exist 31419 let belowArgCount = -Infinity; 31420 let aboveArgCount = Infinity; 31421 for (const sig of signatures) { 31422 const min = getMinTypeArgumentCount(sig.typeParameters); 31423 const max = length(sig.typeParameters); 31424 if (min > argCount) { 31425 aboveArgCount = Math.min(aboveArgCount, min); 31426 } 31427 else if (max < argCount) { 31428 belowArgCount = Math.max(belowArgCount, max); 31429 } 31430 } 31431 if (belowArgCount !== -Infinity && aboveArgCount !== Infinity) { 31432 return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.No_overload_expects_0_type_arguments_but_overloads_do_exist_that_expect_either_1_or_2_type_arguments, argCount, belowArgCount, aboveArgCount); 31433 } 31434 return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, belowArgCount === -Infinity ? aboveArgCount : belowArgCount, argCount); 31435 } 31436 31437 function resolveCall(node: CallLikeExpression, signatures: readonly Signature[], candidatesOutArray: Signature[] | undefined, checkMode: CheckMode, callChainFlags: SignatureFlags, fallbackError?: DiagnosticMessage): Signature { 31438 const isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression; 31439 const isDecorator = node.kind === SyntaxKind.Decorator; 31440 const isJsxOpeningOrSelfClosingElement = isJsxOpeningLikeElement(node); 31441 const isEtsComponentExpression = node.kind === SyntaxKind.EtsComponentExpression; 31442 const reportErrors = !candidatesOutArray; 31443 31444 let typeArguments: NodeArray<TypeNode> | undefined; 31445 let virtual: boolean | undefined; 31446 31447 if (!isDecorator && !isSuperCall(node)) { 31448 typeArguments = (node as CallExpression).typeArguments; 31449 virtual = typeArguments?.some(typeArgument => typeArgument.virtual); 31450 31451 // We already perform checking on the type arguments on the class declaration itself. 31452 if (isTaggedTemplate || isJsxOpeningOrSelfClosingElement || (node as CallExpression).expression.kind !== SyntaxKind.SuperKeyword) { 31453 forEach(typeArguments, checkSourceElement); 31454 } 31455 31456 if (isEtsComponentExpression && checkMode !== CheckMode.SkipEtsComponentBody) { 31457 checkSourceElement((<EtsComponentExpression>node).body); 31458 } 31459 } 31460 31461 const candidates = candidatesOutArray || []; 31462 // reorderCandidates fills up the candidates array directly 31463 reorderCandidates(signatures, candidates, callChainFlags); 31464 if (!candidates.length) { 31465 if (reportErrors) { 31466 diagnostics.add(getDiagnosticForCallNode(node, Diagnostics.Call_target_does_not_contain_any_signatures)); 31467 } 31468 return resolveErrorCall(node); 31469 } 31470 31471 const args = getEffectiveCallArguments(node); 31472 31473 // The excludeArgument array contains true for each context sensitive argument (an argument 31474 // is context sensitive it is susceptible to a one-time permanent contextual typing). 31475 // 31476 // The idea is that we will perform type argument inference & assignability checking once 31477 // without using the susceptible parameters that are functions, and once more for those 31478 // parameters, contextually typing each as we go along. 31479 // 31480 // For a tagged template, then the first argument be 'undefined' if necessary because it 31481 // represents a TemplateStringsArray. 31482 // 31483 // For a decorator, no arguments are susceptible to contextual typing due to the fact 31484 // decorators are applied to a declaration by the emitter, and not to an expression. 31485 const isSingleNonGenericCandidate = candidates.length === 1 && !candidates[0].typeParameters; 31486 let argCheckMode = !isDecorator && !isSingleNonGenericCandidate && some(args, isContextSensitive) ? CheckMode.SkipContextSensitive : CheckMode.Normal; 31487 argCheckMode |= checkMode & CheckMode.IsForStringLiteralArgumentCompletions; 31488 31489 // The following variables are captured and modified by calls to chooseOverload. 31490 // If overload resolution or type argument inference fails, we want to report the 31491 // best error possible. The best error is one which says that an argument was not 31492 // assignable to a parameter. This implies that everything else about the overload 31493 // was fine. So if there is any overload that is only incorrect because of an 31494 // argument, we will report an error on that one. 31495 // 31496 // function foo(s: string): void; 31497 // function foo(n: number): void; // Report argument error on this overload 31498 // function foo(): void; 31499 // foo(true); 31500 // 31501 // If none of the overloads even made it that far, there are two possibilities. 31502 // There was a problem with type arguments for some overload, in which case 31503 // report an error on that. Or none of the overloads even had correct arity, 31504 // in which case give an arity error. 31505 // 31506 // function foo<T extends string>(x: T): void; // Report type argument error 31507 // function foo(): void; 31508 // foo<number>(0); 31509 // 31510 let candidatesForArgumentError: Signature[] | undefined; 31511 let candidateForArgumentArityError: Signature | undefined; 31512 let candidateForTypeArgumentError: Signature | undefined; 31513 let result: Signature | undefined; 31514 31515 // If we are in signature help, a trailing comma indicates that we intend to provide another argument, 31516 // so we will only accept overloads with arity at least 1 higher than the current number of provided arguments. 31517 const signatureHelpTrailingComma = 31518 !!(checkMode & CheckMode.IsForSignatureHelp) && node.kind === SyntaxKind.CallExpression && node.arguments.hasTrailingComma; 31519 31520 // Section 4.12.1: 31521 // if the candidate list contains one or more signatures for which the type of each argument 31522 // expression is a subtype of each corresponding parameter type, the return type of the first 31523 // of those signatures becomes the return type of the function call. 31524 // Otherwise, the return type of the first signature in the candidate list becomes the return 31525 // type of the function call. 31526 // 31527 // Whether the call is an error is determined by assignability of the arguments. The subtype pass 31528 // is just important for choosing the best signature. So in the case where there is only one 31529 // signature, the subtype pass is useless. So skipping it is an optimization. 31530 if (candidates.length > 1) { 31531 result = chooseOverload(candidates, subtypeRelation, isSingleNonGenericCandidate, signatureHelpTrailingComma); 31532 } 31533 if (!result) { 31534 result = chooseOverload(candidates, assignableRelation, isSingleNonGenericCandidate, signatureHelpTrailingComma); 31535 } 31536 if (result) { 31537 return result; 31538 } 31539 31540 result = getCandidateForOverloadFailure(node, candidates, args, !!candidatesOutArray, checkMode); 31541 // Preemptively cache the result; getResolvedSignature will do this after we return, but 31542 // we need to ensure that the result is present for the error checks below so that if 31543 // this signature is encountered again, we handle the circularity (rather than producing a 31544 // different result which may produce no errors and assert). Callers of getResolvedSignature 31545 // don't hit this issue because they only observe this result after it's had a chance to 31546 // be cached, but the error reporting code below executes before getResolvedSignature sets 31547 // resolvedSignature. 31548 getNodeLinks(node).resolvedSignature = result; 31549 31550 // No signatures were applicable. Now report errors based on the last applicable signature with 31551 // no arguments excluded from assignability checks. 31552 // If candidate is undefined, it means that no candidates had a suitable arity. In that case, 31553 // skip the checkApplicableSignature check. 31554 if (reportErrors) { 31555 if (candidatesForArgumentError) { 31556 if (candidatesForArgumentError.length === 1 || candidatesForArgumentError.length > 3) { 31557 const last = candidatesForArgumentError[candidatesForArgumentError.length - 1]; 31558 let chain: DiagnosticMessageChain | undefined; 31559 if (candidatesForArgumentError.length > 3) { 31560 chain = chainDiagnosticMessages(chain, Diagnostics.The_last_overload_gave_the_following_error); 31561 chain = chainDiagnosticMessages(chain, Diagnostics.No_overload_matches_this_call); 31562 } 31563 const diags = getSignatureApplicabilityError(node, args, last, assignableRelation, CheckMode.Normal, /*reportErrors*/ true, () => chain); 31564 if (diags) { 31565 for (const d of diags) { 31566 if (last.declaration && candidatesForArgumentError.length > 3) { 31567 addRelatedInfo(d, createDiagnosticForNode(last.declaration, Diagnostics.The_last_overload_is_declared_here)); 31568 } 31569 addImplementationSuccessElaboration(last, d); 31570 diagnostics.add(d); 31571 } 31572 } 31573 else { 31574 Debug.fail("No error for last overload signature"); 31575 } 31576 } 31577 else { 31578 const allDiagnostics: (readonly DiagnosticRelatedInformation[])[] = []; 31579 let max = 0; 31580 let min = Number.MAX_VALUE; 31581 let minIndex = 0; 31582 let i = 0; 31583 for (const c of candidatesForArgumentError) { 31584 const chain = () => chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Overload_0_of_1_2_gave_the_following_error, i + 1, candidates.length, signatureToString(c)); 31585 const diags = getSignatureApplicabilityError(node, args, c, assignableRelation, CheckMode.Normal, /*reportErrors*/ true, chain); 31586 if (diags) { 31587 if (diags.length <= min) { 31588 min = diags.length; 31589 minIndex = i; 31590 } 31591 max = Math.max(max, diags.length); 31592 allDiagnostics.push(diags); 31593 } 31594 else { 31595 Debug.fail("No error for 3 or fewer overload signatures"); 31596 } 31597 i++; 31598 } 31599 31600 const diags = max > 1 ? allDiagnostics[minIndex] : flatten(allDiagnostics); 31601 Debug.assert(diags.length > 0, "No errors reported for 3 or fewer overload signatures"); 31602 const chain = chainDiagnosticMessages( 31603 map(diags, createDiagnosticMessageChainFromDiagnostic), 31604 Diagnostics.No_overload_matches_this_call); 31605 // The below is a spread to guarantee we get a new (mutable) array - our `flatMap` helper tries to do "smart" optimizations where it reuses input 31606 // arrays and the emptyArray singleton where possible, which is decidedly not what we want while we're still constructing this diagnostic 31607 const related = [...flatMap(diags, d => (d as Diagnostic).relatedInformation) as DiagnosticRelatedInformation[]]; 31608 let diag: Diagnostic; 31609 if (every(diags, d => d.start === diags[0].start && d.length === diags[0].length && d.file === diags[0].file)) { 31610 const { file, start, length } = diags[0]; 31611 diag = { file, start, length, code: chain.code, category: chain.category, messageText: chain, relatedInformation: related }; 31612 } 31613 else { 31614 diag = createDiagnosticForNodeFromMessageChain(node, chain, related); 31615 } 31616 addImplementationSuccessElaboration(candidatesForArgumentError[0], diag); 31617 diagnostics.add(diag); 31618 } 31619 } 31620 else if (candidateForArgumentArityError) { 31621 diagnostics.add(getArgumentArityError(node, [candidateForArgumentArityError], args)); 31622 } 31623 else if (candidateForTypeArgumentError) { 31624 checkTypeArguments(candidateForTypeArgumentError, (node as CallExpression | TaggedTemplateExpression | JsxOpeningLikeElement).typeArguments!, /*reportErrors*/ true, fallbackError); 31625 } 31626 else { 31627 const signaturesWithCorrectTypeArgumentArity = filter(signatures, s => hasCorrectTypeArgumentArity(s, typeArguments, virtual)); 31628 if (signaturesWithCorrectTypeArgumentArity.length === 0) { 31629 diagnostics.add(getTypeArgumentArityError(node, signatures, typeArguments!)); 31630 } 31631 else if (!isDecorator) { 31632 diagnostics.add(getArgumentArityError(node, signaturesWithCorrectTypeArgumentArity, args)); 31633 } 31634 else if (fallbackError) { 31635 diagnostics.add(getDiagnosticForCallNode(node, fallbackError)); 31636 } 31637 } 31638 } 31639 31640 return result; 31641 31642 function addImplementationSuccessElaboration(failed: Signature, diagnostic: Diagnostic) { 31643 const oldCandidatesForArgumentError = candidatesForArgumentError; 31644 const oldCandidateForArgumentArityError = candidateForArgumentArityError; 31645 const oldCandidateForTypeArgumentError = candidateForTypeArgumentError; 31646 31647 const failedSignatureDeclarations = failed.declaration?.symbol?.declarations || emptyArray; 31648 const isOverload = failedSignatureDeclarations.length > 1; 31649 const implDecl = isOverload ? find(failedSignatureDeclarations, d => isFunctionLikeDeclaration(d) && nodeIsPresent(d.body)) : undefined; 31650 if (implDecl) { 31651 const candidate = getSignatureFromDeclaration(implDecl as FunctionLikeDeclaration); 31652 const isSingleNonGenericCandidate = !candidate.typeParameters; 31653 if (chooseOverload([candidate], assignableRelation, isSingleNonGenericCandidate)) { 31654 addRelatedInfo(diagnostic, createDiagnosticForNode(implDecl, Diagnostics.The_call_would_have_succeeded_against_this_implementation_but_implementation_signatures_of_overloads_are_not_externally_visible)); 31655 } 31656 } 31657 31658 candidatesForArgumentError = oldCandidatesForArgumentError; 31659 candidateForArgumentArityError = oldCandidateForArgumentArityError; 31660 candidateForTypeArgumentError = oldCandidateForTypeArgumentError; 31661 } 31662 31663 function chooseOverload(candidates: Signature[], relation: ESMap<string, RelationComparisonResult>, isSingleNonGenericCandidate: boolean, signatureHelpTrailingComma = false) { 31664 candidatesForArgumentError = undefined; 31665 candidateForArgumentArityError = undefined; 31666 candidateForTypeArgumentError = undefined; 31667 31668 if (isSingleNonGenericCandidate) { 31669 const candidate = candidates[0]; 31670 if ((some(typeArguments) && !virtual) || !hasCorrectArity(node, args, candidate, signatureHelpTrailingComma)) { 31671 return undefined; 31672 } 31673 if (getSignatureApplicabilityError(node, args, candidate, relation, CheckMode.Normal, /*reportErrors*/ false, /*containingMessageChain*/ undefined)) { 31674 candidatesForArgumentError = [candidate]; 31675 return undefined; 31676 } 31677 return candidate; 31678 } 31679 31680 for (let candidateIndex = 0; candidateIndex < candidates.length; candidateIndex++) { 31681 const candidate = candidates[candidateIndex]; 31682 if (!hasCorrectTypeArgumentArity(candidate, typeArguments, virtual) || !hasCorrectArity(node, args, candidate, signatureHelpTrailingComma)) { 31683 continue; 31684 } 31685 31686 let checkCandidate: Signature; 31687 let inferenceContext: InferenceContext | undefined; 31688 31689 if (candidate.typeParameters) { 31690 let typeArgumentTypes: Type[] | undefined; 31691 if (some(typeArguments)) { 31692 typeArgumentTypes = checkTypeArguments(candidate, typeArguments, /*reportErrors*/ false); 31693 if (!typeArgumentTypes) { 31694 candidateForTypeArgumentError = candidate; 31695 continue; 31696 } 31697 } 31698 else { 31699 inferenceContext = createInferenceContext(candidate.typeParameters, candidate, /*flags*/ isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None); 31700 typeArgumentTypes = inferTypeArguments(node, candidate, args, argCheckMode | CheckMode.SkipGenericFunctions, inferenceContext); 31701 argCheckMode |= inferenceContext.flags & InferenceFlags.SkippedGenericFunction ? CheckMode.SkipGenericFunctions : CheckMode.Normal; 31702 } 31703 checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration), inferenceContext && inferenceContext.inferredTypeParameters); 31704 // If the original signature has a generic rest type, instantiation may produce a 31705 // signature with different arity and we need to perform another arity check. 31706 if (getNonArrayRestType(candidate) && !hasCorrectArity(node, args, checkCandidate, signatureHelpTrailingComma)) { 31707 candidateForArgumentArityError = checkCandidate; 31708 continue; 31709 } 31710 } 31711 else { 31712 checkCandidate = candidate; 31713 } 31714 if (getSignatureApplicabilityError(node, args, checkCandidate, relation, argCheckMode, /*reportErrors*/ false, /*containingMessageChain*/ undefined)) { 31715 // Give preference to error candidates that have no rest parameters (as they are more specific) 31716 (candidatesForArgumentError || (candidatesForArgumentError = [])).push(checkCandidate); 31717 continue; 31718 } 31719 if (argCheckMode) { 31720 // If one or more context sensitive arguments were excluded, we start including 31721 // them now (and keeping do so for any subsequent candidates) and perform a second 31722 // round of type inference and applicability checking for this particular candidate. 31723 argCheckMode = checkMode & CheckMode.IsForStringLiteralArgumentCompletions; 31724 if (inferenceContext) { 31725 const typeArgumentTypes = inferTypeArguments(node, candidate, args, argCheckMode, inferenceContext); 31726 checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration), inferenceContext.inferredTypeParameters); 31727 // If the original signature has a generic rest type, instantiation may produce a 31728 // signature with different arity and we need to perform another arity check. 31729 if (getNonArrayRestType(candidate) && !hasCorrectArity(node, args, checkCandidate, signatureHelpTrailingComma)) { 31730 candidateForArgumentArityError = checkCandidate; 31731 continue; 31732 } 31733 } 31734 if (getSignatureApplicabilityError(node, args, checkCandidate, relation, argCheckMode, /*reportErrors*/ false, /*containingMessageChain*/ undefined)) { 31735 // Give preference to error candidates that have no rest parameters (as they are more specific) 31736 (candidatesForArgumentError || (candidatesForArgumentError = [])).push(checkCandidate); 31737 continue; 31738 } 31739 } 31740 candidates[candidateIndex] = checkCandidate; 31741 return checkCandidate; 31742 } 31743 31744 return undefined; 31745 } 31746 } 31747 31748 // No signature was applicable. We have already reported the errors for the invalid signature. 31749 function getCandidateForOverloadFailure( 31750 node: CallLikeExpression, 31751 candidates: Signature[], 31752 args: readonly Expression[], 31753 hasCandidatesOutArray: boolean, 31754 checkMode: CheckMode, 31755 ): Signature { 31756 Debug.assert(candidates.length > 0); // Else should not have called this. 31757 checkNodeDeferred(node); 31758 // Normally we will combine overloads. Skip this if they have type parameters since that's hard to combine. 31759 // Don't do this if there is a `candidatesOutArray`, 31760 // because then we want the chosen best candidate to be one of the overloads, not a combination. 31761 return hasCandidatesOutArray || candidates.length === 1 || candidates.some(c => !!c.typeParameters) 31762 ? pickLongestCandidateSignature(node, candidates, args, checkMode) 31763 : createUnionOfSignaturesForOverloadFailure(candidates); 31764 } 31765 31766 function createUnionOfSignaturesForOverloadFailure(candidates: readonly Signature[]): Signature { 31767 const thisParameters = mapDefined(candidates, c => c.thisParameter); 31768 let thisParameter: Symbol | undefined; 31769 if (thisParameters.length) { 31770 thisParameter = createCombinedSymbolFromTypes(thisParameters, thisParameters.map(getTypeOfParameter)); 31771 } 31772 const { min: minArgumentCount, max: maxNonRestParam } = minAndMax(candidates, getNumNonRestParameters); 31773 const parameters: Symbol[] = []; 31774 for (let i = 0; i < maxNonRestParam; i++) { 31775 const symbols = mapDefined(candidates, s => signatureHasRestParameter(s) ? 31776 i < s.parameters.length - 1 ? s.parameters[i] : last(s.parameters) : 31777 i < s.parameters.length ? s.parameters[i] : undefined); 31778 Debug.assert(symbols.length !== 0); 31779 parameters.push(createCombinedSymbolFromTypes(symbols, mapDefined(candidates, candidate => tryGetTypeAtPosition(candidate, i)))); 31780 } 31781 const restParameterSymbols = mapDefined(candidates, c => signatureHasRestParameter(c) ? last(c.parameters) : undefined); 31782 let flags = SignatureFlags.None; 31783 if (restParameterSymbols.length !== 0) { 31784 const type = createArrayType(getUnionType(mapDefined(candidates, tryGetRestTypeOfSignature), UnionReduction.Subtype)); 31785 parameters.push(createCombinedSymbolForOverloadFailure(restParameterSymbols, type)); 31786 flags |= SignatureFlags.HasRestParameter; 31787 } 31788 if (candidates.some(signatureHasLiteralTypes)) { 31789 flags |= SignatureFlags.HasLiteralTypes; 31790 } 31791 return createSignature( 31792 candidates[0].declaration, 31793 /*typeParameters*/ undefined, // Before calling this we tested for `!candidates.some(c => !!c.typeParameters)`. 31794 thisParameter, 31795 parameters, 31796 /*resolvedReturnType*/ getIntersectionType(candidates.map(getReturnTypeOfSignature)), 31797 /*typePredicate*/ undefined, 31798 minArgumentCount, 31799 flags); 31800 } 31801 31802 function getNumNonRestParameters(signature: Signature): number { 31803 const numParams = signature.parameters.length; 31804 return signatureHasRestParameter(signature) ? numParams - 1 : numParams; 31805 } 31806 31807 function createCombinedSymbolFromTypes(sources: readonly Symbol[], types: Type[]): Symbol { 31808 return createCombinedSymbolForOverloadFailure(sources, getUnionType(types, UnionReduction.Subtype)); 31809 } 31810 31811 function createCombinedSymbolForOverloadFailure(sources: readonly Symbol[], type: Type): Symbol { 31812 // This function is currently only used for erroneous overloads, so it's good enough to just use the first source. 31813 return createSymbolWithType(first(sources), type); 31814 } 31815 31816 function pickLongestCandidateSignature(node: CallLikeExpression, candidates: Signature[], args: readonly Expression[], checkMode: CheckMode): Signature { 31817 // Pick the longest signature. This way we can get a contextual type for cases like: 31818 // declare function f(a: { xa: number; xb: number; }, b: number); 31819 // f({ | 31820 // Also, use explicitly-supplied type arguments if they are provided, so we can get a contextual signature in cases like: 31821 // declare function f<T>(k: keyof T); 31822 // f<Foo>(" 31823 const bestIndex = getLongestCandidateIndex(candidates, apparentArgumentCount === undefined ? args.length : apparentArgumentCount); 31824 const candidate = candidates[bestIndex]; 31825 const { typeParameters } = candidate; 31826 if (!typeParameters) { 31827 return candidate; 31828 } 31829 31830 const typeArgumentNodes: readonly TypeNode[] | undefined = callLikeExpressionMayHaveTypeArguments(node) ? node.typeArguments : undefined; 31831 const instantiated = typeArgumentNodes 31832 ? createSignatureInstantiation(candidate, getTypeArgumentsFromNodes(typeArgumentNodes, typeParameters, isInJSFile(node))) 31833 : inferSignatureInstantiationForOverloadFailure(node, typeParameters, candidate, args, checkMode); 31834 candidates[bestIndex] = instantiated; 31835 return instantiated; 31836 } 31837 31838 function getTypeArgumentsFromNodes(typeArgumentNodes: readonly TypeNode[], typeParameters: readonly TypeParameter[], isJs: boolean): readonly Type[] { 31839 const typeArguments = typeArgumentNodes.map(getTypeOfNode); 31840 while (typeArguments.length > typeParameters.length) { 31841 typeArguments.pop(); 31842 } 31843 while (typeArguments.length < typeParameters.length) { 31844 typeArguments.push(getDefaultFromTypeParameter(typeParameters[typeArguments.length]) || getConstraintOfTypeParameter(typeParameters[typeArguments.length]) || getDefaultTypeArgumentType(isJs)); 31845 } 31846 return typeArguments; 31847 } 31848 31849 function inferSignatureInstantiationForOverloadFailure(node: CallLikeExpression, typeParameters: readonly TypeParameter[], candidate: Signature, args: readonly Expression[], checkMode: CheckMode): Signature { 31850 const inferenceContext = createInferenceContext(typeParameters, candidate, /*flags*/ isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None); 31851 const typeArgumentTypes = inferTypeArguments(node, candidate, args, checkMode | CheckMode.SkipContextSensitive | CheckMode.SkipGenericFunctions, inferenceContext); 31852 return createSignatureInstantiation(candidate, typeArgumentTypes); 31853 } 31854 31855 function getLongestCandidateIndex(candidates: Signature[], argsCount: number): number { 31856 let maxParamsIndex = -1; 31857 let maxParams = -1; 31858 31859 for (let i = 0; i < candidates.length; i++) { 31860 const candidate = candidates[i]; 31861 const paramCount = getParameterCount(candidate); 31862 if (hasEffectiveRestParameter(candidate) || paramCount >= argsCount) { 31863 return i; 31864 } 31865 if (paramCount > maxParams) { 31866 maxParams = paramCount; 31867 maxParamsIndex = i; 31868 } 31869 } 31870 31871 return maxParamsIndex; 31872 } 31873 31874 function resolveCallExpression(node: CallExpression | EtsComponentExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { 31875 if (node.expression.kind === SyntaxKind.SuperKeyword) { 31876 const superType = checkSuperExpression(node.expression); 31877 if (isTypeAny(superType)) { 31878 for (const arg of node.arguments) { 31879 checkExpression(arg); // Still visit arguments so they get marked for visibility, etc 31880 } 31881 return anySignature; 31882 } 31883 if (!isErrorType(superType)) { 31884 // In super call, the candidate signatures are the matching arity signatures of the base constructor function instantiated 31885 // with the type arguments specified in the extends clause. 31886 const baseTypeNode = getEffectiveBaseTypeNode(getContainingClass(node)!); 31887 if (baseTypeNode) { 31888 const baseConstructors = getInstantiatedConstructorsForTypeArguments(superType, baseTypeNode.typeArguments, baseTypeNode); 31889 return resolveCall(node, baseConstructors, candidatesOutArray, checkMode, SignatureFlags.None); 31890 } 31891 } 31892 return resolveUntypedCall(node); 31893 } 31894 31895 let callChainFlags: SignatureFlags; 31896 let checkExpressionCheckMode: CheckMode | undefined = checkMode; 31897 if (checkMode !== CheckMode.SkipEtsComponentBody) { 31898 checkExpressionCheckMode = undefined; 31899 } 31900 let funcType = checkExpression(node.expression, checkExpressionCheckMode); 31901 if (isCallChain(node)) { 31902 const nonOptionalType = getOptionalExpressionType(funcType, node.expression); 31903 callChainFlags = nonOptionalType === funcType ? SignatureFlags.None : 31904 isOutermostOptionalChain(node) ? SignatureFlags.IsOuterCallChain : 31905 SignatureFlags.IsInnerCallChain; 31906 funcType = nonOptionalType; 31907 } 31908 else { 31909 callChainFlags = SignatureFlags.None; 31910 } 31911 31912 funcType = checkNonNullTypeWithReporter( 31913 funcType, 31914 node.expression, 31915 reportCannotInvokePossiblyNullOrUndefinedError 31916 ); 31917 31918 if (funcType === silentNeverType) { 31919 return silentNeverSignature; 31920 } 31921 31922 const apparentType = getApparentType(funcType); 31923 if (isErrorType(apparentType)) { 31924 // Another error has already been reported 31925 return resolveErrorCall(node); 31926 } 31927 31928 // Technically, this signatures list may be incomplete. We are taking the apparent type, 31929 // but we are not including call signatures that may have been added to the Object or 31930 // Function interface, since they have none by default. This is a bit of a leap of faith 31931 // that the user will not add any. 31932 const callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call); 31933 const constructSignatures = getSignaturesOfType(apparentType, SignatureKind.Construct); 31934 const numConstructSignatures = constructSignatures.length; 31935 31936 // TS 1.0 Spec: 4.12 31937 // In an untyped function call no TypeArgs are permitted, Args can be any argument list, no contextual 31938 // types are provided for the argument expressions, and the result is always of type Any. 31939 if (isUntypedFunctionCall(funcType, apparentType, callSignatures.length, numConstructSignatures)) { 31940 // The unknownType indicates that an error already occurred (and was reported). No 31941 // need to report another error in this case. 31942 if (!isErrorType(funcType) && node.typeArguments) { 31943 error(node, Diagnostics.Untyped_function_calls_may_not_accept_type_arguments); 31944 } 31945 return resolveUntypedCall(node); 31946 } 31947 // If FuncExpr's apparent type(section 3.8.1) is a function type, the call is a typed function call. 31948 // TypeScript employs overload resolution in typed function calls in order to support functions 31949 // with multiple call signatures. 31950 const isStructDeclaration = isCalledStructDeclaration(apparentType.symbol?.declarations); 31951 if (!callSignatures.length) { 31952 if (numConstructSignatures) { 31953 if (!isStructDeclaration) { 31954 error(node, Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new, typeToString(funcType)); 31955 } 31956 else { 31957 return resolveCall(node, constructSignatures, candidatesOutArray, checkMode, SignatureFlags.None); 31958 } 31959 } 31960 else { 31961 let relatedInformation: DiagnosticRelatedInformation | undefined; 31962 if (node.arguments.length === 1) { 31963 const text = getSourceFileOfNode(node).text; 31964 if (isLineBreak(text.charCodeAt(skipTrivia(text, node.expression.end, /* stopAfterLineBreak */ true) - 1))) { 31965 relatedInformation = createDiagnosticForNode(node.expression, Diagnostics.Are_you_missing_a_semicolon); 31966 } 31967 } 31968 invocationError(node.expression, apparentType, SignatureKind.Call, relatedInformation); 31969 } 31970 return resolveErrorCall(node); 31971 } 31972 // When a call to a generic function is an argument to an outer call to a generic function for which 31973 // inference is in process, we have a choice to make. If the inner call relies on inferences made from 31974 // its contextual type to its return type, deferring the inner call processing allows the best possible 31975 // contextual type to accumulate. But if the outer call relies on inferences made from the return type of 31976 // the inner call, the inner call should be processed early. There's no sure way to know which choice is 31977 // right (only a full unification algorithm can determine that), so we resort to the following heuristic: 31978 // If no type arguments are specified in the inner call and at least one call signature is generic and 31979 // returns a function type, we choose to defer processing. This narrowly permits function composition 31980 // operators to flow inferences through return types, but otherwise processes calls right away. We 31981 // use the resolvingSignature singleton to indicate that we deferred processing. This result will be 31982 // propagated out and eventually turned into silentNeverType (a type that is assignable to anything and 31983 // from which we never make inferences). 31984 if (checkMode & CheckMode.SkipGenericFunctions && !node.typeArguments && callSignatures.some(isGenericFunctionReturningFunction)) { 31985 skippedGenericFunction(node, checkMode); 31986 return resolvingSignature; 31987 } 31988 // If the function is explicitly marked with `@class`, then it must be constructed. 31989 if (callSignatures.some(sig => isInJSFile(sig.declaration) && !!getJSDocClassTag(sig.declaration!))) { 31990 error(node, Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new, typeToString(funcType)); 31991 return resolveErrorCall(node); 31992 } 31993 31994 return resolveCall(node, callSignatures, candidatesOutArray, checkMode, callChainFlags); 31995 } 31996 31997 function isGenericFunctionReturningFunction(signature: Signature) { 31998 return !!(signature.typeParameters && isFunctionType(getReturnTypeOfSignature(signature))); 31999 } 32000 32001 /** 32002 * TS 1.0 spec: 4.12 32003 * If FuncExpr is of type Any, or of an object type that has no call or construct signatures 32004 * but is a subtype of the Function interface, the call is an untyped function call. 32005 */ 32006 function isUntypedFunctionCall(funcType: Type, apparentFuncType: Type, numCallSignatures: number, numConstructSignatures: number): boolean { 32007 // We exclude union types because we may have a union of function types that happen to have no common signatures. 32008 return isTypeAny(funcType) || isTypeAny(apparentFuncType) && !!(funcType.flags & TypeFlags.TypeParameter) || 32009 !numCallSignatures && !numConstructSignatures && !(apparentFuncType.flags & TypeFlags.Union) && !(getReducedType(apparentFuncType).flags & TypeFlags.Never) && isTypeAssignableTo(funcType, globalFunctionType); 32010 } 32011 32012 function resolveNewExpression(node: NewExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { 32013 if (node.arguments && languageVersion < ScriptTarget.ES5) { 32014 const spreadIndex = getSpreadArgumentIndex(node.arguments); 32015 if (spreadIndex >= 0) { 32016 error(node.arguments[spreadIndex], Diagnostics.Spread_operator_in_new_expressions_is_only_available_when_targeting_ECMAScript_5_and_higher); 32017 } 32018 } 32019 32020 let expressionType = checkNonNullExpression(node.expression, checkMode); 32021 if (expressionType === silentNeverType) { 32022 return silentNeverSignature; 32023 } 32024 32025 // If expressionType's apparent type(section 3.8.1) is an object type with one or 32026 // more construct signatures, the expression is processed in the same manner as a 32027 // function call, but using the construct signatures as the initial set of candidate 32028 // signatures for overload resolution. The result type of the function call becomes 32029 // the result type of the operation. 32030 expressionType = getApparentType(expressionType); 32031 if (isErrorType(expressionType)) { 32032 // Another error has already been reported 32033 return resolveErrorCall(node); 32034 } 32035 32036 // TS 1.0 spec: 4.11 32037 // If expressionType is of type Any, Args can be any argument 32038 // list and the result of the operation is of type Any. 32039 if (isTypeAny(expressionType)) { 32040 if (node.typeArguments) { 32041 error(node, Diagnostics.Untyped_function_calls_may_not_accept_type_arguments); 32042 } 32043 return resolveUntypedCall(node); 32044 } 32045 32046 // Technically, this signatures list may be incomplete. We are taking the apparent type, 32047 // but we are not including construct signatures that may have been added to the Object or 32048 // Function interface, since they have none by default. This is a bit of a leap of faith 32049 // that the user will not add any. 32050 const constructSignatures = getSignaturesOfType(expressionType, SignatureKind.Construct); 32051 if (constructSignatures.length) { 32052 if (!isConstructorAccessible(node, constructSignatures[0])) { 32053 return resolveErrorCall(node); 32054 } 32055 // If the expression is a class of abstract type, or an abstract construct signature, 32056 // then it cannot be instantiated. 32057 // In the case of a merged class-module or class-interface declaration, 32058 // only the class declaration node will have the Abstract flag set. 32059 if (someSignature(constructSignatures, signature => !!(signature.flags & SignatureFlags.Abstract))) { 32060 error(node, Diagnostics.Cannot_create_an_instance_of_an_abstract_class); 32061 return resolveErrorCall(node); 32062 } 32063 const valueDecl = expressionType.symbol && getClassLikeDeclarationOfSymbol(expressionType.symbol); 32064 if (valueDecl && hasSyntacticModifier(valueDecl, ModifierFlags.Abstract)) { 32065 error(node, Diagnostics.Cannot_create_an_instance_of_an_abstract_class); 32066 return resolveErrorCall(node); 32067 } 32068 32069 return resolveCall(node, constructSignatures, candidatesOutArray, checkMode, SignatureFlags.None); 32070 } 32071 32072 // If expressionType's apparent type is an object type with no construct signatures but 32073 // one or more call signatures, the expression is processed as a function call. A compile-time 32074 // error occurs if the result of the function call is not Void. The type of the result of the 32075 // operation is Any. It is an error to have a Void this type. 32076 const callSignatures = getSignaturesOfType(expressionType, SignatureKind.Call); 32077 if (callSignatures.length) { 32078 const signature = resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None); 32079 if (!noImplicitAny) { 32080 if (signature.declaration && !isJSConstructor(signature.declaration) && getReturnTypeOfSignature(signature) !== voidType) { 32081 error(node, Diagnostics.Only_a_void_function_can_be_called_with_the_new_keyword); 32082 } 32083 if (getThisTypeOfSignature(signature) === voidType) { 32084 error(node, Diagnostics.A_function_that_is_called_with_the_new_keyword_cannot_have_a_this_type_that_is_void); 32085 } 32086 } 32087 return signature; 32088 } 32089 32090 invocationError(node.expression, expressionType, SignatureKind.Construct); 32091 return resolveErrorCall(node); 32092 } 32093 32094 function someSignature(signatures: Signature | readonly Signature[], f: (s: Signature) => boolean): boolean { 32095 if (isArray(signatures)) { 32096 return some(signatures, signature => someSignature(signature, f)); 32097 } 32098 return signatures.compositeKind === TypeFlags.Union ? some(signatures.compositeSignatures, f) : f(signatures); 32099 } 32100 32101 function typeHasProtectedAccessibleBase(target: Symbol, type: InterfaceType): boolean { 32102 const baseTypes = getBaseTypes(type); 32103 if (!length(baseTypes)) { 32104 return false; 32105 } 32106 const firstBase = baseTypes[0]; 32107 if (firstBase.flags & TypeFlags.Intersection) { 32108 const types = (firstBase as IntersectionType).types; 32109 const mixinFlags = findMixins(types); 32110 let i = 0; 32111 for (const intersectionMember of (firstBase as IntersectionType).types) { 32112 // We want to ignore mixin ctors 32113 if (!mixinFlags[i]) { 32114 if (getObjectFlags(intersectionMember) & (ObjectFlags.Class | ObjectFlags.Interface)) { 32115 if (intersectionMember.symbol === target) { 32116 return true; 32117 } 32118 if (typeHasProtectedAccessibleBase(target, intersectionMember as InterfaceType)) { 32119 return true; 32120 } 32121 } 32122 } 32123 i++; 32124 } 32125 return false; 32126 } 32127 if (firstBase.symbol === target) { 32128 return true; 32129 } 32130 return typeHasProtectedAccessibleBase(target, firstBase as InterfaceType); 32131 } 32132 32133 function isConstructorAccessible(node: NewExpression, signature: Signature) { 32134 if (!signature || !signature.declaration) { 32135 return true; 32136 } 32137 32138 const declaration = signature.declaration; 32139 const modifiers = getSelectedEffectiveModifierFlags(declaration, ModifierFlags.NonPublicAccessibilityModifier); 32140 32141 // (1) Public constructors and (2) constructor functions are always accessible. 32142 if (!modifiers || declaration.kind !== SyntaxKind.Constructor) { 32143 return true; 32144 } 32145 32146 const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(declaration.parent.symbol)!; 32147 const declaringClass = getDeclaredTypeOfSymbol(declaration.parent.symbol) as InterfaceType; 32148 32149 // A private or protected constructor can only be instantiated within its own class (or a subclass, for protected) 32150 if (!isNodeWithinClass(node, declaringClassDeclaration)) { 32151 const containingClass = getContainingClass(node); 32152 if (containingClass && modifiers & ModifierFlags.Protected) { 32153 const containingType = getTypeOfNode(containingClass); 32154 if (typeHasProtectedAccessibleBase(declaration.parent.symbol, containingType as InterfaceType)) { 32155 return true; 32156 } 32157 } 32158 if (modifiers & ModifierFlags.Private) { 32159 error(node, Diagnostics.Constructor_of_class_0_is_private_and_only_accessible_within_the_class_declaration, typeToString(declaringClass)); 32160 } 32161 if (modifiers & ModifierFlags.Protected) { 32162 error(node, Diagnostics.Constructor_of_class_0_is_protected_and_only_accessible_within_the_class_declaration, typeToString(declaringClass)); 32163 } 32164 return false; 32165 } 32166 32167 return true; 32168 } 32169 32170 function invocationErrorDetails(errorTarget: Node, apparentType: Type, kind: SignatureKind): { messageChain: DiagnosticMessageChain, relatedMessage: DiagnosticMessage | undefined } { 32171 let errorInfo: DiagnosticMessageChain | undefined; 32172 const isCall = kind === SignatureKind.Call; 32173 const awaitedType = getAwaitedType(apparentType); 32174 const maybeMissingAwait = awaitedType && getSignaturesOfType(awaitedType, kind).length > 0; 32175 if (apparentType.flags & TypeFlags.Union) { 32176 const types = (apparentType as UnionType).types; 32177 let hasSignatures = false; 32178 for (const constituent of types) { 32179 const signatures = getSignaturesOfType(constituent, kind); 32180 if (signatures.length !== 0) { 32181 hasSignatures = true; 32182 if (errorInfo) { 32183 // Bail early if we already have an error, no chance of "No constituent of type is callable" 32184 break; 32185 } 32186 } 32187 else { 32188 // Error on the first non callable constituent only 32189 if (!errorInfo) { 32190 errorInfo = chainDiagnosticMessages( 32191 errorInfo, 32192 isCall ? 32193 Diagnostics.Type_0_has_no_call_signatures : 32194 Diagnostics.Type_0_has_no_construct_signatures, 32195 typeToString(constituent) 32196 ); 32197 errorInfo = chainDiagnosticMessages( 32198 errorInfo, 32199 isCall ? 32200 Diagnostics.Not_all_constituents_of_type_0_are_callable : 32201 Diagnostics.Not_all_constituents_of_type_0_are_constructable, 32202 typeToString(apparentType) 32203 ); 32204 } 32205 if (hasSignatures) { 32206 // Bail early if we already found a siganture, no chance of "No constituent of type is callable" 32207 break; 32208 } 32209 } 32210 } 32211 if (!hasSignatures) { 32212 errorInfo = chainDiagnosticMessages( 32213 /* detials */ undefined, 32214 isCall ? 32215 Diagnostics.No_constituent_of_type_0_is_callable : 32216 Diagnostics.No_constituent_of_type_0_is_constructable, 32217 typeToString(apparentType) 32218 ); 32219 } 32220 if (!errorInfo) { 32221 errorInfo = chainDiagnosticMessages( 32222 errorInfo, 32223 isCall ? 32224 Diagnostics.Each_member_of_the_union_type_0_has_signatures_but_none_of_those_signatures_are_compatible_with_each_other : 32225 Diagnostics.Each_member_of_the_union_type_0_has_construct_signatures_but_none_of_those_signatures_are_compatible_with_each_other, 32226 typeToString(apparentType) 32227 ); 32228 } 32229 } 32230 else { 32231 errorInfo = chainDiagnosticMessages( 32232 errorInfo, 32233 isCall ? 32234 Diagnostics.Type_0_has_no_call_signatures : 32235 Diagnostics.Type_0_has_no_construct_signatures, 32236 typeToString(apparentType) 32237 ); 32238 } 32239 32240 let headMessage = isCall ? Diagnostics.This_expression_is_not_callable : Diagnostics.This_expression_is_not_constructable; 32241 32242 // Diagnose get accessors incorrectly called as functions 32243 if (isCallExpression(errorTarget.parent) && errorTarget.parent.arguments.length === 0) { 32244 const { resolvedSymbol } = getNodeLinks(errorTarget); 32245 if (resolvedSymbol && resolvedSymbol.flags & SymbolFlags.GetAccessor) { 32246 headMessage = Diagnostics.This_expression_is_not_callable_because_it_is_a_get_accessor_Did_you_mean_to_use_it_without; 32247 } 32248 } 32249 32250 return { 32251 messageChain: chainDiagnosticMessages(errorInfo, headMessage), 32252 relatedMessage: maybeMissingAwait ? Diagnostics.Did_you_forget_to_use_await : undefined, 32253 }; 32254 } 32255 function invocationError(errorTarget: Node, apparentType: Type, kind: SignatureKind, relatedInformation?: DiagnosticRelatedInformation) { 32256 const { messageChain, relatedMessage: relatedInfo } = invocationErrorDetails(errorTarget, apparentType, kind); 32257 const diagnostic = createDiagnosticForNodeFromMessageChain(errorTarget, messageChain); 32258 if (relatedInfo) { 32259 addRelatedInfo(diagnostic, createDiagnosticForNode(errorTarget, relatedInfo)); 32260 } 32261 if (isCallExpression(errorTarget.parent)) { 32262 const { start, length } = getDiagnosticSpanForCallNode(errorTarget.parent, /* doNotIncludeArguments */ true); 32263 diagnostic.start = start; 32264 diagnostic.length = length; 32265 } 32266 diagnostics.add(diagnostic); 32267 invocationErrorRecovery(apparentType, kind, relatedInformation ? addRelatedInfo(diagnostic, relatedInformation) : diagnostic); 32268 } 32269 32270 function invocationErrorRecovery(apparentType: Type, kind: SignatureKind, diagnostic: Diagnostic) { 32271 if (!apparentType.symbol) { 32272 return; 32273 } 32274 const importNode = getSymbolLinks(apparentType.symbol).originatingImport; 32275 // Create a diagnostic on the originating import if possible onto which we can attach a quickfix 32276 // An import call expression cannot be rewritten into another form to correct the error - the only solution is to use `.default` at the use-site 32277 if (importNode && !isImportCall(importNode)) { 32278 const sigs = getSignaturesOfType(getTypeOfSymbol(getSymbolLinks(apparentType.symbol).target!), kind); 32279 if (!sigs || !sigs.length) return; 32280 32281 addRelatedInfo(diagnostic, 32282 createDiagnosticForNode(importNode, Diagnostics.Type_originates_at_this_import_A_namespace_style_import_cannot_be_called_or_constructed_and_will_cause_a_failure_at_runtime_Consider_using_a_default_import_or_import_require_here_instead) 32283 ); 32284 } 32285 } 32286 32287 function resolveTaggedTemplateExpression(node: TaggedTemplateExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { 32288 const tagType = checkExpression(node.tag); 32289 const apparentType = getApparentType(tagType); 32290 32291 if (isErrorType(apparentType)) { 32292 // Another error has already been reported 32293 return resolveErrorCall(node); 32294 } 32295 32296 const callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call); 32297 const numConstructSignatures = getSignaturesOfType(apparentType, SignatureKind.Construct).length; 32298 32299 if (isUntypedFunctionCall(tagType, apparentType, callSignatures.length, numConstructSignatures)) { 32300 return resolveUntypedCall(node); 32301 } 32302 32303 if (!callSignatures.length) { 32304 if (isArrayLiteralExpression(node.parent)) { 32305 const diagnostic = createDiagnosticForNode(node.tag, Diagnostics.It_is_likely_that_you_are_missing_a_comma_to_separate_these_two_template_expressions_They_form_a_tagged_template_expression_which_cannot_be_invoked); 32306 diagnostics.add(diagnostic); 32307 return resolveErrorCall(node); 32308 } 32309 32310 invocationError(node.tag, apparentType, SignatureKind.Call); 32311 return resolveErrorCall(node); 32312 } 32313 32314 return resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None); 32315 } 32316 32317 /** 32318 * Gets the localized diagnostic head message to use for errors when resolving a decorator as a call expression. 32319 */ 32320 function getDiagnosticHeadMessageForDecoratorResolution(node: Decorator) { 32321 switch (node.parent.kind) { 32322 case SyntaxKind.ClassDeclaration: 32323 case SyntaxKind.ClassExpression: 32324 case SyntaxKind.StructDeclaration: 32325 return Diagnostics.Unable_to_resolve_signature_of_class_decorator_when_called_as_an_expression; 32326 32327 case SyntaxKind.Parameter: 32328 return Diagnostics.Unable_to_resolve_signature_of_parameter_decorator_when_called_as_an_expression; 32329 32330 case SyntaxKind.PropertyDeclaration: 32331 return Diagnostics.Unable_to_resolve_signature_of_property_decorator_when_called_as_an_expression; 32332 32333 case SyntaxKind.MethodDeclaration: 32334 case SyntaxKind.GetAccessor: 32335 case SyntaxKind.SetAccessor: 32336 return Diagnostics.Unable_to_resolve_signature_of_method_decorator_when_called_as_an_expression; 32337 32338 case SyntaxKind.FunctionDeclaration: 32339 const decoratorName = getNameOfDecorator(node); 32340 if (isEtsFunctionDecorators(decoratorName, compilerOptions)) { 32341 return Diagnostics.Unable_to_resolve_signature_of_function_decorator_when_decorators_are_not_valid; 32342 } 32343 return Debug.fail(); 32344 32345 default: 32346 return Debug.fail(); 32347 } 32348 } 32349 32350 function annotationHasDefaultValue(node: Annotation): boolean { 32351 const members = node.annotationDeclaration!.members; 32352 return every(members, (elem) => (elem as AnnotationPropertyDeclaration).initializer !== undefined); 32353 } 32354 32355 /** 32356 * Resolves an annotation as if it were a call expression. 32357 */ 32358 function resolveAnnotation(node: Annotation): Signature { 32359 // @Anno 32360 // class C {} 32361 // 32362 // or 32363 // 32364 // @t.Anno 32365 // class C {} 32366 if (isIdentifier(node.expression) || isPropertyAccessExpression(node.expression)) { 32367 const identType = checkExpression(node.expression); 32368 Debug.assert(identType.symbol.flags & SymbolFlags.Annotation); 32369 32370 if (!annotationHasDefaultValue(node)) { 32371 const nodeStr = getTextOfNode(node.expression, /*includeTrivia*/ false); 32372 error(node, Diagnostics.When_annotation_0_is_applied_all_fields_without_default_values_must_be_provided, nodeStr); 32373 return resolveErrorCall(node); 32374 } 32375 return annotationDefaultSignature; 32376 } 32377 32378 Debug.assert(isCallExpression(node.expression)); 32379 // let d = {} 32380 // @Anno(d) 32381 // class C {} 32382 if (!node.expression.arguments || 32383 node.expression.arguments.length !== 1 || 32384 !isObjectLiteralExpression(node.expression.arguments[0])) { 32385 const nodeStr = getTextOfNode(node.expression.arguments[0] || node.expression, /*includeTrivia*/ false); 32386 error(node, Diagnostics.Only_an_object_literal_have_to_be_provided_as_annotation_parameters_list_got_Colon_0, nodeStr); 32387 return resolveErrorCall(node); 32388 } 32389 32390 // let bar = goo() 32391 // @Anno({foo: bar}) 32392 // class C {} 32393 const arg = node.expression.arguments[0]; 32394 const evaluatedProps = new Map<__String, AnnotationConstantExpressionType>(); 32395 for (const prop of arg.properties) { 32396 if (!isPropertyAssignment(prop)) { 32397 const nodeStr = getTextOfNode(arg, /*includeTrivia*/ false); 32398 error(node, Diagnostics.Only_an_object_literal_have_to_be_provided_as_annotation_parameters_list_got_Colon_0, nodeStr); 32399 return resolveErrorCall(node); 32400 } 32401 const evaluated = evaluateAnnotationPropertyConstantExpression(prop.initializer); 32402 if (evaluated === undefined) { 32403 const nodeStr = getTextOfNode(prop.initializer, /*includeTrivia*/ false); 32404 error(node, Diagnostics.All_members_of_object_literal_which_is_provided_as_annotation_parameters_list_have_to_be_constant_expressions_got_Colon_0, nodeStr); 32405 return resolveErrorCall(node); 32406 } 32407 evaluatedProps.set(tryGetTextOfPropertyName(prop.name)!, evaluated); 32408 } 32409 32410 // @Anno() 32411 // class C {} 32412 // 32413 // or 32414 // 32415 // @Anno({...}) 32416 // class C {} 32417 const funcType = checkExpression(node.expression); 32418 const apparentType = getApparentType(funcType); 32419 if (isErrorType(apparentType)) { 32420 return resolveErrorCall(node); 32421 } 32422 32423 const members = node.annotationDeclaration!.members; 32424 for (const m of members) { 32425 const memberName = tryGetTextOfPropertyName(m.name)!; 32426 if (evaluatedProps.has(memberName)) { 32427 const propValue = annotationEvaluatedValueToExpr(evaluatedProps.get(memberName)!, getTypeOfNode(m))!; 32428 if (getNodeLinks(node).annotationObjectLiteralEvaluatedProps === undefined) { 32429 getNodeLinks(node).annotationObjectLiteralEvaluatedProps = new Map<__String, Expression>(); 32430 } 32431 getNodeLinks(node).annotationObjectLiteralEvaluatedProps!.set(memberName, propValue); 32432 } 32433 } 32434 return getResolvedSignature(node.expression); 32435 } 32436 32437 /** 32438 * Resolves a decorator as if it were a call expression. 32439 */ 32440 function resolveDecorator(node: Decorator, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { 32441 const funcType = checkExpression(node.expression); 32442 const apparentType = getApparentType(funcType); 32443 if (isErrorType(apparentType)) { 32444 return resolveErrorCall(node); 32445 } 32446 32447 const callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call); 32448 const numConstructSignatures = getSignaturesOfType(apparentType, SignatureKind.Construct).length; 32449 if (isUntypedFunctionCall(funcType, apparentType, callSignatures.length, numConstructSignatures)) { 32450 return resolveUntypedCall(node); 32451 } 32452 32453 if (isPotentiallyUncalledDecorator(node, callSignatures)) { 32454 const nodeStr = getTextOfNode(node.expression, /*includeTrivia*/ false); 32455 error(node, Diagnostics._0_accepts_too_few_arguments_to_be_used_as_a_decorator_here_Did_you_mean_to_call_it_first_and_write_0, nodeStr); 32456 return resolveErrorCall(node); 32457 } 32458 32459 const headMessage = getDiagnosticHeadMessageForDecoratorResolution(node); 32460 if (!callSignatures.length) { 32461 const errorDetails = invocationErrorDetails(node.expression, apparentType, SignatureKind.Call); 32462 const messageChain = chainDiagnosticMessages(errorDetails.messageChain, headMessage); 32463 const diag = createDiagnosticForNodeFromMessageChain(node.expression, messageChain); 32464 if (errorDetails.relatedMessage) { 32465 addRelatedInfo(diag, createDiagnosticForNode(node.expression, errorDetails.relatedMessage)); 32466 } 32467 diagnostics.add(diag); 32468 invocationErrorRecovery(apparentType, SignatureKind.Call, diag); 32469 return resolveErrorCall(node); 32470 } 32471 32472 return resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None, headMessage); 32473 } 32474 32475 function createSignatureForJSXIntrinsic(node: JsxOpeningLikeElement, result: Type): Signature { 32476 const namespace = getJsxNamespaceAt(node); 32477 const exports = namespace && getExportsOfSymbol(namespace); 32478 // We fake up a SFC signature for each intrinsic, however a more specific per-element signature drawn from the JSX declaration 32479 // file would probably be preferable. 32480 const typeSymbol = exports && getSymbol(exports, JsxNames.Element, SymbolFlags.Type); 32481 const returnNode = typeSymbol && nodeBuilder.symbolToEntityName(typeSymbol, SymbolFlags.Type, node); 32482 const declaration = factory.createFunctionTypeNode(/*typeParameters*/ undefined, 32483 [factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotdotdot*/ undefined, "props", /*questionMark*/ undefined, nodeBuilder.typeToTypeNode(result, node))], 32484 returnNode ? factory.createTypeReferenceNode(returnNode, /*typeArguments*/ undefined) : factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) 32485 ); 32486 const parameterSymbol = createSymbol(SymbolFlags.FunctionScopedVariable, "props" as __String); 32487 parameterSymbol.type = result; 32488 return createSignature( 32489 declaration, 32490 /*typeParameters*/ undefined, 32491 /*thisParameter*/ undefined, 32492 [parameterSymbol], 32493 typeSymbol ? getDeclaredTypeOfSymbol(typeSymbol) : errorType, 32494 /*returnTypePredicate*/ undefined, 32495 1, 32496 SignatureFlags.None 32497 ); 32498 } 32499 32500 function resolveJsxOpeningLikeElement(node: JsxOpeningLikeElement, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { 32501 if (isJsxIntrinsicIdentifier(node.tagName)) { 32502 const result = getIntrinsicAttributesTypeFromJsxOpeningLikeElement(node); 32503 const fakeSignature = createSignatureForJSXIntrinsic(node, result); 32504 checkTypeAssignableToAndOptionallyElaborate(checkExpressionWithContextualType(node.attributes, getEffectiveFirstArgumentForJsxSignature(fakeSignature, node), /*mapper*/ undefined, CheckMode.Normal), result, node.tagName, node.attributes); 32505 if (length(node.typeArguments)) { 32506 forEach(node.typeArguments, checkSourceElement); 32507 diagnostics.add(createDiagnosticForNodeArray(getSourceFileOfNode(node), node.typeArguments!, Diagnostics.Expected_0_type_arguments_but_got_1, 0, length(node.typeArguments))); 32508 } 32509 return fakeSignature; 32510 } 32511 const exprTypes = checkExpression(node.tagName); 32512 const apparentType = getApparentType(exprTypes); 32513 if (isErrorType(apparentType)) { 32514 return resolveErrorCall(node); 32515 } 32516 32517 const signatures = getUninstantiatedJsxSignaturesOfType(exprTypes, node); 32518 if (isUntypedFunctionCall(exprTypes, apparentType, signatures.length, /*constructSignatures*/ 0)) { 32519 return resolveUntypedCall(node); 32520 } 32521 32522 if (signatures.length === 0) { 32523 // We found no signatures at all, which is an error 32524 error(node.tagName, Diagnostics.JSX_element_type_0_does_not_have_any_construct_or_call_signatures, getTextOfNode(node.tagName)); 32525 return resolveErrorCall(node); 32526 } 32527 32528 return resolveCall(node, signatures, candidatesOutArray, checkMode, SignatureFlags.None); 32529 } 32530 32531 /** 32532 * Sometimes, we have a decorator that could accept zero arguments, 32533 * but is receiving too many arguments as part of the decorator invocation. 32534 * In those cases, a user may have meant to *call* the expression before using it as a decorator. 32535 */ 32536 function isPotentiallyUncalledDecorator(decorator: Decorator, signatures: readonly Signature[]) { 32537 return signatures.length && every(signatures, signature => 32538 signature.minArgumentCount === 0 && 32539 !signatureHasRestParameter(signature) && 32540 signature.parameters.length < getDecoratorArgumentCount(decorator, signature)); 32541 } 32542 32543 function resolveSignature(node: CallLikeExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { 32544 switch (node.kind) { 32545 case SyntaxKind.CallExpression: 32546 case SyntaxKind.EtsComponentExpression: 32547 return resolveCallExpression(node, candidatesOutArray, checkMode); 32548 case SyntaxKind.NewExpression: 32549 return resolveNewExpression(node, candidatesOutArray, checkMode); 32550 case SyntaxKind.TaggedTemplateExpression: 32551 return resolveTaggedTemplateExpression(node, candidatesOutArray, checkMode); 32552 case SyntaxKind.Decorator: 32553 if (isAnnotation(node)) { 32554 return resolveAnnotation(node); 32555 } 32556 return resolveDecorator(node, candidatesOutArray, checkMode); 32557 case SyntaxKind.JsxOpeningElement: 32558 case SyntaxKind.JsxSelfClosingElement: 32559 return resolveJsxOpeningLikeElement(node, candidatesOutArray, checkMode); 32560 } 32561 } 32562 32563 /** 32564 * Resolve a signature of a given call-like expression. 32565 * @param node a call-like expression to try resolve a signature for 32566 * @param candidatesOutArray an array of signature to be filled in by the function. It is passed by signature help in the language service; 32567 * the function will fill it up with appropriate candidate signatures 32568 * @return a signature of the call-like expression or undefined if one can't be found 32569 */ 32570 function getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[] | undefined, checkMode?: CheckMode): Signature { 32571 const links = getNodeLinks(node); 32572 // If getResolvedSignature has already been called, we will have cached the resolvedSignature. 32573 // However, it is possible that either candidatesOutArray was not passed in the first time, 32574 // or that a different candidatesOutArray was passed in. Therefore, we need to redo the work 32575 // to correctly fill the candidatesOutArray. 32576 const cached = links.resolvedSignature; 32577 if (cached && cached !== resolvingSignature && !candidatesOutArray) { 32578 return cached; 32579 } 32580 links.resolvedSignature = resolvingSignature; 32581 const result = resolveSignature(node, candidatesOutArray, checkMode || CheckMode.Normal); 32582 // When CheckMode.SkipGenericFunctions is set we use resolvingSignature to indicate that call 32583 // resolution should be deferred. 32584 if (result !== resolvingSignature) { 32585 // If signature resolution originated in control flow type analysis (for example to compute the 32586 // assigned type in a flow assignment) we don't cache the result as it may be based on temporary 32587 // types from the control flow analysis. 32588 links.resolvedSignature = flowLoopStart === flowLoopCount ? result : cached; 32589 } 32590 return result; 32591 } 32592 32593 /** 32594 * Indicates whether a declaration can be treated as a constructor in a JavaScript 32595 * file. 32596 */ 32597 function isJSConstructor(node: Node | undefined): node is FunctionDeclaration | FunctionExpression { 32598 if (!node || !isInJSFile(node)) { 32599 return false; 32600 } 32601 const func = isFunctionDeclaration(node) || isFunctionExpression(node) ? node : 32602 (isVariableDeclaration(node) || isPropertyAssignment(node)) && node.initializer && isFunctionExpression(node.initializer) ? node.initializer : 32603 undefined; 32604 if (func) { 32605 // If the node has a @class or @constructor tag, treat it like a constructor. 32606 if (getJSDocClassTag(node)) return true; 32607 32608 // If the node is a property of an object literal. 32609 if (isPropertyAssignment(walkUpParenthesizedExpressions(func.parent))) return false; 32610 32611 // If the symbol of the node has members, treat it like a constructor. 32612 const symbol = getSymbolOfNode(func); 32613 return !!symbol?.members?.size; 32614 } 32615 return false; 32616 } 32617 32618 function mergeJSSymbols(target: Symbol, source: Symbol | undefined) { 32619 if (source) { 32620 const links = getSymbolLinks(source); 32621 if (!links.inferredClassSymbol || !links.inferredClassSymbol.has(getSymbolId(target))) { 32622 const inferred = isTransientSymbol(target) ? target : cloneSymbol(target) as TransientSymbol; 32623 inferred.exports = inferred.exports || createSymbolTable(); 32624 inferred.members = inferred.members || createSymbolTable(); 32625 inferred.flags |= source.flags & SymbolFlags.Class; 32626 if (source.exports?.size) { 32627 mergeSymbolTable(inferred.exports, source.exports); 32628 } 32629 if (source.members?.size) { 32630 mergeSymbolTable(inferred.members, source.members); 32631 } 32632 (links.inferredClassSymbol || (links.inferredClassSymbol = new Map())).set(getSymbolId(inferred), inferred); 32633 return inferred; 32634 } 32635 return links.inferredClassSymbol.get(getSymbolId(target)); 32636 } 32637 } 32638 32639 function getAssignedClassSymbol(decl: Declaration): Symbol | undefined { 32640 const assignmentSymbol = decl && getSymbolOfExpando(decl, /*allowDeclaration*/ true); 32641 const prototype = assignmentSymbol?.exports?.get("prototype" as __String); 32642 const init = prototype?.valueDeclaration && getAssignedJSPrototype(prototype.valueDeclaration); 32643 return init ? getSymbolOfNode(init) : undefined; 32644 } 32645 32646 function getSymbolOfExpando(node: Node, allowDeclaration: boolean): Symbol | undefined { 32647 if (!node.parent) { 32648 return undefined; 32649 } 32650 let name: Expression | BindingName | undefined; 32651 let decl: Node | undefined; 32652 if (isVariableDeclaration(node.parent) && node.parent.initializer === node) { 32653 if (!isInJSFile(node) && !(isVarConst(node.parent) && isFunctionLikeDeclaration(node))) { 32654 return undefined; 32655 } 32656 name = node.parent.name; 32657 decl = node.parent; 32658 } 32659 else if (isBinaryExpression(node.parent)) { 32660 const parentNode = node.parent; 32661 const parentNodeOperator = node.parent.operatorToken.kind; 32662 if (parentNodeOperator === SyntaxKind.EqualsToken && (allowDeclaration || parentNode.right === node)) { 32663 name = parentNode.left; 32664 decl = name; 32665 } 32666 else if (parentNodeOperator === SyntaxKind.BarBarToken || parentNodeOperator === SyntaxKind.QuestionQuestionToken) { 32667 if (isVariableDeclaration(parentNode.parent) && parentNode.parent.initializer === parentNode) { 32668 name = parentNode.parent.name; 32669 decl = parentNode.parent; 32670 } 32671 else if (isBinaryExpression(parentNode.parent) && parentNode.parent.operatorToken.kind === SyntaxKind.EqualsToken && (allowDeclaration || parentNode.parent.right === parentNode)) { 32672 name = parentNode.parent.left; 32673 decl = name; 32674 } 32675 32676 if (!name || !isBindableStaticNameExpression(name) || !isSameEntityName(name, parentNode.left)) { 32677 return undefined; 32678 } 32679 } 32680 } 32681 else if (allowDeclaration && isFunctionDeclaration(node)) { 32682 name = node.name; 32683 decl = node; 32684 } 32685 32686 if (!decl || !name || (!allowDeclaration && !getExpandoInitializer(node, isPrototypeAccess(name)))) { 32687 return undefined; 32688 } 32689 return getSymbolOfNode(decl); 32690 } 32691 32692 32693 function getAssignedJSPrototype(node: Node) { 32694 if (!node.parent) { 32695 return false; 32696 } 32697 let parent: Node = node.parent; 32698 while (parent && parent.kind === SyntaxKind.PropertyAccessExpression) { 32699 parent = parent.parent; 32700 } 32701 if (parent && isBinaryExpression(parent) && isPrototypeAccess(parent.left) && parent.operatorToken.kind === SyntaxKind.EqualsToken) { 32702 const right = getInitializerOfBinaryExpression(parent); 32703 return isObjectLiteralExpression(right) && right; 32704 } 32705 } 32706 32707 /** 32708 * Syntactically and semantically checks a call or new expression. 32709 * @param node The call/new expression to be checked. 32710 * @returns On success, the expression's signature's return type. On failure, anyType. 32711 */ 32712 function checkCallExpression(node: CallExpression | NewExpression | EtsComponentExpression, checkMode?: CheckMode): Type { 32713 checkGrammarTypeArguments(node, node.typeArguments); 32714 32715 const signature = getResolvedSignature(node, /*candidatesOutArray*/ undefined, checkMode); 32716 if (signature === resolvingSignature) { 32717 // CheckMode.SkipGenericFunctions is enabled and this is a call to a generic function that 32718 // returns a function type. We defer checking and return silentNeverType. 32719 return silentNeverType; 32720 } 32721 32722 checkDeprecatedSignature(signature, node); 32723 32724 if (node.expression.kind === SyntaxKind.SuperKeyword) { 32725 return voidType; 32726 } 32727 32728 if (node.kind === SyntaxKind.NewExpression) { 32729 const declaration = signature.declaration; 32730 32731 if (declaration && 32732 declaration.kind !== SyntaxKind.Constructor && 32733 declaration.kind !== SyntaxKind.ConstructSignature && 32734 declaration.kind !== SyntaxKind.ConstructorType && 32735 !isJSDocConstructSignature(declaration) && 32736 !isJSConstructor(declaration)) { 32737 32738 // When resolved signature is a call signature (and not a construct signature) the result type is any 32739 if (noImplicitAny) { 32740 error(node, Diagnostics.new_expression_whose_target_lacks_a_construct_signature_implicitly_has_an_any_type); 32741 } 32742 return anyType; 32743 } 32744 } 32745 32746 // In JavaScript files, calls to any identifier 'require' are treated as external module imports 32747 if (isInJSFile(node) && isCommonJsRequire(node)) { 32748 return resolveExternalModuleTypeByLiteral(node.arguments![0] as StringLiteral); 32749 } 32750 32751 const returnType = getReturnTypeOfSignature(signature); 32752 // Treat any call to the global 'Symbol' function that is part of a const variable or readonly property 32753 // as a fresh unique symbol literal type. 32754 if (returnType.flags & TypeFlags.ESSymbolLike && isSymbolOrSymbolForCall(node)) { 32755 return getESSymbolLikeTypeForNode(walkUpParenthesizedExpressions(node.parent)); 32756 } 32757 if (node.kind === SyntaxKind.CallExpression && !node.questionDotToken && node.parent.kind === SyntaxKind.ExpressionStatement && 32758 returnType.flags & TypeFlags.Void && getTypePredicateOfSignature(signature)) { 32759 if (!isDottedName(node.expression)) { 32760 error(node.expression, Diagnostics.Assertions_require_the_call_target_to_be_an_identifier_or_qualified_name); 32761 } 32762 else if (!getEffectsSignature(node)) { 32763 const diagnostic = error(node.expression, Diagnostics.Assertions_require_every_name_in_the_call_target_to_be_declared_with_an_explicit_type_annotation); 32764 getTypeOfDottedName(node.expression, diagnostic); 32765 } 32766 } 32767 32768 if (isInJSFile(node)) { 32769 const jsSymbol = getSymbolOfExpando(node, /*allowDeclaration*/ false); 32770 if (jsSymbol?.exports?.size) { 32771 const jsAssignmentType = createAnonymousType(jsSymbol, jsSymbol.exports, emptyArray, emptyArray, emptyArray); 32772 jsAssignmentType.objectFlags |= ObjectFlags.JSLiteral; 32773 return getIntersectionType([returnType, jsAssignmentType]); 32774 } 32775 } 32776 32777 // System UI components can only be used in build/pageTransition method or method/function with the decorator "@Builder" 32778 if (isInETSFile(node) && 32779 isIdentifier(node.expression) && 32780 !isNewExpression(node) && 32781 isSystemEtsComponent(node.expression, compilerOptions) && 32782 !isInBuildOrPageTransitionContext(node, compilerOptions)) { 32783 error(node.expression, Diagnostics.UI_component_0_cannot_be_used_in_this_place, diagnosticName(node.expression)); 32784 } 32785 32786 return returnType; 32787 } 32788 32789 function isSystemEtsComponent(node: Identifier, compilerOptions: CompilerOptions): boolean { 32790 // Check if the node's name is in the components list 32791 const name = getTextOfPropertyName(node).toString(); 32792 if (!compilerOptions.ets?.components.some(component => component === name)) { 32793 return false; 32794 } 32795 32796 // we believe node is an system ets component if it's declared in "ets-loader/declarations/" in sdk 32797 if (!compilerOptions.etsLoaderPath) { 32798 return false; 32799 } 32800 const declarationsPath = resolvePath(compilerOptions.etsLoaderPath, "declarations"); 32801 const symbol = resolveSymbol(getSymbolAtLocation(node)); 32802 const declarations = symbol?.declarations; 32803 // Check if it only has one declaration and was declared in sdk 32804 if (!declarations || declarations.length !== 1) { 32805 return false; 32806 } 32807 const sourceFile = getSourceFileOfNode(declarations[0]); 32808 const fileName = sourceFile?.fileName; 32809 return !!fileName?.startsWith(declarationsPath); 32810 } 32811 32812 function propertyAccessExpressionConditionCheck(node: PropertyAccessExpression) { 32813 if (!jsDocFileCheckInfo.fileNeedCheck || !getJsDocNodeCheckedConfig) { 32814 return; 32815 } 32816 const sourceFile = getSourceFileOfNode(node); 32817 const sourceSymbol: Symbol | undefined = getPropertyAccessExpressionNameSymbol(node); 32818 if (!sourceSymbol || !sourceSymbol.valueDeclaration) { 32819 return; 32820 } 32821 const sourceSymbolSourceFile = getSourceFileOfNode(sourceSymbol.valueDeclaration); 32822 if (!sourceSymbolSourceFile) { 32823 return; 32824 } 32825 const checkParam = getJsDocNodeCheckedConfig(jsDocFileCheckInfo, sourceSymbolSourceFile.fileName); 32826 if (!checkParam.nodeNeedCheck) { 32827 return; 32828 } 32829 if (isIdentifier(node.name)) { 32830 if (sourceSymbol?.declarations && sourceSymbol?.declarations.length >= 2) { 32831 const signatureDeclaration = tryGetSignatureDeclaration(checker, node); 32832 if (signatureDeclaration) { 32833 expressionCheckByJsDoc(signatureDeclaration, node.name, sourceFile, checkParam.checkConfig); 32834 } 32835 } else { 32836 sourceSymbol?.declarations?.forEach(item => { 32837 if (isIdentifier(node.name)) { 32838 expressionCheckByJsDoc(item, node.name, sourceFile, checkParam.checkConfig); 32839 } 32840 }) 32841 } 32842 } 32843 } 32844 32845 function tryGetSignatureDeclaration(typeChecker: TypeChecker, node: Node): SignatureDeclaration | undefined { 32846 const callLike = getAncestorCallLikeExpression(node); 32847 const signature = callLike && typeChecker.tryGetResolvedSignatureWithoutCheck(callLike); 32848 // Don't go to a function type, go to the value having that type. 32849 return tryCast(signature && signature.declaration, (d): d is SignatureDeclaration => isFunctionLike(d) && !isFunctionTypeNode(d)); 32850 } 32851 32852 function getAncestorCallLikeExpression(node: Node): CallLikeExpression | undefined { 32853 const target = findAncestor(node, n => ! isRightSideOfAccessExpression(n)); 32854 const callLike = target?.parent; 32855 return callLike && isCallLikeExpression(callLike) && getInvokedExpression(callLike) === target ? callLike : undefined; 32856 } 32857 32858 function getPropertyAccessExpressionNameSymbol(node: PropertyAccessExpression) { 32859 const right = node.name; 32860 const leftType = checkNonNullExpression(node.expression); 32861 const assignmentKind = getAssignmentTargetKind(node); 32862 const apparentType = getApparentType(assignmentKind !== AssignmentKind.None || isMethodAccessForCall(node) ? getWidenedType(leftType) : leftType); 32863 let sourceSymbol: Symbol | undefined; 32864 if (isPrivateIdentifier(right)) { 32865 const lexicallyScopedSymbol = lookupSymbolForPrivateIdentifierDeclaration(right.escapedText, right); 32866 sourceSymbol = lexicallyScopedSymbol ? getPrivateIdentifierPropertyOfType(leftType, lexicallyScopedSymbol) : undefined; 32867 } 32868 else { 32869 sourceSymbol = getPropertyOfType(apparentType, right.escapedText); 32870 if (!sourceSymbol) { 32871 const etsComponentExpressionNode = getEtsComponentExpressionInnerExpressionStatementNode(node) 32872 || getRootEtsComponentInnerCallExpressionNode(node); 32873 if (etsComponentExpressionNode) { 32874 sourceSymbol = getEtsComponentExpressionPropertyOfType(node, etsComponentExpressionNode, right); 32875 } 32876 } 32877 } 32878 return sourceSymbol; 32879 } 32880 32881 function getEtsComponentExpressionPropertyOfType(node: PropertyAccessExpression, etsComponentExpressionNode: CallExpression | EtsComponentExpression | PropertyAccessExpression | Identifier, right: Identifier) { 32882 let sourceSymbol: Symbol | undefined; 32883 const locals = getSourceFileOfNode(node).locals; 32884 if (locals?.has(right.escapedText)) { 32885 const extraSymbol = locals?.get(right.escapedText); 32886 const etsComponentName = isIdentifier(etsComponentExpressionNode) ? 32887 etsComponentExpressionNode.escapedText : 32888 isIdentifier(node.expression) ? 32889 node.expression.escapedText : 32890 undefined; 32891 const decorators = getAllDecorators(extraSymbol?.valueDeclaration); 32892 if (getEtsExtendDecoratorsComponentNames(decorators, compilerOptions).find(extendComponentName => extendComponentName === etsComponentName)) { 32893 sourceSymbol = extraSymbol; 32894 } 32895 if (hasEtsStylesDecoratorNames(decorators, compilerOptions)) { 32896 sourceSymbol = extraSymbol; 32897 } 32898 } 32899 const props = getContainingStruct(node)?.symbol.members; 32900 if (props?.has(right.escapedText)) { 32901 const stylesSymbol = props?.get(right.escapedText); 32902 const decorators = getAllDecorators(stylesSymbol?.valueDeclaration); 32903 if (hasEtsStylesDecoratorNames(decorators, compilerOptions)) { 32904 sourceSymbol = stylesSymbol; 32905 } 32906 } 32907 return sourceSymbol; 32908 } 32909 32910 function conditionCheck(node: Identifier, jsDocs: readonly JSDocTag[], sourceFile: SourceFile, checkConfig: JsDocNodeCheckConfigItem) { 32911 const specifyJsDocTagValue = getSpecifyJsDocTagValue(jsDocs, checkConfig.tagName); 32912 if (specifyJsDocTagValue === undefined) { 32913 return; 32914 } 32915 const hasIfChecked = hasConditionChecked(node, specifyJsDocTagValue, checkConfig.specifyCheckConditionFuncName); 32916 if (!hasIfChecked && host.getJsDocNodeConditionCheckedResult) { 32917 const jsDocTagInfos: JsDocTagInfo[] = []; 32918 jsDocs.forEach(item => { 32919 jsDocTagInfos.push({ 32920 name: item.tagName.escapedText.toString(), 32921 text: getTextOfJSDocComment(item.comment), 32922 }); 32923 }); 32924 const conditionCheckResult = host.getJsDocNodeConditionCheckedResult(jsDocFileCheckInfo, jsDocTagInfos); 32925 if (conditionCheckResult.valid) { 32926 return; 32927 } else { 32928 const diagnostic = createDiagnosticForNodeInSourceFile(sourceFile, node, Diagnostics.The_statement_must_be_written_use_the_function_0_under_the_if_condition, checkConfig.specifyCheckConditionFuncName); 32929 collectDiagnostics(conditionCheckResult, node, diagnostic); 32930 } 32931 } 32932 } 32933 32934 function expressionCheckByJsDoc(declaration: Declaration, node: Identifier, sourceFile: SourceFile, checkConfig: JsDocNodeCheckConfigItem[]): void { 32935 const jsDocTags = getJSDocTags(declaration); 32936 for (let i = 0; i < checkConfig.length; i++) { 32937 const config = checkConfig[i]; 32938 let tagNameCheckNecessity = true; 32939 if (config.checkJsDocSpecialValidCallback) { 32940 tagNameCheckNecessity = config.checkJsDocSpecialValidCallback(jsDocTags, config); 32941 } 32942 if (!tagNameCheckNecessity) { 32943 continue; 32944 } 32945 let tagNameExisted = false; 32946 if (!config.tagNameShouldExisted && config.needConditionCheck) { 32947 conditionCheck(node, jsDocTags, sourceFile, config); 32948 } 32949 jsDocTags.forEach(item => { 32950 if (config.tagName.includes(item.tagName.escapedText.toString())) { 32951 if(config.checkValidCallback) { 32952 tagNameExisted = config.checkValidCallback(item, config); 32953 } else { 32954 tagNameExisted = true; 32955 } 32956 if (tagNameExisted && !config.tagNameShouldExisted && !config.needConditionCheck) { 32957 const diagnostic = createDiagnosticForNodeInSourceFile(sourceFile, node, Diagnostics.This_API_has_been_Special_Markings_exercise_caution_when_using_this_API); 32958 collectDiagnostics(config, node, diagnostic); 32959 } 32960 } 32961 }); 32962 if (config.tagNameShouldExisted && !tagNameExisted) { 32963 const diagnostic = createDiagnosticForNodeInSourceFile(sourceFile, node, Diagnostics.This_API_has_been_Special_Markings_exercise_caution_when_using_this_API); 32964 collectDiagnostics(config, node, diagnostic); 32965 } 32966 } 32967 } 32968 32969 function collectDiagnostics(config: JsDocNodeCheckConfigItem | ConditionCheckResult, node: Identifier, diagnostic: DiagnosticWithLocation): void { 32970 if (config.message) { 32971 // @ts-ignore 32972 diagnostic.messageText = config.message.replace("{0}", node.getText() === "" ? node.text : node.getText()); 32973 } 32974 diagnostic.category = config.type ? config.type : ts.DiagnosticCategory.Warning; 32975 diagnostics.add(diagnostic); 32976 suggestionDiagnostics.add(diagnostic); 32977 } 32978 32979 function getSpecifyJsDocTagValue(jsDocs: readonly JSDocTag[], specifyTag: string[]): string | undefined { 32980 let specifyJsDocTagValue; 32981 jsDocs.forEach(item => { 32982 if (specifyTag.includes(item.tagName.escapedText.toString())) { 32983 specifyJsDocTagValue = item.comment ?? ""; 32984 } 32985 }); 32986 return specifyJsDocTagValue; 32987 } 32988 32989 function hasConditionChecked(expression: Identifier, importSymbol: string, funcSpecify: string): boolean { 32990 const result = { hasIfChecked: false }; 32991 const container = findAncestor(expression, isSourceFile); 32992 if (!container) { 32993 return result.hasIfChecked; 32994 } 32995 traversalNode(expression, importSymbol, container, result, funcSpecify); 32996 return result.hasIfChecked; 32997 } 32998 32999 function traversalNode(node: Node, importSymbol: string, parent: Node, result: { hasIfChecked: boolean }, specifyFuncName: string): void { 33000 if (result.hasIfChecked) { 33001 return; 33002 } 33003 33004 if (node.parent !== parent) { 33005 if (isIfStatement(node.parent)) { 33006 if (isCallExpression(node.parent.expression) && isTargetCallExpression(node.parent.expression, specifyFuncName, importSymbol)) { 33007 result.hasIfChecked = true; 33008 return; 33009 } 33010 else { 33011 traversalNode(node.parent, importSymbol, parent, result, specifyFuncName); 33012 } 33013 } 33014 traversalNode(node.parent, importSymbol, parent, result, specifyFuncName); 33015 } 33016 else { 33017 return; 33018 } 33019 } 33020 33021 function isTargetCallExpression(node: CallExpression, specifyFuncName: string, importSymbol: string): boolean { 33022 if (isIdentifier(node.expression) && 33023 node.arguments.length === 1 && 33024 node.expression.escapedText.toString() === specifyFuncName) { 33025 const expression = node.arguments[0]; 33026 if (isStringLiteral(expression) && expression.text.toString() === importSymbol) { 33027 return true; 33028 } 33029 } 33030 return false; 33031 } 33032 33033 function checkDeprecatedSignature(signature: Signature, node: CallLikeExpression) { 33034 if (signature.declaration && signature.declaration.flags & NodeFlags.Deprecated) { 33035 const suggestionNode = getDeprecatedSuggestionNode(node); 33036 const name = tryGetPropertyAccessOrIdentifierToString(getInvokedExpression(node)); 33037 addDeprecatedSuggestionWithSignature(suggestionNode, signature.declaration, name, signatureToString(signature)); 33038 } 33039 } 33040 33041 function getDeprecatedSuggestionNode(node: Node): Node { 33042 node = skipParentheses(node); 33043 switch (node.kind) { 33044 case SyntaxKind.CallExpression: 33045 case SyntaxKind.Decorator: 33046 case SyntaxKind.NewExpression: 33047 return getDeprecatedSuggestionNode((node as Decorator | CallExpression | NewExpression).expression); 33048 case SyntaxKind.TaggedTemplateExpression: 33049 return getDeprecatedSuggestionNode((node as TaggedTemplateExpression).tag); 33050 case SyntaxKind.JsxOpeningElement: 33051 case SyntaxKind.JsxSelfClosingElement: 33052 return getDeprecatedSuggestionNode((node as JsxOpeningLikeElement).tagName); 33053 case SyntaxKind.ElementAccessExpression: 33054 return (node as ElementAccessExpression).argumentExpression; 33055 case SyntaxKind.PropertyAccessExpression: 33056 return (node as PropertyAccessExpression).name; 33057 case SyntaxKind.TypeReference: 33058 const typeReference = node as TypeReferenceNode; 33059 return isQualifiedName(typeReference.typeName) ? typeReference.typeName.right : typeReference; 33060 default: 33061 return node; 33062 } 33063 } 33064 33065 function isSymbolOrSymbolForCall(node: Node) { 33066 if (!isCallExpression(node)) return false; 33067 let left = node.expression; 33068 if (isPropertyAccessExpression(left) && left.name.escapedText === "for") { 33069 left = left.expression; 33070 } 33071 if (!isIdentifier(left) || left.escapedText !== "Symbol") { 33072 return false; 33073 } 33074 33075 // make sure `Symbol` is the global symbol 33076 const globalESSymbol = getGlobalESSymbolConstructorSymbol(/*reportErrors*/ false); 33077 if (!globalESSymbol) { 33078 return false; 33079 } 33080 33081 return globalESSymbol === resolveName(left, "Symbol" as __String, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false); 33082 } 33083 33084 function checkImportCallExpression(node: ImportCall): Type { 33085 // Check grammar of dynamic import 33086 checkGrammarImportCallExpression(node); 33087 33088 if (node.arguments.length === 0) { 33089 return createPromiseReturnType(node, anyType); 33090 } 33091 33092 const specifier = node.arguments[0]; 33093 const specifierType = checkExpressionCached(specifier); 33094 const optionsType = node.arguments.length > 1 ? checkExpressionCached(node.arguments[1]) : undefined; 33095 // Even though multiple arguments is grammatically incorrect, type-check extra arguments for completion 33096 for (let i = 2; i < node.arguments.length; ++i) { 33097 checkExpressionCached(node.arguments[i]); 33098 } 33099 33100 if (specifierType.flags & TypeFlags.Undefined || specifierType.flags & TypeFlags.Null || !isTypeAssignableTo(specifierType, stringType)) { 33101 error(specifier, Diagnostics.Dynamic_import_s_specifier_must_be_of_type_string_but_here_has_type_0, typeToString(specifierType)); 33102 } 33103 33104 if (optionsType) { 33105 const importCallOptionsType = getGlobalImportCallOptionsType(/*reportErrors*/ true); 33106 if (importCallOptionsType !== emptyObjectType) { 33107 checkTypeAssignableTo(optionsType, getNullableType(importCallOptionsType, TypeFlags.Undefined), node.arguments[1]); 33108 } 33109 } 33110 33111 // resolveExternalModuleName will return undefined if the moduleReferenceExpression is not a string literal 33112 const moduleSymbol = resolveExternalModuleName(node, specifier); 33113 if (moduleSymbol) { 33114 const esModuleSymbol = resolveESModuleSymbol(moduleSymbol, specifier, /*dontRecursivelyResolve*/ true, /*suppressUsageError*/ false); 33115 if (esModuleSymbol) { 33116 return createPromiseReturnType(node, 33117 getTypeWithSyntheticDefaultOnly(getTypeOfSymbol(esModuleSymbol), esModuleSymbol, moduleSymbol, specifier) || 33118 getTypeWithSyntheticDefaultImportType(getTypeOfSymbol(esModuleSymbol), esModuleSymbol, moduleSymbol, specifier) 33119 ); 33120 } 33121 } 33122 return createPromiseReturnType(node, anyType); 33123 } 33124 33125 function createDefaultPropertyWrapperForModule(symbol: Symbol, originalSymbol: Symbol, anonymousSymbol?: Symbol | undefined) { 33126 const memberTable = createSymbolTable(); 33127 const newSymbol = createSymbol(SymbolFlags.Alias, InternalSymbolName.Default); 33128 newSymbol.parent = originalSymbol; 33129 newSymbol.nameType = getStringLiteralType("default"); 33130 newSymbol.aliasTarget = resolveSymbol(symbol); 33131 memberTable.set(InternalSymbolName.Default, newSymbol); 33132 return createAnonymousType(anonymousSymbol, memberTable, emptyArray, emptyArray, emptyArray); 33133 } 33134 33135 function getTypeWithSyntheticDefaultOnly(type: Type, symbol: Symbol, originalSymbol: Symbol, moduleSpecifier: Expression) { 33136 const hasDefaultOnly = isOnlyImportedAsDefault(moduleSpecifier); 33137 if (hasDefaultOnly && type && !isErrorType(type)) { 33138 const synthType = type as SyntheticDefaultModuleType; 33139 if (!synthType.defaultOnlyType) { 33140 const type = createDefaultPropertyWrapperForModule(symbol, originalSymbol); 33141 synthType.defaultOnlyType = type; 33142 } 33143 return synthType.defaultOnlyType; 33144 } 33145 return undefined; 33146 } 33147 33148 function getTypeWithSyntheticDefaultImportType(type: Type, symbol: Symbol, originalSymbol: Symbol, moduleSpecifier: Expression): Type { 33149 if (allowSyntheticDefaultImports && type && !isErrorType(type)) { 33150 const synthType = type as SyntheticDefaultModuleType; 33151 if (!synthType.syntheticType) { 33152 const file = originalSymbol.declarations?.find(isSourceFile); 33153 const hasSyntheticDefault = canHaveSyntheticDefault(file, originalSymbol, /*dontResolveAlias*/ false, moduleSpecifier); 33154 if (hasSyntheticDefault) { 33155 const anonymousSymbol = createSymbol(SymbolFlags.TypeLiteral, InternalSymbolName.Type); 33156 const defaultContainingObject = createDefaultPropertyWrapperForModule(symbol, originalSymbol, anonymousSymbol); 33157 anonymousSymbol.type = defaultContainingObject; 33158 synthType.syntheticType = isValidSpreadType(type) ? getSpreadType(type, defaultContainingObject, anonymousSymbol, /*objectFlags*/ 0, /*readonly*/ false) : defaultContainingObject; 33159 } 33160 else { 33161 synthType.syntheticType = type; 33162 } 33163 } 33164 return synthType.syntheticType; 33165 } 33166 return type; 33167 } 33168 33169 function isCommonJsRequire(node: Node): boolean { 33170 if (!isRequireCall(node, /*checkArgumentIsStringLiteralLike*/ true)) { 33171 return false; 33172 } 33173 33174 // Make sure require is not a local function 33175 if (!isIdentifier(node.expression)) return Debug.fail(); 33176 const resolvedRequire = resolveName(node.expression, node.expression.escapedText, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ true)!; // TODO: GH#18217 33177 if (resolvedRequire === requireSymbol) { 33178 return true; 33179 } 33180 // project includes symbol named 'require' - make sure that it is ambient and local non-alias 33181 if (resolvedRequire.flags & SymbolFlags.Alias) { 33182 return false; 33183 } 33184 33185 const targetDeclarationKind = resolvedRequire.flags & SymbolFlags.Function 33186 ? SyntaxKind.FunctionDeclaration 33187 : resolvedRequire.flags & SymbolFlags.Variable 33188 ? SyntaxKind.VariableDeclaration 33189 : SyntaxKind.Unknown; 33190 if (targetDeclarationKind !== SyntaxKind.Unknown) { 33191 const decl = getDeclarationOfKind(resolvedRequire, targetDeclarationKind)!; 33192 // function/variable declaration should be ambient 33193 return !!decl && !!(decl.flags & NodeFlags.Ambient); 33194 } 33195 return false; 33196 } 33197 33198 function checkTaggedTemplateExpression(node: TaggedTemplateExpression): Type { 33199 if (!checkGrammarTaggedTemplateChain(node)) checkGrammarTypeArguments(node, node.typeArguments); 33200 if (languageVersion < ScriptTarget.ES2015) { 33201 checkExternalEmitHelpers(node, ExternalEmitHelpers.MakeTemplateObject); 33202 } 33203 const signature = getResolvedSignature(node); 33204 checkDeprecatedSignature(signature, node); 33205 return getReturnTypeOfSignature(signature); 33206 } 33207 33208 function checkAssertion(node: AssertionExpression) { 33209 if (node.kind === SyntaxKind.TypeAssertionExpression) { 33210 const file = getSourceFileOfNode(node); 33211 if (file && fileExtensionIsOneOf(file.fileName, [Extension.Cts, Extension.Mts])) { 33212 grammarErrorOnNode(node, Diagnostics.This_syntax_is_reserved_in_files_with_the_mts_or_cts_extension_Use_an_as_expression_instead); 33213 } 33214 } 33215 return checkAssertionWorker(node, node.type, node.expression); 33216 } 33217 33218 function isValidConstAssertionArgument(node: Node): boolean { 33219 switch (node.kind) { 33220 case SyntaxKind.StringLiteral: 33221 case SyntaxKind.NoSubstitutionTemplateLiteral: 33222 case SyntaxKind.NumericLiteral: 33223 case SyntaxKind.BigIntLiteral: 33224 case SyntaxKind.TrueKeyword: 33225 case SyntaxKind.FalseKeyword: 33226 case SyntaxKind.ArrayLiteralExpression: 33227 case SyntaxKind.ObjectLiteralExpression: 33228 case SyntaxKind.TemplateExpression: 33229 return true; 33230 case SyntaxKind.ParenthesizedExpression: 33231 return isValidConstAssertionArgument((node as ParenthesizedExpression).expression); 33232 case SyntaxKind.PrefixUnaryExpression: 33233 const op = (node as PrefixUnaryExpression).operator; 33234 const arg = (node as PrefixUnaryExpression).operand; 33235 return op === SyntaxKind.MinusToken && (arg.kind === SyntaxKind.NumericLiteral || arg.kind === SyntaxKind.BigIntLiteral) || 33236 op === SyntaxKind.PlusToken && arg.kind === SyntaxKind.NumericLiteral; 33237 case SyntaxKind.PropertyAccessExpression: 33238 case SyntaxKind.ElementAccessExpression: 33239 const expr = (node as PropertyAccessExpression | ElementAccessExpression).expression; 33240 let symbol = getTypeOfNode(expr).symbol; 33241 if (symbol && symbol.flags & SymbolFlags.Alias) { 33242 symbol = resolveAlias(symbol); 33243 } 33244 return !!(symbol && (getAllSymbolFlags(symbol) & SymbolFlags.Enum) && getEnumKind(symbol) === EnumKind.Literal); 33245 } 33246 return false; 33247 } 33248 33249 function checkAssertionWorker(errNode: Node, type: TypeNode, expression: UnaryExpression | Expression, checkMode?: CheckMode) { 33250 let exprType = checkExpression(expression, checkMode); 33251 if (isConstTypeReference(type)) { 33252 if (!isValidConstAssertionArgument(expression)) { 33253 error(expression, Diagnostics.A_const_assertions_can_only_be_applied_to_references_to_enum_members_or_string_number_boolean_array_or_object_literals); 33254 } 33255 return getRegularTypeOfLiteralType(exprType); 33256 } 33257 checkSourceElement(type); 33258 exprType = getRegularTypeOfObjectLiteral(getBaseTypeOfLiteralType(exprType)); 33259 const targetType = getTypeFromTypeNode(type); 33260 if (!isErrorType(targetType)) { 33261 addLazyDiagnostic(() => { 33262 const widenedType = getWidenedType(exprType); 33263 if (!isTypeComparableTo(targetType, widenedType)) { 33264 checkTypeComparableTo(exprType, targetType, errNode, 33265 Diagnostics.Conversion_of_type_0_to_type_1_may_be_a_mistake_because_neither_type_sufficiently_overlaps_with_the_other_If_this_was_intentional_convert_the_expression_to_unknown_first); 33266 } 33267 }); 33268 } 33269 return targetType; 33270 } 33271 33272 function checkNonNullChain(node: NonNullChain) { 33273 const leftType = checkExpression(node.expression); 33274 const nonOptionalType = getOptionalExpressionType(leftType, node.expression); 33275 return propagateOptionalTypeMarker(getNonNullableType(nonOptionalType), node, nonOptionalType !== leftType); 33276 } 33277 33278 function checkNonNullAssertion(node: NonNullExpression) { 33279 return node.flags & NodeFlags.OptionalChain ? checkNonNullChain(node as NonNullChain) : 33280 getNonNullableType(checkExpression(node.expression)); 33281 } 33282 33283 function checkExpressionWithTypeArguments(node: ExpressionWithTypeArguments | TypeQueryNode) { 33284 checkGrammarExpressionWithTypeArguments(node); 33285 const exprType = node.kind === SyntaxKind.ExpressionWithTypeArguments ? checkExpression(node.expression) : 33286 isThisIdentifier(node.exprName) ? checkThisExpression(node.exprName) : 33287 checkExpression(node.exprName); 33288 const typeArguments = node.typeArguments; 33289 if (exprType === silentNeverType || isErrorType(exprType) || !some(typeArguments)) { 33290 return exprType; 33291 } 33292 let hasSomeApplicableSignature = false; 33293 let nonApplicableType: Type | undefined; 33294 const result = getInstantiatedType(exprType); 33295 const errorType = hasSomeApplicableSignature ? nonApplicableType : exprType; 33296 if (errorType) { 33297 diagnostics.add(createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Type_0_has_no_signatures_for_which_the_type_argument_list_is_applicable, typeToString(errorType))); 33298 } 33299 return result; 33300 33301 function getInstantiatedType(type: Type): Type { 33302 let hasSignatures = false; 33303 let hasApplicableSignature = false; 33304 const result = getInstantiatedTypePart(type); 33305 hasSomeApplicableSignature ||= hasApplicableSignature; 33306 if (hasSignatures && !hasApplicableSignature) { 33307 nonApplicableType ??= type; 33308 } 33309 return result; 33310 33311 function getInstantiatedTypePart(type: Type): Type { 33312 if (type.flags & TypeFlags.Object) { 33313 const resolved = resolveStructuredTypeMembers(type as ObjectType); 33314 const callSignatures = getInstantiatedSignatures(resolved.callSignatures); 33315 const constructSignatures = getInstantiatedSignatures(resolved.constructSignatures); 33316 hasSignatures ||= resolved.callSignatures.length !== 0 || resolved.constructSignatures.length !== 0; 33317 hasApplicableSignature ||= callSignatures.length !== 0 || constructSignatures.length !== 0; 33318 if (callSignatures !== resolved.callSignatures || constructSignatures !== resolved.constructSignatures) { 33319 const result = createAnonymousType(undefined, resolved.members, callSignatures, constructSignatures, resolved.indexInfos) as ResolvedType & InstantiationExpressionType; 33320 result.objectFlags |= ObjectFlags.InstantiationExpressionType; 33321 result.node = node; 33322 return result; 33323 } 33324 } 33325 else if (type.flags & TypeFlags.InstantiableNonPrimitive) { 33326 const constraint = getBaseConstraintOfType(type); 33327 if (constraint) { 33328 const instantiated = getInstantiatedTypePart(constraint); 33329 if (instantiated !== constraint) { 33330 return instantiated; 33331 } 33332 } 33333 } 33334 else if (type.flags & TypeFlags.Union) { 33335 return mapType(type, getInstantiatedType); 33336 } 33337 else if (type.flags & TypeFlags.Intersection) { 33338 return getIntersectionType(sameMap((type as IntersectionType).types, getInstantiatedTypePart)); 33339 } 33340 return type; 33341 } 33342 } 33343 33344 function getInstantiatedSignatures(signatures: readonly Signature[]) { 33345 const applicableSignatures = filter(signatures, sig => !!sig.typeParameters && hasCorrectTypeArgumentArity(sig, typeArguments)); 33346 return sameMap(applicableSignatures, sig => { 33347 const typeArgumentTypes = checkTypeArguments(sig, typeArguments!, /*reportErrors*/ true); 33348 return typeArgumentTypes ? getSignatureInstantiation(sig, typeArgumentTypes, isInJSFile(sig.declaration)) : sig; 33349 }); 33350 } 33351 } 33352 33353 function checkSatisfiesExpression(node: SatisfiesExpression) { 33354 checkSourceElement(node.type); 33355 const exprType = checkExpression(node.expression); 33356 33357 const targetType = getTypeFromTypeNode(node.type); 33358 if (isErrorType(targetType)) { 33359 return targetType; 33360 } 33361 33362 checkTypeAssignableToAndOptionallyElaborate(exprType, targetType, node.type, node.expression, Diagnostics.Type_0_does_not_satisfy_the_expected_type_1); 33363 33364 return exprType; 33365 } 33366 33367 function checkMetaProperty(node: MetaProperty): Type { 33368 checkGrammarMetaProperty(node); 33369 33370 if (node.keywordToken === SyntaxKind.NewKeyword) { 33371 return checkNewTargetMetaProperty(node); 33372 } 33373 33374 if (node.keywordToken === SyntaxKind.ImportKeyword) { 33375 return checkImportMetaProperty(node); 33376 } 33377 33378 return Debug.assertNever(node.keywordToken); 33379 } 33380 33381 function checkMetaPropertyKeyword(node: MetaProperty): Type { 33382 switch (node.keywordToken) { 33383 case SyntaxKind.ImportKeyword: 33384 return getGlobalImportMetaExpressionType(); 33385 case SyntaxKind.NewKeyword: 33386 const type = checkNewTargetMetaProperty(node); 33387 return isErrorType(type) ? errorType : createNewTargetExpressionType(type); 33388 default: 33389 Debug.assertNever(node.keywordToken); 33390 } 33391 } 33392 33393 function checkNewTargetMetaProperty(node: MetaProperty) { 33394 const container = getNewTargetContainer(node); 33395 if (!container) { 33396 error(node, Diagnostics.Meta_property_0_is_only_allowed_in_the_body_of_a_function_declaration_function_expression_or_constructor, "new.target"); 33397 return errorType; 33398 } 33399 else if (container.kind === SyntaxKind.Constructor) { 33400 const symbol = getSymbolOfNode(container.parent as ClassLikeDeclaration); 33401 return getTypeOfSymbol(symbol); 33402 } 33403 else { 33404 const symbol = getSymbolOfNode(container)!; 33405 return getTypeOfSymbol(symbol); 33406 } 33407 } 33408 33409 function checkImportMetaProperty(node: MetaProperty) { 33410 if (moduleKind === ModuleKind.Node16 || moduleKind === ModuleKind.NodeNext) { 33411 if (getSourceFileOfNode(node).impliedNodeFormat !== ModuleKind.ESNext) { 33412 error(node, Diagnostics.The_import_meta_meta_property_is_not_allowed_in_files_which_will_build_into_CommonJS_output); 33413 } 33414 } 33415 else if (moduleKind < ModuleKind.ES2020 && moduleKind !== ModuleKind.System) { 33416 error(node, Diagnostics.The_import_meta_meta_property_is_only_allowed_when_the_module_option_is_es2020_es2022_esnext_system_node16_or_nodenext); 33417 } 33418 const file = getSourceFileOfNode(node); 33419 Debug.assert(!!(file.flags & NodeFlags.PossiblyContainsImportMeta), "Containing file is missing import meta node flag."); 33420 return node.name.escapedText === "meta" ? getGlobalImportMetaType() : errorType; 33421 } 33422 33423 function getTypeOfParameter(symbol: Symbol) { 33424 const type = getTypeOfSymbol(symbol); 33425 if (strictNullChecks) { 33426 const declaration = symbol.valueDeclaration; 33427 if (declaration && hasInitializer(declaration)) { 33428 return getOptionalType(type); 33429 } 33430 } 33431 return type; 33432 } 33433 33434 function getTupleElementLabel(d: ParameterDeclaration | NamedTupleMember) { 33435 Debug.assert(isIdentifier(d.name)); // Parameter declarations could be binding patterns, but we only allow identifier names 33436 return d.name.escapedText; 33437 } 33438 33439 function getParameterNameAtPosition(signature: Signature, pos: number, overrideRestType?: Type) { 33440 const paramCount = signature.parameters.length - (signatureHasRestParameter(signature) ? 1 : 0); 33441 if (pos < paramCount) { 33442 return signature.parameters[pos].escapedName; 33443 } 33444 const restParameter = signature.parameters[paramCount] || unknownSymbol; 33445 const restType = overrideRestType || getTypeOfSymbol(restParameter); 33446 if (isTupleType(restType)) { 33447 const associatedNames = ((restType as TypeReference).target as TupleType).labeledElementDeclarations; 33448 const index = pos - paramCount; 33449 return associatedNames && getTupleElementLabel(associatedNames[index]) || restParameter.escapedName + "_" + index as __String; 33450 } 33451 return restParameter.escapedName; 33452 } 33453 33454 function getParameterIdentifierNameAtPosition(signature: Signature, pos: number): [parameterName: __String, isRestParameter: boolean] | undefined { 33455 if (signature.declaration?.kind === SyntaxKind.JSDocFunctionType) { 33456 return undefined; 33457 } 33458 const paramCount = signature.parameters.length - (signatureHasRestParameter(signature) ? 1 : 0); 33459 if (pos < paramCount) { 33460 const param = signature.parameters[pos]; 33461 return isParameterDeclarationWithIdentifierName(param) ? [param.escapedName, false] : undefined; 33462 } 33463 33464 const restParameter = signature.parameters[paramCount] || unknownSymbol; 33465 if (!isParameterDeclarationWithIdentifierName(restParameter)) { 33466 return undefined; 33467 } 33468 33469 const restType = getTypeOfSymbol(restParameter); 33470 if (isTupleType(restType)) { 33471 const associatedNames = ((restType as TypeReference).target as TupleType).labeledElementDeclarations; 33472 const index = pos - paramCount; 33473 const associatedName = associatedNames?.[index]; 33474 const isRestTupleElement = !!associatedName?.dotDotDotToken; 33475 return associatedName ? [ 33476 getTupleElementLabel(associatedName), 33477 isRestTupleElement 33478 ] : undefined; 33479 } 33480 33481 if (pos === paramCount) { 33482 return [restParameter.escapedName, true]; 33483 } 33484 return undefined; 33485 } 33486 33487 function isParameterDeclarationWithIdentifierName(symbol: Symbol) { 33488 return symbol.valueDeclaration && isParameter(symbol.valueDeclaration) && isIdentifier(symbol.valueDeclaration.name); 33489 } 33490 function isValidDeclarationForTupleLabel(d: Declaration): d is NamedTupleMember | (ParameterDeclaration & { name: Identifier }) { 33491 return d.kind === SyntaxKind.NamedTupleMember || (isParameter(d) && d.name && isIdentifier(d.name)); 33492 } 33493 33494 function getNameableDeclarationAtPosition(signature: Signature, pos: number) { 33495 const paramCount = signature.parameters.length - (signatureHasRestParameter(signature) ? 1 : 0); 33496 if (pos < paramCount) { 33497 const decl = signature.parameters[pos].valueDeclaration; 33498 return decl && isValidDeclarationForTupleLabel(decl) ? decl : undefined; 33499 } 33500 const restParameter = signature.parameters[paramCount] || unknownSymbol; 33501 const restType = getTypeOfSymbol(restParameter); 33502 if (isTupleType(restType)) { 33503 const associatedNames = ((restType as TypeReference).target as TupleType).labeledElementDeclarations; 33504 const index = pos - paramCount; 33505 return associatedNames && associatedNames[index]; 33506 } 33507 return restParameter.valueDeclaration && isValidDeclarationForTupleLabel(restParameter.valueDeclaration) ? restParameter.valueDeclaration : undefined; 33508 } 33509 33510 function getTypeAtPosition(signature: Signature, pos: number): Type { 33511 return tryGetTypeAtPosition(signature, pos) || anyType; 33512 } 33513 33514 function tryGetTypeAtPosition(signature: Signature, pos: number): Type | undefined { 33515 const paramCount = signature.parameters.length - (signatureHasRestParameter(signature) ? 1 : 0); 33516 if (pos < paramCount) { 33517 return getTypeOfParameter(signature.parameters[pos]); 33518 } 33519 if (signatureHasRestParameter(signature)) { 33520 // We want to return the value undefined for an out of bounds parameter position, 33521 // so we need to check bounds here before calling getIndexedAccessType (which 33522 // otherwise would return the type 'undefined'). 33523 const restType = getTypeOfSymbol(signature.parameters[paramCount]); 33524 const index = pos - paramCount; 33525 if (!isTupleType(restType) || restType.target.hasRestElement || index < restType.target.fixedLength) { 33526 return getIndexedAccessType(restType, getNumberLiteralType(index)); 33527 } 33528 } 33529 return undefined; 33530 } 33531 33532 function getRestTypeAtPosition(source: Signature, pos: number): Type { 33533 const parameterCount = getParameterCount(source); 33534 const minArgumentCount = getMinArgumentCount(source); 33535 const restType = getEffectiveRestType(source); 33536 if (restType && pos >= parameterCount - 1) { 33537 return pos === parameterCount - 1 ? restType : createArrayType(getIndexedAccessType(restType, numberType)); 33538 } 33539 const types = []; 33540 const flags = []; 33541 const names = []; 33542 for (let i = pos; i < parameterCount; i++) { 33543 if (!restType || i < parameterCount - 1) { 33544 types.push(getTypeAtPosition(source, i)); 33545 flags.push(i < minArgumentCount ? ElementFlags.Required : ElementFlags.Optional); 33546 } 33547 else { 33548 types.push(restType); 33549 flags.push(ElementFlags.Variadic); 33550 } 33551 const name = getNameableDeclarationAtPosition(source, i); 33552 if (name) { 33553 names.push(name); 33554 } 33555 } 33556 return createTupleType(types, flags, /*readonly*/ false, length(names) === length(types) ? names : undefined); 33557 } 33558 33559 // Return the number of parameters in a signature. The rest parameter, if present, counts as one 33560 // parameter. For example, the parameter count of (x: number, y: number, ...z: string[]) is 3 and 33561 // the parameter count of (x: number, ...args: [number, ...string[], boolean])) is also 3. In the 33562 // latter example, the effective rest type is [...string[], boolean]. 33563 function getParameterCount(signature: Signature) { 33564 const length = signature.parameters.length; 33565 if (signatureHasRestParameter(signature)) { 33566 const restType = getTypeOfSymbol(signature.parameters[length - 1]); 33567 if (isTupleType(restType)) { 33568 return length + restType.target.fixedLength - (restType.target.hasRestElement ? 0 : 1); 33569 } 33570 } 33571 return length; 33572 } 33573 33574 function getMinArgumentCount(signature: Signature, flags?: MinArgumentCountFlags) { 33575 const strongArityForUntypedJS = flags! & MinArgumentCountFlags.StrongArityForUntypedJS; 33576 const voidIsNonOptional = flags! & MinArgumentCountFlags.VoidIsNonOptional; 33577 if (voidIsNonOptional || signature.resolvedMinArgumentCount === undefined) { 33578 let minArgumentCount: number | undefined; 33579 if (signatureHasRestParameter(signature)) { 33580 const restType = getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]); 33581 if (isTupleType(restType)) { 33582 const firstOptionalIndex = findIndex(restType.target.elementFlags, f => !(f & ElementFlags.Required)); 33583 const requiredCount = firstOptionalIndex < 0 ? restType.target.fixedLength : firstOptionalIndex; 33584 if (requiredCount > 0) { 33585 minArgumentCount = signature.parameters.length - 1 + requiredCount; 33586 } 33587 } 33588 } 33589 if (minArgumentCount === undefined) { 33590 if (!strongArityForUntypedJS && signature.flags & SignatureFlags.IsUntypedSignatureInJSFile) { 33591 return 0; 33592 } 33593 minArgumentCount = signature.minArgumentCount; 33594 } 33595 if (voidIsNonOptional) { 33596 return minArgumentCount; 33597 } 33598 for (let i = minArgumentCount - 1; i >= 0; i--) { 33599 const type = getTypeAtPosition(signature, i); 33600 if (filterType(type, acceptsVoid).flags & TypeFlags.Never) { 33601 break; 33602 } 33603 minArgumentCount = i; 33604 } 33605 signature.resolvedMinArgumentCount = minArgumentCount; 33606 } 33607 return signature.resolvedMinArgumentCount; 33608 } 33609 33610 function hasEffectiveRestParameter(signature: Signature) { 33611 if (signatureHasRestParameter(signature)) { 33612 const restType = getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]); 33613 return !isTupleType(restType) || restType.target.hasRestElement; 33614 } 33615 return false; 33616 } 33617 33618 function getEffectiveRestType(signature: Signature) { 33619 if (signatureHasRestParameter(signature)) { 33620 const restType = getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]); 33621 if (!isTupleType(restType)) { 33622 return restType; 33623 } 33624 if (restType.target.hasRestElement) { 33625 return sliceTupleType(restType, restType.target.fixedLength); 33626 } 33627 } 33628 return undefined; 33629 } 33630 33631 function getNonArrayRestType(signature: Signature) { 33632 const restType = getEffectiveRestType(signature); 33633 return restType && !isArrayType(restType) && !isTypeAny(restType) && (getReducedType(restType).flags & TypeFlags.Never) === 0 ? restType : undefined; 33634 } 33635 33636 function getTypeOfFirstParameterOfSignature(signature: Signature) { 33637 return getTypeOfFirstParameterOfSignatureWithFallback(signature, neverType); 33638 } 33639 33640 function getTypeOfFirstParameterOfSignatureWithFallback(signature: Signature, fallbackType: Type) { 33641 return signature.parameters.length > 0 ? getTypeAtPosition(signature, 0) : fallbackType; 33642 } 33643 33644 function inferFromAnnotatedParameters(signature: Signature, context: Signature, inferenceContext: InferenceContext) { 33645 const len = signature.parameters.length - (signatureHasRestParameter(signature) ? 1 : 0); 33646 for (let i = 0; i < len; i++) { 33647 const declaration = signature.parameters[i].valueDeclaration as ParameterDeclaration; 33648 if (declaration.type) { 33649 const typeNode = getEffectiveTypeAnnotationNode(declaration); 33650 if (typeNode) { 33651 inferTypes(inferenceContext.inferences, getTypeFromTypeNode(typeNode), getTypeAtPosition(context, i)); 33652 } 33653 } 33654 } 33655 } 33656 33657 function assignContextualParameterTypes(signature: Signature, context: Signature) { 33658 if (context.typeParameters) { 33659 if (!signature.typeParameters) { 33660 signature.typeParameters = context.typeParameters; 33661 } 33662 else { 33663 return; // This signature has already has a contextual inference performed and cached on it! 33664 } 33665 } 33666 if (context.thisParameter) { 33667 const parameter = signature.thisParameter; 33668 if (!parameter || parameter.valueDeclaration && !(parameter.valueDeclaration as ParameterDeclaration).type) { 33669 if (!parameter) { 33670 signature.thisParameter = createSymbolWithType(context.thisParameter, /*type*/ undefined); 33671 } 33672 assignParameterType(signature.thisParameter!, getTypeOfSymbol(context.thisParameter)); 33673 } 33674 } 33675 const len = signature.parameters.length - (signatureHasRestParameter(signature) ? 1 : 0); 33676 for (let i = 0; i < len; i++) { 33677 const parameter = signature.parameters[i]; 33678 if (!getEffectiveTypeAnnotationNode(parameter.valueDeclaration as ParameterDeclaration)) { 33679 const contextualParameterType = tryGetTypeAtPosition(context, i); 33680 assignParameterType(parameter, contextualParameterType); 33681 } 33682 } 33683 if (signatureHasRestParameter(signature)) { 33684 // parameter might be a transient symbol generated by use of `arguments` in the function body. 33685 const parameter = last(signature.parameters); 33686 if (parameter.valueDeclaration 33687 ? !getEffectiveTypeAnnotationNode(parameter.valueDeclaration as ParameterDeclaration) 33688 // a declarationless parameter may still have a `.type` already set by its construction logic 33689 // (which may pull a type from a jsdoc) - only allow fixing on `DeferredType` parameters with a fallback type 33690 : !!(getCheckFlags(parameter) & CheckFlags.DeferredType) 33691 ) { 33692 const contextualParameterType = getRestTypeAtPosition(context, len); 33693 assignParameterType(parameter, contextualParameterType); 33694 } 33695 } 33696 } 33697 33698 function assignNonContextualParameterTypes(signature: Signature) { 33699 if (signature.thisParameter) { 33700 assignParameterType(signature.thisParameter); 33701 } 33702 for (const parameter of signature.parameters) { 33703 assignParameterType(parameter); 33704 } 33705 } 33706 33707 function assignParameterType(parameter: Symbol, type?: Type) { 33708 const links = getSymbolLinks(parameter); 33709 if (!links.type) { 33710 const declaration = parameter.valueDeclaration as ParameterDeclaration | undefined; 33711 links.type = type || (declaration ? getWidenedTypeForVariableLikeDeclaration(declaration, /*reportErrors*/ true) : getTypeOfSymbol(parameter)); 33712 if (declaration && declaration.name.kind !== SyntaxKind.Identifier) { 33713 // if inference didn't come up with anything but unknown, fall back to the binding pattern if present. 33714 if (links.type === unknownType) { 33715 links.type = getTypeFromBindingPattern(declaration.name); 33716 } 33717 assignBindingElementTypes(declaration.name, links.type); 33718 } 33719 } 33720 else if (type) { 33721 Debug.assertEqual(links.type, type, "Parameter symbol already has a cached type which differs from newly assigned type"); 33722 } 33723 } 33724 33725 // When contextual typing assigns a type to a parameter that contains a binding pattern, we also need to push 33726 // the destructured type into the contained binding elements. 33727 function assignBindingElementTypes(pattern: BindingPattern, parentType: Type) { 33728 for (const element of pattern.elements) { 33729 if (!isOmittedExpression(element)) { 33730 const type = getBindingElementTypeFromParentType(element, parentType); 33731 if (element.name.kind === SyntaxKind.Identifier) { 33732 getSymbolLinks(getSymbolOfNode(element)).type = type; 33733 } 33734 else { 33735 assignBindingElementTypes(element.name, type); 33736 } 33737 } 33738 } 33739 } 33740 33741 function createPromiseType(promisedType: Type): Type { 33742 // creates a `Promise<T>` type where `T` is the promisedType argument 33743 const globalPromiseType = getGlobalPromiseType(/*reportErrors*/ true); 33744 if (globalPromiseType !== emptyGenericType) { 33745 // if the promised type is itself a promise, get the underlying type; otherwise, fallback to the promised type 33746 // Unwrap an `Awaited<T>` to `T` to improve inference. 33747 promisedType = getAwaitedTypeNoAlias(unwrapAwaitedType(promisedType)) || unknownType; 33748 return createTypeReference(globalPromiseType, [promisedType]); 33749 } 33750 33751 return unknownType; 33752 } 33753 33754 function createPromiseLikeType(promisedType: Type): Type { 33755 // creates a `PromiseLike<T>` type where `T` is the promisedType argument 33756 const globalPromiseLikeType = getGlobalPromiseLikeType(/*reportErrors*/ true); 33757 if (globalPromiseLikeType !== emptyGenericType) { 33758 // if the promised type is itself a promise, get the underlying type; otherwise, fallback to the promised type 33759 // Unwrap an `Awaited<T>` to `T` to improve inference. 33760 promisedType = getAwaitedTypeNoAlias(unwrapAwaitedType(promisedType)) || unknownType; 33761 return createTypeReference(globalPromiseLikeType, [promisedType]); 33762 } 33763 33764 return unknownType; 33765 } 33766 33767 function createPromiseReturnType(func: FunctionLikeDeclaration | ImportCall, promisedType: Type) { 33768 const promiseType = createPromiseType(promisedType); 33769 if (promiseType === unknownType) { 33770 error(func, isImportCall(func) ? 33771 Diagnostics.A_dynamic_import_call_returns_a_Promise_Make_sure_you_have_a_declaration_for_Promise_or_include_ES2015_in_your_lib_option : 33772 Diagnostics.An_async_function_or_method_must_return_a_Promise_Make_sure_you_have_a_declaration_for_Promise_or_include_ES2015_in_your_lib_option); 33773 return errorType; 33774 } 33775 else if (!getGlobalPromiseConstructorSymbol(/*reportErrors*/ true)) { 33776 error(func, isImportCall(func) ? 33777 Diagnostics.A_dynamic_import_call_in_ES5_SlashES3_requires_the_Promise_constructor_Make_sure_you_have_a_declaration_for_the_Promise_constructor_or_include_ES2015_in_your_lib_option : 33778 Diagnostics.An_async_function_or_method_in_ES5_SlashES3_requires_the_Promise_constructor_Make_sure_you_have_a_declaration_for_the_Promise_constructor_or_include_ES2015_in_your_lib_option); 33779 } 33780 33781 return promiseType; 33782 } 33783 33784 function createNewTargetExpressionType(targetType: Type): Type { 33785 // Create a synthetic type `NewTargetExpression { target: TargetType; }` 33786 const symbol = createSymbol(SymbolFlags.None, "NewTargetExpression" as __String); 33787 33788 const targetPropertySymbol = createSymbol(SymbolFlags.Property, "target" as __String, CheckFlags.Readonly); 33789 targetPropertySymbol.parent = symbol; 33790 targetPropertySymbol.type = targetType; 33791 33792 const members = createSymbolTable([targetPropertySymbol]); 33793 symbol.members = members; 33794 return createAnonymousType(symbol, members, emptyArray, emptyArray, emptyArray); 33795 } 33796 33797 function getReturnTypeFromBody(func: FunctionLikeDeclaration, checkMode?: CheckMode): Type { 33798 if (!func.body) { 33799 return errorType; 33800 } 33801 33802 const functionFlags = getFunctionFlags(func); 33803 const isAsync = (functionFlags & FunctionFlags.Async) !== 0; 33804 const isGenerator = (functionFlags & FunctionFlags.Generator) !== 0; 33805 33806 let returnType: Type | undefined; 33807 let yieldType: Type | undefined; 33808 let nextType: Type | undefined; 33809 let fallbackReturnType: Type = voidType; 33810 if (func.body.kind !== SyntaxKind.Block) { // Async or normal arrow function 33811 returnType = checkExpressionCached(func.body, checkMode && checkMode & ~CheckMode.SkipGenericFunctions); 33812 if (isAsync) { 33813 // From within an async function you can return either a non-promise value or a promise. Any 33814 // Promise/A+ compatible implementation will always assimilate any foreign promise, so the 33815 // return type of the body should be unwrapped to its awaited type, which we will wrap in 33816 // the native Promise<T> type later in this function. 33817 returnType = unwrapAwaitedType(checkAwaitedType(returnType, /*withAlias*/ false, /*errorNode*/ func, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member)); 33818 } 33819 } 33820 else if (isGenerator) { // Generator or AsyncGenerator function 33821 const returnTypes = checkAndAggregateReturnExpressionTypes(func, checkMode); 33822 if (!returnTypes) { 33823 fallbackReturnType = neverType; 33824 } 33825 else if (returnTypes.length > 0) { 33826 returnType = getUnionType(returnTypes, UnionReduction.Subtype); 33827 } 33828 const { yieldTypes, nextTypes } = checkAndAggregateYieldOperandTypes(func, checkMode); 33829 yieldType = some(yieldTypes) ? getUnionType(yieldTypes, UnionReduction.Subtype) : undefined; 33830 nextType = some(nextTypes) ? getIntersectionType(nextTypes) : undefined; 33831 } 33832 else { // Async or normal function 33833 const types = checkAndAggregateReturnExpressionTypes(func, checkMode); 33834 if (!types) { 33835 // For an async function, the return type will not be never, but rather a Promise for never. 33836 return functionFlags & FunctionFlags.Async 33837 ? createPromiseReturnType(func, neverType) // Async function 33838 : neverType; // Normal function 33839 } 33840 if (types.length === 0) { 33841 // For an async function, the return type will not be void, but rather a Promise for void. 33842 return functionFlags & FunctionFlags.Async 33843 ? createPromiseReturnType(func, voidType) // Async function 33844 : voidType; // Normal function 33845 } 33846 33847 // Return a union of the return expression types. 33848 returnType = getUnionType(types, UnionReduction.Subtype); 33849 } 33850 33851 if (returnType || yieldType || nextType) { 33852 if (yieldType) reportErrorsFromWidening(func, yieldType, WideningKind.GeneratorYield); 33853 if (returnType) reportErrorsFromWidening(func, returnType, WideningKind.FunctionReturn); 33854 if (nextType) reportErrorsFromWidening(func, nextType, WideningKind.GeneratorNext); 33855 if (returnType && isUnitType(returnType) || 33856 yieldType && isUnitType(yieldType) || 33857 nextType && isUnitType(nextType)) { 33858 const contextualSignature = getContextualSignatureForFunctionLikeDeclaration(func); 33859 const contextualType = !contextualSignature ? undefined : 33860 contextualSignature === getSignatureFromDeclaration(func) ? isGenerator ? undefined : returnType : 33861 instantiateContextualType(getReturnTypeOfSignature(contextualSignature), func, /*contextFlags*/ undefined); 33862 if (isGenerator) { 33863 yieldType = getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded(yieldType, contextualType, IterationTypeKind.Yield, isAsync); 33864 returnType = getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded(returnType, contextualType, IterationTypeKind.Return, isAsync); 33865 nextType = getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded(nextType, contextualType, IterationTypeKind.Next, isAsync); 33866 } 33867 else { 33868 returnType = getWidenedLiteralLikeTypeForContextualReturnTypeIfNeeded(returnType, contextualType, isAsync); 33869 } 33870 } 33871 33872 if (yieldType) yieldType = getWidenedType(yieldType); 33873 if (returnType) returnType = getWidenedType(returnType); 33874 if (nextType) nextType = getWidenedType(nextType); 33875 } 33876 33877 if (isGenerator) { 33878 return createGeneratorReturnType( 33879 yieldType || neverType, 33880 returnType || fallbackReturnType, 33881 nextType || getContextualIterationType(IterationTypeKind.Next, func) || unknownType, 33882 isAsync); 33883 } 33884 else { 33885 // From within an async function you can return either a non-promise value or a promise. Any 33886 // Promise/A+ compatible implementation will always assimilate any foreign promise, so the 33887 // return type of the body is awaited type of the body, wrapped in a native Promise<T> type. 33888 return isAsync 33889 ? createPromiseType(returnType || fallbackReturnType) 33890 : returnType || fallbackReturnType; 33891 } 33892 } 33893 33894 function createGeneratorReturnType(yieldType: Type, returnType: Type, nextType: Type, isAsyncGenerator: boolean) { 33895 const resolver = isAsyncGenerator ? asyncIterationTypesResolver : syncIterationTypesResolver; 33896 const globalGeneratorType = resolver.getGlobalGeneratorType(/*reportErrors*/ false); 33897 yieldType = resolver.resolveIterationType(yieldType, /*errorNode*/ undefined) || unknownType; 33898 returnType = resolver.resolveIterationType(returnType, /*errorNode*/ undefined) || unknownType; 33899 nextType = resolver.resolveIterationType(nextType, /*errorNode*/ undefined) || unknownType; 33900 if (globalGeneratorType === emptyGenericType) { 33901 // Fall back to the global IterableIterator if returnType is assignable to the expected return iteration 33902 // type of IterableIterator, and the expected next iteration type of IterableIterator is assignable to 33903 // nextType. 33904 const globalType = resolver.getGlobalIterableIteratorType(/*reportErrors*/ false); 33905 const iterationTypes = globalType !== emptyGenericType ? getIterationTypesOfGlobalIterableType(globalType, resolver) : undefined; 33906 const iterableIteratorReturnType = iterationTypes ? iterationTypes.returnType : anyType; 33907 const iterableIteratorNextType = iterationTypes ? iterationTypes.nextType : undefinedType; 33908 if (isTypeAssignableTo(returnType, iterableIteratorReturnType) && 33909 isTypeAssignableTo(iterableIteratorNextType, nextType)) { 33910 if (globalType !== emptyGenericType) { 33911 return createTypeFromGenericGlobalType(globalType, [yieldType]); 33912 } 33913 33914 // The global IterableIterator type doesn't exist, so report an error 33915 resolver.getGlobalIterableIteratorType(/*reportErrors*/ true); 33916 return emptyObjectType; 33917 } 33918 33919 // The global Generator type doesn't exist, so report an error 33920 resolver.getGlobalGeneratorType(/*reportErrors*/ true); 33921 return emptyObjectType; 33922 } 33923 33924 return createTypeFromGenericGlobalType(globalGeneratorType, [yieldType, returnType, nextType]); 33925 } 33926 33927 function checkAndAggregateYieldOperandTypes(func: FunctionLikeDeclaration, checkMode: CheckMode | undefined) { 33928 const yieldTypes: Type[] = []; 33929 const nextTypes: Type[] = []; 33930 const isAsync = (getFunctionFlags(func) & FunctionFlags.Async) !== 0; 33931 forEachYieldExpression(func.body as Block, yieldExpression => { 33932 const yieldExpressionType = yieldExpression.expression ? checkExpression(yieldExpression.expression, checkMode) : undefinedWideningType; 33933 pushIfUnique(yieldTypes, getYieldedTypeOfYieldExpression(yieldExpression, yieldExpressionType, anyType, isAsync)); 33934 let nextType: Type | undefined; 33935 if (yieldExpression.asteriskToken) { 33936 const iterationTypes = getIterationTypesOfIterable( 33937 yieldExpressionType, 33938 isAsync ? IterationUse.AsyncYieldStar : IterationUse.YieldStar, 33939 yieldExpression.expression); 33940 nextType = iterationTypes && iterationTypes.nextType; 33941 } 33942 else { 33943 nextType = getContextualType(yieldExpression, /*contextFlags*/ undefined); 33944 } 33945 if (nextType) pushIfUnique(nextTypes, nextType); 33946 }); 33947 return { yieldTypes, nextTypes }; 33948 } 33949 33950 function getYieldedTypeOfYieldExpression(node: YieldExpression, expressionType: Type, sentType: Type, isAsync: boolean): Type | undefined { 33951 const errorNode = node.expression || node; 33952 // A `yield*` expression effectively yields everything that its operand yields 33953 const yieldedType = node.asteriskToken ? checkIteratedTypeOrElementType(isAsync ? IterationUse.AsyncYieldStar : IterationUse.YieldStar, expressionType, sentType, errorNode) : expressionType; 33954 return !isAsync ? yieldedType : getAwaitedType(yieldedType, errorNode, node.asteriskToken 33955 ? Diagnostics.Type_of_iterated_elements_of_a_yield_Asterisk_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member 33956 : Diagnostics.Type_of_yield_operand_in_an_async_generator_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member); 33957 } 33958 33959 // Return the combined not-equal type facts for all cases except those between the start and end indices. 33960 function getNotEqualFactsFromTypeofSwitch(start: number, end: number, witnesses: (string | undefined)[]): TypeFacts { 33961 let facts: TypeFacts = TypeFacts.None; 33962 for (let i = 0; i < witnesses.length; i++) { 33963 const witness = i < start || i >= end ? witnesses[i] : undefined; 33964 facts |= witness !== undefined ? typeofNEFacts.get(witness) || TypeFacts.TypeofNEHostObject : 0; 33965 } 33966 return facts; 33967 } 33968 33969 function isExhaustiveSwitchStatement(node: SwitchStatement): boolean { 33970 const links = getNodeLinks(node); 33971 if (links.isExhaustive === undefined) { 33972 links.isExhaustive = 0; // Indicate resolution is in process 33973 const exhaustive = computeExhaustiveSwitchStatement(node); 33974 if (links.isExhaustive === 0) { 33975 links.isExhaustive = exhaustive; 33976 } 33977 } 33978 else if (links.isExhaustive === 0) { 33979 links.isExhaustive = false; // Resolve circularity to false 33980 } 33981 return links.isExhaustive; 33982 } 33983 33984 function computeExhaustiveSwitchStatement(node: SwitchStatement): boolean { 33985 if (node.expression.kind === SyntaxKind.TypeOfExpression) { 33986 const witnesses = getSwitchClauseTypeOfWitnesses(node); 33987 if (!witnesses) { 33988 return false; 33989 } 33990 const operandConstraint = getBaseConstraintOrType(checkExpressionCached((node.expression as TypeOfExpression).expression)); 33991 // Get the not-equal flags for all handled cases. 33992 const notEqualFacts = getNotEqualFactsFromTypeofSwitch(0, 0, witnesses); 33993 if (operandConstraint.flags & TypeFlags.AnyOrUnknown) { 33994 // We special case the top types to be exhaustive when all cases are handled. 33995 return (TypeFacts.AllTypeofNE & notEqualFacts) === TypeFacts.AllTypeofNE; 33996 } 33997 // A missing not-equal flag indicates that the type wasn't handled by some case. 33998 return !someType(operandConstraint, t => (getTypeFacts(t) & notEqualFacts) === notEqualFacts); 33999 } 34000 const type = checkExpressionCached(node.expression); 34001 if (!isLiteralType(type)) { 34002 return false; 34003 } 34004 const switchTypes = getSwitchClauseTypes(node); 34005 if (!switchTypes.length || some(switchTypes, isNeitherUnitTypeNorNever)) { 34006 return false; 34007 } 34008 return eachTypeContainedIn(mapType(type, getRegularTypeOfLiteralType), switchTypes); 34009 } 34010 34011 function functionHasImplicitReturn(func: FunctionLikeDeclaration) { 34012 return func.endFlowNode && isReachableFlowNode(func.endFlowNode); 34013 } 34014 34015 /** NOTE: Return value of `[]` means a different thing than `undefined`. `[]` means func returns `void`, `undefined` means it returns `never`. */ 34016 function checkAndAggregateReturnExpressionTypes(func: FunctionLikeDeclaration, checkMode: CheckMode | undefined): Type[] | undefined { 34017 const functionFlags = getFunctionFlags(func); 34018 const aggregatedTypes: Type[] = []; 34019 let hasReturnWithNoExpression = functionHasImplicitReturn(func); 34020 let hasReturnOfTypeNever = false; 34021 forEachReturnStatement(func.body as Block, returnStatement => { 34022 const expr = returnStatement.expression; 34023 if (expr) { 34024 let type = checkExpressionCached(expr, checkMode && checkMode & ~CheckMode.SkipGenericFunctions); 34025 if (functionFlags & FunctionFlags.Async) { 34026 // From within an async function you can return either a non-promise value or a promise. Any 34027 // Promise/A+ compatible implementation will always assimilate any foreign promise, so the 34028 // return type of the body should be unwrapped to its awaited type, which should be wrapped in 34029 // the native Promise<T> type by the caller. 34030 type = unwrapAwaitedType(checkAwaitedType(type, /*withAlias*/ false, func, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member)); 34031 } 34032 if (type.flags & TypeFlags.Never) { 34033 hasReturnOfTypeNever = true; 34034 } 34035 pushIfUnique(aggregatedTypes, type); 34036 } 34037 else { 34038 hasReturnWithNoExpression = true; 34039 } 34040 }); 34041 if (aggregatedTypes.length === 0 && !hasReturnWithNoExpression && (hasReturnOfTypeNever || mayReturnNever(func))) { 34042 return undefined; 34043 } 34044 if (strictNullChecks && aggregatedTypes.length && hasReturnWithNoExpression && 34045 !(isJSConstructor(func) && aggregatedTypes.some(t => t.symbol === func.symbol))) { 34046 // Javascript "callable constructors", containing eg `if (!(this instanceof A)) return new A()` should not add undefined 34047 pushIfUnique(aggregatedTypes, undefinedType); 34048 } 34049 return aggregatedTypes; 34050 } 34051 function mayReturnNever(func: FunctionLikeDeclaration): boolean { 34052 switch (func.kind) { 34053 case SyntaxKind.FunctionExpression: 34054 case SyntaxKind.ArrowFunction: 34055 return true; 34056 case SyntaxKind.MethodDeclaration: 34057 return func.parent.kind === SyntaxKind.ObjectLiteralExpression; 34058 default: 34059 return false; 34060 } 34061 } 34062 34063 /** 34064 * TypeScript Specification 1.0 (6.3) - July 2014 34065 * An explicitly typed function whose return type isn't the Void type, 34066 * the Any type, or a union type containing the Void or Any type as a constituent 34067 * must have at least one return statement somewhere in its body. 34068 * An exception to this rule is if the function implementation consists of a single 'throw' statement. 34069 * 34070 * @param returnType - return type of the function, can be undefined if return type is not explicitly specified 34071 */ 34072 function checkAllCodePathsInNonVoidFunctionReturnOrThrow(func: FunctionLikeDeclaration | MethodSignature, returnType: Type | undefined) { 34073 addLazyDiagnostic(checkAllCodePathsInNonVoidFunctionReturnOrThrowDiagnostics); 34074 return; 34075 34076 function checkAllCodePathsInNonVoidFunctionReturnOrThrowDiagnostics(): void { 34077 const functionFlags = getFunctionFlags(func); 34078 const type = returnType && unwrapReturnType(returnType, functionFlags); 34079 34080 // Functions with with an explicitly specified 'void' or 'any' return type don't need any return expressions. 34081 if (type && maybeTypeOfKind(type, TypeFlags.Any | TypeFlags.Void)) { 34082 return; 34083 } 34084 34085 if (isFunctionDeclaration(func) && func.illegalDecorators && returnType) { 34086 const extendNames = getEtsExtendDecoratorsComponentNames(func.illegalDecorators, compilerOptions); 34087 if (extendNames.length !== 0) { 34088 let returnTypeReferenceName; 34089 compilerOptions.ets?.extend.components.forEach(({ name, type }) => { 34090 if (name === last(extendNames)) { 34091 returnTypeReferenceName = type; 34092 } 34093 }); 34094 if (returnType?.symbol?.escapedName === returnTypeReferenceName) { 34095 return; 34096 } 34097 else { 34098 error(getEffectiveReturnTypeNode(func), Diagnostics.Should_not_add_return_type_to_the_function_that_is_annotated_by_Extend); 34099 return; 34100 } 34101 } 34102 34103 const stylesNames = getEtsStylesDecoratorComponentNames(func.illegalDecorators, compilerOptions); 34104 if (stylesNames.length > 0) { 34105 return judgeReturnTypeOfStyles(); 34106 } 34107 } 34108 34109 if (isMethodDeclaration(func) && func.modifiers && func.modifiers.length && returnType) { 34110 const stylesNames = getEtsStylesDecoratorComponentNames(func.modifiers as NodeArray<Decorator>, compilerOptions); 34111 if (stylesNames.length > 0) { 34112 return judgeReturnTypeOfStyles(); 34113 } 34114 } 34115 34116 // If all we have is a function signature, or an arrow function with an expression body, then there is nothing to check. 34117 // also if HasImplicitReturn flag is not set this means that all codepaths in function body end with return or throw 34118 if (func.kind === SyntaxKind.MethodSignature || nodeIsMissing(func.body) || func.body!.kind !== SyntaxKind.Block || !functionHasImplicitReturn(func)) { 34119 return; 34120 } 34121 34122 const hasExplicitReturn = func.flags & NodeFlags.HasExplicitReturn; 34123 const errorNode = getEffectiveReturnTypeNode(func) || func; 34124 34125 if (type && type.flags & TypeFlags.Never) { 34126 error(errorNode, Diagnostics.A_function_returning_never_cannot_have_a_reachable_end_point); 34127 } 34128 else if (type && !hasExplicitReturn) { 34129 // minimal check: function has syntactic return type annotation and no explicit return statements in the body 34130 // this function does not conform to the specification. 34131 error(errorNode, Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value); 34132 } 34133 else if (type && strictNullChecks && !isTypeAssignableTo(undefinedType, type)) { 34134 error(errorNode, Diagnostics.Function_lacks_ending_return_statement_and_return_type_does_not_include_undefined); 34135 } 34136 else if (compilerOptions.noImplicitReturns) { 34137 if (!type) { 34138 // If return type annotation is omitted check if function has any explicit return statements. 34139 // If it does not have any - its inferred return type is void - don't do any checks. 34140 // Otherwise get inferred return type from function body and report error only if it is not void / anytype 34141 if (!hasExplicitReturn) { 34142 return; 34143 } 34144 const inferredReturnType = getReturnTypeOfSignature(getSignatureFromDeclaration(func)); 34145 if (isUnwrappedReturnTypeVoidOrAny(func, inferredReturnType)) { 34146 return; 34147 } 34148 } 34149 error(errorNode, Diagnostics.Not_all_code_paths_return_a_value); 34150 } 34151 34152 function judgeReturnTypeOfStyles(): void { 34153 const returnTypeReferenceName = compilerOptions.ets?.styles.component.type; 34154 if (returnType?.symbol?.escapedName === returnTypeReferenceName) { 34155 return; 34156 } 34157 else { 34158 error(getEffectiveReturnTypeNode(func), Diagnostics.Should_not_add_return_type_to_the_function_that_is_annotated_by_Styles); 34159 return; 34160 } 34161 } 34162 } 34163 } 34164 34165 function checkFunctionExpressionOrObjectLiteralMethod(node: FunctionExpression | ArrowFunction | MethodDeclaration, checkMode?: CheckMode): Type { 34166 Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); 34167 checkNodeDeferred(node); 34168 34169 if (isFunctionExpression(node)) { 34170 checkCollisionsForDeclarationName(node, node.name); 34171 } 34172 34173 // The identityMapper object is used to indicate that function expressions are wildcards 34174 if (checkMode && checkMode & CheckMode.SkipContextSensitive && isContextSensitive(node)) { 34175 // Skip parameters, return signature with return type that retains noncontextual parts so inferences can still be drawn in an early stage 34176 if (!getEffectiveReturnTypeNode(node) && !hasContextSensitiveParameters(node)) { 34177 // Return plain anyFunctionType if there is no possibility we'll make inferences from the return type 34178 const contextualSignature = getContextualSignature(node); 34179 if (contextualSignature && couldContainTypeVariables(getReturnTypeOfSignature(contextualSignature))) { 34180 const links = getNodeLinks(node); 34181 if (links.contextFreeType) { 34182 return links.contextFreeType; 34183 } 34184 const returnType = getReturnTypeFromBody(node, checkMode); 34185 const returnOnlySignature = createSignature(undefined, undefined, undefined, emptyArray, returnType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.None); 34186 const returnOnlyType = createAnonymousType(node.symbol, emptySymbols, [returnOnlySignature], emptyArray, emptyArray); 34187 returnOnlyType.objectFlags |= ObjectFlags.NonInferrableType; 34188 return links.contextFreeType = returnOnlyType; 34189 } 34190 } 34191 return anyFunctionType; 34192 } 34193 34194 // Grammar checking 34195 const hasGrammarError = checkGrammarFunctionLikeDeclaration(node); 34196 if (!hasGrammarError && node.kind === SyntaxKind.FunctionExpression) { 34197 checkGrammarForGenerator(node); 34198 } 34199 34200 contextuallyCheckFunctionExpressionOrObjectLiteralMethod(node, checkMode); 34201 34202 return getTypeOfSymbol(getSymbolOfNode(node)); 34203 } 34204 34205 function contextuallyCheckFunctionExpressionOrObjectLiteralMethod(node: FunctionExpression | ArrowFunction | MethodDeclaration, checkMode?: CheckMode) { 34206 const links = getNodeLinks(node); 34207 // Check if function expression is contextually typed and assign parameter types if so. 34208 if (!(links.flags & NodeCheckFlags.ContextChecked)) { 34209 const contextualSignature = getContextualSignature(node); 34210 // If a type check is started at a function expression that is an argument of a function call, obtaining the 34211 // contextual type may recursively get back to here during overload resolution of the call. If so, we will have 34212 // already assigned contextual types. 34213 if (!(links.flags & NodeCheckFlags.ContextChecked)) { 34214 links.flags |= NodeCheckFlags.ContextChecked; 34215 const signature = firstOrUndefined(getSignaturesOfType(getTypeOfSymbol(getSymbolOfNode(node)), SignatureKind.Call)); 34216 if (!signature) { 34217 return; 34218 } 34219 if (isContextSensitive(node)) { 34220 if (contextualSignature) { 34221 const inferenceContext = getInferenceContext(node); 34222 let instantiatedContextualSignature: Signature | undefined; 34223 if (checkMode && checkMode & CheckMode.Inferential) { 34224 inferFromAnnotatedParameters(signature, contextualSignature, inferenceContext!); 34225 const restType = getEffectiveRestType(contextualSignature); 34226 if (restType && restType.flags & TypeFlags.TypeParameter) { 34227 instantiatedContextualSignature = instantiateSignature(contextualSignature, inferenceContext!.nonFixingMapper); 34228 } 34229 } 34230 instantiatedContextualSignature ||= inferenceContext ? 34231 instantiateSignature(contextualSignature, inferenceContext.mapper) : contextualSignature; 34232 assignContextualParameterTypes(signature, instantiatedContextualSignature); 34233 } 34234 else { 34235 // Force resolution of all parameter types such that the absence of a contextual type is consistently reflected. 34236 assignNonContextualParameterTypes(signature); 34237 } 34238 } 34239 if (contextualSignature && !getReturnTypeFromAnnotation(node) && !signature.resolvedReturnType) { 34240 const returnType = getReturnTypeFromBody(node, checkMode); 34241 if (!signature.resolvedReturnType) { 34242 signature.resolvedReturnType = returnType; 34243 } 34244 } 34245 checkSignatureDeclaration(node); 34246 } 34247 } 34248 } 34249 34250 function checkFunctionExpressionOrObjectLiteralMethodDeferred(node: ArrowFunction | FunctionExpression | MethodDeclaration) { 34251 Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); 34252 34253 const functionFlags = getFunctionFlags(node); 34254 const returnType = getReturnTypeFromAnnotation(node); 34255 checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, returnType); 34256 34257 if (node.body) { 34258 if (!getEffectiveReturnTypeNode(node)) { 34259 // There are some checks that are only performed in getReturnTypeFromBody, that may produce errors 34260 // we need. An example is the noImplicitAny errors resulting from widening the return expression 34261 // of a function. Because checking of function expression bodies is deferred, there was never an 34262 // appropriate time to do this during the main walk of the file (see the comment at the top of 34263 // checkFunctionExpressionBodies). So it must be done now. 34264 getReturnTypeOfSignature(getSignatureFromDeclaration(node)); 34265 } 34266 34267 if (node.body.kind === SyntaxKind.Block) { 34268 checkSourceElement(node.body); 34269 } 34270 else { 34271 // From within an async function you can return either a non-promise value or a promise. Any 34272 // Promise/A+ compatible implementation will always assimilate any foreign promise, so we 34273 // should not be checking assignability of a promise to the return type. Instead, we need to 34274 // check assignability of the awaited type of the expression body against the promised type of 34275 // its return type annotation. 34276 const exprType = checkExpression(node.body); 34277 const returnOrPromisedType = returnType && unwrapReturnType(returnType, functionFlags); 34278 if (returnOrPromisedType) { 34279 if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async) { // Async function 34280 const awaitedType = checkAwaitedType(exprType, /*withAlias*/ false, node.body, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member); 34281 checkTypeAssignableToAndOptionallyElaborate(awaitedType, returnOrPromisedType, node.body, node.body); 34282 } 34283 else { // Normal function 34284 checkTypeAssignableToAndOptionallyElaborate(exprType, returnOrPromisedType, node.body, node.body); 34285 } 34286 } 34287 } 34288 } 34289 } 34290 34291 function checkArithmeticOperandType(operand: Node, type: Type, diagnostic: DiagnosticMessage, isAwaitValid = false): boolean { 34292 if (!isTypeAssignableTo(type, numberOrBigIntType)) { 34293 const awaitedType = isAwaitValid && getAwaitedTypeOfPromise(type); 34294 errorAndMaybeSuggestAwait( 34295 operand, 34296 !!awaitedType && isTypeAssignableTo(awaitedType, numberOrBigIntType), 34297 diagnostic); 34298 return false; 34299 } 34300 return true; 34301 } 34302 34303 function isReadonlyAssignmentDeclaration(d: Declaration) { 34304 if (!isCallExpression(d)) { 34305 return false; 34306 } 34307 if (!isBindableObjectDefinePropertyCall(d)) { 34308 return false; 34309 } 34310 const objectLitType = checkExpressionCached(d.arguments[2]); 34311 const valueType = getTypeOfPropertyOfType(objectLitType, "value" as __String); 34312 if (valueType) { 34313 const writableProp = getPropertyOfType(objectLitType, "writable" as __String); 34314 const writableType = writableProp && getTypeOfSymbol(writableProp); 34315 if (!writableType || writableType === falseType || writableType === regularFalseType) { 34316 return true; 34317 } 34318 // We include this definition whereupon we walk back and check the type at the declaration because 34319 // The usual definition of `Object.defineProperty` will _not_ cause literal types to be preserved in the 34320 // argument types, should the type be contextualized by the call itself. 34321 if (writableProp && writableProp.valueDeclaration && isPropertyAssignment(writableProp.valueDeclaration)) { 34322 const initializer = writableProp.valueDeclaration.initializer; 34323 const rawOriginalType = checkExpression(initializer); 34324 if (rawOriginalType === falseType || rawOriginalType === regularFalseType) { 34325 return true; 34326 } 34327 } 34328 return false; 34329 } 34330 const setProp = getPropertyOfType(objectLitType, "set" as __String); 34331 return !setProp; 34332 } 34333 34334 function isReadonlySymbol(symbol: Symbol): boolean { 34335 // The following symbols are considered read-only: 34336 // Properties with a 'readonly' modifier 34337 // Variables declared with 'const' 34338 // Get accessors without matching set accessors 34339 // Enum members 34340 // Object.defineProperty assignments with writable false or no setter 34341 // Unions and intersections of the above (unions and intersections eagerly set isReadonly on creation) 34342 return !!(getCheckFlags(symbol) & CheckFlags.Readonly || 34343 symbol.flags & SymbolFlags.Property && getDeclarationModifierFlagsFromSymbol(symbol) & ModifierFlags.Readonly || 34344 symbol.flags & SymbolFlags.Variable && getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Const || 34345 symbol.flags & SymbolFlags.Accessor && !(symbol.flags & SymbolFlags.SetAccessor) || 34346 symbol.flags & SymbolFlags.EnumMember || 34347 some(symbol.declarations, isReadonlyAssignmentDeclaration) 34348 ); 34349 } 34350 34351 function isAssignmentToReadonlyEntity(expr: Expression, symbol: Symbol, assignmentKind: AssignmentKind) { 34352 if (assignmentKind === AssignmentKind.None) { 34353 // no assigment means it doesn't matter whether the entity is readonly 34354 return false; 34355 } 34356 if (isReadonlySymbol(symbol)) { 34357 // Allow assignments to readonly properties within constructors of the same class declaration. 34358 if (symbol.flags & SymbolFlags.Property && 34359 isAccessExpression(expr) && 34360 expr.expression.kind === SyntaxKind.ThisKeyword) { 34361 // Look for if this is the constructor for the class that `symbol` is a property of. 34362 const ctor = getContainingFunction(expr); 34363 if (!(ctor && (ctor.kind === SyntaxKind.Constructor || isJSConstructor(ctor)))) { 34364 return true; 34365 } 34366 if (symbol.valueDeclaration) { 34367 const isAssignmentDeclaration = isBinaryExpression(symbol.valueDeclaration); 34368 const isLocalPropertyDeclaration = ctor.parent === symbol.valueDeclaration.parent; 34369 const isLocalParameterProperty = ctor === symbol.valueDeclaration.parent; 34370 const isLocalThisPropertyAssignment = isAssignmentDeclaration && symbol.parent?.valueDeclaration === ctor.parent; 34371 const isLocalThisPropertyAssignmentConstructorFunction = isAssignmentDeclaration && symbol.parent?.valueDeclaration === ctor; 34372 const isWriteableSymbol = 34373 isLocalPropertyDeclaration 34374 || isLocalParameterProperty 34375 || isLocalThisPropertyAssignment 34376 || isLocalThisPropertyAssignmentConstructorFunction; 34377 return !isWriteableSymbol; 34378 } 34379 } 34380 return true; 34381 } 34382 if (isAccessExpression(expr)) { 34383 // references through namespace import should be readonly 34384 const node = skipParentheses(expr.expression); 34385 if (node.kind === SyntaxKind.Identifier) { 34386 const symbol = getNodeLinks(node).resolvedSymbol!; 34387 if (symbol.flags & SymbolFlags.Alias) { 34388 const declaration = getDeclarationOfAliasSymbol(symbol); 34389 return !!declaration && declaration.kind === SyntaxKind.NamespaceImport; 34390 } 34391 } 34392 } 34393 return false; 34394 } 34395 34396 function checkReferenceExpression(expr: Expression, invalidReferenceMessage: DiagnosticMessage, invalidOptionalChainMessage: DiagnosticMessage): boolean { 34397 // References are combinations of identifiers, parentheses, and property accesses. 34398 const node = skipOuterExpressions(expr, OuterExpressionKinds.Assertions | OuterExpressionKinds.Parentheses); 34399 if (node.kind !== SyntaxKind.Identifier && !isAccessExpression(node)) { 34400 error(expr, invalidReferenceMessage); 34401 return false; 34402 } 34403 if (node.flags & NodeFlags.OptionalChain) { 34404 error(expr, invalidOptionalChainMessage); 34405 return false; 34406 } 34407 return true; 34408 } 34409 34410 function checkDeleteExpression(node: DeleteExpression): Type { 34411 checkExpression(node.expression); 34412 const expr = skipParentheses(node.expression); 34413 if (!isAccessExpression(expr)) { 34414 error(expr, Diagnostics.The_operand_of_a_delete_operator_must_be_a_property_reference); 34415 return booleanType; 34416 } 34417 if (isPropertyAccessExpression(expr) && isPrivateIdentifier(expr.name)) { 34418 error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_private_identifier); 34419 } 34420 const links = getNodeLinks(expr); 34421 const symbol = getExportSymbolOfValueSymbolIfExported(links.resolvedSymbol); 34422 if (symbol) { 34423 if (isReadonlySymbol(symbol)) { 34424 error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_read_only_property); 34425 } 34426 checkDeleteExpressionMustBeOptional(expr, symbol); 34427 } 34428 return booleanType; 34429 } 34430 34431 function checkDeleteExpressionMustBeOptional(expr: AccessExpression, symbol: Symbol) { 34432 const type = getTypeOfSymbol(symbol); 34433 if (strictNullChecks && 34434 !(type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Never)) && 34435 !(exactOptionalPropertyTypes ? symbol.flags & SymbolFlags.Optional : getTypeFacts(type) & TypeFacts.IsUndefined)) { 34436 error(expr, Diagnostics.The_operand_of_a_delete_operator_must_be_optional); 34437 } 34438 } 34439 34440 function checkTypeOfExpression(node: TypeOfExpression): Type { 34441 checkExpression(node.expression); 34442 return typeofType; 34443 } 34444 34445 function checkVoidExpression(node: VoidExpression): Type { 34446 checkExpression(node.expression); 34447 return undefinedWideningType; 34448 } 34449 34450 function checkAwaitExpressionGrammar(node: AwaitExpression): void { 34451 // Grammar checking 34452 const container = getContainingFunctionOrClassStaticBlock(node); 34453 if (container && isClassStaticBlockDeclaration(container)) { 34454 error(node, Diagnostics.Await_expression_cannot_be_used_inside_a_class_static_block); 34455 } 34456 else if (!(node.flags & NodeFlags.AwaitContext)) { 34457 if (isInTopLevelContext(node)) { 34458 const sourceFile = getSourceFileOfNode(node); 34459 if (!hasParseDiagnostics(sourceFile)) { 34460 let span: TextSpan | undefined; 34461 if (!isEffectiveExternalModule(sourceFile, compilerOptions)) { 34462 span ??= getSpanOfTokenAtPosition(sourceFile, node.pos); 34463 const diagnostic = createFileDiagnostic(sourceFile, span.start, span.length, 34464 Diagnostics.await_expressions_are_only_allowed_at_the_top_level_of_a_file_when_that_file_is_a_module_but_this_file_has_no_imports_or_exports_Consider_adding_an_empty_export_to_make_this_file_a_module); 34465 diagnostics.add(diagnostic); 34466 } 34467 switch (moduleKind) { 34468 case ModuleKind.Node16: 34469 case ModuleKind.NodeNext: 34470 if (sourceFile.impliedNodeFormat === ModuleKind.CommonJS) { 34471 span ??= getSpanOfTokenAtPosition(sourceFile, node.pos); 34472 diagnostics.add( 34473 createFileDiagnostic(sourceFile, span.start, span.length, Diagnostics.The_current_file_is_a_CommonJS_module_and_cannot_use_await_at_the_top_level) 34474 ); 34475 break; 34476 } 34477 // fallthrough 34478 case ModuleKind.ES2022: 34479 case ModuleKind.ESNext: 34480 case ModuleKind.System: 34481 if (languageVersion >= ScriptTarget.ES2017) { 34482 break; 34483 } 34484 // fallthrough 34485 default: 34486 span ??= getSpanOfTokenAtPosition(sourceFile, node.pos); 34487 diagnostics.add( 34488 createFileDiagnostic(sourceFile, span.start, span.length, 34489 Diagnostics.Top_level_await_expressions_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_or_nodenext_and_the_target_option_is_set_to_es2017_or_higher 34490 ) 34491 ); 34492 break; 34493 } 34494 } 34495 } 34496 else { 34497 // use of 'await' in non-async function 34498 const sourceFile = getSourceFileOfNode(node); 34499 if (!hasParseDiagnostics(sourceFile)) { 34500 const span = getSpanOfTokenAtPosition(sourceFile, node.pos); 34501 const diagnostic = createFileDiagnostic(sourceFile, span.start, span.length, Diagnostics.await_expressions_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules); 34502 if (container && container.kind !== SyntaxKind.Constructor && (getFunctionFlags(container) & FunctionFlags.Async) === 0) { 34503 const relatedInfo = createDiagnosticForNode(container, Diagnostics.Did_you_mean_to_mark_this_function_as_async); 34504 addRelatedInfo(diagnostic, relatedInfo); 34505 } 34506 diagnostics.add(diagnostic); 34507 } 34508 } 34509 } 34510 34511 if (isInParameterInitializerBeforeContainingFunction(node)) { 34512 error(node, Diagnostics.await_expressions_cannot_be_used_in_a_parameter_initializer); 34513 } 34514 } 34515 34516 function checkAwaitExpression(node: AwaitExpression): Type { 34517 addLazyDiagnostic(() => checkAwaitExpressionGrammar(node)); 34518 34519 const operandType = checkExpression(node.expression); 34520 const awaitedType = checkAwaitedType(operandType, /*withAlias*/ true, node, Diagnostics.Type_of_await_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member); 34521 if (awaitedType === operandType && !isErrorType(awaitedType) && !(operandType.flags & TypeFlags.AnyOrUnknown)) { 34522 addErrorOrSuggestion(/*isError*/ false, createDiagnosticForNode(node, Diagnostics.await_has_no_effect_on_the_type_of_this_expression)); 34523 } 34524 return awaitedType; 34525 } 34526 34527 function checkPrefixUnaryExpression(node: PrefixUnaryExpression): Type { 34528 const operandType = checkExpression(node.operand); 34529 if (operandType === silentNeverType) { 34530 return silentNeverType; 34531 } 34532 switch (node.operand.kind) { 34533 case SyntaxKind.NumericLiteral: 34534 switch (node.operator) { 34535 case SyntaxKind.MinusToken: 34536 return getFreshTypeOfLiteralType(getNumberLiteralType(-(node.operand as NumericLiteral).text)); 34537 case SyntaxKind.PlusToken: 34538 return getFreshTypeOfLiteralType(getNumberLiteralType(+(node.operand as NumericLiteral).text)); 34539 } 34540 break; 34541 case SyntaxKind.BigIntLiteral: 34542 if (node.operator === SyntaxKind.MinusToken) { 34543 return getFreshTypeOfLiteralType(getBigIntLiteralType({ 34544 negative: true, 34545 base10Value: parsePseudoBigInt((node.operand as BigIntLiteral).text) 34546 })); 34547 } 34548 } 34549 switch (node.operator) { 34550 case SyntaxKind.PlusToken: 34551 case SyntaxKind.MinusToken: 34552 case SyntaxKind.TildeToken: 34553 checkNonNullType(operandType, node.operand); 34554 if (maybeTypeOfKindConsideringBaseConstraint(operandType, TypeFlags.ESSymbolLike)) { 34555 error(node.operand, Diagnostics.The_0_operator_cannot_be_applied_to_type_symbol, tokenToString(node.operator)); 34556 } 34557 if (node.operator === SyntaxKind.PlusToken) { 34558 if (maybeTypeOfKindConsideringBaseConstraint(operandType, TypeFlags.BigIntLike)) { 34559 error(node.operand, Diagnostics.Operator_0_cannot_be_applied_to_type_1, tokenToString(node.operator), typeToString(getBaseTypeOfLiteralType(operandType))); 34560 } 34561 return numberType; 34562 } 34563 return getUnaryResultType(operandType); 34564 case SyntaxKind.ExclamationToken: 34565 checkTruthinessExpression(node.operand); 34566 const facts = getTypeFacts(operandType) & (TypeFacts.Truthy | TypeFacts.Falsy); 34567 return facts === TypeFacts.Truthy ? falseType : 34568 facts === TypeFacts.Falsy ? trueType : 34569 booleanType; 34570 case SyntaxKind.PlusPlusToken: 34571 case SyntaxKind.MinusMinusToken: 34572 const ok = checkArithmeticOperandType(node.operand, checkNonNullType(operandType, node.operand), 34573 Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_bigint_or_an_enum_type); 34574 if (ok) { 34575 // run check only if former checks succeeded to avoid reporting cascading errors 34576 checkReferenceExpression( 34577 node.operand, 34578 Diagnostics.The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access, 34579 Diagnostics.The_operand_of_an_increment_or_decrement_operator_may_not_be_an_optional_property_access); 34580 } 34581 return getUnaryResultType(operandType); 34582 } 34583 } 34584 34585 function checkPostfixUnaryExpression(node: PostfixUnaryExpression): Type { 34586 const operandType = checkExpression(node.operand); 34587 if (operandType === silentNeverType) { 34588 return silentNeverType; 34589 } 34590 const ok = checkArithmeticOperandType( 34591 node.operand, 34592 checkNonNullType(operandType, node.operand), 34593 Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_bigint_or_an_enum_type); 34594 if (ok) { 34595 // run check only if former checks succeeded to avoid reporting cascading errors 34596 checkReferenceExpression( 34597 node.operand, 34598 Diagnostics.The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access, 34599 Diagnostics.The_operand_of_an_increment_or_decrement_operator_may_not_be_an_optional_property_access); 34600 } 34601 return getUnaryResultType(operandType); 34602 } 34603 34604 function getUnaryResultType(operandType: Type): Type { 34605 if (maybeTypeOfKind(operandType, TypeFlags.BigIntLike)) { 34606 return isTypeAssignableToKind(operandType, TypeFlags.AnyOrUnknown) || maybeTypeOfKind(operandType, TypeFlags.NumberLike) 34607 ? numberOrBigIntType 34608 : bigintType; 34609 } 34610 // If it's not a bigint type, implicit coercion will result in a number 34611 return numberType; 34612 } 34613 34614 function maybeTypeOfKindConsideringBaseConstraint(type: Type, kind: TypeFlags): boolean { 34615 if (maybeTypeOfKind(type, kind)) { 34616 return true; 34617 } 34618 34619 const baseConstraint = getBaseConstraintOrType(type); 34620 return !!baseConstraint && maybeTypeOfKind(baseConstraint, kind); 34621 } 34622 34623 // Return true if type might be of the given kind. A union or intersection type might be of a given 34624 // kind if at least one constituent type is of the given kind. 34625 function maybeTypeOfKind(type: Type, kind: TypeFlags): boolean { 34626 if (type.flags & kind) { 34627 return true; 34628 } 34629 if (type.flags & TypeFlags.UnionOrIntersection) { 34630 const types = (type as UnionOrIntersectionType).types; 34631 for (const t of types) { 34632 if (maybeTypeOfKind(t, kind)) { 34633 return true; 34634 } 34635 } 34636 } 34637 return false; 34638 } 34639 34640 function isTypeAssignableToKind(source: Type, kind: TypeFlags, strict?: boolean): boolean { 34641 if (source.flags & kind) { 34642 return true; 34643 } 34644 if (strict && source.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Void | TypeFlags.Undefined | TypeFlags.Null)) { 34645 return false; 34646 } 34647 return !!(kind & TypeFlags.NumberLike) && isTypeAssignableTo(source, numberType) || 34648 !!(kind & TypeFlags.BigIntLike) && isTypeAssignableTo(source, bigintType) || 34649 !!(kind & TypeFlags.StringLike) && isTypeAssignableTo(source, stringType) || 34650 !!(kind & TypeFlags.BooleanLike) && isTypeAssignableTo(source, booleanType) || 34651 !!(kind & TypeFlags.Void) && isTypeAssignableTo(source, voidType) || 34652 !!(kind & TypeFlags.Never) && isTypeAssignableTo(source, neverType) || 34653 !!(kind & TypeFlags.Null) && isTypeAssignableTo(source, nullType) || 34654 !!(kind & TypeFlags.Undefined) && isTypeAssignableTo(source, undefinedType) || 34655 !!(kind & TypeFlags.ESSymbol) && isTypeAssignableTo(source, esSymbolType) || 34656 !!(kind & TypeFlags.NonPrimitive) && isTypeAssignableTo(source, nonPrimitiveType); 34657 } 34658 34659 function allTypesAssignableToKind(source: Type, kind: TypeFlags, strict?: boolean): boolean { 34660 return source.flags & TypeFlags.Union ? 34661 every((source as UnionType).types, subType => allTypesAssignableToKind(subType, kind, strict)) : 34662 isTypeAssignableToKind(source, kind, strict); 34663 } 34664 34665 function isConstEnumObjectType(type: Type): boolean { 34666 return !!(getObjectFlags(type) & ObjectFlags.Anonymous) && !!type.symbol && isConstEnumSymbol(type.symbol); 34667 } 34668 34669 function isConstEnumSymbol(symbol: Symbol): boolean { 34670 return (symbol.flags & SymbolFlags.ConstEnum) !== 0; 34671 } 34672 34673 function checkInstanceOfExpression(left: Expression, right: Expression, leftType: Type, rightType: Type): Type { 34674 if (leftType === silentNeverType || rightType === silentNeverType) { 34675 return silentNeverType; 34676 } 34677 // TypeScript 1.0 spec (April 2014): 4.15.4 34678 // The instanceof operator requires the left operand to be of type Any, an object type, or a type parameter type, 34679 // and the right operand to be of type Any, a subtype of the 'Function' interface type, or have a call or construct signature. 34680 // The result is always of the Boolean primitive type. 34681 // NOTE: do not raise error if leftType is unknown as related error was already reported 34682 if (!isTypeAny(leftType) && 34683 allTypesAssignableToKind(leftType, TypeFlags.Primitive)) { 34684 error(left, Diagnostics.The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter); 34685 } 34686 // NOTE: do not raise error if right is unknown as related error was already reported 34687 if (!(isTypeAny(rightType) || typeHasCallOrConstructSignatures(rightType) || isTypeSubtypeOf(rightType, globalFunctionType))) { 34688 error(right, Diagnostics.The_right_hand_side_of_an_instanceof_expression_must_be_of_type_any_or_of_a_type_assignable_to_the_Function_interface_type); 34689 } 34690 return booleanType; 34691 } 34692 34693 function hasEmptyObjectIntersection(type: Type): boolean { 34694 return someType(type, t => t === unknownEmptyObjectType || !!(t.flags & TypeFlags.Intersection) && some((t as IntersectionType).types, isEmptyAnonymousObjectType)); 34695 } 34696 34697 function checkInExpression(left: Expression, right: Expression, leftType: Type, rightType: Type): Type { 34698 if (leftType === silentNeverType || rightType === silentNeverType) { 34699 return silentNeverType; 34700 } 34701 if (isPrivateIdentifier(left)) { 34702 if (languageVersion < ScriptTarget.ESNext) { 34703 checkExternalEmitHelpers(left, ExternalEmitHelpers.ClassPrivateFieldIn); 34704 } 34705 // Unlike in 'checkPrivateIdentifierExpression' we now have access to the RHS type 34706 // which provides us with the opportunity to emit more detailed errors 34707 if (!getNodeLinks(left).resolvedSymbol && getContainingClass(left)) { 34708 const isUncheckedJS = isUncheckedJSSuggestion(left, rightType.symbol, /*excludeClasses*/ true); 34709 reportNonexistentProperty(left, rightType, isUncheckedJS); 34710 } 34711 } 34712 else { 34713 // The type of the lef operand must be assignable to string, number, or symbol. 34714 checkTypeAssignableTo(checkNonNullType(leftType, left), stringNumberSymbolType, left); 34715 } 34716 // The type of the right operand must be assignable to 'object'. 34717 if (checkTypeAssignableTo(checkNonNullType(rightType, right), nonPrimitiveType, right)) { 34718 // The {} type is assignable to the object type, yet {} might represent a primitive type. Here we 34719 // detect and error on {} that results from narrowing the unknown type, as well as intersections 34720 // that include {} (we know that the other types in such intersections are assignable to object 34721 // since we already checked for that). 34722 if (hasEmptyObjectIntersection(rightType)) { 34723 error(right, Diagnostics.Type_0_may_represent_a_primitive_value_which_is_not_permitted_as_the_right_operand_of_the_in_operator, typeToString(rightType)); 34724 } 34725 } 34726 // The result is always of the Boolean primitive type. 34727 return booleanType; 34728 } 34729 34730 function checkObjectLiteralAssignment(node: ObjectLiteralExpression, sourceType: Type, rightIsThis?: boolean): Type { 34731 const properties = node.properties; 34732 if (strictNullChecks && properties.length === 0) { 34733 return checkNonNullType(sourceType, node); 34734 } 34735 for (let i = 0; i < properties.length; i++) { 34736 checkObjectLiteralDestructuringPropertyAssignment(node, sourceType, i, properties, rightIsThis); 34737 } 34738 return sourceType; 34739 } 34740 34741 /** Note: If property cannot be a SpreadAssignment, then allProperties does not need to be provided */ 34742 function checkObjectLiteralDestructuringPropertyAssignment(node: ObjectLiteralExpression, objectLiteralType: Type, propertyIndex: number, allProperties?: NodeArray<ObjectLiteralElementLike>, rightIsThis = false) { 34743 const properties = node.properties; 34744 const property = properties[propertyIndex]; 34745 if (property.kind === SyntaxKind.PropertyAssignment || property.kind === SyntaxKind.ShorthandPropertyAssignment) { 34746 const name = property.name; 34747 const exprType = getLiteralTypeFromPropertyName(name); 34748 if (isTypeUsableAsPropertyName(exprType)) { 34749 const text = getPropertyNameFromType(exprType); 34750 const prop = getPropertyOfType(objectLiteralType, text); 34751 if (prop) { 34752 markPropertyAsReferenced(prop, property, rightIsThis); 34753 checkPropertyAccessibility(property, /*isSuper*/ false, /*writing*/ true, objectLiteralType, prop); 34754 } 34755 } 34756 const elementType = getIndexedAccessType(objectLiteralType, exprType, AccessFlags.ExpressionPosition, name); 34757 const type = getFlowTypeOfDestructuring(property, elementType); 34758 return checkDestructuringAssignment(property.kind === SyntaxKind.ShorthandPropertyAssignment ? property : property.initializer, type); 34759 } 34760 else if (property.kind === SyntaxKind.SpreadAssignment) { 34761 if (propertyIndex < properties.length - 1) { 34762 error(property, Diagnostics.A_rest_element_must_be_last_in_a_destructuring_pattern); 34763 } 34764 else { 34765 if (languageVersion < ScriptTarget.ESNext) { 34766 checkExternalEmitHelpers(property, ExternalEmitHelpers.Rest); 34767 } 34768 const nonRestNames: PropertyName[] = []; 34769 if (allProperties) { 34770 for (const otherProperty of allProperties) { 34771 if (!isSpreadAssignment(otherProperty)) { 34772 nonRestNames.push(otherProperty.name); 34773 } 34774 } 34775 } 34776 const type = getRestType(objectLiteralType, nonRestNames, objectLiteralType.symbol); 34777 checkGrammarForDisallowedTrailingComma(allProperties, Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma); 34778 return checkDestructuringAssignment(property.expression, type); 34779 } 34780 } 34781 else { 34782 error(property, Diagnostics.Property_assignment_expected); 34783 } 34784 } 34785 34786 function checkArrayLiteralAssignment(node: ArrayLiteralExpression, sourceType: Type, checkMode?: CheckMode): Type { 34787 const elements = node.elements; 34788 if (languageVersion < ScriptTarget.ES2015 && compilerOptions.downlevelIteration) { 34789 checkExternalEmitHelpers(node, ExternalEmitHelpers.Read); 34790 } 34791 // This elementType will be used if the specific property corresponding to this index is not 34792 // present (aka the tuple element property). This call also checks that the parentType is in 34793 // fact an iterable or array (depending on target language). 34794 const possiblyOutOfBoundsType = checkIteratedTypeOrElementType(IterationUse.Destructuring | IterationUse.PossiblyOutOfBounds, sourceType, undefinedType, node) || errorType; 34795 let inBoundsType: Type | undefined = compilerOptions.noUncheckedIndexedAccess ? undefined: possiblyOutOfBoundsType; 34796 for (let i = 0; i < elements.length; i++) { 34797 let type = possiblyOutOfBoundsType; 34798 if (node.elements[i].kind === SyntaxKind.SpreadElement) { 34799 type = inBoundsType = inBoundsType ?? (checkIteratedTypeOrElementType(IterationUse.Destructuring, sourceType, undefinedType, node) || errorType); 34800 } 34801 checkArrayLiteralDestructuringElementAssignment(node, sourceType, i, type, checkMode); 34802 } 34803 return sourceType; 34804 } 34805 34806 function checkArrayLiteralDestructuringElementAssignment(node: ArrayLiteralExpression, sourceType: Type, 34807 elementIndex: number, elementType: Type, checkMode?: CheckMode) { 34808 const elements = node.elements; 34809 const element = elements[elementIndex]; 34810 if (element.kind !== SyntaxKind.OmittedExpression) { 34811 if (element.kind !== SyntaxKind.SpreadElement) { 34812 const indexType = getNumberLiteralType(elementIndex); 34813 if (isArrayLikeType(sourceType)) { 34814 // We create a synthetic expression so that getIndexedAccessType doesn't get confused 34815 // when the element is a SyntaxKind.ElementAccessExpression. 34816 const accessFlags = AccessFlags.ExpressionPosition | (hasDefaultValue(element) ? AccessFlags.NoTupleBoundsCheck : 0); 34817 const elementType = getIndexedAccessTypeOrUndefined(sourceType, indexType, accessFlags, createSyntheticExpression(element, indexType)) || errorType; 34818 const assignedType = hasDefaultValue(element) ? getTypeWithFacts(elementType, TypeFacts.NEUndefined) : elementType; 34819 const type = getFlowTypeOfDestructuring(element, assignedType); 34820 return checkDestructuringAssignment(element, type, checkMode); 34821 } 34822 return checkDestructuringAssignment(element, elementType, checkMode); 34823 } 34824 if (elementIndex < elements.length - 1) { 34825 error(element, Diagnostics.A_rest_element_must_be_last_in_a_destructuring_pattern); 34826 } 34827 else { 34828 const restExpression = (element as SpreadElement).expression; 34829 if (restExpression.kind === SyntaxKind.BinaryExpression && (restExpression as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken) { 34830 error((restExpression as BinaryExpression).operatorToken, Diagnostics.A_rest_element_cannot_have_an_initializer); 34831 } 34832 else { 34833 checkGrammarForDisallowedTrailingComma(node.elements, Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma); 34834 const type = everyType(sourceType, isTupleType) ? 34835 mapType(sourceType, t => sliceTupleType(t as TupleTypeReference, elementIndex)) : 34836 createArrayType(elementType); 34837 return checkDestructuringAssignment(restExpression, type, checkMode); 34838 } 34839 } 34840 } 34841 return undefined; 34842 } 34843 34844 function checkDestructuringAssignment(exprOrAssignment: Expression | ShorthandPropertyAssignment, sourceType: Type, checkMode?: CheckMode, rightIsThis?: boolean): Type { 34845 let target: Expression; 34846 if (exprOrAssignment.kind === SyntaxKind.ShorthandPropertyAssignment) { 34847 const prop = exprOrAssignment as ShorthandPropertyAssignment; 34848 if (prop.objectAssignmentInitializer) { 34849 // In strict null checking mode, if a default value of a non-undefined type is specified, remove 34850 // undefined from the final type. 34851 if (strictNullChecks && 34852 !(getTypeFacts(checkExpression(prop.objectAssignmentInitializer)) & TypeFacts.IsUndefined)) { 34853 sourceType = getTypeWithFacts(sourceType, TypeFacts.NEUndefined); 34854 } 34855 checkBinaryLikeExpression(prop.name, prop.equalsToken!, prop.objectAssignmentInitializer, checkMode); 34856 } 34857 target = (exprOrAssignment as ShorthandPropertyAssignment).name; 34858 } 34859 else { 34860 target = exprOrAssignment; 34861 } 34862 34863 if (target.kind === SyntaxKind.BinaryExpression && (target as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken) { 34864 checkBinaryExpression(target as BinaryExpression, checkMode); 34865 target = (target as BinaryExpression).left; 34866 // A default value is specified, so remove undefined from the final type. 34867 if (strictNullChecks) { 34868 sourceType = getTypeWithFacts(sourceType, TypeFacts.NEUndefined); 34869 } 34870 } 34871 if (target.kind === SyntaxKind.ObjectLiteralExpression) { 34872 return checkObjectLiteralAssignment(target as ObjectLiteralExpression, sourceType, rightIsThis); 34873 } 34874 if (target.kind === SyntaxKind.ArrayLiteralExpression) { 34875 return checkArrayLiteralAssignment(target as ArrayLiteralExpression, sourceType, checkMode); 34876 } 34877 return checkReferenceAssignment(target, sourceType, checkMode); 34878 } 34879 34880 function checkReferenceAssignment(target: Expression, sourceType: Type, checkMode?: CheckMode): Type { 34881 const targetType = checkExpression(target, checkMode); 34882 const error = target.parent.kind === SyntaxKind.SpreadAssignment ? 34883 Diagnostics.The_target_of_an_object_rest_assignment_must_be_a_variable_or_a_property_access : 34884 Diagnostics.The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access; 34885 const optionalError = target.parent.kind === SyntaxKind.SpreadAssignment ? 34886 Diagnostics.The_target_of_an_object_rest_assignment_may_not_be_an_optional_property_access : 34887 Diagnostics.The_left_hand_side_of_an_assignment_expression_may_not_be_an_optional_property_access; 34888 if (checkReferenceExpression(target, error, optionalError)) { 34889 checkTypeAssignableToAndOptionallyElaborate(sourceType, targetType, target, target); 34890 } 34891 if (isPrivateIdentifierPropertyAccessExpression(target)) { 34892 checkExternalEmitHelpers(target.parent, ExternalEmitHelpers.ClassPrivateFieldSet); 34893 } 34894 return sourceType; 34895 } 34896 34897 /** 34898 * This is a *shallow* check: An expression is side-effect-free if the 34899 * evaluation of the expression *itself* cannot produce side effects. 34900 * For example, x++ / 3 is side-effect free because the / operator 34901 * does not have side effects. 34902 * The intent is to "smell test" an expression for correctness in positions where 34903 * its value is discarded (e.g. the left side of the comma operator). 34904 */ 34905 function isSideEffectFree(node: Node): boolean { 34906 node = skipParentheses(node); 34907 switch (node.kind) { 34908 case SyntaxKind.Identifier: 34909 case SyntaxKind.StringLiteral: 34910 case SyntaxKind.RegularExpressionLiteral: 34911 case SyntaxKind.TaggedTemplateExpression: 34912 case SyntaxKind.TemplateExpression: 34913 case SyntaxKind.NoSubstitutionTemplateLiteral: 34914 case SyntaxKind.NumericLiteral: 34915 case SyntaxKind.BigIntLiteral: 34916 case SyntaxKind.TrueKeyword: 34917 case SyntaxKind.FalseKeyword: 34918 case SyntaxKind.NullKeyword: 34919 case SyntaxKind.UndefinedKeyword: 34920 case SyntaxKind.FunctionExpression: 34921 case SyntaxKind.ClassExpression: 34922 case SyntaxKind.ArrowFunction: 34923 case SyntaxKind.ArrayLiteralExpression: 34924 case SyntaxKind.ObjectLiteralExpression: 34925 case SyntaxKind.TypeOfExpression: 34926 case SyntaxKind.NonNullExpression: 34927 case SyntaxKind.JsxSelfClosingElement: 34928 case SyntaxKind.JsxElement: 34929 return true; 34930 34931 case SyntaxKind.ConditionalExpression: 34932 return isSideEffectFree((node as ConditionalExpression).whenTrue) && 34933 isSideEffectFree((node as ConditionalExpression).whenFalse); 34934 34935 case SyntaxKind.BinaryExpression: 34936 if (isAssignmentOperator((node as BinaryExpression).operatorToken.kind)) { 34937 return false; 34938 } 34939 return isSideEffectFree((node as BinaryExpression).left) && 34940 isSideEffectFree((node as BinaryExpression).right); 34941 34942 case SyntaxKind.PrefixUnaryExpression: 34943 case SyntaxKind.PostfixUnaryExpression: 34944 // Unary operators ~, !, +, and - have no side effects. 34945 // The rest do. 34946 switch ((node as PrefixUnaryExpression).operator) { 34947 case SyntaxKind.ExclamationToken: 34948 case SyntaxKind.PlusToken: 34949 case SyntaxKind.MinusToken: 34950 case SyntaxKind.TildeToken: 34951 return true; 34952 } 34953 return false; 34954 34955 // Some forms listed here for clarity 34956 case SyntaxKind.VoidExpression: // Explicit opt-out 34957 case SyntaxKind.TypeAssertionExpression: // Not SEF, but can produce useful type warnings 34958 case SyntaxKind.AsExpression: // Not SEF, but can produce useful type warnings 34959 default: 34960 return false; 34961 } 34962 } 34963 34964 function isTypeEqualityComparableTo(source: Type, target: Type) { 34965 return (target.flags & TypeFlags.Nullable) !== 0 || isTypeComparableTo(source, target); 34966 } 34967 34968 function createCheckBinaryExpression() { 34969 interface WorkArea { 34970 readonly checkMode: CheckMode | undefined; 34971 skip: boolean; 34972 stackIndex: number; 34973 /** 34974 * Holds the types from the left-side of an expression from [0..stackIndex]. 34975 * Holds the type of the result at stackIndex+1. This allows us to reuse existing stack entries 34976 * and avoid storing an extra property on the object (i.e., `lastResult`). 34977 */ 34978 typeStack: (Type | undefined)[]; 34979 } 34980 34981 const trampoline = createBinaryExpressionTrampoline(onEnter, onLeft, onOperator, onRight, onExit, foldState); 34982 34983 return (node: BinaryExpression, checkMode: CheckMode | undefined) => { 34984 const result = trampoline(node, checkMode); 34985 Debug.assertIsDefined(result); 34986 return result; 34987 }; 34988 34989 function onEnter(node: BinaryExpression, state: WorkArea | undefined, checkMode: CheckMode | undefined) { 34990 if (state) { 34991 state.stackIndex++; 34992 state.skip = false; 34993 setLeftType(state, /*type*/ undefined); 34994 setLastResult(state, /*type*/ undefined); 34995 } 34996 else { 34997 state = { 34998 checkMode, 34999 skip: false, 35000 stackIndex: 0, 35001 typeStack: [undefined, undefined], 35002 }; 35003 } 35004 35005 if (isInJSFile(node) && getAssignedExpandoInitializer(node)) { 35006 state.skip = true; 35007 setLastResult(state, checkExpression(node.right, checkMode)); 35008 return state; 35009 } 35010 35011 checkGrammarNullishCoalesceWithLogicalExpression(node); 35012 35013 const operator = node.operatorToken.kind; 35014 if (operator === SyntaxKind.EqualsToken && (node.left.kind === SyntaxKind.ObjectLiteralExpression || node.left.kind === SyntaxKind.ArrayLiteralExpression)) { 35015 state.skip = true; 35016 setLastResult(state, checkDestructuringAssignment(node.left, checkExpression(node.right, checkMode), checkMode, node.right.kind === SyntaxKind.ThisKeyword)); 35017 return state; 35018 } 35019 35020 return state; 35021 } 35022 35023 function onLeft(left: Expression, state: WorkArea, _node: BinaryExpression) { 35024 if (!state.skip) { 35025 return maybeCheckExpression(state, left); 35026 } 35027 } 35028 35029 function onOperator(operatorToken: BinaryOperatorToken, state: WorkArea, node: BinaryExpression) { 35030 if (!state.skip) { 35031 const leftType = getLastResult(state); 35032 Debug.assertIsDefined(leftType); 35033 setLeftType(state, leftType); 35034 setLastResult(state, /*type*/ undefined); 35035 const operator = operatorToken.kind; 35036 if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken || operator === SyntaxKind.QuestionQuestionToken) { 35037 if (operator === SyntaxKind.AmpersandAmpersandToken) { 35038 let parent = node.parent; 35039 while (parent.kind === SyntaxKind.ParenthesizedExpression 35040 || isBinaryExpression(parent) && (parent.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken || parent.operatorToken.kind === SyntaxKind.BarBarToken)) { 35041 parent = parent.parent; 35042 } 35043 checkTestingKnownTruthyCallableOrAwaitableType(node.left, leftType, isIfStatement(parent) ? parent.thenStatement : undefined); 35044 } 35045 checkTruthinessOfType(leftType, node.left); 35046 } 35047 } 35048 } 35049 35050 function onRight(right: Expression, state: WorkArea, _node: BinaryExpression) { 35051 if (!state.skip) { 35052 return maybeCheckExpression(state, right); 35053 } 35054 } 35055 35056 function onExit(node: BinaryExpression, state: WorkArea): Type | undefined { 35057 let result: Type | undefined; 35058 if (state.skip) { 35059 result = getLastResult(state); 35060 } 35061 else { 35062 const leftType = getLeftType(state); 35063 Debug.assertIsDefined(leftType); 35064 35065 const rightType = getLastResult(state); 35066 Debug.assertIsDefined(rightType); 35067 35068 result = checkBinaryLikeExpressionWorker(node.left, node.operatorToken, node.right, leftType, rightType, node); 35069 } 35070 35071 state.skip = false; 35072 setLeftType(state, /*type*/ undefined); 35073 setLastResult(state, /*type*/ undefined); 35074 state.stackIndex--; 35075 return result; 35076 } 35077 35078 function foldState(state: WorkArea, result: Type | undefined, _side: "left" | "right") { 35079 setLastResult(state, result); 35080 return state; 35081 } 35082 35083 function maybeCheckExpression(state: WorkArea, node: Expression): BinaryExpression | undefined { 35084 if (isBinaryExpression(node)) { 35085 return node; 35086 } 35087 setLastResult(state, checkExpression(node, state.checkMode)); 35088 } 35089 35090 function getLeftType(state: WorkArea) { 35091 return state.typeStack[state.stackIndex]; 35092 } 35093 35094 function setLeftType(state: WorkArea, type: Type | undefined) { 35095 state.typeStack[state.stackIndex] = type; 35096 } 35097 35098 function getLastResult(state: WorkArea) { 35099 return state.typeStack[state.stackIndex + 1]; 35100 } 35101 35102 function setLastResult(state: WorkArea, type: Type | undefined) { 35103 // To reduce overhead, reuse the next stack entry to store the 35104 // last result. This avoids the overhead of an additional property 35105 // on `WorkArea` and reuses empty stack entries as we walk back up 35106 // the stack. 35107 state.typeStack[state.stackIndex + 1] = type; 35108 } 35109 } 35110 35111 function checkGrammarNullishCoalesceWithLogicalExpression(node: BinaryExpression) { 35112 const { left, operatorToken, right } = node; 35113 if (operatorToken.kind === SyntaxKind.QuestionQuestionToken) { 35114 if (isBinaryExpression(left) && (left.operatorToken.kind === SyntaxKind.BarBarToken || left.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken)) { 35115 grammarErrorOnNode(left, Diagnostics._0_and_1_operations_cannot_be_mixed_without_parentheses, tokenToString(left.operatorToken.kind), tokenToString(operatorToken.kind)); 35116 } 35117 if (isBinaryExpression(right) && (right.operatorToken.kind === SyntaxKind.BarBarToken || right.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken)) { 35118 grammarErrorOnNode(right, Diagnostics._0_and_1_operations_cannot_be_mixed_without_parentheses, tokenToString(right.operatorToken.kind), tokenToString(operatorToken.kind)); 35119 } 35120 } 35121 } 35122 35123 // Note that this and `checkBinaryExpression` above should behave mostly the same, except this elides some 35124 // expression-wide checks and does not use a work stack to fold nested binary expressions into the same callstack frame 35125 function checkBinaryLikeExpression(left: Expression, operatorToken: Node, right: Expression, checkMode?: CheckMode, errorNode?: Node): Type { 35126 const operator = operatorToken.kind; 35127 if (operator === SyntaxKind.EqualsToken && (left.kind === SyntaxKind.ObjectLiteralExpression || left.kind === SyntaxKind.ArrayLiteralExpression)) { 35128 return checkDestructuringAssignment(left, checkExpression(right, checkMode), checkMode, right.kind === SyntaxKind.ThisKeyword); 35129 } 35130 let leftType: Type; 35131 if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken || operator === SyntaxKind.QuestionQuestionToken) { 35132 leftType = checkTruthinessExpression(left, checkMode); 35133 } 35134 else { 35135 leftType = checkExpression(left, checkMode); 35136 } 35137 35138 const rightType = checkExpression(right, checkMode); 35139 return checkBinaryLikeExpressionWorker(left, operatorToken, right, leftType, rightType, errorNode); 35140 } 35141 35142 function checkBinaryLikeExpressionWorker( 35143 left: Expression, 35144 operatorToken: Node, 35145 right: Expression, 35146 leftType: Type, 35147 rightType: Type, 35148 errorNode?: Node 35149 ): Type { 35150 const operator = operatorToken.kind; 35151 switch (operator) { 35152 case SyntaxKind.AsteriskToken: 35153 case SyntaxKind.AsteriskAsteriskToken: 35154 case SyntaxKind.AsteriskEqualsToken: 35155 case SyntaxKind.AsteriskAsteriskEqualsToken: 35156 case SyntaxKind.SlashToken: 35157 case SyntaxKind.SlashEqualsToken: 35158 case SyntaxKind.PercentToken: 35159 case SyntaxKind.PercentEqualsToken: 35160 case SyntaxKind.MinusToken: 35161 case SyntaxKind.MinusEqualsToken: 35162 case SyntaxKind.LessThanLessThanToken: 35163 case SyntaxKind.LessThanLessThanEqualsToken: 35164 case SyntaxKind.GreaterThanGreaterThanToken: 35165 case SyntaxKind.GreaterThanGreaterThanEqualsToken: 35166 case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: 35167 case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: 35168 case SyntaxKind.BarToken: 35169 case SyntaxKind.BarEqualsToken: 35170 case SyntaxKind.CaretToken: 35171 case SyntaxKind.CaretEqualsToken: 35172 case SyntaxKind.AmpersandToken: 35173 case SyntaxKind.AmpersandEqualsToken: 35174 if (leftType === silentNeverType || rightType === silentNeverType) { 35175 return silentNeverType; 35176 } 35177 35178 leftType = checkNonNullType(leftType, left); 35179 rightType = checkNonNullType(rightType, right); 35180 35181 let suggestedOperator: SyntaxKind | undefined; 35182 // if a user tries to apply a bitwise operator to 2 boolean operands 35183 // try and return them a helpful suggestion 35184 if ((leftType.flags & TypeFlags.BooleanLike) && 35185 (rightType.flags & TypeFlags.BooleanLike) && 35186 (suggestedOperator = getSuggestedBooleanOperator(operatorToken.kind)) !== undefined) { 35187 error(errorNode || operatorToken, Diagnostics.The_0_operator_is_not_allowed_for_boolean_types_Consider_using_1_instead, tokenToString(operatorToken.kind), tokenToString(suggestedOperator)); 35188 return numberType; 35189 } 35190 else { 35191 // otherwise just check each operand separately and report errors as normal 35192 const leftOk = checkArithmeticOperandType(left, leftType, Diagnostics.The_left_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_bigint_or_an_enum_type, /*isAwaitValid*/ true); 35193 const rightOk = checkArithmeticOperandType(right, rightType, Diagnostics.The_right_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_bigint_or_an_enum_type, /*isAwaitValid*/ true); 35194 let resultType: Type; 35195 // If both are any or unknown, allow operation; assume it will resolve to number 35196 if ((isTypeAssignableToKind(leftType, TypeFlags.AnyOrUnknown) && isTypeAssignableToKind(rightType, TypeFlags.AnyOrUnknown)) || 35197 // Or, if neither could be bigint, implicit coercion results in a number result 35198 !(maybeTypeOfKind(leftType, TypeFlags.BigIntLike) || maybeTypeOfKind(rightType, TypeFlags.BigIntLike)) 35199 ) { 35200 resultType = numberType; 35201 } 35202 // At least one is assignable to bigint, so check that both are 35203 else if (bothAreBigIntLike(leftType, rightType)) { 35204 switch (operator) { 35205 case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: 35206 case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: 35207 reportOperatorError(); 35208 break; 35209 case SyntaxKind.AsteriskAsteriskToken: 35210 case SyntaxKind.AsteriskAsteriskEqualsToken: 35211 if (languageVersion < ScriptTarget.ES2016) { 35212 error(errorNode, Diagnostics.Exponentiation_cannot_be_performed_on_bigint_values_unless_the_target_option_is_set_to_es2016_or_later); 35213 } 35214 } 35215 resultType = bigintType; 35216 } 35217 // Exactly one of leftType/rightType is assignable to bigint 35218 else { 35219 reportOperatorError(bothAreBigIntLike); 35220 resultType = errorType; 35221 } 35222 if (leftOk && rightOk) { 35223 checkAssignmentOperator(resultType); 35224 } 35225 return resultType; 35226 } 35227 case SyntaxKind.PlusToken: 35228 case SyntaxKind.PlusEqualsToken: 35229 if (leftType === silentNeverType || rightType === silentNeverType) { 35230 return silentNeverType; 35231 } 35232 35233 if (!isTypeAssignableToKind(leftType, TypeFlags.StringLike) && !isTypeAssignableToKind(rightType, TypeFlags.StringLike)) { 35234 leftType = checkNonNullType(leftType, left); 35235 rightType = checkNonNullType(rightType, right); 35236 } 35237 35238 let resultType: Type | undefined; 35239 if (isTypeAssignableToKind(leftType, TypeFlags.NumberLike, /*strict*/ true) && isTypeAssignableToKind(rightType, TypeFlags.NumberLike, /*strict*/ true)) { 35240 // Operands of an enum type are treated as having the primitive type Number. 35241 // If both operands are of the Number primitive type, the result is of the Number primitive type. 35242 resultType = numberType; 35243 } 35244 else if (isTypeAssignableToKind(leftType, TypeFlags.BigIntLike, /*strict*/ true) && isTypeAssignableToKind(rightType, TypeFlags.BigIntLike, /*strict*/ true)) { 35245 // If both operands are of the BigInt primitive type, the result is of the BigInt primitive type. 35246 resultType = bigintType; 35247 } 35248 else if (isTypeAssignableToKind(leftType, TypeFlags.StringLike, /*strict*/ true) || isTypeAssignableToKind(rightType, TypeFlags.StringLike, /*strict*/ true)) { 35249 // If one or both operands are of the String primitive type, the result is of the String primitive type. 35250 resultType = stringType; 35251 } 35252 else if (isTypeAny(leftType) || isTypeAny(rightType)) { 35253 // Otherwise, the result is of type Any. 35254 // NOTE: unknown type here denotes error type. Old compiler treated this case as any type so do we. 35255 resultType = isErrorType(leftType) || isErrorType(rightType) ? errorType : anyType; 35256 } 35257 35258 // Symbols are not allowed at all in arithmetic expressions 35259 if (resultType && !checkForDisallowedESSymbolOperand(operator)) { 35260 return resultType; 35261 } 35262 35263 if (!resultType) { 35264 // Types that have a reasonably good chance of being a valid operand type. 35265 // If both types have an awaited type of one of these, we'll assume the user 35266 // might be missing an await without doing an exhaustive check that inserting 35267 // await(s) will actually be a completely valid binary expression. 35268 const closeEnoughKind = TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.AnyOrUnknown; 35269 reportOperatorError((left, right) => 35270 isTypeAssignableToKind(left, closeEnoughKind) && 35271 isTypeAssignableToKind(right, closeEnoughKind)); 35272 return anyType; 35273 } 35274 35275 if (operator === SyntaxKind.PlusEqualsToken) { 35276 checkAssignmentOperator(resultType); 35277 } 35278 return resultType; 35279 case SyntaxKind.LessThanToken: 35280 case SyntaxKind.GreaterThanToken: 35281 case SyntaxKind.LessThanEqualsToken: 35282 case SyntaxKind.GreaterThanEqualsToken: 35283 if (checkForDisallowedESSymbolOperand(operator)) { 35284 leftType = getBaseTypeOfLiteralType(checkNonNullType(leftType, left)); 35285 rightType = getBaseTypeOfLiteralType(checkNonNullType(rightType, right)); 35286 reportOperatorErrorUnless((left, right) => 35287 isTypeComparableTo(left, right) || isTypeComparableTo(right, left) || ( 35288 isTypeAssignableTo(left, numberOrBigIntType) && isTypeAssignableTo(right, numberOrBigIntType))); 35289 } 35290 return booleanType; 35291 case SyntaxKind.EqualsEqualsToken: 35292 case SyntaxKind.ExclamationEqualsToken: 35293 case SyntaxKind.EqualsEqualsEqualsToken: 35294 case SyntaxKind.ExclamationEqualsEqualsToken: 35295 if (isLiteralExpressionOfObject(left) || isLiteralExpressionOfObject(right)) { 35296 const eqType = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.EqualsEqualsEqualsToken; 35297 error(errorNode, Diagnostics.This_condition_will_always_return_0_since_JavaScript_compares_objects_by_reference_not_value, eqType ? "false" : "true"); 35298 } 35299 checkNaNEquality(errorNode, operator, left, right); 35300 reportOperatorErrorUnless((left, right) => isTypeEqualityComparableTo(left, right) || isTypeEqualityComparableTo(right, left)); 35301 return booleanType; 35302 35303 case SyntaxKind.InstanceOfKeyword: 35304 return checkInstanceOfExpression(left, right, leftType, rightType); 35305 case SyntaxKind.InKeyword: 35306 return checkInExpression(left, right, leftType, rightType); 35307 case SyntaxKind.AmpersandAmpersandToken: 35308 case SyntaxKind.AmpersandAmpersandEqualsToken: { 35309 const resultType = getTypeFacts(leftType) & TypeFacts.Truthy ? 35310 getUnionType([extractDefinitelyFalsyTypes(strictNullChecks ? leftType : getBaseTypeOfLiteralType(rightType)), rightType]) : 35311 leftType; 35312 if (operator === SyntaxKind.AmpersandAmpersandEqualsToken) { 35313 checkAssignmentOperator(rightType); 35314 } 35315 return resultType; 35316 } 35317 case SyntaxKind.BarBarToken: 35318 case SyntaxKind.BarBarEqualsToken: { 35319 const resultType = getTypeFacts(leftType) & TypeFacts.Falsy ? 35320 getUnionType([getNonNullableType(removeDefinitelyFalsyTypes(leftType)), rightType], UnionReduction.Subtype) : 35321 leftType; 35322 if (operator === SyntaxKind.BarBarEqualsToken) { 35323 checkAssignmentOperator(rightType); 35324 } 35325 return resultType; 35326 } 35327 case SyntaxKind.QuestionQuestionToken: 35328 case SyntaxKind.QuestionQuestionEqualsToken: { 35329 const resultType = getTypeFacts(leftType) & TypeFacts.EQUndefinedOrNull ? 35330 getUnionType([getNonNullableType(leftType), rightType], UnionReduction.Subtype) : 35331 leftType; 35332 if (operator === SyntaxKind.QuestionQuestionEqualsToken) { 35333 checkAssignmentOperator(rightType); 35334 } 35335 return resultType; 35336 } 35337 case SyntaxKind.EqualsToken: 35338 const declKind = isBinaryExpression(left.parent) ? getAssignmentDeclarationKind(left.parent) : AssignmentDeclarationKind.None; 35339 checkAssignmentDeclaration(declKind, rightType); 35340 if (isAssignmentDeclaration(declKind)) { 35341 if (!(rightType.flags & TypeFlags.Object) || 35342 declKind !== AssignmentDeclarationKind.ModuleExports && 35343 declKind !== AssignmentDeclarationKind.Prototype && 35344 !isEmptyObjectType(rightType) && 35345 !isFunctionObjectType(rightType as ObjectType) && 35346 !(getObjectFlags(rightType) & ObjectFlags.Class)) { 35347 // don't check assignability of module.exports=, C.prototype=, or expando types because they will necessarily be incomplete 35348 checkAssignmentOperator(rightType); 35349 } 35350 return leftType; 35351 } 35352 else { 35353 checkAssignmentOperator(rightType); 35354 return getRegularTypeOfObjectLiteral(rightType); 35355 } 35356 case SyntaxKind.CommaToken: 35357 if (!compilerOptions.allowUnreachableCode && isSideEffectFree(left) && !isEvalNode(right)) { 35358 const sf = getSourceFileOfNode(left); 35359 const sourceText = sf.text; 35360 const start = skipTrivia(sourceText, left.pos); 35361 const isInDiag2657 = sf.parseDiagnostics.some(diag => { 35362 if (diag.code !== Diagnostics.JSX_expressions_must_have_one_parent_element.code) return false; 35363 return textSpanContainsPosition(diag, start); 35364 }); 35365 if (!isInDiag2657) error(left, Diagnostics.Left_side_of_comma_operator_is_unused_and_has_no_side_effects); 35366 } 35367 return rightType; 35368 35369 default: 35370 return Debug.fail(); 35371 } 35372 35373 function bothAreBigIntLike(left: Type, right: Type): boolean { 35374 return isTypeAssignableToKind(left, TypeFlags.BigIntLike) && isTypeAssignableToKind(right, TypeFlags.BigIntLike); 35375 } 35376 35377 function checkAssignmentDeclaration(kind: AssignmentDeclarationKind, rightType: Type) { 35378 if (kind === AssignmentDeclarationKind.ModuleExports) { 35379 for (const prop of getPropertiesOfObjectType(rightType)) { 35380 const propType = getTypeOfSymbol(prop); 35381 if (propType.symbol && propType.symbol.flags & SymbolFlags.Class) { 35382 const name = prop.escapedName; 35383 const symbol = resolveName(prop.valueDeclaration, name, SymbolFlags.Type, undefined, name, /*isUse*/ false); 35384 if (symbol?.declarations && symbol.declarations.some(isJSDocTypedefTag)) { 35385 addDuplicateDeclarationErrorsForSymbols(symbol, Diagnostics.Duplicate_identifier_0, unescapeLeadingUnderscores(name), prop); 35386 addDuplicateDeclarationErrorsForSymbols(prop, Diagnostics.Duplicate_identifier_0, unescapeLeadingUnderscores(name), symbol); 35387 } 35388 } 35389 } 35390 } 35391 } 35392 35393 function isEvalNode(node: Expression) { 35394 return node.kind === SyntaxKind.Identifier && (node as Identifier).escapedText === "eval"; 35395 } 35396 35397 // Return true if there was no error, false if there was an error. 35398 function checkForDisallowedESSymbolOperand(operator: SyntaxKind): boolean { 35399 const offendingSymbolOperand = 35400 maybeTypeOfKindConsideringBaseConstraint(leftType, TypeFlags.ESSymbolLike) ? left : 35401 maybeTypeOfKindConsideringBaseConstraint(rightType, TypeFlags.ESSymbolLike) ? right : 35402 undefined; 35403 35404 if (offendingSymbolOperand) { 35405 error(offendingSymbolOperand, Diagnostics.The_0_operator_cannot_be_applied_to_type_symbol, tokenToString(operator)); 35406 return false; 35407 } 35408 35409 return true; 35410 } 35411 35412 function getSuggestedBooleanOperator(operator: SyntaxKind): SyntaxKind | undefined { 35413 switch (operator) { 35414 case SyntaxKind.BarToken: 35415 case SyntaxKind.BarEqualsToken: 35416 return SyntaxKind.BarBarToken; 35417 case SyntaxKind.CaretToken: 35418 case SyntaxKind.CaretEqualsToken: 35419 return SyntaxKind.ExclamationEqualsEqualsToken; 35420 case SyntaxKind.AmpersandToken: 35421 case SyntaxKind.AmpersandEqualsToken: 35422 return SyntaxKind.AmpersandAmpersandToken; 35423 default: 35424 return undefined; 35425 } 35426 } 35427 35428 function checkAssignmentOperator(valueType: Type): void { 35429 if (isAssignmentOperator(operator)) { 35430 addLazyDiagnostic(checkAssignmentOperatorWorker); 35431 } 35432 35433 function checkAssignmentOperatorWorker() { 35434 // TypeScript 1.0 spec (April 2014): 4.17 35435 // An assignment of the form 35436 // VarExpr = ValueExpr 35437 // requires VarExpr to be classified as a reference 35438 // A compound assignment furthermore requires VarExpr to be classified as a reference (section 4.1) 35439 // and the type of the non-compound operation to be assignable to the type of VarExpr. 35440 35441 if (checkReferenceExpression(left, 35442 Diagnostics.The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access, 35443 Diagnostics.The_left_hand_side_of_an_assignment_expression_may_not_be_an_optional_property_access) 35444 && (!isIdentifier(left) || unescapeLeadingUnderscores(left.escapedText) !== "exports")) { 35445 35446 let headMessage: DiagnosticMessage | undefined; 35447 if (exactOptionalPropertyTypes && isPropertyAccessExpression(left) && maybeTypeOfKind(valueType, TypeFlags.Undefined)) { 35448 const target = getTypeOfPropertyOfType(getTypeOfExpression(left.expression), left.name.escapedText); 35449 if (isExactOptionalPropertyMismatch(valueType, target)) { 35450 headMessage = Diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_type_of_the_target; 35451 } 35452 } 35453 // to avoid cascading errors check assignability only if 'isReference' check succeeded and no errors were reported 35454 checkTypeAssignableToAndOptionallyElaborate(valueType, leftType, left, right, headMessage); 35455 } 35456 } 35457 } 35458 35459 function isAssignmentDeclaration(kind: AssignmentDeclarationKind) { 35460 switch (kind) { 35461 case AssignmentDeclarationKind.ModuleExports: 35462 return true; 35463 case AssignmentDeclarationKind.ExportsProperty: 35464 case AssignmentDeclarationKind.Property: 35465 case AssignmentDeclarationKind.Prototype: 35466 case AssignmentDeclarationKind.PrototypeProperty: 35467 case AssignmentDeclarationKind.ThisProperty: 35468 const symbol = getSymbolOfNode(left); 35469 const init = getAssignedExpandoInitializer(right); 35470 return !!init && isObjectLiteralExpression(init) && 35471 !!symbol?.exports?.size; 35472 default: 35473 return false; 35474 } 35475 } 35476 35477 /** 35478 * Returns true if an error is reported 35479 */ 35480 function reportOperatorErrorUnless(typesAreCompatible: (left: Type, right: Type) => boolean): boolean { 35481 if (!typesAreCompatible(leftType, rightType)) { 35482 reportOperatorError(typesAreCompatible); 35483 return true; 35484 } 35485 return false; 35486 } 35487 35488 function reportOperatorError(isRelated?: (left: Type, right: Type) => boolean) { 35489 let wouldWorkWithAwait = false; 35490 const errNode = errorNode || operatorToken; 35491 if (isRelated) { 35492 const awaitedLeftType = getAwaitedTypeNoAlias(leftType); 35493 const awaitedRightType = getAwaitedTypeNoAlias(rightType); 35494 wouldWorkWithAwait = !(awaitedLeftType === leftType && awaitedRightType === rightType) 35495 && !!(awaitedLeftType && awaitedRightType) 35496 && isRelated(awaitedLeftType, awaitedRightType); 35497 } 35498 35499 let effectiveLeft = leftType; 35500 let effectiveRight = rightType; 35501 if (!wouldWorkWithAwait && isRelated) { 35502 [effectiveLeft, effectiveRight] = getBaseTypesIfUnrelated(leftType, rightType, isRelated); 35503 } 35504 const [leftStr, rightStr] = getTypeNamesForErrorDisplay(effectiveLeft, effectiveRight); 35505 if (!tryGiveBetterPrimaryError(errNode, wouldWorkWithAwait, leftStr, rightStr)) { 35506 errorAndMaybeSuggestAwait( 35507 errNode, 35508 wouldWorkWithAwait, 35509 Diagnostics.Operator_0_cannot_be_applied_to_types_1_and_2, 35510 tokenToString(operatorToken.kind), 35511 leftStr, 35512 rightStr, 35513 ); 35514 } 35515 } 35516 35517 function tryGiveBetterPrimaryError(errNode: Node, maybeMissingAwait: boolean, leftStr: string, rightStr: string) { 35518 switch (operatorToken.kind) { 35519 case SyntaxKind.EqualsEqualsEqualsToken: 35520 case SyntaxKind.EqualsEqualsToken: 35521 case SyntaxKind.ExclamationEqualsEqualsToken: 35522 case SyntaxKind.ExclamationEqualsToken: 35523 return errorAndMaybeSuggestAwait( 35524 errNode, 35525 maybeMissingAwait, 35526 Diagnostics.This_comparison_appears_to_be_unintentional_because_the_types_0_and_1_have_no_overlap, 35527 leftStr, rightStr); 35528 default: 35529 return undefined; 35530 } 35531 } 35532 35533 function checkNaNEquality(errorNode: Node | undefined, operator: SyntaxKind, left: Expression, right: Expression) { 35534 const isLeftNaN = isGlobalNaN(skipParentheses(left)); 35535 const isRightNaN = isGlobalNaN(skipParentheses(right)); 35536 if (isLeftNaN || isRightNaN) { 35537 const err = error(errorNode, Diagnostics.This_condition_will_always_return_0, 35538 tokenToString(operator === SyntaxKind.EqualsEqualsEqualsToken || operator === SyntaxKind.EqualsEqualsToken ? SyntaxKind.FalseKeyword : SyntaxKind.TrueKeyword)); 35539 if (isLeftNaN && isRightNaN) return; 35540 const operatorString = operator === SyntaxKind.ExclamationEqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken ? tokenToString(SyntaxKind.ExclamationToken) : ""; 35541 const location = isLeftNaN ? right : left; 35542 const expression = skipParentheses(location); 35543 addRelatedInfo(err, createDiagnosticForNode(location, Diagnostics.Did_you_mean_0, 35544 `${operatorString}Number.isNaN(${isEntityNameExpression(expression) ? entityNameToString(expression) : "..."})`)); 35545 } 35546 } 35547 35548 function isGlobalNaN(expr: Expression): boolean { 35549 if (isIdentifier(expr) && expr.escapedText === "NaN") { 35550 const globalNaNSymbol = getGlobalNaNSymbol(); 35551 return !!globalNaNSymbol && globalNaNSymbol === getResolvedSymbol(expr); 35552 } 35553 return false; 35554 } 35555 } 35556 35557 function getBaseTypesIfUnrelated(leftType: Type, rightType: Type, isRelated: (left: Type, right: Type) => boolean): [Type, Type] { 35558 let effectiveLeft = leftType; 35559 let effectiveRight = rightType; 35560 const leftBase = getBaseTypeOfLiteralType(leftType); 35561 const rightBase = getBaseTypeOfLiteralType(rightType); 35562 if (!isRelated(leftBase, rightBase)) { 35563 effectiveLeft = leftBase; 35564 effectiveRight = rightBase; 35565 } 35566 return [ effectiveLeft, effectiveRight ]; 35567 } 35568 35569 function checkYieldExpression(node: YieldExpression): Type { 35570 addLazyDiagnostic(checkYieldExpressionGrammar); 35571 35572 const func = getContainingFunction(node); 35573 if (!func) return anyType; 35574 const functionFlags = getFunctionFlags(func); 35575 35576 if (!(functionFlags & FunctionFlags.Generator)) { 35577 // If the user's code is syntactically correct, the func should always have a star. After all, we are in a yield context. 35578 return anyType; 35579 } 35580 35581 const isAsync = (functionFlags & FunctionFlags.Async) !== 0; 35582 if (node.asteriskToken) { 35583 // Async generator functions prior to ESNext require the __await, __asyncDelegator, 35584 // and __asyncValues helpers 35585 if (isAsync && languageVersion < ScriptTarget.ESNext) { 35586 checkExternalEmitHelpers(node, ExternalEmitHelpers.AsyncDelegatorIncludes); 35587 } 35588 35589 // Generator functions prior to ES2015 require the __values helper 35590 if (!isAsync && languageVersion < ScriptTarget.ES2015 && compilerOptions.downlevelIteration) { 35591 checkExternalEmitHelpers(node, ExternalEmitHelpers.Values); 35592 } 35593 } 35594 35595 // There is no point in doing an assignability check if the function 35596 // has no explicit return type because the return type is directly computed 35597 // from the yield expressions. 35598 const returnType = getReturnTypeFromAnnotation(func); 35599 const iterationTypes = returnType && getIterationTypesOfGeneratorFunctionReturnType(returnType, isAsync); 35600 const signatureYieldType = iterationTypes && iterationTypes.yieldType || anyType; 35601 const signatureNextType = iterationTypes && iterationTypes.nextType || anyType; 35602 const resolvedSignatureNextType = isAsync ? getAwaitedType(signatureNextType) || anyType : signatureNextType; 35603 const yieldExpressionType = node.expression ? checkExpression(node.expression) : undefinedWideningType; 35604 const yieldedType = getYieldedTypeOfYieldExpression(node, yieldExpressionType, resolvedSignatureNextType, isAsync); 35605 if (returnType && yieldedType) { 35606 checkTypeAssignableToAndOptionallyElaborate(yieldedType, signatureYieldType, node.expression || node, node.expression); 35607 } 35608 35609 if (node.asteriskToken) { 35610 const use = isAsync ? IterationUse.AsyncYieldStar : IterationUse.YieldStar; 35611 return getIterationTypeOfIterable(use, IterationTypeKind.Return, yieldExpressionType, node.expression) 35612 || anyType; 35613 } 35614 else if (returnType) { 35615 return getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Next, returnType, isAsync) 35616 || anyType; 35617 } 35618 let type = getContextualIterationType(IterationTypeKind.Next, func); 35619 if (!type) { 35620 type = anyType; 35621 addLazyDiagnostic(() => { 35622 if (noImplicitAny && !expressionResultIsUnused(node)) { 35623 const contextualType = getContextualType(node, /*contextFlags*/ undefined); 35624 if (!contextualType || isTypeAny(contextualType)) { 35625 error(node, Diagnostics.yield_expression_implicitly_results_in_an_any_type_because_its_containing_generator_lacks_a_return_type_annotation); 35626 } 35627 } 35628 }); 35629 } 35630 return type; 35631 35632 function checkYieldExpressionGrammar() { 35633 if (!(node.flags & NodeFlags.YieldContext)) { 35634 grammarErrorOnFirstToken(node, Diagnostics.A_yield_expression_is_only_allowed_in_a_generator_body); 35635 } 35636 35637 if (isInParameterInitializerBeforeContainingFunction(node)) { 35638 error(node, Diagnostics.yield_expressions_cannot_be_used_in_a_parameter_initializer); 35639 } 35640 } 35641 } 35642 35643 function checkConditionalExpression(node: ConditionalExpression, checkMode?: CheckMode): Type { 35644 const type = checkTruthinessExpression(node.condition); 35645 checkTestingKnownTruthyCallableOrAwaitableType(node.condition, type, node.whenTrue); 35646 const type1 = checkExpression(node.whenTrue, checkMode); 35647 const type2 = checkExpression(node.whenFalse, checkMode); 35648 return getUnionType([type1, type2], UnionReduction.Subtype); 35649 } 35650 35651 function isTemplateLiteralContext(node: Node): boolean { 35652 const parent = node.parent; 35653 return isParenthesizedExpression(parent) && isTemplateLiteralContext(parent) || 35654 isElementAccessExpression(parent) && parent.argumentExpression === node; 35655 } 35656 35657 function checkTemplateExpression(node: TemplateExpression): Type { 35658 const texts = [node.head.text]; 35659 const types = []; 35660 for (const span of node.templateSpans) { 35661 const type = checkExpression(span.expression); 35662 if (maybeTypeOfKindConsideringBaseConstraint(type, TypeFlags.ESSymbolLike)) { 35663 error(span.expression, Diagnostics.Implicit_conversion_of_a_symbol_to_a_string_will_fail_at_runtime_Consider_wrapping_this_expression_in_String); 35664 } 35665 texts.push(span.literal.text); 35666 types.push(isTypeAssignableTo(type, templateConstraintType) ? type : stringType); 35667 } 35668 return isConstContext(node) || isTemplateLiteralContext(node) || someType(getContextualType(node, /*contextFlags*/ undefined) || unknownType, isTemplateLiteralContextualType) ? getTemplateLiteralType(texts, types) : stringType; 35669 } 35670 35671 function isTemplateLiteralContextualType(type: Type): boolean { 35672 return !!(type.flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral) || 35673 type.flags & TypeFlags.InstantiableNonPrimitive && maybeTypeOfKind(getBaseConstraintOfType(type) || unknownType, TypeFlags.StringLike)); 35674 } 35675 35676 function getContextNode(node: Expression): Node { 35677 if (node.kind === SyntaxKind.JsxAttributes && !isJsxSelfClosingElement(node.parent)) { 35678 return node.parent.parent; // Needs to be the root JsxElement, so it encompasses the attributes _and_ the children (which are essentially part of the attributes) 35679 } 35680 return node; 35681 } 35682 35683 function checkExpressionWithContextualType(node: Expression, contextualType: Type, inferenceContext: InferenceContext | undefined, checkMode: CheckMode): Type { 35684 const context = getContextNode(node); 35685 const saveContextualType = context.contextualType; 35686 const saveInferenceContext = context.inferenceContext; 35687 try { 35688 context.contextualType = contextualType; 35689 context.inferenceContext = inferenceContext; 35690 const type = checkExpression(node, checkMode | CheckMode.Contextual | (inferenceContext ? CheckMode.Inferential : 0)); 35691 // In CheckMode.Inferential we collect intra-expression inference sites to process before fixing any type 35692 // parameters. This information is no longer needed after the call to checkExpression. 35693 if (inferenceContext && inferenceContext.intraExpressionInferenceSites) { 35694 inferenceContext.intraExpressionInferenceSites = undefined; 35695 } 35696 // We strip literal freshness when an appropriate contextual type is present such that contextually typed 35697 // literals always preserve their literal types (otherwise they might widen during type inference). An alternative 35698 // here would be to not mark contextually typed literals as fresh in the first place. 35699 const result = maybeTypeOfKind(type, TypeFlags.Literal) && isLiteralOfContextualType(type, instantiateContextualType(contextualType, node, /*contextFlags*/ undefined)) ? 35700 getRegularTypeOfLiteralType(type) : type; 35701 return result; 35702 } 35703 finally { 35704 // In the event our operation is canceled or some other exception occurs, reset the contextual type 35705 // so that we do not accidentally hold onto an instance of the checker, as a Type created in the services layer 35706 // may hold onto the checker that created it. 35707 context.contextualType = saveContextualType; 35708 context.inferenceContext = saveInferenceContext; 35709 } 35710 } 35711 35712 function checkExpressionCached(node: Expression | QualifiedName, checkMode?: CheckMode): Type { 35713 if (checkMode && checkMode !== CheckMode.Normal) { 35714 return checkExpression(node, checkMode); 35715 } 35716 const links = getNodeLinks(node); 35717 if (!links.resolvedType) { 35718 // When computing a type that we're going to cache, we need to ignore any ongoing control flow 35719 // analysis because variables may have transient types in indeterminable states. Moving flowLoopStart 35720 // to the top of the stack ensures all transient types are computed from a known point. 35721 const saveFlowLoopStart = flowLoopStart; 35722 const saveFlowTypeCache = flowTypeCache; 35723 flowLoopStart = flowLoopCount; 35724 flowTypeCache = undefined; 35725 links.resolvedType = checkExpression(node, checkMode); 35726 flowTypeCache = saveFlowTypeCache; 35727 flowLoopStart = saveFlowLoopStart; 35728 } 35729 return links.resolvedType; 35730 } 35731 35732 function isTypeAssertion(node: Expression) { 35733 node = skipParentheses(node, /*excludeJSDocTypeAssertions*/ true); 35734 return node.kind === SyntaxKind.TypeAssertionExpression || 35735 node.kind === SyntaxKind.AsExpression || 35736 isJSDocTypeAssertion(node); 35737 } 35738 35739 function checkDeclarationInitializer( 35740 declaration: HasExpressionInitializer, 35741 checkMode: CheckMode, 35742 contextualType?: Type | undefined 35743 ) { 35744 const initializer = getEffectiveInitializer(declaration)!; 35745 const type = getQuickTypeOfExpression(initializer) || 35746 (contextualType ? 35747 checkExpressionWithContextualType(initializer, contextualType, /*inferenceContext*/ undefined, checkMode || CheckMode.Normal) 35748 : checkExpressionCached(initializer, checkMode)); 35749 return isParameter(declaration) && declaration.name.kind === SyntaxKind.ArrayBindingPattern && 35750 isTupleType(type) && !type.target.hasRestElement && getTypeReferenceArity(type) < declaration.name.elements.length ? 35751 padTupleType(type, declaration.name) : type; 35752 } 35753 35754 function padTupleType(type: TupleTypeReference, pattern: ArrayBindingPattern) { 35755 const patternElements = pattern.elements; 35756 const elementTypes = getTypeArguments(type).slice(); 35757 const elementFlags = type.target.elementFlags.slice(); 35758 for (let i = getTypeReferenceArity(type); i < patternElements.length; i++) { 35759 const e = patternElements[i]; 35760 if (i < patternElements.length - 1 || !(e.kind === SyntaxKind.BindingElement && e.dotDotDotToken)) { 35761 elementTypes.push(!isOmittedExpression(e) && hasDefaultValue(e) ? getTypeFromBindingElement(e, /*includePatternInType*/ false, /*reportErrors*/ false) : anyType); 35762 elementFlags.push(ElementFlags.Optional); 35763 if (!isOmittedExpression(e) && !hasDefaultValue(e)) { 35764 reportImplicitAny(e, anyType); 35765 } 35766 } 35767 } 35768 return createTupleType(elementTypes, elementFlags, type.target.readonly); 35769 } 35770 35771 function widenTypeInferredFromInitializer(declaration: HasExpressionInitializer, type: Type) { 35772 const widened = getCombinedNodeFlags(declaration) & NodeFlags.Const || isDeclarationReadonly(declaration) ? type : getWidenedLiteralType(type); 35773 if (isInJSFile(declaration)) { 35774 if (isEmptyLiteralType(widened)) { 35775 reportImplicitAny(declaration, anyType); 35776 return anyType; 35777 } 35778 else if (isEmptyArrayLiteralType(widened)) { 35779 reportImplicitAny(declaration, anyArrayType); 35780 return anyArrayType; 35781 } 35782 } 35783 return widened; 35784 } 35785 35786 function isLiteralOfContextualType(candidateType: Type, contextualType: Type | undefined): boolean { 35787 if (contextualType) { 35788 if (contextualType.flags & TypeFlags.UnionOrIntersection) { 35789 const types = (contextualType as UnionType).types; 35790 return some(types, t => isLiteralOfContextualType(candidateType, t)); 35791 } 35792 if (contextualType.flags & TypeFlags.InstantiableNonPrimitive) { 35793 // If the contextual type is a type variable constrained to a primitive type, consider 35794 // this a literal context for literals of that primitive type. For example, given a 35795 // type parameter 'T extends string', infer string literal types for T. 35796 const constraint = getBaseConstraintOfType(contextualType) || unknownType; 35797 return maybeTypeOfKind(constraint, TypeFlags.String) && maybeTypeOfKind(candidateType, TypeFlags.StringLiteral) || 35798 maybeTypeOfKind(constraint, TypeFlags.Number) && maybeTypeOfKind(candidateType, TypeFlags.NumberLiteral) || 35799 maybeTypeOfKind(constraint, TypeFlags.BigInt) && maybeTypeOfKind(candidateType, TypeFlags.BigIntLiteral) || 35800 maybeTypeOfKind(constraint, TypeFlags.ESSymbol) && maybeTypeOfKind(candidateType, TypeFlags.UniqueESSymbol) || 35801 isLiteralOfContextualType(candidateType, constraint); 35802 } 35803 // If the contextual type is a literal of a particular primitive type, we consider this a 35804 // literal context for all literals of that primitive type. 35805 return !!(contextualType.flags & (TypeFlags.StringLiteral | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) && maybeTypeOfKind(candidateType, TypeFlags.StringLiteral) || 35806 contextualType.flags & TypeFlags.NumberLiteral && maybeTypeOfKind(candidateType, TypeFlags.NumberLiteral) || 35807 contextualType.flags & TypeFlags.BigIntLiteral && maybeTypeOfKind(candidateType, TypeFlags.BigIntLiteral) || 35808 contextualType.flags & TypeFlags.BooleanLiteral && maybeTypeOfKind(candidateType, TypeFlags.BooleanLiteral) || 35809 contextualType.flags & TypeFlags.UniqueESSymbol && maybeTypeOfKind(candidateType, TypeFlags.UniqueESSymbol)); 35810 } 35811 return false; 35812 } 35813 35814 function isConstContext(node: Expression): boolean { 35815 const parent = node.parent; 35816 return isAssertionExpression(parent) && isConstTypeReference(parent.type) || 35817 isJSDocTypeAssertion(parent) && isConstTypeReference(getJSDocTypeAssertionType(parent)) || 35818 (isParenthesizedExpression(parent) || isArrayLiteralExpression(parent) || isSpreadElement(parent)) && isConstContext(parent) || 35819 (isPropertyAssignment(parent) || isShorthandPropertyAssignment(parent) || isTemplateSpan(parent)) && isConstContext(parent.parent); 35820 } 35821 35822 function checkExpressionForMutableLocation(node: Expression, checkMode: CheckMode | undefined, contextualType?: Type, forceTuple?: boolean): Type { 35823 const type = checkExpression(node, checkMode, forceTuple); 35824 return isConstContext(node) || isCommonJsExportedExpression(node) ? getRegularTypeOfLiteralType(type) : 35825 isTypeAssertion(node) ? type : 35826 getWidenedLiteralLikeTypeForContextualType(type, instantiateContextualType(arguments.length === 2 ? getContextualType(node, /*contextFlags*/ undefined) : contextualType, node, /*contextFlags*/ undefined)); 35827 } 35828 35829 function checkPropertyAssignment(node: PropertyAssignment, checkMode?: CheckMode): Type { 35830 // Do not use hasDynamicName here, because that returns false for well known symbols. 35831 // We want to perform checkComputedPropertyName for all computed properties, including 35832 // well known symbols. 35833 if (node.name.kind === SyntaxKind.ComputedPropertyName) { 35834 checkComputedPropertyName(node.name); 35835 } 35836 35837 return checkExpressionForMutableLocation(node.initializer, checkMode); 35838 } 35839 35840 function checkObjectLiteralMethod(node: MethodDeclaration, checkMode?: CheckMode): Type { 35841 // Grammar checking 35842 checkGrammarMethod(node); 35843 35844 // Do not use hasDynamicName here, because that returns false for well known symbols. 35845 // We want to perform checkComputedPropertyName for all computed properties, including 35846 // well known symbols. 35847 if (node.name.kind === SyntaxKind.ComputedPropertyName) { 35848 checkComputedPropertyName(node.name); 35849 } 35850 35851 const uninstantiatedType = checkFunctionExpressionOrObjectLiteralMethod(node, checkMode); 35852 return instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, checkMode); 35853 } 35854 35855 function instantiateTypeWithSingleGenericCallSignature(node: Expression | MethodDeclaration | QualifiedName, type: Type, checkMode?: CheckMode) { 35856 if (checkMode && checkMode & (CheckMode.Inferential | CheckMode.SkipGenericFunctions)) { 35857 const callSignature = getSingleSignature(type, SignatureKind.Call, /*allowMembers*/ true); 35858 const constructSignature = getSingleSignature(type, SignatureKind.Construct, /*allowMembers*/ true); 35859 const signature = callSignature || constructSignature; 35860 if (signature && signature.typeParameters) { 35861 const contextualType = getApparentTypeOfContextualType(node as Expression, ContextFlags.NoConstraints); 35862 if (contextualType) { 35863 const contextualSignature = getSingleSignature(getNonNullableType(contextualType), callSignature ? SignatureKind.Call : SignatureKind.Construct, /*allowMembers*/ false); 35864 if (contextualSignature && !contextualSignature.typeParameters) { 35865 if (checkMode & CheckMode.SkipGenericFunctions) { 35866 skippedGenericFunction(node, checkMode); 35867 return anyFunctionType; 35868 } 35869 const context = getInferenceContext(node)!; 35870 // We have an expression that is an argument of a generic function for which we are performing 35871 // type argument inference. The expression is of a function type with a single generic call 35872 // signature and a contextual function type with a single non-generic call signature. Now check 35873 // if the outer function returns a function type with a single non-generic call signature and 35874 // if some of the outer function type parameters have no inferences so far. If so, we can 35875 // potentially add inferred type parameters to the outer function return type. 35876 const returnType = context.signature && getReturnTypeOfSignature(context.signature); 35877 const returnSignature = returnType && getSingleCallOrConstructSignature(returnType); 35878 if (returnSignature && !returnSignature.typeParameters && !every(context.inferences, hasInferenceCandidates)) { 35879 // Instantiate the signature with its own type parameters as type arguments, possibly 35880 // renaming the type parameters to ensure they have unique names. 35881 const uniqueTypeParameters = getUniqueTypeParameters(context, signature.typeParameters); 35882 const instantiatedSignature = getSignatureInstantiationWithoutFillingInTypeArguments(signature, uniqueTypeParameters); 35883 // Infer from the parameters of the instantiated signature to the parameters of the 35884 // contextual signature starting with an empty set of inference candidates. 35885 const inferences = map(context.inferences, info => createInferenceInfo(info.typeParameter)); 35886 applyToParameterTypes(instantiatedSignature, contextualSignature, (source, target) => { 35887 inferTypes(inferences, source, target, /*priority*/ 0, /*contravariant*/ true); 35888 }); 35889 if (some(inferences, hasInferenceCandidates)) { 35890 // We have inference candidates, indicating that one or more type parameters are referenced 35891 // in the parameter types of the contextual signature. Now also infer from the return type. 35892 applyToReturnTypes(instantiatedSignature, contextualSignature, (source, target) => { 35893 inferTypes(inferences, source, target); 35894 }); 35895 // If the type parameters for which we produced candidates do not have any inferences yet, 35896 // we adopt the new inference candidates and add the type parameters of the expression type 35897 // to the set of inferred type parameters for the outer function return type. 35898 if (!hasOverlappingInferences(context.inferences, inferences)) { 35899 mergeInferences(context.inferences, inferences); 35900 context.inferredTypeParameters = concatenate(context.inferredTypeParameters, uniqueTypeParameters); 35901 return getOrCreateTypeFromSignature(instantiatedSignature); 35902 } 35903 } 35904 } 35905 return getOrCreateTypeFromSignature(instantiateSignatureInContextOf(signature, contextualSignature, context)); 35906 } 35907 } 35908 } 35909 } 35910 return type; 35911 } 35912 35913 function skippedGenericFunction(node: Node, checkMode: CheckMode) { 35914 if (checkMode & CheckMode.Inferential) { 35915 // We have skipped a generic function during inferential typing. Obtain the inference context and 35916 // indicate this has occurred such that we know a second pass of inference is be needed. 35917 const context = getInferenceContext(node)!; 35918 context.flags |= InferenceFlags.SkippedGenericFunction; 35919 } 35920 } 35921 35922 function hasInferenceCandidates(info: InferenceInfo) { 35923 return !!(info.candidates || info.contraCandidates); 35924 } 35925 35926 function hasInferenceCandidatesOrDefault(info: InferenceInfo) { 35927 return !!(info.candidates || info.contraCandidates || hasTypeParameterDefault(info.typeParameter)); 35928 } 35929 35930 function hasOverlappingInferences(a: InferenceInfo[], b: InferenceInfo[]) { 35931 for (let i = 0; i < a.length; i++) { 35932 if (hasInferenceCandidates(a[i]) && hasInferenceCandidates(b[i])) { 35933 return true; 35934 } 35935 } 35936 return false; 35937 } 35938 35939 function mergeInferences(target: InferenceInfo[], source: InferenceInfo[]) { 35940 for (let i = 0; i < target.length; i++) { 35941 if (!hasInferenceCandidates(target[i]) && hasInferenceCandidates(source[i])) { 35942 target[i] = source[i]; 35943 } 35944 } 35945 } 35946 35947 function getUniqueTypeParameters(context: InferenceContext, typeParameters: readonly TypeParameter[]): readonly TypeParameter[] { 35948 const result: TypeParameter[] = []; 35949 let oldTypeParameters: TypeParameter[] | undefined; 35950 let newTypeParameters: TypeParameter[] | undefined; 35951 for (const tp of typeParameters) { 35952 const name = tp.symbol.escapedName; 35953 if (hasTypeParameterByName(context.inferredTypeParameters, name) || hasTypeParameterByName(result, name)) { 35954 const newName = getUniqueTypeParameterName(concatenate(context.inferredTypeParameters, result), name); 35955 const symbol = createSymbol(SymbolFlags.TypeParameter, newName); 35956 const newTypeParameter = createTypeParameter(symbol); 35957 newTypeParameter.target = tp; 35958 oldTypeParameters = append(oldTypeParameters, tp); 35959 newTypeParameters = append(newTypeParameters, newTypeParameter); 35960 result.push(newTypeParameter); 35961 } 35962 else { 35963 result.push(tp); 35964 } 35965 } 35966 if (newTypeParameters) { 35967 const mapper = createTypeMapper(oldTypeParameters!, newTypeParameters); 35968 for (const tp of newTypeParameters) { 35969 tp.mapper = mapper; 35970 } 35971 } 35972 return result; 35973 } 35974 35975 function hasTypeParameterByName(typeParameters: readonly TypeParameter[] | undefined, name: __String) { 35976 return some(typeParameters, tp => tp.symbol.escapedName === name); 35977 } 35978 35979 function getUniqueTypeParameterName(typeParameters: readonly TypeParameter[], baseName: __String) { 35980 let len = (baseName as string).length; 35981 while (len > 1 && (baseName as string).charCodeAt(len - 1) >= CharacterCodes._0 && (baseName as string).charCodeAt(len - 1) <= CharacterCodes._9) len--; 35982 const s = (baseName as string).slice(0, len); 35983 for (let index = 1; true; index++) { 35984 const augmentedName = (s + index as __String); 35985 if (!hasTypeParameterByName(typeParameters, augmentedName)) { 35986 return augmentedName; 35987 } 35988 } 35989 } 35990 35991 function getReturnTypeOfSingleNonGenericCallSignature(funcType: Type) { 35992 const signature = getSingleCallSignature(funcType); 35993 if (signature && !signature.typeParameters) { 35994 return getReturnTypeOfSignature(signature); 35995 } 35996 } 35997 35998 function getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr: CallChain) { 35999 const funcType = checkExpression(expr.expression); 36000 const nonOptionalType = getOptionalExpressionType(funcType, expr.expression); 36001 const returnType = getReturnTypeOfSingleNonGenericCallSignature(funcType); 36002 return returnType && propagateOptionalTypeMarker(returnType, expr, nonOptionalType !== funcType); 36003 } 36004 36005 /** 36006 * Returns the type of an expression. Unlike checkExpression, this function is simply concerned 36007 * with computing the type and may not fully check all contained sub-expressions for errors. 36008 */ 36009 function getTypeOfExpression(node: Expression, checkMode?: CheckMode) { 36010 // Don't bother caching types that require no flow analysis and are quick to compute. 36011 const quickType = getQuickTypeOfExpression(node); 36012 if (quickType) { 36013 return quickType; 36014 } 36015 // If a type has been cached for the node, return it. 36016 if (node.flags & NodeFlags.TypeCached && flowTypeCache) { 36017 const cachedType = flowTypeCache[getNodeId(node)]; 36018 if (cachedType) { 36019 return cachedType; 36020 } 36021 } 36022 const startInvocationCount = flowInvocationCount; 36023 const type = checkExpression(node, checkMode); 36024 // If control flow analysis was required to determine the type, it is worth caching. 36025 if (flowInvocationCount !== startInvocationCount) { 36026 const cache = flowTypeCache || (flowTypeCache = []); 36027 cache[getNodeId(node)] = type; 36028 setNodeFlags(node, node.flags | NodeFlags.TypeCached); 36029 } 36030 return type; 36031 } 36032 36033 function getQuickTypeOfExpression(node: Expression) { 36034 let expr = skipParentheses(node, /*excludeJSDocTypeAssertions*/ true); 36035 if (isJSDocTypeAssertion(expr)) { 36036 const type = getJSDocTypeAssertionType(expr); 36037 if (!isConstTypeReference(type)) { 36038 return getTypeFromTypeNode(type); 36039 } 36040 } 36041 expr = skipParentheses(node); 36042 // Optimize for the common case of a call to a function with a single non-generic call 36043 // signature where we can just fetch the return type without checking the arguments. 36044 if (isCallExpression(expr) && expr.expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(expr, /*checkArgumentIsStringLiteralLike*/ true) && !isSymbolOrSymbolForCall(expr)) { 36045 const type = isCallChain(expr) ? getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr) : 36046 getReturnTypeOfSingleNonGenericCallSignature(checkNonNullExpression(expr.expression, CheckMode.SkipEtsComponentBody)); 36047 if (type) { 36048 return type; 36049 } 36050 } 36051 else if (isEtsComponentExpression(expr) && expr.expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(expr, /*checkArgumentIsStringLiteralLike*/ true) && !isSymbolOrSymbolForCall(expr)) { 36052 const type = isCallChain(expr) ? getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr) : 36053 getReturnTypeOfSingleNonGenericCallSignature(checkNonNullExpression(expr.expression, CheckMode.SkipEtsComponentBody)); 36054 if (type) { 36055 return type; 36056 } 36057 } 36058 else if (isAssertionExpression(expr) && !isConstTypeReference(expr.type)) { 36059 return getTypeFromTypeNode((expr as TypeAssertion).type); 36060 } 36061 else if (node.kind === SyntaxKind.NumericLiteral || node.kind === SyntaxKind.StringLiteral || 36062 node.kind === SyntaxKind.TrueKeyword || node.kind === SyntaxKind.FalseKeyword) { 36063 return checkExpression(node); 36064 } 36065 return undefined; 36066 } 36067 36068 /** 36069 * Returns the type of an expression. Unlike checkExpression, this function is simply concerned 36070 * with computing the type and may not fully check all contained sub-expressions for errors. 36071 * It is intended for uses where you know there is no contextual type, 36072 * and requesting the contextual type might cause a circularity or other bad behaviour. 36073 * It sets the contextual type of the node to any before calling getTypeOfExpression. 36074 */ 36075 function getContextFreeTypeOfExpression(node: Expression) { 36076 const links = getNodeLinks(node); 36077 if (links.contextFreeType) { 36078 return links.contextFreeType; 36079 } 36080 const saveContextualType = node.contextualType; 36081 node.contextualType = anyType; 36082 try { 36083 const type = links.contextFreeType = checkExpression(node, CheckMode.SkipContextSensitive); 36084 return type; 36085 } 36086 finally { 36087 // In the event our operation is canceled or some other exception occurs, reset the contextual type 36088 // so that we do not accidentally hold onto an instance of the checker, as a Type created in the services layer 36089 // may hold onto the checker that created it. 36090 node.contextualType = saveContextualType; 36091 } 36092 } 36093 36094 function checkExpression(node: Expression | QualifiedName, checkMode?: CheckMode, forceTuple?: boolean): Type { 36095 tracing?.push(tracing.Phase.Check, "checkExpression", { kind: node.kind, pos: node.pos, end: node.end, path: (node as TracingNode).tracingPath }); 36096 const saveCurrentNode = currentNode; 36097 currentNode = node; 36098 instantiationCount = 0; 36099 const uninstantiatedType = checkExpressionWorker(node, checkMode, forceTuple); 36100 const type = instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, checkMode); 36101 if (isConstEnumObjectType(type)) { 36102 checkConstEnumAccess(node, type); 36103 } 36104 currentNode = saveCurrentNode; 36105 tracing?.pop(); 36106 return type; 36107 } 36108 36109 function checkConstEnumAccess(node: Expression | QualifiedName, type: Type) { 36110 // enum object type for const enums are only permitted in: 36111 // - 'left' in property access 36112 // - 'object' in indexed access 36113 // - target in rhs of import statement 36114 const ok = 36115 (node.parent.kind === SyntaxKind.PropertyAccessExpression && (node.parent as PropertyAccessExpression).expression === node) || 36116 (node.parent.kind === SyntaxKind.ElementAccessExpression && (node.parent as ElementAccessExpression).expression === node) || 36117 ((node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName) && isInRightSideOfImportOrExportAssignment(node as Identifier) || 36118 (node.parent.kind === SyntaxKind.TypeQuery && (node.parent as TypeQueryNode).exprName === node)) || 36119 (node.parent.kind === SyntaxKind.ExportSpecifier); // We allow reexporting const enums 36120 36121 if (!ok) { 36122 error(node, Diagnostics.const_enums_can_only_be_used_in_property_or_index_access_expressions_or_the_right_hand_side_of_an_import_declaration_or_export_assignment_or_type_query); 36123 } 36124 36125 if (compilerOptions.isolatedModules) { 36126 Debug.assert(!!(type.symbol.flags & SymbolFlags.ConstEnum)); 36127 const constEnumDeclaration = type.symbol.valueDeclaration as EnumDeclaration; 36128 if (constEnumDeclaration.flags & NodeFlags.Ambient) { 36129 error(node, Diagnostics.Cannot_access_ambient_const_enums_when_the_isolatedModules_flag_is_provided); 36130 } 36131 } 36132 } 36133 36134 function checkParenthesizedExpression(node: ParenthesizedExpression, checkMode?: CheckMode): Type { 36135 if (hasJSDocNodes(node) && isJSDocTypeAssertion(node)) { 36136 const type = getJSDocTypeAssertionType(node); 36137 return checkAssertionWorker(type, type, node.expression, checkMode); 36138 } 36139 return checkExpression(node.expression, checkMode); 36140 } 36141 36142 function checkExpressionWorker(node: Expression | QualifiedName, checkMode: CheckMode | undefined, forceTuple?: boolean): Type { 36143 const kind = node.kind; 36144 if (cancellationToken) { 36145 // Only bother checking on a few construct kinds. We don't want to be excessively 36146 // hitting the cancellation token on every node we check. 36147 switch (kind) { 36148 case SyntaxKind.ClassExpression: 36149 case SyntaxKind.FunctionExpression: 36150 case SyntaxKind.ArrowFunction: 36151 cancellationToken.throwIfCancellationRequested(); 36152 } 36153 } 36154 switch (kind) { 36155 case SyntaxKind.Identifier: 36156 return checkIdentifier(node as Identifier, checkMode); 36157 case SyntaxKind.PrivateIdentifier: 36158 return checkPrivateIdentifierExpression(node as PrivateIdentifier); 36159 case SyntaxKind.ThisKeyword: 36160 return checkThisExpression(node); 36161 case SyntaxKind.SuperKeyword: 36162 return checkSuperExpression(node); 36163 case SyntaxKind.NullKeyword: 36164 return nullWideningType; 36165 case SyntaxKind.NoSubstitutionTemplateLiteral: 36166 case SyntaxKind.StringLiteral: 36167 return getFreshTypeOfLiteralType(getStringLiteralType((node as StringLiteralLike).text)); 36168 case SyntaxKind.NumericLiteral: 36169 checkGrammarNumericLiteral(node as NumericLiteral); 36170 return getFreshTypeOfLiteralType(getNumberLiteralType(+(node as NumericLiteral).text)); 36171 case SyntaxKind.BigIntLiteral: 36172 checkGrammarBigIntLiteral(node as BigIntLiteral); 36173 return getFreshTypeOfLiteralType(getBigIntLiteralType({ 36174 negative: false, 36175 base10Value: parsePseudoBigInt((node as BigIntLiteral).text) 36176 })); 36177 case SyntaxKind.TrueKeyword: 36178 return trueType; 36179 case SyntaxKind.FalseKeyword: 36180 return falseType; 36181 case SyntaxKind.TemplateExpression: 36182 return checkTemplateExpression(node as TemplateExpression); 36183 case SyntaxKind.RegularExpressionLiteral: 36184 return globalRegExpType; 36185 case SyntaxKind.ArrayLiteralExpression: 36186 return checkArrayLiteral(node as ArrayLiteralExpression, checkMode, forceTuple); 36187 case SyntaxKind.ObjectLiteralExpression: 36188 return checkObjectLiteral(node as ObjectLiteralExpression, checkMode); 36189 case SyntaxKind.PropertyAccessExpression: 36190 return checkPropertyAccessExpression(node as PropertyAccessExpression, checkMode); 36191 case SyntaxKind.QualifiedName: 36192 return checkQualifiedName(node as QualifiedName, checkMode); 36193 case SyntaxKind.ElementAccessExpression: 36194 return checkIndexedAccess(node as ElementAccessExpression, checkMode); 36195 case SyntaxKind.CallExpression: 36196 if ((node as CallExpression).expression.kind === SyntaxKind.ImportKeyword) { 36197 return checkImportCallExpression(node as ImportCall); 36198 } 36199 // falls through 36200 case SyntaxKind.NewExpression: 36201 return checkCallExpression(node as CallExpression, checkMode); 36202 case SyntaxKind.EtsComponentExpression: 36203 const newNode = <EtsComponentExpression>node; 36204 if (newNode.body && newNode.body.statements.length) { 36205 traverseEtsComponentStatements(newNode.body.statements, checkMode); 36206 } 36207 return checkCallExpression(node as EtsComponentExpression, checkMode); 36208 case SyntaxKind.TaggedTemplateExpression: 36209 return checkTaggedTemplateExpression(node as TaggedTemplateExpression); 36210 case SyntaxKind.ParenthesizedExpression: 36211 return checkParenthesizedExpression(node as ParenthesizedExpression, checkMode); 36212 case SyntaxKind.ClassExpression: 36213 return checkClassExpression(node as ClassExpression); 36214 case SyntaxKind.FunctionExpression: 36215 case SyntaxKind.ArrowFunction: 36216 return checkFunctionExpressionOrObjectLiteralMethod(node as FunctionExpression | ArrowFunction, checkMode); 36217 case SyntaxKind.TypeOfExpression: 36218 return checkTypeOfExpression(node as TypeOfExpression); 36219 case SyntaxKind.TypeAssertionExpression: 36220 case SyntaxKind.AsExpression: 36221 return checkAssertion(node as AssertionExpression); 36222 case SyntaxKind.NonNullExpression: 36223 return checkNonNullAssertion(node as NonNullExpression); 36224 case SyntaxKind.ExpressionWithTypeArguments: 36225 return checkExpressionWithTypeArguments(node as ExpressionWithTypeArguments); 36226 case SyntaxKind.SatisfiesExpression: 36227 return checkSatisfiesExpression(node as SatisfiesExpression); 36228 case SyntaxKind.MetaProperty: 36229 return checkMetaProperty(node as MetaProperty); 36230 case SyntaxKind.DeleteExpression: 36231 return checkDeleteExpression(node as DeleteExpression); 36232 case SyntaxKind.VoidExpression: 36233 return checkVoidExpression(node as VoidExpression); 36234 case SyntaxKind.AwaitExpression: 36235 return checkAwaitExpression(node as AwaitExpression); 36236 case SyntaxKind.PrefixUnaryExpression: 36237 return checkPrefixUnaryExpression(node as PrefixUnaryExpression); 36238 case SyntaxKind.PostfixUnaryExpression: 36239 return checkPostfixUnaryExpression(node as PostfixUnaryExpression); 36240 case SyntaxKind.BinaryExpression: 36241 return checkBinaryExpression(node as BinaryExpression, checkMode); 36242 case SyntaxKind.ConditionalExpression: 36243 return checkConditionalExpression(node as ConditionalExpression, checkMode); 36244 case SyntaxKind.SpreadElement: 36245 return checkSpreadExpression(node as SpreadElement, checkMode); 36246 case SyntaxKind.OmittedExpression: 36247 return undefinedWideningType; 36248 case SyntaxKind.YieldExpression: 36249 return checkYieldExpression(node as YieldExpression); 36250 case SyntaxKind.SyntheticExpression: 36251 return checkSyntheticExpression(node as SyntheticExpression); 36252 case SyntaxKind.JsxExpression: 36253 return checkJsxExpression(node as JsxExpression, checkMode); 36254 case SyntaxKind.JsxElement: 36255 return checkJsxElement(node as JsxElement, checkMode); 36256 case SyntaxKind.JsxSelfClosingElement: 36257 return checkJsxSelfClosingElement(node as JsxSelfClosingElement, checkMode); 36258 case SyntaxKind.JsxFragment: 36259 return checkJsxFragment(node as JsxFragment); 36260 case SyntaxKind.JsxAttributes: 36261 return checkJsxAttributes(node as JsxAttributes, checkMode); 36262 case SyntaxKind.JsxOpeningElement: 36263 Debug.fail("Shouldn't ever directly check a JsxOpeningElement"); 36264 } 36265 return errorType; 36266 } 36267 36268 // Traverse Ets Component 36269 function checkIfEtsComponent(node: IfStatement, checkMode: CheckMode | undefined): void { 36270 checkIfChildComponent(node, checkMode); 36271 if (node.thenStatement && isBlock(node.thenStatement) && node.thenStatement.statements) { 36272 traverseEtsComponentStatements(node.thenStatement.statements, checkMode); 36273 } 36274 if (node.elseStatement) { 36275 if (isIfStatement(node.elseStatement)) { 36276 checkIfEtsComponent(node.elseStatement, checkMode); 36277 } 36278 if (isBlock(node.elseStatement) && node.elseStatement.statements) { 36279 traverseEtsComponentStatements(node.elseStatement.statements, checkMode); 36280 } 36281 } 36282 } 36283 function checkIfChildComponent(node: Node, checkMode: CheckMode | undefined): void { 36284 if ((<ExpressionStatement>node).expression) { 36285 checkExpressionWorker((<ExpressionStatement>node).expression, checkMode); 36286 } 36287 // @ts-ignore 36288 node.getChildren().forEach((item: Node) => checkIfChildComponent(item, checkMode)); 36289 } 36290 function traverseEtsComponentStatements(statements: NodeArray<Statement>, checkMode: CheckMode | undefined): void { 36291 if (statements.length) { 36292 statements.forEach(item => { 36293 if (isIfStatement(item)) { 36294 checkIfEtsComponent(item, checkMode); 36295 } 36296 else if ((<ExpressionStatement>item).expression) { 36297 checkExpressionWorker((<ExpressionStatement>item).expression, checkMode); 36298 } 36299 }); 36300 } 36301 } 36302 36303 // DECLARATION AND STATEMENT TYPE CHECKING 36304 36305 function checkTypeParameter(node: TypeParameterDeclaration) { 36306 // Grammar Checking 36307 checkGrammarModifiers(node); 36308 if (node.expression) { 36309 grammarErrorOnFirstToken(node.expression, Diagnostics.Type_expected); 36310 } 36311 36312 checkSourceElement(node.constraint); 36313 checkSourceElement(node.default); 36314 const typeParameter = getDeclaredTypeOfTypeParameter(getSymbolOfNode(node)); 36315 // Resolve base constraint to reveal circularity errors 36316 getBaseConstraintOfType(typeParameter); 36317 if (!hasNonCircularTypeParameterDefault(typeParameter)) { 36318 error(node.default, Diagnostics.Type_parameter_0_has_a_circular_default, typeToString(typeParameter)); 36319 } 36320 const constraintType = getConstraintOfTypeParameter(typeParameter); 36321 const defaultType = getDefaultFromTypeParameter(typeParameter); 36322 if (constraintType && defaultType) { 36323 checkTypeAssignableTo(defaultType, getTypeWithThisArgument(instantiateType(constraintType, makeUnaryTypeMapper(typeParameter, defaultType)), defaultType), node.default, Diagnostics.Type_0_does_not_satisfy_the_constraint_1); 36324 } 36325 checkNodeDeferred(node); 36326 addLazyDiagnostic(() => checkTypeNameIsReserved(node.name, Diagnostics.Type_parameter_name_cannot_be_0)); 36327 } 36328 36329 function checkTypeParameterDeferred(node: TypeParameterDeclaration) { 36330 if (isInterfaceDeclaration(node.parent) || isClassLike(node.parent) || isTypeAliasDeclaration(node.parent)) { 36331 const typeParameter = getDeclaredTypeOfTypeParameter(getSymbolOfNode(node)); 36332 const modifiers = getVarianceModifiers(typeParameter); 36333 if (modifiers) { 36334 const symbol = getSymbolOfNode(node.parent); 36335 if (isTypeAliasDeclaration(node.parent) && !(getObjectFlags(getDeclaredTypeOfSymbol(symbol)) & (ObjectFlags.Anonymous | ObjectFlags.Mapped))) { 36336 error(node, Diagnostics.Variance_annotations_are_only_supported_in_type_aliases_for_object_function_constructor_and_mapped_types); 36337 } 36338 else if (modifiers === ModifierFlags.In || modifiers === ModifierFlags.Out) { 36339 tracing?.push(tracing.Phase.CheckTypes, "checkTypeParameterDeferred", { parent: getTypeId(getDeclaredTypeOfSymbol(symbol)), id: getTypeId(typeParameter) }); 36340 const source = createMarkerType(symbol, typeParameter, modifiers === ModifierFlags.Out ? markerSubTypeForCheck : markerSuperTypeForCheck); 36341 const target = createMarkerType(symbol, typeParameter, modifiers === ModifierFlags.Out ? markerSuperTypeForCheck : markerSubTypeForCheck); 36342 const saveVarianceTypeParameter = typeParameter; 36343 varianceTypeParameter = typeParameter; 36344 checkTypeAssignableTo(source, target, node, Diagnostics.Type_0_is_not_assignable_to_type_1_as_implied_by_variance_annotation); 36345 varianceTypeParameter = saveVarianceTypeParameter; 36346 tracing?.pop(); 36347 } 36348 } 36349 } 36350 } 36351 36352 function checkParameter(node: ParameterDeclaration) { 36353 // Grammar checking 36354 // It is a SyntaxError if the Identifier "eval" or the Identifier "arguments" occurs as the 36355 // Identifier in a PropertySetParameterList of a PropertyAssignment that is contained in strict code 36356 // or if its FunctionBody is strict code(11.1.5). 36357 checkGrammarDecoratorsAndModifiers(node); 36358 36359 checkVariableLikeDeclaration(node); 36360 const func = getContainingFunction(node)!; 36361 if (hasSyntacticModifier(node, ModifierFlags.ParameterPropertyModifier)) { 36362 if (!(func.kind === SyntaxKind.Constructor && nodeIsPresent(func.body))) { 36363 error(node, Diagnostics.A_parameter_property_is_only_allowed_in_a_constructor_implementation); 36364 } 36365 if (func.kind === SyntaxKind.Constructor && isIdentifier(node.name) && node.name.escapedText === "constructor") { 36366 error(node.name, Diagnostics.constructor_cannot_be_used_as_a_parameter_property_name); 36367 } 36368 } 36369 if ((node.questionToken || isJSDocOptionalParameter(node)) && isBindingPattern(node.name) && (func as FunctionLikeDeclaration).body) { 36370 error(node, Diagnostics.A_binding_pattern_parameter_cannot_be_optional_in_an_implementation_signature); 36371 } 36372 if (node.name && isIdentifier(node.name) && (node.name.escapedText === "this" || node.name.escapedText === "new")) { 36373 if (func.parameters.indexOf(node) !== 0) { 36374 error(node, Diagnostics.A_0_parameter_must_be_the_first_parameter, node.name.escapedText as string); 36375 } 36376 if (func.kind === SyntaxKind.Constructor || func.kind === SyntaxKind.ConstructSignature || func.kind === SyntaxKind.ConstructorType) { 36377 error(node, Diagnostics.A_constructor_cannot_have_a_this_parameter); 36378 } 36379 if (func.kind === SyntaxKind.ArrowFunction) { 36380 error(node, Diagnostics.An_arrow_function_cannot_have_a_this_parameter); 36381 } 36382 if (func.kind === SyntaxKind.GetAccessor || func.kind === SyntaxKind.SetAccessor) { 36383 error(node, Diagnostics.get_and_set_accessors_cannot_declare_this_parameters); 36384 } 36385 } 36386 36387 // Only check rest parameter type if it's not a binding pattern. Since binding patterns are 36388 // not allowed in a rest parameter, we already have an error from checkGrammarParameterList. 36389 if (node.dotDotDotToken && !isBindingPattern(node.name) && !isTypeAssignableTo(getReducedType(getTypeOfSymbol(node.symbol)), anyReadonlyArrayType)) { 36390 error(node, Diagnostics.A_rest_parameter_must_be_of_an_array_type); 36391 } 36392 } 36393 36394 function checkTypePredicate(node: TypePredicateNode): void { 36395 const parent = getTypePredicateParent(node); 36396 if (!parent) { 36397 // The parent must not be valid. 36398 error(node, Diagnostics.A_type_predicate_is_only_allowed_in_return_type_position_for_functions_and_methods); 36399 return; 36400 } 36401 36402 const signature = getSignatureFromDeclaration(parent); 36403 const typePredicate = getTypePredicateOfSignature(signature); 36404 if (!typePredicate) { 36405 return; 36406 } 36407 36408 checkSourceElement(node.type); 36409 36410 const { parameterName } = node; 36411 if (typePredicate.kind === TypePredicateKind.This || typePredicate.kind === TypePredicateKind.AssertsThis) { 36412 getTypeFromThisTypeNode(parameterName as ThisTypeNode); 36413 } 36414 else { 36415 if (typePredicate.parameterIndex >= 0) { 36416 if (signatureHasRestParameter(signature) && typePredicate.parameterIndex === signature.parameters.length - 1) { 36417 error(parameterName, Diagnostics.A_type_predicate_cannot_reference_a_rest_parameter); 36418 } 36419 else { 36420 if (typePredicate.type) { 36421 const leadingError = () => chainDiagnosticMessages(/*details*/ undefined, Diagnostics.A_type_predicate_s_type_must_be_assignable_to_its_parameter_s_type); 36422 checkTypeAssignableTo(typePredicate.type, 36423 getTypeOfSymbol(signature.parameters[typePredicate.parameterIndex]), 36424 node.type, 36425 /*headMessage*/ undefined, 36426 leadingError); 36427 } 36428 } 36429 } 36430 else if (parameterName) { 36431 let hasReportedError = false; 36432 for (const { name } of parent.parameters) { 36433 if (isBindingPattern(name) && 36434 checkIfTypePredicateVariableIsDeclaredInBindingPattern(name, parameterName, typePredicate.parameterName)) { 36435 hasReportedError = true; 36436 break; 36437 } 36438 } 36439 if (!hasReportedError) { 36440 error(node.parameterName, Diagnostics.Cannot_find_parameter_0, typePredicate.parameterName); 36441 } 36442 } 36443 } 36444 } 36445 36446 function getTypePredicateParent(node: Node): SignatureDeclaration | undefined { 36447 switch (node.parent.kind) { 36448 case SyntaxKind.ArrowFunction: 36449 case SyntaxKind.CallSignature: 36450 case SyntaxKind.FunctionDeclaration: 36451 case SyntaxKind.FunctionExpression: 36452 case SyntaxKind.FunctionType: 36453 case SyntaxKind.MethodDeclaration: 36454 case SyntaxKind.MethodSignature: 36455 const parent = node.parent as SignatureDeclaration; 36456 if (node === parent.type) { 36457 return parent; 36458 } 36459 } 36460 } 36461 36462 function checkIfTypePredicateVariableIsDeclaredInBindingPattern( 36463 pattern: BindingPattern, 36464 predicateVariableNode: Node, 36465 predicateVariableName: string) { 36466 for (const element of pattern.elements) { 36467 if (isOmittedExpression(element)) { 36468 continue; 36469 } 36470 36471 const name = element.name; 36472 if (name.kind === SyntaxKind.Identifier && name.escapedText === predicateVariableName) { 36473 error(predicateVariableNode, 36474 Diagnostics.A_type_predicate_cannot_reference_element_0_in_a_binding_pattern, 36475 predicateVariableName); 36476 return true; 36477 } 36478 else if (name.kind === SyntaxKind.ArrayBindingPattern || name.kind === SyntaxKind.ObjectBindingPattern) { 36479 if (checkIfTypePredicateVariableIsDeclaredInBindingPattern( 36480 name, 36481 predicateVariableNode, 36482 predicateVariableName)) { 36483 return true; 36484 } 36485 } 36486 } 36487 } 36488 36489 function checkSignatureDeclaration(node: SignatureDeclaration) { 36490 // Grammar checking 36491 if (node.kind === SyntaxKind.IndexSignature) { 36492 checkGrammarIndexSignature(node); 36493 } 36494 // TODO (yuisu): Remove this check in else-if when SyntaxKind.Construct is moved and ambient context is handled 36495 else if (node.kind === SyntaxKind.FunctionType || node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.ConstructorType || 36496 node.kind === SyntaxKind.CallSignature || node.kind === SyntaxKind.Constructor || 36497 node.kind === SyntaxKind.ConstructSignature) { 36498 checkGrammarFunctionLikeDeclaration(node as FunctionLikeDeclaration); 36499 } 36500 36501 const functionFlags = getFunctionFlags(node as FunctionLikeDeclaration); 36502 if (!(functionFlags & FunctionFlags.Invalid)) { 36503 // Async generators prior to ESNext require the __await and __asyncGenerator helpers 36504 if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.AsyncGenerator && languageVersion < ScriptTarget.ESNext) { 36505 checkExternalEmitHelpers(node, ExternalEmitHelpers.AsyncGeneratorIncludes); 36506 } 36507 36508 // Async functions prior to ES2017 require the __awaiter helper 36509 if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async && languageVersion < ScriptTarget.ES2017) { 36510 checkExternalEmitHelpers(node, ExternalEmitHelpers.Awaiter); 36511 } 36512 36513 // Generator functions, Async functions, and Async Generator functions prior to 36514 // ES2015 require the __generator helper 36515 if ((functionFlags & FunctionFlags.AsyncGenerator) !== FunctionFlags.Normal && languageVersion < ScriptTarget.ES2015) { 36516 checkExternalEmitHelpers(node, ExternalEmitHelpers.Generator); 36517 } 36518 } 36519 36520 checkTypeParameters(getEffectiveTypeParameterDeclarations(node)); 36521 checkUnmatchedJSDocParameters(node); 36522 36523 forEach(node.parameters, checkParameter); 36524 36525 // TODO(rbuckton): Should we start checking JSDoc types? 36526 if (node.type) { 36527 checkSourceElement(node.type); 36528 } 36529 36530 addLazyDiagnostic(checkSignatureDeclarationDiagnostics); 36531 36532 function checkSignatureDeclarationDiagnostics() { 36533 checkCollisionWithArgumentsInGeneratedCode(node); 36534 const returnTypeNode = getEffectiveReturnTypeNode(node); 36535 if (noImplicitAny && !returnTypeNode) { 36536 switch (node.kind) { 36537 case SyntaxKind.ConstructSignature: 36538 error(node, Diagnostics.Construct_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type); 36539 break; 36540 case SyntaxKind.CallSignature: 36541 error(node, Diagnostics.Call_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type); 36542 break; 36543 } 36544 } 36545 36546 if (returnTypeNode) { 36547 const functionFlags = getFunctionFlags(node as FunctionDeclaration); 36548 if ((functionFlags & (FunctionFlags.Invalid | FunctionFlags.Generator)) === FunctionFlags.Generator) { 36549 const returnType = getTypeFromTypeNode(returnTypeNode); 36550 if (returnType === voidType) { 36551 error(returnTypeNode, Diagnostics.A_generator_cannot_have_a_void_type_annotation); 36552 } 36553 else { 36554 // Naively, one could check that Generator<any, any, any> is assignable to the return type annotation. 36555 // However, that would not catch the error in the following case. 36556 // 36557 // interface BadGenerator extends Iterable<number>, Iterator<string> { } 36558 // function* g(): BadGenerator { } // Iterable and Iterator have different types! 36559 // 36560 const generatorYieldType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Yield, returnType, (functionFlags & FunctionFlags.Async) !== 0) || anyType; 36561 const generatorReturnType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, returnType, (functionFlags & FunctionFlags.Async) !== 0) || generatorYieldType; 36562 const generatorNextType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Next, returnType, (functionFlags & FunctionFlags.Async) !== 0) || unknownType; 36563 const generatorInstantiation = createGeneratorReturnType(generatorYieldType, generatorReturnType, generatorNextType, !!(functionFlags & FunctionFlags.Async)); 36564 checkTypeAssignableTo(generatorInstantiation, returnType, returnTypeNode); 36565 } 36566 } 36567 else if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async) { 36568 checkAsyncFunctionReturnType(node as FunctionLikeDeclaration, returnTypeNode); 36569 } 36570 } 36571 if (node.kind !== SyntaxKind.IndexSignature && node.kind !== SyntaxKind.JSDocFunctionType) { 36572 registerForUnusedIdentifiersCheck(node); 36573 } 36574 } 36575 } 36576 36577 function checkClassForDuplicateDeclarations(node: ClassLikeDeclaration | AnnotationDeclaration) { 36578 const instanceNames = new Map<__String, DeclarationMeaning>(); 36579 const staticNames = new Map<__String, DeclarationMeaning>(); 36580 // instance and static private identifiers share the same scope 36581 const privateIdentifiers = new Map<__String, DeclarationMeaning>(); 36582 for (const member of node.members) { 36583 if (member.kind === SyntaxKind.Constructor) { 36584 for (const param of (member as ConstructorDeclaration).parameters) { 36585 if (isParameterPropertyDeclaration(param, member) && !isBindingPattern(param.name)) { 36586 addName(instanceNames, param.name, param.name.escapedText, DeclarationMeaning.GetOrSetAccessor); 36587 } 36588 } 36589 } 36590 else { 36591 const isStaticMember = isStatic(member); 36592 const name = member.name; 36593 if (!name) { 36594 continue; 36595 } 36596 const isPrivate = isPrivateIdentifier(name); 36597 const privateStaticFlags = isPrivate && isStaticMember ? DeclarationMeaning.PrivateStatic : 0; 36598 const names = 36599 isPrivate ? privateIdentifiers : 36600 isStaticMember ? staticNames : 36601 instanceNames; 36602 36603 const memberName = name && getPropertyNameForPropertyNameNode(name); 36604 if (memberName) { 36605 switch (member.kind) { 36606 case SyntaxKind.GetAccessor: 36607 addName(names, name, memberName, DeclarationMeaning.GetAccessor | privateStaticFlags); 36608 break; 36609 36610 case SyntaxKind.SetAccessor: 36611 addName(names, name, memberName, DeclarationMeaning.SetAccessor | privateStaticFlags); 36612 break; 36613 36614 case SyntaxKind.PropertyDeclaration: 36615 addName(names, name, memberName, DeclarationMeaning.GetOrSetAccessor | privateStaticFlags); 36616 break; 36617 36618 case SyntaxKind.AnnotationPropertyDeclaration: 36619 addName(names, name, memberName, DeclarationMeaning.GetOrSetAccessor | privateStaticFlags); 36620 break; 36621 36622 case SyntaxKind.MethodDeclaration: 36623 addName(names, name, memberName, DeclarationMeaning.Method | privateStaticFlags); 36624 break; 36625 } 36626 } 36627 } 36628 } 36629 36630 function addName(names: UnderscoreEscapedMap<DeclarationMeaning>, location: Node, name: __String, meaning: DeclarationMeaning) { 36631 const prev = names.get(name); 36632 if (prev) { 36633 // For private identifiers, do not allow mixing of static and instance members with the same name 36634 if ((prev & DeclarationMeaning.PrivateStatic) !== (meaning & DeclarationMeaning.PrivateStatic)) { 36635 error(location, Diagnostics.Duplicate_identifier_0_Static_and_instance_elements_cannot_share_the_same_private_name, getTextOfNode(location)); 36636 } 36637 else { 36638 const prevIsMethod = !!(prev & DeclarationMeaning.Method); 36639 const isMethod = !!(meaning & DeclarationMeaning.Method); 36640 if (prevIsMethod || isMethod) { 36641 if (prevIsMethod !== isMethod) { 36642 error(location, Diagnostics.Duplicate_identifier_0, getTextOfNode(location)); 36643 } 36644 // If this is a method/method duplication is might be an overload, so this will be handled when overloads are considered 36645 } 36646 else if (prev & meaning & ~DeclarationMeaning.PrivateStatic) { 36647 error(location, Diagnostics.Duplicate_identifier_0, getTextOfNode(location)); 36648 } 36649 else { 36650 names.set(name, prev | meaning); 36651 } 36652 } 36653 } 36654 else { 36655 names.set(name, meaning); 36656 } 36657 } 36658 } 36659 36660 /** 36661 * Static members being set on a constructor function may conflict with built-in properties 36662 * of Function. Esp. in ECMAScript 5 there are non-configurable and non-writable 36663 * built-in properties. This check issues a transpile error when a class has a static 36664 * member with the same name as a non-writable built-in property. 36665 * 36666 * @see http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.3 36667 * @see http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.5 36668 * @see http://www.ecma-international.org/ecma-262/6.0/#sec-properties-of-the-function-constructor 36669 * @see http://www.ecma-international.org/ecma-262/6.0/#sec-function-instances 36670 */ 36671 function checkClassForStaticPropertyNameConflicts(node: ClassLikeDeclaration) { 36672 for (const member of node.members) { 36673 const memberNameNode = member.name; 36674 const isStaticMember = isStatic(member); 36675 if (isStaticMember && memberNameNode) { 36676 const memberName = getPropertyNameForPropertyNameNode(memberNameNode); 36677 switch (memberName) { 36678 case "name": 36679 case "length": 36680 case "caller": 36681 case "arguments": 36682 case "prototype": 36683 const message = Diagnostics.Static_property_0_conflicts_with_built_in_property_Function_0_of_constructor_function_1; 36684 const className = getNameOfSymbolAsWritten(getSymbolOfNode(node)); 36685 error(memberNameNode, message, memberName, className); 36686 break; 36687 } 36688 } 36689 } 36690 } 36691 36692 function checkObjectTypeForDuplicateDeclarations(node: TypeLiteralNode | InterfaceDeclaration) { 36693 const names = new Map<string, boolean>(); 36694 for (const member of node.members) { 36695 if (member.kind === SyntaxKind.PropertySignature) { 36696 let memberName: string; 36697 const name = member.name!; 36698 switch (name.kind) { 36699 case SyntaxKind.StringLiteral: 36700 case SyntaxKind.NumericLiteral: 36701 memberName = name.text; 36702 break; 36703 case SyntaxKind.Identifier: 36704 memberName = idText(name); 36705 break; 36706 default: 36707 continue; 36708 } 36709 36710 if (names.get(memberName)) { 36711 error(getNameOfDeclaration(member.symbol.valueDeclaration), Diagnostics.Duplicate_identifier_0, memberName); 36712 error(member.name, Diagnostics.Duplicate_identifier_0, memberName); 36713 } 36714 else { 36715 names.set(memberName, true); 36716 } 36717 } 36718 } 36719 } 36720 36721 function checkTypeForDuplicateIndexSignatures(node: Node) { 36722 if (node.kind === SyntaxKind.InterfaceDeclaration) { 36723 const nodeSymbol = getSymbolOfNode(node as InterfaceDeclaration); 36724 // in case of merging interface declaration it is possible that we'll enter this check procedure several times for every declaration 36725 // to prevent this run check only for the first declaration of a given kind 36726 if (nodeSymbol.declarations && nodeSymbol.declarations.length > 0 && nodeSymbol.declarations[0] !== node) { 36727 return; 36728 } 36729 } 36730 36731 // TypeScript 1.0 spec (April 2014) 36732 // 3.7.4: An object type can contain at most one string index signature and one numeric index signature. 36733 // 8.5: A class declaration can have at most one string index member declaration and one numeric index member declaration 36734 const indexSymbol = getIndexSymbol(getSymbolOfNode(node)!); 36735 if (indexSymbol?.declarations) { 36736 const indexSignatureMap = new Map<TypeId, { type: Type, declarations: IndexSignatureDeclaration[] }>(); 36737 for (const declaration of (indexSymbol.declarations as IndexSignatureDeclaration[])) { 36738 if (declaration.parameters.length === 1 && declaration.parameters[0].type) { 36739 forEachType(getTypeFromTypeNode(declaration.parameters[0].type), type => { 36740 const entry = indexSignatureMap.get(getTypeId(type)); 36741 if (entry) { 36742 entry.declarations.push(declaration); 36743 } 36744 else { 36745 indexSignatureMap.set(getTypeId(type), { type, declarations: [declaration] }); 36746 } 36747 }); 36748 } 36749 } 36750 indexSignatureMap.forEach(entry => { 36751 if (entry.declarations.length > 1) { 36752 for (const declaration of entry.declarations) { 36753 error(declaration, Diagnostics.Duplicate_index_signature_for_type_0, typeToString(entry.type)); 36754 } 36755 } 36756 }); 36757 } 36758 } 36759 36760 function isAllowedAnnotationPropertyEnumType(type: Type): boolean { 36761 // Non-constant enums are prohibited 36762 if (!type.symbol || !isConstEnumSymbol(type.symbol)) { 36763 return false; 36764 } 36765 // Mixing of numbers and strings is prohibited 36766 if (type.symbol.declarations) { 36767 for (const decl of type.symbol.declarations) { 36768 if (decl.kind === SyntaxKind.EnumDeclaration) { 36769 const members = (decl as EnumDeclaration).members; 36770 for (let i = 0; i < members.length; ++i) { 36771 if (i > 1 && typeof getConstantValue(members[i - 1]) !== typeof getConstantValue(members[i])) { 36772 return false; 36773 } 36774 } 36775 } 36776 } 36777 } 36778 return true; 36779 } 36780 36781 function isAllowedAnnotationPropertyType(type: Type): boolean { 36782 if (type === numberType || 36783 type === booleanType || 36784 type === stringType || 36785 isAllowedAnnotationPropertyEnumType(type)) { 36786 return true; 36787 } 36788 else if (isArrayType(type)) { 36789 const elemType = getElementTypeOfArrayType(type); 36790 if (!elemType) { 36791 return false; 36792 } 36793 return isAllowedAnnotationPropertyType(elemType); 36794 } 36795 return false; 36796 } 36797 36798 function annotationEvaluatedValueToExpr(initVal: AnnotationConstantExpressionType, initValType: Type): Expression | undefined { 36799 if (initVal === undefined || initValType === errorType) { 36800 return undefined; 36801 } 36802 if (isArrayType(initValType) && !Array.isArray(initVal)) { 36803 return undefined; 36804 } 36805 if (typeof initVal === "number") { 36806 return factory.createNumericLiteral(initVal); 36807 } 36808 else if (typeof initVal === "string") { 36809 return factory.createStringLiteral(initVal); 36810 } 36811 else if (initValType === booleanType && typeof initVal === "boolean") { 36812 return (initVal) ? factory.createTrue() : factory.createFalse(); 36813 } 36814 else if (isArrayType(initValType)) { 36815 Debug.assert(Array.isArray(initVal)); 36816 const elemType = (initValType as GenericType).resolvedTypeArguments![0]; 36817 // It is a special case since we need to store information about array element type, 36818 // when array literal is empty. For example, 36819 // '[]' -- have no information about element type 36820 // 'new Array<T>()' -- is valid expression with explicit type annotation and the same semantics with '[]' 36821 if (initVal.length === 0) { 36822 if (isArrayType(elemType)) { 36823 return factory.createArrayLiteralExpression([annotationEvaluatedValueToExpr(initVal, elemType)!]); 36824 } 36825 const args = new Array<Expression>(); 36826 // We add the argument '1' just for indicating that enum has numeric members 36827 // '3' - string members 36828 if (elemType.symbol && isConstEnumSymbol(elemType.symbol)) { 36829 const enumMembers = (elemType.symbol.declarations![0] as EnumDeclaration).members; 36830 if (enumMembers.length === 0 || typeof getConstantValue(enumMembers[0]) === "number") { 36831 args.push(factory.createNumericLiteral(1)); 36832 } 36833 else { 36834 args.push(factory.createNumericLiteral(3)); 36835 } 36836 } 36837 return factory.createNewExpression( 36838 factory.createIdentifier("Array"), 36839 [nodeBuilder.typeToTypeNode(elemType) as TypeNode], 36840 args); 36841 } 36842 const result = new Array<Expression>(initVal.length); 36843 for (let i = 0; i < initVal.length; ++i) { 36844 result[i] = annotationEvaluatedValueToExpr(initVal[i], elemType)!; 36845 if (result[i] === undefined){ 36846 return undefined; 36847 } 36848 } 36849 return factory.createArrayLiteralExpression(result); 36850 } 36851 } 36852 36853 function evaluateAnnotationPropertyConstantExpression(expr: Expression): AnnotationConstantExpressionType | undefined { 36854 switch (expr.kind) { 36855 case SyntaxKind.PrefixUnaryExpression: 36856 const value = evaluateAnnotationPropertyConstantExpression((expr as PrefixUnaryExpression).operand); 36857 if (typeof value === "number" || typeof value === "string" || typeof value === "boolean") { 36858 switch ((expr as PrefixUnaryExpression).operator) { 36859 case SyntaxKind.ExclamationToken: return !value; 36860 } 36861 } 36862 if (typeof value === "number") { 36863 switch ((expr as PrefixUnaryExpression).operator) { 36864 case SyntaxKind.PlusToken: return value; 36865 case SyntaxKind.MinusToken: return -value; 36866 case SyntaxKind.TildeToken: return ~value; 36867 } 36868 } 36869 break; 36870 case SyntaxKind.BinaryExpression: 36871 const left = evaluateAnnotationPropertyConstantExpression((expr as BinaryExpression).left); 36872 const right = evaluateAnnotationPropertyConstantExpression((expr as BinaryExpression).right); 36873 // `number` binop `number` 36874 // `string` binop `string` 36875 // `boolean` binop `boolean` 36876 if (left !== undefined && right !== undefined && typeof left === typeof right) { 36877 switch ((expr as BinaryExpression).operatorToken.kind) { 36878 case SyntaxKind.LessThanToken: return left < right; 36879 case SyntaxKind.LessThanEqualsToken: return left <= right; 36880 case SyntaxKind.GreaterThanToken: return left > right; 36881 case SyntaxKind.GreaterThanEqualsToken: return left >= right; 36882 case SyntaxKind.EqualsEqualsEqualsToken: return left === right; 36883 case SyntaxKind.ExclamationEqualsEqualsToken: return left !== right; 36884 case SyntaxKind.EqualsEqualsToken: return left == right; 36885 case SyntaxKind.ExclamationEqualsToken: return left != right; 36886 case SyntaxKind.AmpersandAmpersandToken: return left && right; 36887 case SyntaxKind.BarBarToken: return left || right; 36888 } 36889 } 36890 // `number` binop (`number` | `string` | `boolean`) 36891 // `string` binop (`number` | `string` | `boolean`) 36892 // `boolean` binop (`number` | `string` | `boolean`) 36893 if ((typeof left === "number" || typeof left === "string" || typeof left === "boolean") && 36894 (typeof right === "number" || typeof right === "string" || typeof right === "boolean")) { 36895 switch ((expr as BinaryExpression).operatorToken.kind) { 36896 case SyntaxKind.AmpersandAmpersandToken: return left && right; 36897 case SyntaxKind.BarBarToken: return left || right; 36898 } 36899 } 36900 if (typeof left === "number" && typeof right === "number") { 36901 switch ((expr as BinaryExpression).operatorToken.kind) { 36902 case SyntaxKind.BarToken: return left | right; 36903 case SyntaxKind.AmpersandToken: return left & right; 36904 case SyntaxKind.GreaterThanGreaterThanToken: return left >> right; 36905 case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: return left >>> right; 36906 case SyntaxKind.LessThanLessThanToken: return left << right; 36907 case SyntaxKind.CaretToken: return left ^ right; 36908 case SyntaxKind.AsteriskToken: return left * right; 36909 case SyntaxKind.SlashToken: return left / right; 36910 case SyntaxKind.PlusToken: return left + right; 36911 case SyntaxKind.MinusToken: return left - right; 36912 case SyntaxKind.PercentToken: return left % right; 36913 case SyntaxKind.AsteriskAsteriskToken: return left ** right; 36914 } 36915 } 36916 else if (typeof left === "string" && typeof right === "string") { 36917 switch ((expr as BinaryExpression).operatorToken.kind) { 36918 case SyntaxKind.PlusToken: return left + right; 36919 } 36920 } 36921 break; 36922 case SyntaxKind.ArrayLiteralExpression: 36923 const elements = (expr as ArrayLiteralExpression).elements; 36924 const result = new Array<AnnotationConstantExpressionType>(elements.length); 36925 for (let i = 0; i < elements.length; ++i) { 36926 const elem = evaluateAnnotationPropertyConstantExpression(elements[i]); 36927 if (elem === undefined) { 36928 return undefined; 36929 } 36930 if (i > 0 && (typeof result[i - 1] !== typeof elem)) { 36931 return undefined; 36932 } 36933 result[i] = elem; 36934 } 36935 return result; 36936 case SyntaxKind.TrueKeyword: 36937 return true; 36938 case SyntaxKind.FalseKeyword: 36939 return false; 36940 case SyntaxKind.StringLiteral: 36941 case SyntaxKind.NoSubstitutionTemplateLiteral: 36942 return (expr as StringLiteralLike).text; 36943 case SyntaxKind.NumericLiteral: 36944 checkGrammarNumericLiteral(expr as NumericLiteral); 36945 return +(expr as NumericLiteral).text; 36946 case SyntaxKind.ParenthesizedExpression: 36947 return evaluateAnnotationPropertyConstantExpression((expr as ParenthesizedExpression).expression); 36948 case SyntaxKind.Identifier: 36949 if (isInfinityOrNaNString((expr as Identifier).escapedText)) { 36950 return +((expr as Identifier).escapedText); 36951 } 36952 const symbol = getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(expr as Identifier)); 36953 // Only `const a = ...` like are prohibited 36954 if (!symbol || !isConstVariable(symbol)) { 36955 return undefined; 36956 } 36957 // Initializer must be present and able to be evaluated as constant expression 36958 if (symbol.valueDeclaration && hasOnlyExpressionInitializer(symbol.valueDeclaration) && symbol.valueDeclaration.initializer) { 36959 return evaluateAnnotationPropertyConstantExpression(symbol.valueDeclaration.initializer); 36960 } 36961 break; 36962 case SyntaxKind.PropertyAccessExpression: 36963 if (isConstantMemberAccess(expr)) { 36964 return getConstantValue(expr); 36965 } 36966 break; 36967 } 36968 return undefined; 36969 } 36970 36971 function checkPropertyDeclaration(node: PropertyDeclaration | PropertySignature | AnnotationPropertyDeclaration) { 36972 // Grammar checking 36973 if (!isAnnotationPropertyDeclaration(node) && !checkGrammarDecoratorsAndModifiers(node) && !checkGrammarProperty(node)) checkGrammarComputedPropertyName(node.name); 36974 if (isAnnotationPropertyDeclaration(node)) { 36975 if (!node.type && !node.initializer) { 36976 error(node, Diagnostics.An_annotation_property_must_have_a_type_or_Slashand_an_initializer); 36977 } 36978 } 36979 checkVariableLikeDeclaration(node); 36980 36981 setNodeLinksForPrivateIdentifierScope(node); 36982 36983 // property signatures already report "initializer not allowed in ambient context" elsewhere 36984 if (hasSyntacticModifier(node, ModifierFlags.Abstract) && node.kind === SyntaxKind.PropertyDeclaration && node.initializer) { 36985 error(node, Diagnostics.Property_0_cannot_have_an_initializer_because_it_is_marked_abstract, declarationNameToString(node.name)); 36986 } 36987 36988 if (isAnnotationPropertyDeclaration(node)) { 36989 checkAnnotationPropertyDeclaration(node); 36990 } 36991 } 36992 36993 function checkAnnotationPropertyDeclaration(node: AnnotationPropertyDeclaration) { 36994 const propType = getTypeOfNode(node); 36995 if (!isAllowedAnnotationPropertyType(propType)) { 36996 error(node, Diagnostics.A_type_of_annotation_property_have_to_be_number_boolean_string_const_enumeration_types_or_array_of_above_types_got_Colon_0, typeToString(propType)); 36997 } 36998 if (node.initializer) { 36999 const evaluated = evaluateAnnotationPropertyConstantExpression(node.initializer); 37000 if (evaluated === undefined) { 37001 error(node, Diagnostics.Default_value_of_annotation_property_can_be_a_constant_expression_got_Colon_0, getTextOfNode(node.initializer, /*includeTrivia*/ false)); 37002 } 37003 else { 37004 const evaluatedExpr = annotationEvaluatedValueToExpr(evaluated, getTypeOfNode(node)); 37005 getNodeLinks(node).annotationPropertyEvaluatedInitializer = evaluatedExpr; 37006 } 37007 } 37008 37009 // Special cases for enums 37010 if (!node.initializer) { 37011 const initializer = addAnnotationPropertyEnumInitalizer(propType); 37012 if (initializer) { 37013 getNodeLinks(node).annotationPropertyEvaluatedInitializer = initializer; 37014 } 37015 } 37016 37017 getNodeLinks(node).annotationPropertyInferredType = nodeBuilder.typeToTypeNode(propType); 37018 } 37019 37020 function addAnnotationPropertyEnumInitalizer(propType: Type): Expression | undefined { 37021 // Since we need to store information about type of enum members 37022 // We introduce a prohibited for users "useless" expression with explicit type annotation 37023 // For example; 37024 // const enum E {A, B} 37025 // 37026 // @interface Anno { 37027 // a: E --> a: E = new Number(0) as number 37028 // } 37029 // Following expression indicates that the E is enum with numeric members 37030 if (propType.symbol && isConstEnumSymbol(propType.symbol)) { 37031 const enumMembers = (propType.symbol.declarations![0] as EnumDeclaration).members; 37032 const firstMemeberVal = getConstantValue(enumMembers[0])!; 37033 if (enumMembers.length === 0 || typeof firstMemeberVal === "number") { 37034 return factory.createAsExpression( 37035 factory.createNewExpression( 37036 factory.createIdentifier( 37037 typeToString(globalNumberType) 37038 ), 37039 /* typeArguments */ undefined, 37040 [factory.createNumericLiteral(firstMemeberVal)]), 37041 nodeBuilder.typeToTypeNode(numberType)! 37042 ); 37043 } 37044 } 37045 // @interface Anno { 37046 // a: NumberEnum[] --> a: NumberEnum[] = new Array<NumberEnum>(0) 37047 // } 37048 // 37049 // or 37050 // 37051 // @interface Anno { 37052 // a: StringEnum[] --> a: StringEnum[] = new Array<StringEnum>(2) 37053 // } 37054 // 37055 // or 37056 // 37057 // @interface Anno { 37058 // a: StringEnum[][] --> a: StringEnum[][] = [new Array<StringEnum>(2)] 37059 // } 37060 else if (isArrayType(propType)) { 37061 return addAnnotationPropertyEnumArrayInitalizer(propType); 37062 } 37063 return undefined; 37064 } 37065 37066 function addAnnotationPropertyEnumArrayInitalizer(propType: Type): Expression | undefined { 37067 if (isArrayType(propType)) { 37068 const elemType = (propType as GenericType).resolvedTypeArguments![0]; 37069 if (isArrayType(elemType)) { 37070 const arr = addAnnotationPropertyEnumArrayInitalizer(elemType); 37071 if (arr) { 37072 return factory.createArrayLiteralExpression([arr]); 37073 } 37074 } 37075 if (elemType.symbol && isConstEnumSymbol(elemType.symbol)) { 37076 const args = new Array<Expression>(); 37077 const enumMembers = (elemType.symbol.declarations![0] as EnumDeclaration).members; 37078 if (enumMembers.length === 0 || typeof getConstantValue(enumMembers[0]) === "number") { 37079 args.push(factory.createNumericLiteral(0)); 37080 } 37081 else { 37082 args.push(factory.createNumericLiteral(2)); 37083 } 37084 return factory.createNewExpression( 37085 factory.createIdentifier( 37086 typeToString(propType, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType) 37087 ), 37088 /*typeArguments*/ undefined, 37089 args); 37090 } 37091 } 37092 return undefined; 37093 } 37094 37095 function checkPropertySignature(node: PropertySignature) { 37096 if (isPrivateIdentifier(node.name)) { 37097 error(node, Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies); 37098 } 37099 return checkPropertyDeclaration(node); 37100 } 37101 37102 function checkMethodDeclaration(node: MethodDeclaration | MethodSignature) { 37103 // Grammar checking 37104 if (!checkGrammarMethod(node)) checkGrammarComputedPropertyName(node.name); 37105 37106 if (isMethodDeclaration(node) && node.asteriskToken && isIdentifier(node.name) && idText(node.name) === "constructor") { 37107 error(node.name, Diagnostics.Class_constructor_may_not_be_a_generator); 37108 } 37109 37110 // Grammar checking for modifiers is done inside the function checkGrammarFunctionLikeDeclaration 37111 checkFunctionOrMethodDeclaration(node); 37112 37113 // method signatures already report "implementation not allowed in ambient context" elsewhere 37114 if (hasSyntacticModifier(node, ModifierFlags.Abstract) && node.kind === SyntaxKind.MethodDeclaration && node.body) { 37115 error(node, Diagnostics.Method_0_cannot_have_an_implementation_because_it_is_marked_abstract, declarationNameToString(node.name)); 37116 } 37117 37118 // Private named methods are only allowed in class declarations 37119 if (isPrivateIdentifier(node.name) && !getContainingClass(node)) { 37120 error(node, Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies); 37121 } 37122 37123 setNodeLinksForPrivateIdentifierScope(node); 37124 } 37125 37126 function setNodeLinksForPrivateIdentifierScope(node: PropertyDeclaration | PropertySignature | AnnotationPropertyDeclaration | MethodDeclaration | MethodSignature | AccessorDeclaration) { 37127 if (isPrivateIdentifier(node.name) && languageVersion < ScriptTarget.ESNext) { 37128 for (let lexicalScope = getEnclosingBlockScopeContainer(node); !!lexicalScope; lexicalScope = getEnclosingBlockScopeContainer(lexicalScope)) { 37129 getNodeLinks(lexicalScope).flags |= NodeCheckFlags.ContainsClassWithPrivateIdentifiers; 37130 } 37131 37132 // If this is a private element in a class expression inside the body of a loop, 37133 // then we must use a block-scoped binding to store the additional variables required 37134 // to transform private elements. 37135 if (isClassExpression(node.parent)) { 37136 const enclosingIterationStatement = getEnclosingIterationStatement(node.parent); 37137 if (enclosingIterationStatement) { 37138 getNodeLinks(node.name).flags |= NodeCheckFlags.BlockScopedBindingInLoop; 37139 getNodeLinks(enclosingIterationStatement).flags |= NodeCheckFlags.LoopWithCapturedBlockScopedBinding; 37140 } 37141 } 37142 } 37143 } 37144 37145 function checkClassStaticBlockDeclaration(node: ClassStaticBlockDeclaration) { 37146 checkGrammarDecoratorsAndModifiers(node); 37147 37148 forEachChild(node, checkSourceElement); 37149 } 37150 37151 function checkConstructorDeclaration(node: ConstructorDeclaration) { 37152 // If constructor is virtual node, skip it 37153 if (node.virtual) { 37154 return; 37155 } 37156 37157 // Grammar check on signature of constructor and modifier of the constructor is done in checkSignatureDeclaration function. 37158 checkSignatureDeclaration(node); 37159 // Grammar check for checking only related to constructorDeclaration 37160 if (!checkGrammarConstructorTypeParameters(node)) checkGrammarConstructorTypeAnnotation(node); 37161 37162 checkSourceElement(node.body); 37163 37164 const symbol = getSymbolOfNode(node); 37165 const firstDeclaration = getDeclarationOfKind(symbol, node.kind); 37166 37167 // Only type check the symbol once 37168 if (node === firstDeclaration) { 37169 checkFunctionOrConstructorSymbol(symbol); 37170 } 37171 37172 // exit early in the case of signature - super checks are not relevant to them 37173 if (nodeIsMissing(node.body)) { 37174 return; 37175 } 37176 37177 addLazyDiagnostic(checkConstructorDeclarationDiagnostics); 37178 37179 return; 37180 37181 function isInstancePropertyWithInitializerOrPrivateIdentifierProperty(n: Node): boolean { 37182 if (isPrivateIdentifierClassElementDeclaration(n)) { 37183 return true; 37184 } 37185 return n.kind === SyntaxKind.PropertyDeclaration && 37186 !isStatic(n) && 37187 !!(n as PropertyDeclaration).initializer; 37188 } 37189 37190 function checkConstructorDeclarationDiagnostics() { 37191 // TS 1.0 spec (April 2014): 8.3.2 37192 // Constructors of classes with no extends clause may not contain super calls, whereas 37193 // constructors of derived classes must contain at least one super call somewhere in their function body. 37194 const containingClassDecl = node.parent as ClassDeclaration; 37195 if (getClassExtendsHeritageElement(containingClassDecl)) { 37196 captureLexicalThis(node.parent, containingClassDecl); 37197 const classExtendsNull = classDeclarationExtendsNull(containingClassDecl); 37198 const superCall = findFirstSuperCall(node.body!); 37199 if (superCall) { 37200 if (classExtendsNull) { 37201 error(superCall, Diagnostics.A_constructor_cannot_contain_a_super_call_when_its_class_extends_null); 37202 } 37203 37204 // A super call must be root-level in a constructor if both of the following are true: 37205 // - The containing class is a derived class. 37206 // - The constructor declares parameter properties 37207 // or the containing class declares instance member variables with initializers. 37208 37209 const superCallShouldBeRootLevel = 37210 (getEmitScriptTarget(compilerOptions) !== ScriptTarget.ESNext || !useDefineForClassFields) && 37211 (some((node.parent as ClassDeclaration).members, isInstancePropertyWithInitializerOrPrivateIdentifierProperty) || 37212 some(node.parameters, p => hasSyntacticModifier(p, ModifierFlags.ParameterPropertyModifier))); 37213 37214 if (superCallShouldBeRootLevel) { 37215 // Until we have better flow analysis, it is an error to place the super call within any kind of block or conditional 37216 // See GH #8277 37217 if (!superCallIsRootLevelInConstructor(superCall, node.body!)) { 37218 error(superCall, Diagnostics.A_super_call_must_be_a_root_level_statement_within_a_constructor_of_a_derived_class_that_contains_initialized_properties_parameter_properties_or_private_identifiers); 37219 } 37220 // Skip past any prologue directives to check statements for referring to 'super' or 'this' before a super call 37221 else { 37222 let superCallStatement: ExpressionStatement | undefined; 37223 37224 for (const statement of node.body!.statements) { 37225 if (isExpressionStatement(statement) && isSuperCall(skipOuterExpressions(statement.expression))) { 37226 superCallStatement = statement; 37227 break; 37228 } 37229 if (nodeImmediatelyReferencesSuperOrThis(statement)) { 37230 break; 37231 } 37232 } 37233 37234 // Until we have better flow analysis, it is an error to place the super call within any kind of block or conditional 37235 // See GH #8277 37236 if (superCallStatement === undefined) { 37237 error(node, Diagnostics.A_super_call_must_be_the_first_statement_in_the_constructor_to_refer_to_super_or_this_when_a_derived_class_contains_initialized_properties_parameter_properties_or_private_identifiers); 37238 } 37239 } 37240 } 37241 } 37242 else if (!classExtendsNull) { 37243 error(node, Diagnostics.Constructors_for_derived_classes_must_contain_a_super_call); 37244 } 37245 } 37246 } 37247 } 37248 37249 function superCallIsRootLevelInConstructor(superCall: Node, body: Block) { 37250 const superCallParent = walkUpParenthesizedExpressions(superCall.parent); 37251 return isExpressionStatement(superCallParent) && superCallParent.parent === body; 37252 } 37253 37254 function nodeImmediatelyReferencesSuperOrThis(node: Node): boolean { 37255 if (node.kind === SyntaxKind.SuperKeyword || node.kind === SyntaxKind.ThisKeyword) { 37256 return true; 37257 } 37258 37259 if (isThisContainerOrFunctionBlock(node)) { 37260 return false; 37261 } 37262 37263 return !!forEachChild(node, nodeImmediatelyReferencesSuperOrThis); 37264 } 37265 37266 function checkAccessorDeclaration(node: AccessorDeclaration) { 37267 if (isIdentifier(node.name) && idText(node.name) === "constructor") { 37268 error(node.name, Diagnostics.Class_constructor_may_not_be_an_accessor); 37269 } 37270 addLazyDiagnostic(checkAccessorDeclarationDiagnostics); 37271 checkSourceElement(node.body); 37272 setNodeLinksForPrivateIdentifierScope(node); 37273 37274 function checkAccessorDeclarationDiagnostics() { 37275 // Grammar checking accessors 37276 if (!checkGrammarFunctionLikeDeclaration(node) && !checkGrammarAccessor(node)) checkGrammarComputedPropertyName(node.name); 37277 37278 checkDecorators(node); 37279 checkSignatureDeclaration(node); 37280 if (node.kind === SyntaxKind.GetAccessor) { 37281 if (!(node.flags & NodeFlags.Ambient) && nodeIsPresent(node.body) && (node.flags & NodeFlags.HasImplicitReturn)) { 37282 if (!(node.flags & NodeFlags.HasExplicitReturn)) { 37283 error(node.name, Diagnostics.A_get_accessor_must_return_a_value); 37284 } 37285 } 37286 } 37287 // Do not use hasDynamicName here, because that returns false for well known symbols. 37288 // We want to perform checkComputedPropertyName for all computed properties, including 37289 // well known symbols. 37290 if (node.name.kind === SyntaxKind.ComputedPropertyName) { 37291 checkComputedPropertyName(node.name); 37292 } 37293 37294 if (hasBindableName(node)) { 37295 // TypeScript 1.0 spec (April 2014): 8.4.3 37296 // Accessors for the same member name must specify the same accessibility. 37297 const symbol = getSymbolOfNode(node); 37298 const getter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.GetAccessor); 37299 const setter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.SetAccessor); 37300 if (getter && setter && !(getNodeCheckFlags(getter) & NodeCheckFlags.TypeChecked)) { 37301 getNodeLinks(getter).flags |= NodeCheckFlags.TypeChecked; 37302 const getterFlags = getEffectiveModifierFlags(getter); 37303 const setterFlags = getEffectiveModifierFlags(setter); 37304 if ((getterFlags & ModifierFlags.Abstract) !== (setterFlags & ModifierFlags.Abstract)) { 37305 error(getter.name, Diagnostics.Accessors_must_both_be_abstract_or_non_abstract); 37306 error(setter.name, Diagnostics.Accessors_must_both_be_abstract_or_non_abstract); 37307 } 37308 if (((getterFlags & ModifierFlags.Protected) && !(setterFlags & (ModifierFlags.Protected | ModifierFlags.Private))) || 37309 ((getterFlags & ModifierFlags.Private) && !(setterFlags & ModifierFlags.Private))) { 37310 error(getter.name, Diagnostics.A_get_accessor_must_be_at_least_as_accessible_as_the_setter); 37311 error(setter.name, Diagnostics.A_get_accessor_must_be_at_least_as_accessible_as_the_setter); 37312 } 37313 37314 const getterType = getAnnotatedAccessorType(getter); 37315 const setterType = getAnnotatedAccessorType(setter); 37316 if (getterType && setterType) { 37317 checkTypeAssignableTo(getterType, setterType, getter, Diagnostics.The_return_type_of_a_get_accessor_must_be_assignable_to_its_set_accessor_type); 37318 } 37319 } 37320 } 37321 const returnType = getTypeOfAccessors(getSymbolOfNode(node)); 37322 if (node.kind === SyntaxKind.GetAccessor) { 37323 checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, returnType); 37324 } 37325 } 37326 } 37327 37328 function checkMissingDeclaration(node: Node) { 37329 checkDecorators(node); 37330 } 37331 37332 function getEffectiveTypeArgumentAtIndex(node: TypeReferenceNode | ExpressionWithTypeArguments, typeParameters: readonly TypeParameter[], index: number): Type { 37333 if (node.typeArguments && index < node.typeArguments.length) { 37334 return getTypeFromTypeNode(node.typeArguments[index]); 37335 } 37336 return getEffectiveTypeArguments(node, typeParameters)[index]; 37337 } 37338 37339 function getEffectiveTypeArguments(node: TypeReferenceNode | ExpressionWithTypeArguments, typeParameters: readonly TypeParameter[]): Type[] { 37340 return fillMissingTypeArguments(map(node.typeArguments!, getTypeFromTypeNode), typeParameters, 37341 getMinTypeArgumentCount(typeParameters), isInJSFile(node)); 37342 } 37343 37344 function checkTypeArgumentConstraints(node: TypeReferenceNode | ExpressionWithTypeArguments, typeParameters: readonly TypeParameter[]): boolean { 37345 let typeArguments: Type[] | undefined; 37346 let mapper: TypeMapper | undefined; 37347 let result = true; 37348 for (let i = 0; i < typeParameters.length; i++) { 37349 const constraint = getConstraintOfTypeParameter(typeParameters[i]); 37350 if (constraint) { 37351 if (!typeArguments) { 37352 typeArguments = getEffectiveTypeArguments(node, typeParameters); 37353 mapper = createTypeMapper(typeParameters, typeArguments); 37354 } 37355 result = result && checkTypeAssignableTo( 37356 typeArguments[i], 37357 instantiateType(constraint, mapper), 37358 node.typeArguments![i], 37359 Diagnostics.Type_0_does_not_satisfy_the_constraint_1); 37360 } 37361 } 37362 return result; 37363 } 37364 37365 function getTypeParametersForTypeReference(node: TypeReferenceNode | ExpressionWithTypeArguments) { 37366 const type = getTypeFromTypeReference(node); 37367 if (!isErrorType(type)) { 37368 const symbol = getNodeLinks(node).resolvedSymbol; 37369 if (symbol) { 37370 return symbol.flags & SymbolFlags.TypeAlias && getSymbolLinks(symbol).typeParameters || 37371 (getObjectFlags(type) & ObjectFlags.Reference ? (type as TypeReference).target.localTypeParameters : undefined); 37372 } 37373 } 37374 return undefined; 37375 } 37376 37377 function checkTypeReferenceNode(node: TypeReferenceNode | ExpressionWithTypeArguments) { 37378 checkGrammarTypeArguments(node, node.typeArguments); 37379 if (node.kind === SyntaxKind.TypeReference && node.typeName.jsdocDotPos !== undefined && !isInJSFile(node) && !isInJSDoc(node)) { 37380 grammarErrorAtPos(node, node.typeName.jsdocDotPos, 1, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments); 37381 } 37382 forEach(node.typeArguments, checkSourceElement); 37383 const type = getTypeFromTypeReference(node); 37384 if (type.symbol && (type.symbol.flags & SymbolFlags.Annotation)) { 37385 error(node, Diagnostics.Annotation_cannot_be_used_as_a_type); 37386 } 37387 if (!isErrorType(type)) { 37388 if (node.typeArguments) { 37389 addLazyDiagnostic(() => { 37390 const typeParameters = getTypeParametersForTypeReference(node); 37391 if (typeParameters) { 37392 checkTypeArgumentConstraints(node, typeParameters); 37393 } 37394 }); 37395 } 37396 const symbol = getNodeLinks(node).resolvedSymbol; 37397 if (symbol) { 37398 if (some(symbol.declarations, d => isTypeDeclaration(d) && !!(d.flags & NodeFlags.Deprecated))) { 37399 addDeprecatedSuggestion( 37400 getDeprecatedSuggestionNode(node), 37401 symbol.declarations!, 37402 symbol.escapedName as string 37403 ); 37404 } 37405 if (type.flags & TypeFlags.Enum && symbol.flags & SymbolFlags.EnumMember) { 37406 error(node, Diagnostics.Enum_type_0_has_members_with_initializers_that_are_not_literals, typeToString(type)); 37407 } 37408 } 37409 } 37410 } 37411 37412 function getTypeArgumentConstraint(node: TypeNode): Type | undefined { 37413 const typeReferenceNode = tryCast(node.parent, isTypeReferenceType); 37414 if (!typeReferenceNode) return undefined; 37415 const typeParameters = getTypeParametersForTypeReference(typeReferenceNode); 37416 if (!typeParameters) return undefined; 37417 const constraint = getConstraintOfTypeParameter(typeParameters[typeReferenceNode.typeArguments!.indexOf(node)]); 37418 return constraint && instantiateType(constraint, createTypeMapper(typeParameters, getEffectiveTypeArguments(typeReferenceNode, typeParameters))); 37419 } 37420 37421 function checkTypeQuery(node: TypeQueryNode) { 37422 getTypeFromTypeQueryNode(node); 37423 } 37424 37425 function checkTypeLiteral(node: TypeLiteralNode) { 37426 forEach(node.members, checkSourceElement); 37427 addLazyDiagnostic(checkTypeLiteralDiagnostics); 37428 37429 function checkTypeLiteralDiagnostics() { 37430 const type = getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node); 37431 checkIndexConstraints(type, type.symbol); 37432 checkTypeForDuplicateIndexSignatures(node); 37433 checkObjectTypeForDuplicateDeclarations(node); 37434 } 37435 } 37436 37437 function checkArrayType(node: ArrayTypeNode) { 37438 checkSourceElement(node.elementType); 37439 } 37440 37441 function checkTupleType(node: TupleTypeNode) { 37442 const elementTypes = node.elements; 37443 let seenOptionalElement = false; 37444 let seenRestElement = false; 37445 const hasNamedElement = some(elementTypes, isNamedTupleMember); 37446 for (const e of elementTypes) { 37447 if (e.kind !== SyntaxKind.NamedTupleMember && hasNamedElement) { 37448 grammarErrorOnNode(e, Diagnostics.Tuple_members_must_all_have_names_or_all_not_have_names); 37449 break; 37450 } 37451 const flags = getTupleElementFlags(e); 37452 if (flags & ElementFlags.Variadic) { 37453 const type = getTypeFromTypeNode((e as RestTypeNode | NamedTupleMember).type); 37454 if (!isArrayLikeType(type)) { 37455 error(e, Diagnostics.A_rest_element_type_must_be_an_array_type); 37456 break; 37457 } 37458 if (isArrayType(type) || isTupleType(type) && type.target.combinedFlags & ElementFlags.Rest) { 37459 seenRestElement = true; 37460 } 37461 } 37462 else if (flags & ElementFlags.Rest) { 37463 if (seenRestElement) { 37464 grammarErrorOnNode(e, Diagnostics.A_rest_element_cannot_follow_another_rest_element); 37465 break; 37466 } 37467 seenRestElement = true; 37468 } 37469 else if (flags & ElementFlags.Optional) { 37470 if (seenRestElement) { 37471 grammarErrorOnNode(e, Diagnostics.An_optional_element_cannot_follow_a_rest_element); 37472 break; 37473 } 37474 seenOptionalElement = true; 37475 } 37476 else if (seenOptionalElement) { 37477 grammarErrorOnNode(e, Diagnostics.A_required_element_cannot_follow_an_optional_element); 37478 break; 37479 } 37480 } 37481 forEach(node.elements, checkSourceElement); 37482 getTypeFromTypeNode(node); 37483 } 37484 37485 function checkUnionOrIntersectionType(node: UnionOrIntersectionTypeNode) { 37486 forEach(node.types, checkSourceElement); 37487 getTypeFromTypeNode(node); 37488 } 37489 37490 function checkIndexedAccessIndexType(type: Type, accessNode: IndexedAccessTypeNode | ElementAccessExpression) { 37491 if (!(type.flags & TypeFlags.IndexedAccess)) { 37492 return type; 37493 } 37494 // Check if the index type is assignable to 'keyof T' for the object type. 37495 const objectType = (type as IndexedAccessType).objectType; 37496 const indexType = (type as IndexedAccessType).indexType; 37497 if (isTypeAssignableTo(indexType, getIndexType(objectType, /*stringsOnly*/ false))) { 37498 if (accessNode.kind === SyntaxKind.ElementAccessExpression && isAssignmentTarget(accessNode) && 37499 getObjectFlags(objectType) & ObjectFlags.Mapped && getMappedTypeModifiers(objectType as MappedType) & MappedTypeModifiers.IncludeReadonly) { 37500 error(accessNode, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(objectType)); 37501 } 37502 return type; 37503 } 37504 // Check if we're indexing with a numeric type and if either object or index types 37505 // is a generic type with a constraint that has a numeric index signature. 37506 const apparentObjectType = getApparentType(objectType); 37507 if (getIndexInfoOfType(apparentObjectType, numberType) && isTypeAssignableToKind(indexType, TypeFlags.NumberLike)) { 37508 return type; 37509 } 37510 if (isGenericObjectType(objectType)) { 37511 const propertyName = getPropertyNameFromIndex(indexType, accessNode); 37512 if (propertyName) { 37513 const propertySymbol = forEachType(apparentObjectType, t => getPropertyOfType(t, propertyName)); 37514 if (propertySymbol && getDeclarationModifierFlagsFromSymbol(propertySymbol) & ModifierFlags.NonPublicAccessibilityModifier) { 37515 error(accessNode, Diagnostics.Private_or_protected_member_0_cannot_be_accessed_on_a_type_parameter, unescapeLeadingUnderscores(propertyName)); 37516 return errorType; 37517 } 37518 } 37519 } 37520 error(accessNode, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(objectType)); 37521 return errorType; 37522 } 37523 37524 function checkIndexedAccessType(node: IndexedAccessTypeNode) { 37525 checkSourceElement(node.objectType); 37526 checkSourceElement(node.indexType); 37527 checkIndexedAccessIndexType(getTypeFromIndexedAccessTypeNode(node), node); 37528 } 37529 37530 function checkMappedType(node: MappedTypeNode) { 37531 checkGrammarMappedType(node); 37532 checkSourceElement(node.typeParameter); 37533 checkSourceElement(node.nameType); 37534 checkSourceElement(node.type); 37535 37536 if (!node.type) { 37537 reportImplicitAny(node, anyType); 37538 } 37539 37540 const type = getTypeFromMappedTypeNode(node) as MappedType; 37541 const nameType = getNameTypeFromMappedType(type); 37542 if (nameType) { 37543 checkTypeAssignableTo(nameType, keyofConstraintType, node.nameType); 37544 } 37545 else { 37546 const constraintType = getConstraintTypeFromMappedType(type); 37547 checkTypeAssignableTo(constraintType, keyofConstraintType, getEffectiveConstraintOfTypeParameter(node.typeParameter)); 37548 } 37549 } 37550 37551 function checkGrammarMappedType(node: MappedTypeNode) { 37552 if (node.members?.length) { 37553 return grammarErrorOnNode(node.members[0], Diagnostics.A_mapped_type_may_not_declare_properties_or_methods); 37554 } 37555 } 37556 37557 function checkThisType(node: ThisTypeNode) { 37558 getTypeFromThisTypeNode(node); 37559 } 37560 37561 function checkTypeOperator(node: TypeOperatorNode) { 37562 checkGrammarTypeOperatorNode(node); 37563 checkSourceElement(node.type); 37564 } 37565 37566 function checkConditionalType(node: ConditionalTypeNode) { 37567 forEachChild(node, checkSourceElement); 37568 } 37569 37570 function checkInferType(node: InferTypeNode) { 37571 if (!findAncestor(node, n => n.parent && n.parent.kind === SyntaxKind.ConditionalType && (n.parent as ConditionalTypeNode).extendsType === n)) { 37572 grammarErrorOnNode(node, Diagnostics.infer_declarations_are_only_permitted_in_the_extends_clause_of_a_conditional_type); 37573 } 37574 checkSourceElement(node.typeParameter); 37575 const symbol = getSymbolOfNode(node.typeParameter); 37576 if (symbol.declarations && symbol.declarations.length > 1) { 37577 const links = getSymbolLinks(symbol); 37578 if (!links.typeParametersChecked) { 37579 links.typeParametersChecked = true; 37580 const typeParameter = getDeclaredTypeOfTypeParameter(symbol); 37581 const declarations: TypeParameterDeclaration[] = getDeclarationsOfKind(symbol, SyntaxKind.TypeParameter); 37582 if (!areTypeParametersIdentical(declarations, [typeParameter], decl => [decl])) { 37583 // Report an error on every conflicting declaration. 37584 const name = symbolToString(symbol); 37585 for (const declaration of declarations) { 37586 error(declaration.name, Diagnostics.All_declarations_of_0_must_have_identical_constraints, name); 37587 } 37588 } 37589 } 37590 } 37591 registerForUnusedIdentifiersCheck(node); 37592 } 37593 37594 function checkTemplateLiteralType(node: TemplateLiteralTypeNode) { 37595 for (const span of node.templateSpans) { 37596 checkSourceElement(span.type); 37597 const type = getTypeFromTypeNode(span.type); 37598 checkTypeAssignableTo(type, templateConstraintType, span.type); 37599 } 37600 getTypeFromTypeNode(node); 37601 } 37602 37603 function checkImportType(node: ImportTypeNode) { 37604 checkSourceElement(node.argument); 37605 37606 if (node.assertions) { 37607 const override = getResolutionModeOverrideForClause(node.assertions.assertClause, grammarErrorOnNode); 37608 if (override) { 37609 if (!isNightly()) { 37610 grammarErrorOnNode(node.assertions.assertClause, Diagnostics.resolution_mode_assertions_are_unstable_Use_nightly_TypeScript_to_silence_this_error_Try_updating_with_npm_install_D_typescript_next); 37611 } 37612 if (getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Node16 && getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeNext) { 37613 grammarErrorOnNode(node.assertions.assertClause, Diagnostics.resolution_mode_assertions_are_only_supported_when_moduleResolution_is_node16_or_nodenext); 37614 } 37615 } 37616 } 37617 37618 getTypeFromTypeNode(node); 37619 } 37620 37621 function checkNamedTupleMember(node: NamedTupleMember) { 37622 if (node.dotDotDotToken && node.questionToken) { 37623 grammarErrorOnNode(node, Diagnostics.A_tuple_member_cannot_be_both_optional_and_rest); 37624 } 37625 if (node.type.kind === SyntaxKind.OptionalType) { 37626 grammarErrorOnNode(node.type, Diagnostics.A_labeled_tuple_element_is_declared_as_optional_with_a_question_mark_after_the_name_and_before_the_colon_rather_than_after_the_type); 37627 } 37628 if (node.type.kind === SyntaxKind.RestType) { 37629 grammarErrorOnNode(node.type, Diagnostics.A_labeled_tuple_element_is_declared_as_rest_with_a_before_the_name_rather_than_before_the_type); 37630 } 37631 checkSourceElement(node.type); 37632 getTypeFromTypeNode(node); 37633 } 37634 37635 function isPrivateWithinAmbient(node: Node): boolean { 37636 return (hasEffectiveModifier(node, ModifierFlags.Private) || isPrivateIdentifierClassElementDeclaration(node)) && !!(node.flags & NodeFlags.Ambient); 37637 } 37638 37639 function getEffectiveDeclarationFlags(n: Declaration, flagsToCheck: ModifierFlags): ModifierFlags { 37640 let flags = getCombinedModifierFlags(n); 37641 37642 // children of classes (even ambient classes) should not be marked as ambient or export 37643 // because those flags have no useful semantics there. 37644 if (n.parent.kind !== SyntaxKind.InterfaceDeclaration && 37645 n.parent.kind !== SyntaxKind.ClassDeclaration && 37646 n.parent.kind !== SyntaxKind.ClassExpression && 37647 n.flags & NodeFlags.Ambient) { 37648 if (!(flags & ModifierFlags.Ambient) && !(isModuleBlock(n.parent) && isModuleDeclaration(n.parent.parent) && isGlobalScopeAugmentation(n.parent.parent))) { 37649 // It is nested in an ambient context, which means it is automatically exported 37650 flags |= ModifierFlags.Export; 37651 } 37652 flags |= ModifierFlags.Ambient; 37653 } 37654 37655 return flags & flagsToCheck; 37656 } 37657 37658 function checkFunctionOrConstructorSymbol(symbol: Symbol): void { 37659 addLazyDiagnostic(() => checkFunctionOrConstructorSymbolWorker(symbol)); 37660 } 37661 37662 function checkFunctionOrConstructorSymbolWorker(symbol: Symbol): void { 37663 function getCanonicalOverload(overloads: Declaration[], implementation: FunctionLikeDeclaration | undefined): Declaration { 37664 // Consider the canonical set of flags to be the flags of the bodyDeclaration or the first declaration 37665 // Error on all deviations from this canonical set of flags 37666 // The caveat is that if some overloads are defined in lib.d.ts, we don't want to 37667 // report the errors on those. To achieve this, we will say that the implementation is 37668 // the canonical signature only if it is in the same container as the first overload 37669 const implementationSharesContainerWithFirstOverload = implementation !== undefined && implementation.parent === overloads[0].parent; 37670 return implementationSharesContainerWithFirstOverload ? implementation : overloads[0]; 37671 } 37672 37673 function checkFlagAgreementBetweenOverloads(overloads: Declaration[], implementation: FunctionLikeDeclaration | undefined, flagsToCheck: ModifierFlags, someOverloadFlags: ModifierFlags, allOverloadFlags: ModifierFlags): void { 37674 // Error if some overloads have a flag that is not shared by all overloads. To find the 37675 // deviations, we XOR someOverloadFlags with allOverloadFlags 37676 const someButNotAllOverloadFlags = someOverloadFlags ^ allOverloadFlags; 37677 if (someButNotAllOverloadFlags !== 0) { 37678 const canonicalFlags = getEffectiveDeclarationFlags(getCanonicalOverload(overloads, implementation), flagsToCheck); 37679 forEach(overloads, o => { 37680 const deviation = getEffectiveDeclarationFlags(o, flagsToCheck) ^ canonicalFlags; 37681 if (deviation & ModifierFlags.Export) { 37682 error(getNameOfDeclaration(o), Diagnostics.Overload_signatures_must_all_be_exported_or_non_exported); 37683 } 37684 else if (deviation & ModifierFlags.Ambient) { 37685 error(getNameOfDeclaration(o), Diagnostics.Overload_signatures_must_all_be_ambient_or_non_ambient); 37686 } 37687 else if (deviation & (ModifierFlags.Private | ModifierFlags.Protected)) { 37688 error(getNameOfDeclaration(o) || o, Diagnostics.Overload_signatures_must_all_be_public_private_or_protected); 37689 } 37690 else if (deviation & ModifierFlags.Abstract) { 37691 error(getNameOfDeclaration(o), Diagnostics.Overload_signatures_must_all_be_abstract_or_non_abstract); 37692 } 37693 }); 37694 } 37695 } 37696 37697 function checkQuestionTokenAgreementBetweenOverloads(overloads: Declaration[], implementation: FunctionLikeDeclaration | undefined, someHaveQuestionToken: boolean, allHaveQuestionToken: boolean): void { 37698 if (someHaveQuestionToken !== allHaveQuestionToken) { 37699 const canonicalHasQuestionToken = hasQuestionToken(getCanonicalOverload(overloads, implementation)); 37700 forEach(overloads, o => { 37701 const deviation = hasQuestionToken(o) !== canonicalHasQuestionToken; 37702 if (deviation) { 37703 error(getNameOfDeclaration(o), Diagnostics.Overload_signatures_must_all_be_optional_or_required); 37704 } 37705 }); 37706 } 37707 } 37708 37709 const flagsToCheck: ModifierFlags = ModifierFlags.Export | ModifierFlags.Ambient | ModifierFlags.Private | ModifierFlags.Protected | ModifierFlags.Abstract; 37710 let someNodeFlags: ModifierFlags = ModifierFlags.None; 37711 let allNodeFlags = flagsToCheck; 37712 let someHaveQuestionToken = false; 37713 let allHaveQuestionToken = true; 37714 let hasOverloads = false; 37715 let bodyDeclaration: FunctionLikeDeclaration | undefined; 37716 let lastSeenNonAmbientDeclaration: FunctionLikeDeclaration | undefined; 37717 let previousDeclaration: SignatureDeclaration | undefined; 37718 37719 const declarations = symbol.declarations; 37720 const isConstructor = (symbol.flags & SymbolFlags.Constructor) !== 0; 37721 37722 function reportImplementationExpectedError(node: SignatureDeclaration): void { 37723 if (node.name && nodeIsMissing(node.name)) { 37724 return; 37725 } 37726 37727 let seen = false; 37728 const subsequentNode = forEachChild(node.parent, c => { 37729 if (seen) { 37730 return c; 37731 } 37732 else { 37733 seen = c === node; 37734 } 37735 }); 37736 // We may be here because of some extra nodes between overloads that could not be parsed into a valid node. 37737 // In this case the subsequent node is not really consecutive (.pos !== node.end), and we must ignore it here. 37738 if (subsequentNode && subsequentNode.pos === node.end) { 37739 if (subsequentNode.kind === node.kind) { 37740 const errorNode: Node = (subsequentNode as FunctionLikeDeclaration).name || subsequentNode; 37741 const subsequentName = (subsequentNode as FunctionLikeDeclaration).name; 37742 if (node.name && subsequentName && ( 37743 // both are private identifiers 37744 isPrivateIdentifier(node.name) && isPrivateIdentifier(subsequentName) && node.name.escapedText === subsequentName.escapedText || 37745 // Both are computed property names 37746 // TODO: GH#17345: These are methods, so handle computed name case. (`Always allowing computed property names is *not* the correct behavior!) 37747 isComputedPropertyName(node.name) && isComputedPropertyName(subsequentName) || 37748 // Both are literal property names that are the same. 37749 isPropertyNameLiteral(node.name) && isPropertyNameLiteral(subsequentName) && 37750 getEscapedTextOfIdentifierOrLiteral(node.name) === getEscapedTextOfIdentifierOrLiteral(subsequentName) 37751 )) { 37752 const reportError = 37753 (node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature) && 37754 isStatic(node) !== isStatic(subsequentNode); 37755 // we can get here in two cases 37756 // 1. mixed static and instance class members 37757 // 2. something with the same name was defined before the set of overloads that prevents them from merging 37758 // here we'll report error only for the first case since for second we should already report error in binder 37759 if (reportError) { 37760 const diagnostic = isStatic(node) ? Diagnostics.Function_overload_must_be_static : Diagnostics.Function_overload_must_not_be_static; 37761 error(errorNode, diagnostic); 37762 } 37763 return; 37764 } 37765 if (nodeIsPresent((subsequentNode as FunctionLikeDeclaration).body)) { 37766 error(errorNode, Diagnostics.Function_implementation_name_must_be_0, declarationNameToString(node.name)); 37767 return; 37768 } 37769 } 37770 } 37771 const errorNode: Node = node.name || node; 37772 if (isConstructor) { 37773 error(errorNode, Diagnostics.Constructor_implementation_is_missing); 37774 } 37775 else { 37776 // Report different errors regarding non-consecutive blocks of declarations depending on whether 37777 // the node in question is abstract. 37778 if (hasSyntacticModifier(node, ModifierFlags.Abstract)) { 37779 error(errorNode, Diagnostics.All_declarations_of_an_abstract_method_must_be_consecutive); 37780 } 37781 else { 37782 error(errorNode, Diagnostics.Function_implementation_is_missing_or_not_immediately_following_the_declaration); 37783 } 37784 } 37785 } 37786 37787 let duplicateFunctionDeclaration = false; 37788 let multipleConstructorImplementation = false; 37789 let hasNonAmbientClass = false; 37790 const functionDeclarations = [] as Declaration[]; 37791 if (declarations) { 37792 for (const current of declarations) { 37793 const node = current as SignatureDeclaration | ClassDeclaration | ClassExpression; 37794 const inAmbientContext = node.flags & NodeFlags.Ambient; 37795 const inAmbientContextOrInterface = node.parent && (node.parent.kind === SyntaxKind.InterfaceDeclaration || node.parent.kind === SyntaxKind.TypeLiteral) || inAmbientContext; 37796 if (inAmbientContextOrInterface) { 37797 // check if declarations are consecutive only if they are non-ambient 37798 // 1. ambient declarations can be interleaved 37799 // i.e. this is legal 37800 // declare function foo(); 37801 // declare function bar(); 37802 // declare function foo(); 37803 // 2. mixing ambient and non-ambient declarations is a separate error that will be reported - do not want to report an extra one 37804 previousDeclaration = undefined; 37805 } 37806 37807 if ((node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression) && !inAmbientContext) { 37808 hasNonAmbientClass = true; 37809 } 37810 37811 if (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature || node.kind === SyntaxKind.Constructor) { 37812 functionDeclarations.push(node); 37813 const currentNodeFlags = getEffectiveDeclarationFlags(node, flagsToCheck); 37814 someNodeFlags |= currentNodeFlags; 37815 allNodeFlags &= currentNodeFlags; 37816 someHaveQuestionToken = someHaveQuestionToken || hasQuestionToken(node); 37817 allHaveQuestionToken = allHaveQuestionToken && hasQuestionToken(node); 37818 const bodyIsPresent = nodeIsPresent((node as FunctionLikeDeclaration).body); 37819 37820 if (bodyIsPresent && bodyDeclaration) { 37821 if (isConstructor) { 37822 multipleConstructorImplementation = true; 37823 } 37824 else { 37825 duplicateFunctionDeclaration = true; 37826 } 37827 } 37828 else if (previousDeclaration?.parent === node.parent && previousDeclaration.end !== node.pos) { 37829 reportImplementationExpectedError(previousDeclaration); 37830 } 37831 37832 if (bodyIsPresent) { 37833 if (!bodyDeclaration) { 37834 bodyDeclaration = node as FunctionLikeDeclaration; 37835 } 37836 } 37837 else { 37838 hasOverloads = true; 37839 } 37840 37841 previousDeclaration = node; 37842 37843 if (!inAmbientContextOrInterface) { 37844 lastSeenNonAmbientDeclaration = node as FunctionLikeDeclaration; 37845 } 37846 } 37847 } 37848 } 37849 37850 if (multipleConstructorImplementation) { 37851 forEach(functionDeclarations, declaration => { 37852 error(declaration, Diagnostics.Multiple_constructor_implementations_are_not_allowed); 37853 }); 37854 } 37855 37856 if (duplicateFunctionDeclaration) { 37857 forEach(functionDeclarations, declaration => { 37858 error(getNameOfDeclaration(declaration) || declaration, Diagnostics.Duplicate_function_implementation); 37859 }); 37860 } 37861 37862 if (hasNonAmbientClass && !isConstructor && symbol.flags & SymbolFlags.Function && declarations) { 37863 const relatedDiagnostics = filter(declarations, d => d.kind === SyntaxKind.ClassDeclaration) 37864 .map(d => createDiagnosticForNode(d, Diagnostics.Consider_adding_a_declare_modifier_to_this_class)); 37865 37866 forEach(declarations, declaration => { 37867 const diagnostic = declaration.kind === SyntaxKind.ClassDeclaration 37868 ? Diagnostics.Class_declaration_cannot_implement_overload_list_for_0 37869 : declaration.kind === SyntaxKind.FunctionDeclaration 37870 ? Diagnostics.Function_with_bodies_can_only_merge_with_classes_that_are_ambient 37871 : undefined; 37872 if (diagnostic) { 37873 addRelatedInfo( 37874 error(getNameOfDeclaration(declaration) || declaration, diagnostic, symbolName(symbol)), 37875 ...relatedDiagnostics 37876 ); 37877 } 37878 }); 37879 } 37880 37881 // Abstract methods can't have an implementation -- in particular, they don't need one. 37882 if (lastSeenNonAmbientDeclaration && !lastSeenNonAmbientDeclaration.body && 37883 !hasSyntacticModifier(lastSeenNonAmbientDeclaration, ModifierFlags.Abstract) && !lastSeenNonAmbientDeclaration.questionToken) { 37884 reportImplementationExpectedError(lastSeenNonAmbientDeclaration); 37885 } 37886 37887 if (hasOverloads) { 37888 if (declarations) { 37889 checkFlagAgreementBetweenOverloads(declarations, bodyDeclaration, flagsToCheck, someNodeFlags, allNodeFlags); 37890 checkQuestionTokenAgreementBetweenOverloads(declarations, bodyDeclaration, someHaveQuestionToken, allHaveQuestionToken); 37891 } 37892 37893 if (bodyDeclaration) { 37894 const signatures = getSignaturesOfSymbol(symbol); 37895 const bodySignature = getSignatureFromDeclaration(bodyDeclaration); 37896 for (const signature of signatures) { 37897 if (!isImplementationCompatibleWithOverload(bodySignature, signature)) { 37898 addRelatedInfo( 37899 error(signature.declaration, Diagnostics.This_overload_signature_is_not_compatible_with_its_implementation_signature), 37900 createDiagnosticForNode(bodyDeclaration, Diagnostics.The_implementation_signature_is_declared_here) 37901 ); 37902 break; 37903 } 37904 } 37905 } 37906 } 37907 } 37908 37909 function checkExportsOnMergedDeclarations(node: Declaration): void { 37910 addLazyDiagnostic(() => checkExportsOnMergedDeclarationsWorker(node)); 37911 } 37912 37913 function checkExportsOnMergedDeclarationsWorker(node: Declaration): void { 37914 // if localSymbol is defined on node then node itself is exported - check is required 37915 let symbol = node.localSymbol; 37916 if (!symbol) { 37917 // local symbol is undefined => this declaration is non-exported. 37918 // however symbol might contain other declarations that are exported 37919 symbol = getSymbolOfNode(node)!; 37920 if (!symbol.exportSymbol) { 37921 // this is a pure local symbol (all declarations are non-exported) - no need to check anything 37922 return; 37923 } 37924 } 37925 37926 // run the check only for the first declaration in the list 37927 if (getDeclarationOfKind(symbol, node.kind) !== node) { 37928 return; 37929 } 37930 37931 let exportedDeclarationSpaces = DeclarationSpaces.None; 37932 let nonExportedDeclarationSpaces = DeclarationSpaces.None; 37933 let defaultExportedDeclarationSpaces = DeclarationSpaces.None; 37934 for (const d of symbol.declarations!) { 37935 const declarationSpaces = getDeclarationSpaces(d); 37936 const effectiveDeclarationFlags = getEffectiveDeclarationFlags(d, ModifierFlags.Export | ModifierFlags.Default); 37937 37938 if (effectiveDeclarationFlags & ModifierFlags.Export) { 37939 if (effectiveDeclarationFlags & ModifierFlags.Default) { 37940 defaultExportedDeclarationSpaces |= declarationSpaces; 37941 } 37942 else { 37943 exportedDeclarationSpaces |= declarationSpaces; 37944 } 37945 } 37946 else { 37947 nonExportedDeclarationSpaces |= declarationSpaces; 37948 } 37949 } 37950 37951 // Spaces for anything not declared a 'default export'. 37952 const nonDefaultExportedDeclarationSpaces = exportedDeclarationSpaces | nonExportedDeclarationSpaces; 37953 37954 const commonDeclarationSpacesForExportsAndLocals = exportedDeclarationSpaces & nonExportedDeclarationSpaces; 37955 const commonDeclarationSpacesForDefaultAndNonDefault = defaultExportedDeclarationSpaces & nonDefaultExportedDeclarationSpaces; 37956 37957 if (commonDeclarationSpacesForExportsAndLocals || commonDeclarationSpacesForDefaultAndNonDefault) { 37958 // declaration spaces for exported and non-exported declarations intersect 37959 for (const d of symbol.declarations!) { 37960 const declarationSpaces = getDeclarationSpaces(d); 37961 37962 const name = getNameOfDeclaration(d); 37963 // Only error on the declarations that contributed to the intersecting spaces. 37964 if (declarationSpaces & commonDeclarationSpacesForDefaultAndNonDefault) { 37965 error(name, Diagnostics.Merged_declaration_0_cannot_include_a_default_export_declaration_Consider_adding_a_separate_export_default_0_declaration_instead, declarationNameToString(name)); 37966 } 37967 else if (declarationSpaces & commonDeclarationSpacesForExportsAndLocals) { 37968 error(name, Diagnostics.Individual_declarations_in_merged_declaration_0_must_be_all_exported_or_all_local, declarationNameToString(name)); 37969 } 37970 } 37971 } 37972 37973 function getDeclarationSpaces(decl: Declaration): DeclarationSpaces { 37974 let d = decl as Node; 37975 switch (d.kind) { 37976 case SyntaxKind.InterfaceDeclaration: 37977 case SyntaxKind.TypeAliasDeclaration: 37978 37979 // A jsdoc typedef and callback are, by definition, type aliases. 37980 // falls through 37981 case SyntaxKind.JSDocTypedefTag: 37982 case SyntaxKind.JSDocCallbackTag: 37983 case SyntaxKind.JSDocEnumTag: 37984 return DeclarationSpaces.ExportType; 37985 case SyntaxKind.ModuleDeclaration: 37986 return isAmbientModule(d as ModuleDeclaration) || getModuleInstanceState(d as ModuleDeclaration) !== ModuleInstanceState.NonInstantiated 37987 ? DeclarationSpaces.ExportNamespace | DeclarationSpaces.ExportValue 37988 : DeclarationSpaces.ExportNamespace; 37989 case SyntaxKind.ClassDeclaration: 37990 case SyntaxKind.StructDeclaration: 37991 case SyntaxKind.AnnotationDeclaration: 37992 case SyntaxKind.EnumDeclaration: 37993 case SyntaxKind.EnumMember: 37994 return DeclarationSpaces.ExportType | DeclarationSpaces.ExportValue; 37995 case SyntaxKind.SourceFile: 37996 return DeclarationSpaces.ExportType | DeclarationSpaces.ExportValue | DeclarationSpaces.ExportNamespace; 37997 case SyntaxKind.ExportAssignment: 37998 case SyntaxKind.BinaryExpression: 37999 const node = d as ExportAssignment | BinaryExpression; 38000 const expression = isExportAssignment(node) ? node.expression : node.right; 38001 // Export assigned entity name expressions act as aliases and should fall through, otherwise they export values 38002 if (!isEntityNameExpression(expression)) { 38003 return DeclarationSpaces.ExportValue; 38004 } 38005 d = expression; 38006 38007 // The below options all declare an Alias, which is allowed to merge with other values within the importing module. 38008 // falls through 38009 case SyntaxKind.ImportEqualsDeclaration: 38010 case SyntaxKind.NamespaceImport: 38011 case SyntaxKind.ImportClause: 38012 let result = DeclarationSpaces.None; 38013 const target = resolveAlias(getSymbolOfNode(d)!); 38014 forEach(target.declarations, d => { 38015 result |= getDeclarationSpaces(d); 38016 }); 38017 return result; 38018 case SyntaxKind.VariableDeclaration: 38019 case SyntaxKind.BindingElement: 38020 case SyntaxKind.FunctionDeclaration: 38021 case SyntaxKind.ImportSpecifier: // https://github.com/Microsoft/TypeScript/pull/7591 38022 case SyntaxKind.Identifier: // https://github.com/microsoft/TypeScript/issues/36098 38023 // Identifiers are used as declarations of assignment declarations whose parents may be 38024 // SyntaxKind.CallExpression - `Object.defineProperty(thing, "aField", {value: 42});` 38025 // SyntaxKind.ElementAccessExpression - `thing["aField"] = 42;` or `thing["aField"];` (with a doc comment on it) 38026 // or SyntaxKind.PropertyAccessExpression - `thing.aField = 42;` 38027 // all of which are pretty much always values, or at least imply a value meaning. 38028 // It may be apprpriate to treat these as aliases in the future. 38029 return DeclarationSpaces.ExportValue; 38030 default: 38031 return Debug.failBadSyntaxKind(d); 38032 } 38033 } 38034 } 38035 38036 function getAwaitedTypeOfPromise(type: Type, errorNode?: Node, diagnosticMessage?: DiagnosticMessage, arg0?: string | number): Type | undefined { 38037 const promisedType = getPromisedTypeOfPromise(type, errorNode); 38038 return promisedType && getAwaitedType(promisedType, errorNode, diagnosticMessage, arg0); 38039 } 38040 38041 /** 38042 * Gets the "promised type" of a promise. 38043 * @param type The type of the promise. 38044 * @remarks The "promised type" of a type is the type of the "value" parameter of the "onfulfilled" callback. 38045 */ 38046 function getPromisedTypeOfPromise(type: Type, errorNode?: Node, thisTypeForErrorOut?: { value?: Type }): Type | undefined { 38047 // 38048 // { // type 38049 // then( // thenFunction 38050 // onfulfilled: ( // onfulfilledParameterType 38051 // value: T // valueParameterType 38052 // ) => any 38053 // ): any; 38054 // } 38055 // 38056 38057 if (isTypeAny(type)) { 38058 return undefined; 38059 } 38060 38061 const typeAsPromise = type as PromiseOrAwaitableType; 38062 if (typeAsPromise.promisedTypeOfPromise) { 38063 return typeAsPromise.promisedTypeOfPromise; 38064 } 38065 38066 if (isReferenceToType(type, getGlobalPromiseType(/*reportErrors*/ false))) { 38067 return typeAsPromise.promisedTypeOfPromise = getTypeArguments(type as GenericType)[0]; 38068 } 38069 38070 // primitives with a `{ then() }` won't be unwrapped/adopted. 38071 if (allTypesAssignableToKind(getBaseConstraintOrType(type), TypeFlags.Primitive | TypeFlags.Never)) { 38072 return undefined; 38073 } 38074 38075 const thenFunction = getTypeOfPropertyOfType(type, "then" as __String)!; // TODO: GH#18217 38076 if (isTypeAny(thenFunction)) { 38077 return undefined; 38078 } 38079 38080 const thenSignatures = thenFunction ? getSignaturesOfType(thenFunction, SignatureKind.Call) : emptyArray; 38081 if (thenSignatures.length === 0) { 38082 if (errorNode) { 38083 error(errorNode, Diagnostics.A_promise_must_have_a_then_method); 38084 } 38085 return undefined; 38086 } 38087 38088 let thisTypeForError: Type | undefined; 38089 let candidates: Signature[] | undefined; 38090 for (const thenSignature of thenSignatures) { 38091 const thisType = getThisTypeOfSignature(thenSignature); 38092 if (thisType && thisType !== voidType && !isTypeRelatedTo(type, thisType, subtypeRelation)) { 38093 thisTypeForError = thisType; 38094 } 38095 else { 38096 candidates = append(candidates, thenSignature); 38097 } 38098 } 38099 38100 if (!candidates) { 38101 Debug.assertIsDefined(thisTypeForError); 38102 if (thisTypeForErrorOut) { 38103 thisTypeForErrorOut.value = thisTypeForError; 38104 } 38105 if (errorNode) { 38106 error(errorNode, Diagnostics.The_this_context_of_type_0_is_not_assignable_to_method_s_this_of_type_1, typeToString(type), typeToString(thisTypeForError)); 38107 } 38108 return undefined; 38109 } 38110 38111 const onfulfilledParameterType = getTypeWithFacts(getUnionType(map(candidates, getTypeOfFirstParameterOfSignature)), TypeFacts.NEUndefinedOrNull); 38112 if (isTypeAny(onfulfilledParameterType)) { 38113 return undefined; 38114 } 38115 38116 const onfulfilledParameterSignatures = getSignaturesOfType(onfulfilledParameterType, SignatureKind.Call); 38117 if (onfulfilledParameterSignatures.length === 0) { 38118 if (errorNode) { 38119 error(errorNode, Diagnostics.The_first_parameter_of_the_then_method_of_a_promise_must_be_a_callback); 38120 } 38121 return undefined; 38122 } 38123 38124 return typeAsPromise.promisedTypeOfPromise = getUnionType(map(onfulfilledParameterSignatures, getTypeOfFirstParameterOfSignature), UnionReduction.Subtype); 38125 } 38126 38127 /** 38128 * Gets the "awaited type" of a type. 38129 * @param type The type to await. 38130 * @param withAlias When `true`, wraps the "awaited type" in `Awaited<T>` if needed. 38131 * @remarks The "awaited type" of an expression is its "promised type" if the expression is a 38132 * Promise-like type; otherwise, it is the type of the expression. This is used to reflect 38133 * The runtime behavior of the `await` keyword. 38134 */ 38135 function checkAwaitedType(type: Type, withAlias: boolean, errorNode: Node, diagnosticMessage: DiagnosticMessage, arg0?: string | number): Type { 38136 const awaitedType = withAlias ? 38137 getAwaitedType(type, errorNode, diagnosticMessage, arg0) : 38138 getAwaitedTypeNoAlias(type, errorNode, diagnosticMessage, arg0); 38139 return awaitedType || errorType; 38140 } 38141 38142 /** 38143 * Determines whether a type is an object with a callable `then` member. 38144 */ 38145 function isThenableType(type: Type): boolean { 38146 if (allTypesAssignableToKind(getBaseConstraintOrType(type), TypeFlags.Primitive | TypeFlags.Never)) { 38147 // primitive types cannot be considered "thenable" since they are not objects. 38148 return false; 38149 } 38150 38151 const thenFunction = getTypeOfPropertyOfType(type, "then" as __String); 38152 return !!thenFunction && getSignaturesOfType(getTypeWithFacts(thenFunction, TypeFacts.NEUndefinedOrNull), SignatureKind.Call).length > 0; 38153 } 38154 38155 interface AwaitedTypeInstantiation extends Type { 38156 _awaitedTypeBrand: never; 38157 aliasSymbol: Symbol; 38158 aliasTypeArguments: readonly Type[]; 38159 } 38160 38161 function isAwaitedTypeInstantiation(type: Type): type is AwaitedTypeInstantiation { 38162 if (type.flags & TypeFlags.Conditional) { 38163 const awaitedSymbol = getGlobalAwaitedSymbol(/*reportErrors*/ false); 38164 return !!awaitedSymbol && type.aliasSymbol === awaitedSymbol && type.aliasTypeArguments?.length === 1; 38165 } 38166 return false; 38167 } 38168 38169 /** 38170 * For a generic `Awaited<T>`, gets `T`. 38171 */ 38172 function unwrapAwaitedType(type: Type) { 38173 return type.flags & TypeFlags.Union ? mapType(type, unwrapAwaitedType) : 38174 isAwaitedTypeInstantiation(type) ? type.aliasTypeArguments[0] : 38175 type; 38176 } 38177 38178 function isAwaitedTypeNeeded(type: Type) { 38179 // If this is already an `Awaited<T>`, we shouldn't wrap it. This helps to avoid `Awaited<Awaited<T>>` in higher-order. 38180 if (isTypeAny(type) || isAwaitedTypeInstantiation(type)) { 38181 return false; 38182 } 38183 38184 // We only need `Awaited<T>` if `T` contains possibly non-primitive types. 38185 if (isGenericObjectType(type)) { 38186 const baseConstraint = getBaseConstraintOfType(type); 38187 // We only need `Awaited<T>` if `T` is a type variable that has no base constraint, or the base constraint of `T` is `any`, `unknown`, `{}`, `object`, 38188 // or is promise-like. 38189 if (baseConstraint ? 38190 baseConstraint.flags & TypeFlags.AnyOrUnknown || isEmptyObjectType(baseConstraint) || someType(baseConstraint, isThenableType) : 38191 maybeTypeOfKind(type, TypeFlags.TypeVariable)) { 38192 return true; 38193 } 38194 } 38195 38196 return false; 38197 } 38198 38199 function tryCreateAwaitedType(type: Type): Type | undefined { 38200 // Nothing to do if `Awaited<T>` doesn't exist 38201 const awaitedSymbol = getGlobalAwaitedSymbol(/*reportErrors*/ true); 38202 if (awaitedSymbol) { 38203 // Unwrap unions that may contain `Awaited<T>`, otherwise its possible to manufacture an `Awaited<Awaited<T> | U>` where 38204 // an `Awaited<T | U>` would suffice. 38205 return getTypeAliasInstantiation(awaitedSymbol, [unwrapAwaitedType(type)]); 38206 } 38207 38208 return undefined; 38209 } 38210 38211 function createAwaitedTypeIfNeeded(type: Type): Type { 38212 // We wrap type `T` in `Awaited<T>` based on the following conditions: 38213 // - `T` is not already an `Awaited<U>`, and 38214 // - `T` is generic, and 38215 // - One of the following applies: 38216 // - `T` has no base constraint, or 38217 // - The base constraint of `T` is `any`, `unknown`, `object`, or `{}`, or 38218 // - The base constraint of `T` is an object type with a callable `then` method. 38219 38220 if (isAwaitedTypeNeeded(type)) { 38221 const awaitedType = tryCreateAwaitedType(type); 38222 if (awaitedType) { 38223 return awaitedType; 38224 } 38225 } 38226 38227 Debug.assert(getPromisedTypeOfPromise(type) === undefined, "type provided should not be a non-generic 'promise'-like."); 38228 return type; 38229 } 38230 38231 /** 38232 * Gets the "awaited type" of a type. 38233 * 38234 * The "awaited type" of an expression is its "promised type" if the expression is a 38235 * Promise-like type; otherwise, it is the type of the expression. If the "promised 38236 * type" is itself a Promise-like, the "promised type" is recursively unwrapped until a 38237 * non-promise type is found. 38238 * 38239 * This is used to reflect the runtime behavior of the `await` keyword. 38240 */ 38241 function getAwaitedType(type: Type, errorNode?: Node, diagnosticMessage?: DiagnosticMessage, arg0?: string | number): Type | undefined { 38242 const awaitedType = getAwaitedTypeNoAlias(type, errorNode, diagnosticMessage, arg0); 38243 return awaitedType && createAwaitedTypeIfNeeded(awaitedType); 38244 } 38245 38246 /** 38247 * Gets the "awaited type" of a type without introducing an `Awaited<T>` wrapper. 38248 * 38249 * @see {@link getAwaitedType} 38250 */ 38251 function getAwaitedTypeNoAlias(type: Type, errorNode?: Node, diagnosticMessage?: DiagnosticMessage, arg0?: string | number): Type | undefined { 38252 if (isTypeAny(type)) { 38253 return type; 38254 } 38255 38256 // If this is already an `Awaited<T>`, just return it. This avoids `Awaited<Awaited<T>>` in higher-order 38257 if (isAwaitedTypeInstantiation(type)) { 38258 return type; 38259 } 38260 38261 // If we've already cached an awaited type, return a possible `Awaited<T>` for it. 38262 const typeAsAwaitable = type as PromiseOrAwaitableType; 38263 if (typeAsAwaitable.awaitedTypeOfType) { 38264 return typeAsAwaitable.awaitedTypeOfType; 38265 } 38266 38267 // For a union, get a union of the awaited types of each constituent. 38268 if (type.flags & TypeFlags.Union) { 38269 if (awaitedTypeStack.lastIndexOf(type.id) >= 0) { 38270 if (errorNode) { 38271 error(errorNode, Diagnostics.Type_is_referenced_directly_or_indirectly_in_the_fulfillment_callback_of_its_own_then_method); 38272 } 38273 return undefined; 38274 } 38275 38276 const mapper = errorNode ? (constituentType: Type) => getAwaitedTypeNoAlias(constituentType, errorNode, diagnosticMessage, arg0) : getAwaitedTypeNoAlias; 38277 38278 awaitedTypeStack.push(type.id); 38279 const mapped = mapType(type, mapper); 38280 awaitedTypeStack.pop(); 38281 38282 return typeAsAwaitable.awaitedTypeOfType = mapped; 38283 } 38284 38285 // If `type` is generic and should be wrapped in `Awaited<T>`, return it. 38286 if (isAwaitedTypeNeeded(type)) { 38287 return typeAsAwaitable.awaitedTypeOfType = type; 38288 } 38289 38290 const thisTypeForErrorOut: { value: Type | undefined } = { value: undefined }; 38291 const promisedType = getPromisedTypeOfPromise(type, /*errorNode*/ undefined, thisTypeForErrorOut); 38292 if (promisedType) { 38293 if (type.id === promisedType.id || awaitedTypeStack.lastIndexOf(promisedType.id) >= 0) { 38294 // Verify that we don't have a bad actor in the form of a promise whose 38295 // promised type is the same as the promise type, or a mutually recursive 38296 // promise. If so, we return undefined as we cannot guess the shape. If this 38297 // were the actual case in the JavaScript, this Promise would never resolve. 38298 // 38299 // An example of a bad actor with a singly-recursive promise type might 38300 // be: 38301 // 38302 // interface BadPromise { 38303 // then( 38304 // onfulfilled: (value: BadPromise) => any, 38305 // onrejected: (error: any) => any): BadPromise; 38306 // } 38307 // 38308 // The above interface will pass the PromiseLike check, and return a 38309 // promised type of `BadPromise`. Since this is a self reference, we 38310 // don't want to keep recursing ad infinitum. 38311 // 38312 // An example of a bad actor in the form of a mutually-recursive 38313 // promise type might be: 38314 // 38315 // interface BadPromiseA { 38316 // then( 38317 // onfulfilled: (value: BadPromiseB) => any, 38318 // onrejected: (error: any) => any): BadPromiseB; 38319 // } 38320 // 38321 // interface BadPromiseB { 38322 // then( 38323 // onfulfilled: (value: BadPromiseA) => any, 38324 // onrejected: (error: any) => any): BadPromiseA; 38325 // } 38326 // 38327 if (errorNode) { 38328 error(errorNode, Diagnostics.Type_is_referenced_directly_or_indirectly_in_the_fulfillment_callback_of_its_own_then_method); 38329 } 38330 return undefined; 38331 } 38332 38333 // Keep track of the type we're about to unwrap to avoid bad recursive promise types. 38334 // See the comments above for more information. 38335 awaitedTypeStack.push(type.id); 38336 const awaitedType = getAwaitedTypeNoAlias(promisedType, errorNode, diagnosticMessage, arg0); 38337 awaitedTypeStack.pop(); 38338 38339 if (!awaitedType) { 38340 return undefined; 38341 } 38342 38343 return typeAsAwaitable.awaitedTypeOfType = awaitedType; 38344 } 38345 38346 // The type was not a promise, so it could not be unwrapped any further. 38347 // As long as the type does not have a callable "then" property, it is 38348 // safe to return the type; otherwise, an error is reported and we return 38349 // undefined. 38350 // 38351 // An example of a non-promise "thenable" might be: 38352 // 38353 // await { then(): void {} } 38354 // 38355 // The "thenable" does not match the minimal definition for a promise. When 38356 // a Promise/A+-compatible or ES6 promise tries to adopt this value, the promise 38357 // will never settle. We treat this as an error to help flag an early indicator 38358 // of a runtime problem. If the user wants to return this value from an async 38359 // function, they would need to wrap it in some other value. If they want it to 38360 // be treated as a promise, they can cast to <any>. 38361 if (isThenableType(type)) { 38362 if (errorNode) { 38363 Debug.assertIsDefined(diagnosticMessage); 38364 let chain: DiagnosticMessageChain | undefined; 38365 if (thisTypeForErrorOut.value) { 38366 chain = chainDiagnosticMessages(chain, Diagnostics.The_this_context_of_type_0_is_not_assignable_to_method_s_this_of_type_1, typeToString(type), typeToString(thisTypeForErrorOut.value)); 38367 } 38368 chain = chainDiagnosticMessages(chain, diagnosticMessage, arg0); 38369 diagnostics.add(createDiagnosticForNodeFromMessageChain(errorNode, chain)); 38370 } 38371 return undefined; 38372 } 38373 38374 return typeAsAwaitable.awaitedTypeOfType = type; 38375 } 38376 38377 /** 38378 * Checks the return type of an async function to ensure it is a compatible 38379 * Promise implementation. 38380 * 38381 * This checks that an async function has a valid Promise-compatible return type. 38382 * An async function has a valid Promise-compatible return type if the resolved value 38383 * of the return type has a construct signature that takes in an `initializer` function 38384 * that in turn supplies a `resolve` function as one of its arguments and results in an 38385 * object with a callable `then` signature. 38386 * 38387 * @param node The signature to check 38388 */ 38389 function checkAsyncFunctionReturnType(node: FunctionLikeDeclaration | MethodSignature, returnTypeNode: TypeNode) { 38390 // As part of our emit for an async function, we will need to emit the entity name of 38391 // the return type annotation as an expression. To meet the necessary runtime semantics 38392 // for __awaiter, we must also check that the type of the declaration (e.g. the static 38393 // side or "constructor" of the promise type) is compatible `PromiseConstructorLike`. 38394 // 38395 // An example might be (from lib.es6.d.ts): 38396 // 38397 // interface Promise<T> { ... } 38398 // interface PromiseConstructor { 38399 // new <T>(...): Promise<T>; 38400 // } 38401 // declare var Promise: PromiseConstructor; 38402 // 38403 // When an async function declares a return type annotation of `Promise<T>`, we 38404 // need to get the type of the `Promise` variable declaration above, which would 38405 // be `PromiseConstructor`. 38406 // 38407 // The same case applies to a class: 38408 // 38409 // declare class Promise<T> { 38410 // constructor(...); 38411 // then<U>(...): Promise<U>; 38412 // } 38413 // 38414 const returnType = getTypeFromTypeNode(returnTypeNode); 38415 38416 if (languageVersion >= ScriptTarget.ES2015) { 38417 if (isErrorType(returnType)) { 38418 return; 38419 } 38420 const globalPromiseType = getGlobalPromiseType(/*reportErrors*/ true); 38421 if (globalPromiseType !== emptyGenericType && !isReferenceToType(returnType, globalPromiseType)) { 38422 // The promise type was not a valid type reference to the global promise type, so we 38423 // report an error and return the unknown type. 38424 error(returnTypeNode, Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type_Did_you_mean_to_write_Promise_0, typeToString(getAwaitedTypeNoAlias(returnType) || voidType)); 38425 return; 38426 } 38427 } 38428 else { 38429 // Always mark the type node as referenced if it points to a value 38430 markTypeNodeAsReferenced(returnTypeNode); 38431 38432 if (isErrorType(returnType)) { 38433 return; 38434 } 38435 38436 const promiseConstructorName = getEntityNameFromTypeNode(returnTypeNode); 38437 if (promiseConstructorName === undefined) { 38438 error(returnTypeNode, Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, typeToString(returnType)); 38439 return; 38440 } 38441 38442 const promiseConstructorSymbol = resolveEntityName(promiseConstructorName, SymbolFlags.Value, /*ignoreErrors*/ true); 38443 const promiseConstructorType = promiseConstructorSymbol ? getTypeOfSymbol(promiseConstructorSymbol) : errorType; 38444 if (isErrorType(promiseConstructorType)) { 38445 if (promiseConstructorName.kind === SyntaxKind.Identifier && promiseConstructorName.escapedText === "Promise" && getTargetType(returnType) === getGlobalPromiseType(/*reportErrors*/ false)) { 38446 error(returnTypeNode, Diagnostics.An_async_function_or_method_in_ES5_SlashES3_requires_the_Promise_constructor_Make_sure_you_have_a_declaration_for_the_Promise_constructor_or_include_ES2015_in_your_lib_option); 38447 } 38448 else { 38449 error(returnTypeNode, Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, entityNameToString(promiseConstructorName)); 38450 } 38451 return; 38452 } 38453 38454 const globalPromiseConstructorLikeType = getGlobalPromiseConstructorLikeType(/*reportErrors*/ true); 38455 if (globalPromiseConstructorLikeType === emptyObjectType) { 38456 // If we couldn't resolve the global PromiseConstructorLike type we cannot verify 38457 // compatibility with __awaiter. 38458 error(returnTypeNode, Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, entityNameToString(promiseConstructorName)); 38459 return; 38460 } 38461 38462 if (!checkTypeAssignableTo(promiseConstructorType, globalPromiseConstructorLikeType, returnTypeNode, 38463 Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value)) { 38464 return; 38465 } 38466 38467 // Verify there is no local declaration that could collide with the promise constructor. 38468 const rootName = promiseConstructorName && getFirstIdentifier(promiseConstructorName); 38469 const collidingSymbol = getSymbol(node.locals!, rootName.escapedText, SymbolFlags.Value); 38470 if (collidingSymbol) { 38471 error(collidingSymbol.valueDeclaration, Diagnostics.Duplicate_identifier_0_Compiler_uses_declaration_1_to_support_async_functions, 38472 idText(rootName), 38473 entityNameToString(promiseConstructorName)); 38474 return; 38475 } 38476 } 38477 checkAwaitedType(returnType, /*withAlias*/ false, node, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member); 38478 } 38479 38480 /** Check a decorator */ 38481 function checkDecorator(node: Decorator): void { 38482 const signature = getResolvedSignature(node); 38483 checkDeprecatedSignature(signature, node); 38484 const returnType = getReturnTypeOfSignature(signature); 38485 if (returnType.flags & TypeFlags.Any) { 38486 return; 38487 } 38488 38489 let headMessage: DiagnosticMessage; 38490 let expectedReturnType: Type; 38491 switch (node.parent.kind) { 38492 case SyntaxKind.ClassDeclaration: 38493 case SyntaxKind.StructDeclaration: 38494 headMessage = Diagnostics.Decorator_function_return_type_0_is_not_assignable_to_type_1; 38495 const classSymbol = getSymbolOfNode(node.parent); 38496 const classConstructorType = getTypeOfSymbol(classSymbol); 38497 expectedReturnType = getUnionType([classConstructorType, voidType]); 38498 break; 38499 38500 case SyntaxKind.PropertyDeclaration: 38501 case SyntaxKind.Parameter: 38502 headMessage = Diagnostics.Decorator_function_return_type_is_0_but_is_expected_to_be_void_or_any; 38503 expectedReturnType = voidType; 38504 break; 38505 38506 case SyntaxKind.MethodDeclaration: 38507 case SyntaxKind.GetAccessor: 38508 case SyntaxKind.SetAccessor: 38509 headMessage = Diagnostics.Decorator_function_return_type_0_is_not_assignable_to_type_1; 38510 const methodType = getTypeOfNode(node.parent); 38511 const descriptorType = createTypedPropertyDescriptorType(methodType); 38512 expectedReturnType = getUnionType([descriptorType, voidType]); 38513 break; 38514 38515 default: 38516 return Debug.fail(); 38517 } 38518 38519 checkTypeAssignableTo( 38520 returnType, 38521 expectedReturnType, 38522 node, 38523 headMessage); 38524 } 38525 38526 /** 38527 * If a TypeNode can be resolved to a value symbol imported from an external module, it is 38528 * marked as referenced to prevent import elision. 38529 */ 38530 function markTypeNodeAsReferenced(node: TypeNode) { 38531 markEntityNameOrEntityExpressionAsReference(node && getEntityNameFromTypeNode(node), /*forDecoratorMetadata*/ false); 38532 } 38533 38534 function markEntityNameOrEntityExpressionAsReference(typeName: EntityNameOrEntityNameExpression | undefined, forDecoratorMetadata: boolean) { 38535 if (!typeName) return; 38536 38537 const rootName = getFirstIdentifier(typeName); 38538 const meaning = (typeName.kind === SyntaxKind.Identifier ? SymbolFlags.Type : SymbolFlags.Namespace) | SymbolFlags.Alias; 38539 const rootSymbol = resolveName(rootName, rootName.escapedText, meaning, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isReference*/ true); 38540 if (rootSymbol && rootSymbol.flags & SymbolFlags.Alias) { 38541 if (symbolIsValue(rootSymbol) 38542 && !isConstEnumOrConstEnumOnlyModule(resolveAlias(rootSymbol)) 38543 && !getTypeOnlyAliasDeclaration(rootSymbol)) { 38544 markAliasSymbolAsReferenced(rootSymbol); 38545 } 38546 else if (forDecoratorMetadata 38547 && compilerOptions.isolatedModules 38548 && getEmitModuleKind(compilerOptions) >= ModuleKind.ES2015 38549 && !symbolIsValue(rootSymbol) 38550 && !some(rootSymbol.declarations, isTypeOnlyImportOrExportDeclaration)) { 38551 const diag = error(typeName, Diagnostics.A_type_referenced_in_a_decorated_signature_must_be_imported_with_import_type_or_a_namespace_import_when_isolatedModules_and_emitDecoratorMetadata_are_enabled); 38552 const aliasDeclaration = find(rootSymbol.declarations || emptyArray, isAliasSymbolDeclaration); 38553 if (aliasDeclaration) { 38554 addRelatedInfo(diag, createDiagnosticForNode(aliasDeclaration, Diagnostics._0_was_imported_here, idText(rootName))); 38555 } 38556 } 38557 } 38558 } 38559 38560 /** 38561 * This function marks the type used for metadata decorator as referenced if it is import 38562 * from external module. 38563 * This is different from markTypeNodeAsReferenced because it tries to simplify type nodes in 38564 * union and intersection type 38565 * @param node 38566 */ 38567 function markDecoratorMedataDataTypeNodeAsReferenced(node: TypeNode | undefined): void { 38568 const entityName = getEntityNameForDecoratorMetadata(node); 38569 if (entityName && isEntityName(entityName)) { 38570 markEntityNameOrEntityExpressionAsReference(entityName, /*forDecoratorMetadata*/ true); 38571 } 38572 } 38573 38574 function getEntityNameForDecoratorMetadata(node: TypeNode | undefined): EntityName | undefined { 38575 if (node) { 38576 switch (node.kind) { 38577 case SyntaxKind.IntersectionType: 38578 case SyntaxKind.UnionType: 38579 return getEntityNameForDecoratorMetadataFromTypeList((node as UnionOrIntersectionTypeNode).types); 38580 38581 case SyntaxKind.ConditionalType: 38582 return getEntityNameForDecoratorMetadataFromTypeList([(node as ConditionalTypeNode).trueType, (node as ConditionalTypeNode).falseType]); 38583 38584 case SyntaxKind.ParenthesizedType: 38585 case SyntaxKind.NamedTupleMember: 38586 return getEntityNameForDecoratorMetadata((node as ParenthesizedTypeNode).type); 38587 38588 case SyntaxKind.TypeReference: 38589 return (node as TypeReferenceNode).typeName; 38590 } 38591 } 38592 } 38593 38594 function getEntityNameForDecoratorMetadataFromTypeList(types: readonly TypeNode[]): EntityName | undefined { 38595 let commonEntityName: EntityName | undefined; 38596 for (let typeNode of types) { 38597 while (typeNode.kind === SyntaxKind.ParenthesizedType || typeNode.kind === SyntaxKind.NamedTupleMember) { 38598 typeNode = (typeNode as ParenthesizedTypeNode | NamedTupleMember).type; // Skip parens if need be 38599 } 38600 if (typeNode.kind === SyntaxKind.NeverKeyword) { 38601 continue; // Always elide `never` from the union/intersection if possible 38602 } 38603 if (!strictNullChecks && (typeNode.kind === SyntaxKind.LiteralType && (typeNode as LiteralTypeNode).literal.kind === SyntaxKind.NullKeyword || typeNode.kind === SyntaxKind.UndefinedKeyword)) { 38604 continue; // Elide null and undefined from unions for metadata, just like what we did prior to the implementation of strict null checks 38605 } 38606 const individualEntityName = getEntityNameForDecoratorMetadata(typeNode); 38607 if (!individualEntityName) { 38608 // Individual is something like string number 38609 // So it would be serialized to either that type or object 38610 // Safe to return here 38611 return undefined; 38612 } 38613 38614 if (commonEntityName) { 38615 // Note this is in sync with the transformation that happens for type node. 38616 // Keep this in sync with serializeUnionOrIntersectionType 38617 // Verify if they refer to same entity and is identifier 38618 // return undefined if they dont match because we would emit object 38619 if (!isIdentifier(commonEntityName) || 38620 !isIdentifier(individualEntityName) || 38621 commonEntityName.escapedText !== individualEntityName.escapedText) { 38622 return undefined; 38623 } 38624 } 38625 else { 38626 commonEntityName = individualEntityName; 38627 } 38628 } 38629 return commonEntityName; 38630 } 38631 38632 function getParameterTypeNodeForDecoratorCheck(node: ParameterDeclaration): TypeNode | undefined { 38633 const typeNode = getEffectiveTypeAnnotationNode(node); 38634 return isRestParameter(node) ? getRestParameterElementType(typeNode) : typeNode; 38635 } 38636 38637 function checkIdentifierJsDoc(node: Identifier, sourceSymbol: Symbol): void { 38638 if (node.virtual || !jsDocFileCheckInfo.fileNeedCheck || !getJsDocNodeCheckedConfig) { 38639 return; 38640 } 38641 if (!sourceSymbol || !sourceSymbol.valueDeclaration) { 38642 return; 38643 } 38644 const sourceSymbolSourceFile = getSourceFileOfNode(sourceSymbol.valueDeclaration); 38645 if (!sourceSymbolSourceFile) { 38646 return; 38647 } 38648 const sourceFile = getSourceFileOfNode(node); 38649 const checkParam = getJsDocNodeCheckedConfig(jsDocFileCheckInfo, sourceSymbolSourceFile.fileName); 38650 if (!checkParam.nodeNeedCheck) { 38651 return; 38652 } 38653 38654 sourceSymbol.declarations?.forEach(declaration => { 38655 expressionCheckByJsDoc(declaration, node, sourceFile, checkParam.checkConfig); 38656 }); 38657 } 38658 38659 /** Check the annotation of a node */ 38660 function checkAnnotation(annotation: Annotation, annotationsSet: Set<String>): void { 38661 const signature = getResolvedSignature(annotation); 38662 const returnType = getReturnTypeOfSignature(signature); 38663 if (isErrorType(returnType)) { 38664 return; 38665 } 38666 38667 const annotatedDecl = annotation.parent; 38668 38669 // Only classes or methods must be annotated 38670 if (!isClassDeclaration(annotatedDecl) && !isMethodDeclaration(annotatedDecl)) { 38671 const nodeStr = getTextOfNode(annotatedDecl, /*includeTrivia*/ false); 38672 error(annotation, Diagnostics.Annotation_have_to_be_applied_for_classes_or_methods_only_got_Colon_0, nodeStr); 38673 return; 38674 } 38675 38676 // Prohibit application of annotation for abstract classes and methods 38677 if (hasSyntacticModifier(annotatedDecl, ModifierFlags.Abstract)) { 38678 const nodeStr = getTextOfNode(annotatedDecl, /*includeTrivia*/ false); 38679 error(annotation, Diagnostics.Annotation_have_to_be_applied_only_for_non_abstract_class_declarations_and_method_declarations_in_non_abstract_classes_got_Colon_0, nodeStr); 38680 return; 38681 } 38682 38683 switch (annotatedDecl.kind) { 38684 case SyntaxKind.ClassDeclaration: 38685 break; 38686 case SyntaxKind.MethodDeclaration: 38687 const enclosingDecl = annotatedDecl.parent; 38688 Debug.assert(isClassDeclaration(enclosingDecl)); 38689 38690 /* abstract class C { 38691 * @goo 38692 * puiblic foo(){} 38693 * } 38694 */ 38695 if (hasSyntacticModifier(enclosingDecl, ModifierFlags.Abstract)) { 38696 const nodeStr = getTextOfNode(enclosingDecl, /*includeTrivia*/ false); 38697 error(annotation, Diagnostics.Annotation_have_to_be_applied_only_for_non_abstract_class_declarations_and_method_declarations_in_non_abstract_classes_got_Colon_0, nodeStr); 38698 } 38699 break; 38700 default: 38701 Debug.fail(); 38702 } 38703 38704 // Check duplication 38705 38706 Debug.assert(annotation.annotationDeclaration); 38707 const typeName = typeToString(getTypeOfSymbol(getSymbolOfNode(annotation.annotationDeclaration)), /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType); 38708 if (annotationsSet.size && annotationsSet.has(typeName)) { 38709 const nodeStr = getTextOfNode(annotation, /*includeTrivia*/ false); 38710 error(annotation, Diagnostics.Repeatable_annotation_are_not_supported_got_Colon_0, nodeStr); 38711 return; 38712 } 38713 else { 38714 annotationsSet.add(typeName); 38715 } 38716 } 38717 38718 /** Returns declaration which is related to an annotation */ 38719 function getAnnotationDeclaration(da: Decorator | Annotation): AnnotationDeclaration | undefined { 38720 let ident; 38721 switch (da.expression.kind) { 38722 case SyntaxKind.Identifier: 38723 ident = da.expression as Identifier; 38724 break; 38725 case SyntaxKind.PropertyAccessExpression: 38726 ident = da.expression as PropertyAccessExpression; 38727 break; 38728 case SyntaxKind.CallExpression: 38729 ident = getIdentifierFromEntityNameExpression((da.expression as CallExpression).expression); 38730 break; 38731 default: 38732 return undefined; 38733 } 38734 if (!ident) { 38735 return undefined; 38736 } 38737 const symbol = getSymbolOfNameOrPropertyAccessExpression(ident, /*ignoreErrors*/ true); 38738 if (!symbol) { 38739 return undefined; 38740 } 38741 const type = getTypeOfSymbolAtLocation(symbol, ident); 38742 if (!type || !type.symbol || !type.symbol.declarations) { 38743 return undefined; 38744 } 38745 if (!isAnnotationDeclaration(type.symbol.declarations[0])) { 38746 return undefined; 38747 } 38748 return type.symbol.declarations[0]; 38749 } 38750 38751 /** Check the decorators of a node */ 38752 function checkDecorators(node: Node): void { 38753 let atLeastOneDecorator = false; 38754 getAllDecorators(node).forEach(item => { 38755 if (isIdentifier(item.expression)) { 38756 const symbol = getResolvedSymbol(item.expression); 38757 if (symbol !== unknownSymbol) { 38758 checkIdentifierJsDoc(item.expression, symbol); 38759 } 38760 } 38761 const annotationDecl = getAnnotationDeclaration(item); 38762 if (annotationDecl) { 38763 (item as Mutable<Decorator>).annotationDeclaration = annotationDecl; 38764 } 38765 else { 38766 atLeastOneDecorator = true; 38767 } 38768 }); 38769 38770 // skip this check for nodes that cannot have decorators. These should have already had an error reported by 38771 // checkGrammarDecorators. 38772 if (!canHaveDecorators(node) || !hasDecorators(node) && !hasAnnotations(node) || !node.modifiers || !nodeCanBeDecorated(node, node.parent, node.parent.parent)) { 38773 return; 38774 } 38775 38776 // Skip checking if we have no at least one decorator 38777 if (atLeastOneDecorator && !compilerOptions.experimentalDecorators) { 38778 error(node, Diagnostics.Experimental_support_for_decorators_is_a_feature_that_is_subject_to_change_in_a_future_release_Set_the_experimentalDecorators_option_in_your_tsconfig_or_jsconfig_to_remove_this_warning); 38779 } 38780 38781 // Accumulator for duplications check 38782 const annotationsSet = new Set<String>(); 38783 // Detect annotations and performing specific checks 38784 for (const modifier of node.modifiers) { 38785 if (isAnnotation(modifier)) { 38786 checkAnnotation(modifier, annotationsSet); 38787 } 38788 } 38789 38790 const firstDecorator = find(node.modifiers, isDecorator); 38791 if (!firstDecorator) { 38792 return; 38793 } 38794 38795 checkExternalEmitHelpers(firstDecorator, ExternalEmitHelpers.Decorate); 38796 if (node.kind === SyntaxKind.Parameter) { 38797 checkExternalEmitHelpers(firstDecorator, ExternalEmitHelpers.Param); 38798 } 38799 38800 if (compilerOptions.emitDecoratorMetadata) { 38801 checkExternalEmitHelpers(firstDecorator, ExternalEmitHelpers.Metadata); 38802 38803 // we only need to perform these checks if we are emitting serialized type metadata for the target of a decorator. 38804 switch (node.kind) { 38805 case SyntaxKind.ClassDeclaration: 38806 const constructor = getFirstConstructorWithBody(node); 38807 if (constructor) { 38808 for (const parameter of constructor.parameters) { 38809 markDecoratorMedataDataTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(parameter)); 38810 } 38811 } 38812 break; 38813 38814 case SyntaxKind.GetAccessor: 38815 case SyntaxKind.SetAccessor: 38816 const otherKind = node.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor : SyntaxKind.GetAccessor; 38817 const otherAccessor = getDeclarationOfKind<AccessorDeclaration>(getSymbolOfNode(node), otherKind); 38818 markDecoratorMedataDataTypeNodeAsReferenced(getAnnotatedAccessorTypeNode(node) || otherAccessor && getAnnotatedAccessorTypeNode(otherAccessor)); 38819 break; 38820 case SyntaxKind.MethodDeclaration: 38821 for (const parameter of node.parameters) { 38822 markDecoratorMedataDataTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(parameter)); 38823 } 38824 38825 markDecoratorMedataDataTypeNodeAsReferenced(getEffectiveReturnTypeNode(node)); 38826 break; 38827 38828 case SyntaxKind.PropertyDeclaration: 38829 markDecoratorMedataDataTypeNodeAsReferenced(getEffectiveTypeAnnotationNode(node)); 38830 break; 38831 38832 case SyntaxKind.Parameter: 38833 markDecoratorMedataDataTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(node)); 38834 const containingSignature = node.parent; 38835 for (const parameter of containingSignature.parameters) { 38836 markDecoratorMedataDataTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(parameter)); 38837 } 38838 break; 38839 } 38840 } 38841 38842 for (const modifier of node.modifiers) { 38843 if (isDecorator(modifier)) { 38844 checkDecorator(modifier); 38845 } 38846 } 38847 } 38848 38849 function checkFunctionDeclaration(node: FunctionDeclaration): void { 38850 addLazyDiagnostic(checkFunctionDeclarationDiagnostics); 38851 38852 function checkFunctionDeclarationDiagnostics() { 38853 checkFunctionOrMethodDeclaration(node); 38854 checkGrammarForGenerator(node); 38855 checkCollisionsForDeclarationName(node, node.name); 38856 } 38857 } 38858 38859 function checkJSDocTypeAliasTag(node: JSDocTypedefTag | JSDocCallbackTag) { 38860 if (!node.typeExpression) { 38861 // If the node had `@property` tags, `typeExpression` would have been set to the first property tag. 38862 error(node.name, Diagnostics.JSDoc_typedef_tag_should_either_have_a_type_annotation_or_be_followed_by_property_or_member_tags); 38863 } 38864 38865 if (node.name) { 38866 checkTypeNameIsReserved(node.name, Diagnostics.Type_alias_name_cannot_be_0); 38867 } 38868 checkSourceElement(node.typeExpression); 38869 checkTypeParameters(getEffectiveTypeParameterDeclarations(node)); 38870 } 38871 38872 function checkJSDocTemplateTag(node: JSDocTemplateTag): void { 38873 checkSourceElement(node.constraint); 38874 for (const tp of node.typeParameters) { 38875 checkSourceElement(tp); 38876 } 38877 } 38878 38879 function checkJSDocTypeTag(node: JSDocTypeTag) { 38880 checkSourceElement(node.typeExpression); 38881 } 38882 38883 function checkJSDocLinkLikeTag(node: JSDocLink | JSDocLinkCode | JSDocLinkPlain) { 38884 if (node.name) { 38885 resolveJSDocMemberName(node.name, /*ignoreErrors*/ true); 38886 } 38887 } 38888 38889 function checkJSDocParameterTag(node: JSDocParameterTag) { 38890 checkSourceElement(node.typeExpression); 38891 } 38892 function checkJSDocPropertyTag(node: JSDocPropertyTag) { 38893 checkSourceElement(node.typeExpression); 38894 } 38895 38896 function checkJSDocFunctionType(node: JSDocFunctionType): void { 38897 addLazyDiagnostic(checkJSDocFunctionTypeImplicitAny); 38898 checkSignatureDeclaration(node); 38899 38900 function checkJSDocFunctionTypeImplicitAny() { 38901 if (!node.type && !isJSDocConstructSignature(node)) { 38902 reportImplicitAny(node, anyType); 38903 } 38904 } 38905 } 38906 38907 function checkJSDocImplementsTag(node: JSDocImplementsTag): void { 38908 const classLike = getEffectiveJSDocHost(node); 38909 if (!classLike || !isClassDeclaration(classLike) && !isClassExpression(classLike)) { 38910 error(classLike, Diagnostics.JSDoc_0_is_not_attached_to_a_class, idText(node.tagName)); 38911 } 38912 } 38913 38914 function checkJSDocAugmentsTag(node: JSDocAugmentsTag): void { 38915 const classLike = getEffectiveJSDocHost(node); 38916 if (!classLike || !isClassDeclaration(classLike) && !isClassExpression(classLike)) { 38917 error(classLike, Diagnostics.JSDoc_0_is_not_attached_to_a_class, idText(node.tagName)); 38918 return; 38919 } 38920 38921 const augmentsTags = getJSDocTags(classLike).filter(isJSDocAugmentsTag); 38922 Debug.assert(augmentsTags.length > 0); 38923 if (augmentsTags.length > 1) { 38924 error(augmentsTags[1], Diagnostics.Class_declarations_cannot_have_more_than_one_augments_or_extends_tag); 38925 } 38926 38927 const name = getIdentifierFromEntityNameExpression(node.class.expression); 38928 const extend = getClassExtendsHeritageElement(classLike); 38929 if (extend) { 38930 const className = getIdentifierFromEntityNameExpression(extend.expression); 38931 if (className && name.escapedText !== className.escapedText) { 38932 error(name, Diagnostics.JSDoc_0_1_does_not_match_the_extends_2_clause, idText(node.tagName), idText(name), idText(className)); 38933 } 38934 } 38935 } 38936 38937 function checkJSDocAccessibilityModifiers(node: JSDocPublicTag | JSDocProtectedTag | JSDocPrivateTag): void { 38938 const host = getJSDocHost(node); 38939 if (host && isPrivateIdentifierClassElementDeclaration(host)) { 38940 error(node, Diagnostics.An_accessibility_modifier_cannot_be_used_with_a_private_identifier); 38941 } 38942 } 38943 38944 function getIdentifierFromEntityNameExpression(node: Identifier | PropertyAccessExpression): Identifier | PrivateIdentifier; 38945 function getIdentifierFromEntityNameExpression(node: Expression): Identifier | PrivateIdentifier | undefined; 38946 function getIdentifierFromEntityNameExpression(node: Expression): Identifier | PrivateIdentifier | undefined { 38947 switch (node.kind) { 38948 case SyntaxKind.Identifier: 38949 return node as Identifier; 38950 case SyntaxKind.PropertyAccessExpression: 38951 return (node as PropertyAccessExpression).name; 38952 default: 38953 return undefined; 38954 } 38955 } 38956 38957 function checkFunctionOrMethodDeclaration(node: FunctionDeclaration | MethodDeclaration | MethodSignature): void { 38958 checkDecorators(node); 38959 checkSignatureDeclaration(node); 38960 const functionFlags = getFunctionFlags(node); 38961 38962 // Do not use hasDynamicName here, because that returns false for well known symbols. 38963 // We want to perform checkComputedPropertyName for all computed properties, including 38964 // well known symbols. 38965 if (node.name && node.name.kind === SyntaxKind.ComputedPropertyName) { 38966 // This check will account for methods in class/interface declarations, 38967 // as well as accessors in classes/object literals 38968 checkComputedPropertyName(node.name); 38969 } 38970 38971 if (hasBindableName(node)) { 38972 // first we want to check the local symbol that contain this declaration 38973 // - if node.localSymbol !== undefined - this is current declaration is exported and localSymbol points to the local symbol 38974 // - if node.localSymbol === undefined - this node is non-exported so we can just pick the result of getSymbolOfNode 38975 const symbol = getSymbolOfNode(node); 38976 const localSymbol = node.localSymbol || symbol; 38977 38978 // Since the javascript won't do semantic analysis like typescript, 38979 // if the javascript file comes before the typescript file and both contain same name functions, 38980 // checkFunctionOrConstructorSymbol wouldn't be called if we didnt ignore javascript function. 38981 const firstDeclaration = localSymbol.declarations?.find( 38982 // Get first non javascript function declaration 38983 declaration => declaration.kind === node.kind && !(declaration.flags & NodeFlags.JavaScriptFile)); 38984 38985 // Only type check the symbol once 38986 if (node === firstDeclaration) { 38987 checkFunctionOrConstructorSymbol(localSymbol); 38988 } 38989 38990 if (symbol.parent) { 38991 // run check on export symbol to check that modifiers agree across all exported declarations 38992 checkFunctionOrConstructorSymbol(symbol); 38993 } 38994 } 38995 38996 const body = node.kind === SyntaxKind.MethodSignature ? undefined : node.body; 38997 checkSourceElement(body); 38998 checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, getReturnTypeFromAnnotation(node)); 38999 39000 addLazyDiagnostic(checkFunctionOrMethodDeclarationDiagnostics); 39001 39002 // A js function declaration can have a @type tag instead of a return type node, but that type must have a call signature 39003 if (isInJSFile(node)) { 39004 const typeTag = getJSDocTypeTag(node); 39005 if (typeTag && typeTag.typeExpression && !getContextualCallSignature(getTypeFromTypeNode(typeTag.typeExpression), node)) { 39006 error(typeTag.typeExpression.type, Diagnostics.The_type_of_a_function_declaration_must_match_the_function_s_signature); 39007 } 39008 } 39009 39010 function checkFunctionOrMethodDeclarationDiagnostics() { 39011 if (!getEffectiveReturnTypeNode(node)) { 39012 // Report an implicit any error if there is no body, no explicit return type, and node is not a private method 39013 // in an ambient context 39014 if (nodeIsMissing(body) && !isPrivateWithinAmbient(node)) { 39015 reportImplicitAny(node, anyType); 39016 } 39017 39018 if (functionFlags & FunctionFlags.Generator && nodeIsPresent(body)) { 39019 // A generator with a body and no type annotation can still cause errors. It can error if the 39020 // yielded values have no common supertype, or it can give an implicit any error if it has no 39021 // yielded values. The only way to trigger these errors is to try checking its return type. 39022 getReturnTypeOfSignature(getSignatureFromDeclaration(node)); 39023 } 39024 } 39025 } 39026 } 39027 39028 function registerForUnusedIdentifiersCheck(node: PotentiallyUnusedIdentifier): void { 39029 addLazyDiagnostic(registerForUnusedIdentifiersCheckDiagnostics); 39030 39031 function registerForUnusedIdentifiersCheckDiagnostics() { 39032 // May be in a call such as getTypeOfNode that happened to call this. But potentiallyUnusedIdentifiers is only defined in the scope of `checkSourceFile`. 39033 const sourceFile = getSourceFileOfNode(node); 39034 let potentiallyUnusedIdentifiers = allPotentiallyUnusedIdentifiers.get(sourceFile.path); 39035 if (!potentiallyUnusedIdentifiers) { 39036 potentiallyUnusedIdentifiers = []; 39037 allPotentiallyUnusedIdentifiers.set(sourceFile.path, potentiallyUnusedIdentifiers); 39038 } 39039 // TODO: GH#22580 39040 // Debug.assert(addToSeen(seenPotentiallyUnusedIdentifiers, getNodeId(node)), "Adding potentially-unused identifier twice"); 39041 potentiallyUnusedIdentifiers.push(node); 39042 } 39043 } 39044 39045 type PotentiallyUnusedIdentifier = 39046 | SourceFile | ModuleDeclaration | ClassLikeDeclaration | InterfaceDeclaration 39047 | Block | CaseBlock | ForStatement | ForInStatement | ForOfStatement 39048 | Exclude<SignatureDeclaration, IndexSignatureDeclaration | JSDocFunctionType> | TypeAliasDeclaration 39049 | InferTypeNode; 39050 39051 function checkUnusedIdentifiers(potentiallyUnusedIdentifiers: readonly PotentiallyUnusedIdentifier[], addDiagnostic: AddUnusedDiagnostic) { 39052 for (const node of potentiallyUnusedIdentifiers) { 39053 switch (node.kind) { 39054 case SyntaxKind.ClassDeclaration: 39055 case SyntaxKind.ClassExpression: 39056 case SyntaxKind.StructDeclaration: 39057 checkUnusedClassMembers(node, addDiagnostic); 39058 checkUnusedTypeParameters(node, addDiagnostic); 39059 break; 39060 case SyntaxKind.SourceFile: 39061 case SyntaxKind.ModuleDeclaration: 39062 case SyntaxKind.Block: 39063 case SyntaxKind.CaseBlock: 39064 case SyntaxKind.ForStatement: 39065 case SyntaxKind.ForInStatement: 39066 case SyntaxKind.ForOfStatement: 39067 checkUnusedLocalsAndParameters(node, addDiagnostic); 39068 break; 39069 case SyntaxKind.Constructor: 39070 case SyntaxKind.FunctionExpression: 39071 case SyntaxKind.FunctionDeclaration: 39072 case SyntaxKind.ArrowFunction: 39073 case SyntaxKind.MethodDeclaration: 39074 case SyntaxKind.GetAccessor: 39075 case SyntaxKind.SetAccessor: 39076 if (node.body) { // Don't report unused parameters in overloads 39077 checkUnusedLocalsAndParameters(node, addDiagnostic); 39078 } 39079 checkUnusedTypeParameters(node, addDiagnostic); 39080 break; 39081 case SyntaxKind.MethodSignature: 39082 case SyntaxKind.CallSignature: 39083 case SyntaxKind.ConstructSignature: 39084 case SyntaxKind.FunctionType: 39085 case SyntaxKind.ConstructorType: 39086 case SyntaxKind.TypeAliasDeclaration: 39087 case SyntaxKind.InterfaceDeclaration: 39088 checkUnusedTypeParameters(node, addDiagnostic); 39089 break; 39090 case SyntaxKind.InferType: 39091 checkUnusedInferTypeParameter(node, addDiagnostic); 39092 break; 39093 default: 39094 Debug.assertNever(node, "Node should not have been registered for unused identifiers check"); 39095 } 39096 } 39097 } 39098 39099 function errorUnusedLocal(declaration: Declaration, name: string, addDiagnostic: AddUnusedDiagnostic) { 39100 const node = getNameOfDeclaration(declaration) || declaration; 39101 const message = isTypeDeclaration(declaration) ? Diagnostics._0_is_declared_but_never_used : Diagnostics._0_is_declared_but_its_value_is_never_read; 39102 addDiagnostic(declaration, UnusedKind.Local, createDiagnosticForNode(node, message, name)); 39103 } 39104 39105 function isIdentifierThatStartsWithUnderscore(node: Node) { 39106 return isIdentifier(node) && idText(node).charCodeAt(0) === CharacterCodes._; 39107 } 39108 39109 function checkUnusedClassMembers(node: ClassDeclaration | ClassExpression | StructDeclaration, addDiagnostic: AddUnusedDiagnostic): void { 39110 for (const member of node.members) { 39111 switch (member.kind) { 39112 case SyntaxKind.MethodDeclaration: 39113 case SyntaxKind.PropertyDeclaration: 39114 case SyntaxKind.GetAccessor: 39115 case SyntaxKind.SetAccessor: 39116 if (member.kind === SyntaxKind.SetAccessor && member.symbol.flags & SymbolFlags.GetAccessor) { 39117 // Already would have reported an error on the getter. 39118 break; 39119 } 39120 const symbol = getSymbolOfNode(member); 39121 if (!symbol.isReferenced 39122 && (hasEffectiveModifier(member, ModifierFlags.Private) || isNamedDeclaration(member) && isPrivateIdentifier(member.name)) 39123 && !(member.flags & NodeFlags.Ambient)) { 39124 addDiagnostic(member, UnusedKind.Local, createDiagnosticForNode(member.name!, Diagnostics._0_is_declared_but_its_value_is_never_read, symbolToString(symbol))); 39125 } 39126 break; 39127 case SyntaxKind.Constructor: 39128 for (const parameter of (member as ConstructorDeclaration).parameters) { 39129 if (!parameter.symbol.isReferenced && hasSyntacticModifier(parameter, ModifierFlags.Private)) { 39130 addDiagnostic(parameter, UnusedKind.Local, createDiagnosticForNode(parameter.name, Diagnostics.Property_0_is_declared_but_its_value_is_never_read, symbolName(parameter.symbol))); 39131 } 39132 } 39133 break; 39134 case SyntaxKind.IndexSignature: 39135 case SyntaxKind.SemicolonClassElement: 39136 case SyntaxKind.ClassStaticBlockDeclaration: 39137 // Can't be private 39138 break; 39139 default: 39140 Debug.fail("Unexpected class member"); 39141 } 39142 } 39143 } 39144 39145 function checkUnusedInferTypeParameter(node: InferTypeNode, addDiagnostic: AddUnusedDiagnostic): void { 39146 const { typeParameter } = node; 39147 if (isTypeParameterUnused(typeParameter)) { 39148 addDiagnostic(node, UnusedKind.Parameter, createDiagnosticForNode(node, Diagnostics._0_is_declared_but_its_value_is_never_read, idText(typeParameter.name))); 39149 } 39150 } 39151 39152 function checkUnusedTypeParameters(node: ClassLikeDeclaration | SignatureDeclaration | InterfaceDeclaration | TypeAliasDeclaration, addDiagnostic: AddUnusedDiagnostic): void { 39153 // Only report errors on the last declaration for the type parameter container; 39154 // this ensures that all uses have been accounted for. 39155 const declarations = getSymbolOfNode(node).declarations; 39156 if (!declarations || last(declarations) !== node) return; 39157 39158 const typeParameters = getEffectiveTypeParameterDeclarations(node); 39159 const seenParentsWithEveryUnused = new Set<DeclarationWithTypeParameterChildren>(); 39160 39161 for (const typeParameter of typeParameters) { 39162 if (!isTypeParameterUnused(typeParameter)) continue; 39163 39164 const name = idText(typeParameter.name); 39165 const { parent } = typeParameter; 39166 if (parent.kind !== SyntaxKind.InferType && parent.typeParameters!.every(isTypeParameterUnused)) { 39167 if (tryAddToSet(seenParentsWithEveryUnused, parent)) { 39168 const sourceFile = getSourceFileOfNode(parent); 39169 const range = isJSDocTemplateTag(parent) 39170 // Whole @template tag 39171 ? rangeOfNode(parent) 39172 // Include the `<>` in the error message 39173 : rangeOfTypeParameters(sourceFile, parent.typeParameters!); 39174 const only = parent.typeParameters!.length === 1; 39175 //TODO: following line is possible reason for bug #41974, unusedTypeParameters_TemplateTag 39176 const message = only ? Diagnostics._0_is_declared_but_its_value_is_never_read : Diagnostics.All_type_parameters_are_unused; 39177 const arg0 = only ? name : undefined; 39178 addDiagnostic(typeParameter, UnusedKind.Parameter, createFileDiagnostic(sourceFile, range.pos, range.end - range.pos, message, arg0)); 39179 } 39180 } 39181 else { 39182 //TODO: following line is possible reason for bug #41974, unusedTypeParameters_TemplateTag 39183 addDiagnostic(typeParameter, UnusedKind.Parameter, createDiagnosticForNode(typeParameter, Diagnostics._0_is_declared_but_its_value_is_never_read, name)); 39184 } 39185 } 39186 } 39187 function isTypeParameterUnused(typeParameter: TypeParameterDeclaration): boolean { 39188 return !(getMergedSymbol(typeParameter.symbol).isReferenced! & SymbolFlags.TypeParameter) && !isIdentifierThatStartsWithUnderscore(typeParameter.name); 39189 } 39190 39191 function addToGroup<K, V>(map: ESMap<string, [K, V[]]>, key: K, value: V, getKey: (key: K) => number | string): void { 39192 const keyString = String(getKey(key)); 39193 const group = map.get(keyString); 39194 if (group) { 39195 group[1].push(value); 39196 } 39197 else { 39198 map.set(keyString, [key, [value]]); 39199 } 39200 } 39201 39202 function tryGetRootParameterDeclaration(node: Node): ParameterDeclaration | undefined { 39203 return tryCast(getRootDeclaration(node), isParameter); 39204 } 39205 39206 function isValidUnusedLocalDeclaration(declaration: Declaration): boolean { 39207 if (isBindingElement(declaration)) { 39208 if (isObjectBindingPattern(declaration.parent)) { 39209 /** 39210 * ignore starts with underscore names _ 39211 * const { a: _a } = { a: 1 } 39212 */ 39213 return !!(declaration.propertyName && isIdentifierThatStartsWithUnderscore(declaration.name)); 39214 } 39215 return isIdentifierThatStartsWithUnderscore(declaration.name); 39216 } 39217 return isAmbientModule(declaration) || 39218 (isVariableDeclaration(declaration) && isForInOrOfStatement(declaration.parent.parent) || isImportedDeclaration(declaration)) && isIdentifierThatStartsWithUnderscore(declaration.name!); 39219 } 39220 39221 function checkUnusedLocalsAndParameters(nodeWithLocals: Node, addDiagnostic: AddUnusedDiagnostic): void { 39222 // Ideally we could use the ImportClause directly as a key, but must wait until we have full ES6 maps. So must store key along with value. 39223 const unusedImports = new Map<string, [ImportClause, ImportedDeclaration[]]>(); 39224 const unusedDestructures = new Map<string, [BindingPattern, BindingElement[]]>(); 39225 const unusedVariables = new Map<string, [VariableDeclarationList, VariableDeclaration[]]>(); 39226 nodeWithLocals.locals!.forEach(local => { 39227 // If it's purely a type parameter, ignore, will be checked in `checkUnusedTypeParameters`. 39228 // If it's a type parameter merged with a parameter, check if the parameter-side is used. 39229 if (local.flags & SymbolFlags.TypeParameter ? !(local.flags & SymbolFlags.Variable && !(local.isReferenced! & SymbolFlags.Variable)) : local.isReferenced || local.exportSymbol) { 39230 return; 39231 } 39232 39233 if (local.declarations) { 39234 for (const declaration of local.declarations) { 39235 if (isValidUnusedLocalDeclaration(declaration)) { 39236 continue; 39237 } 39238 39239 if (isImportedDeclaration(declaration)) { 39240 addToGroup(unusedImports, importClauseFromImported(declaration), declaration, getNodeId); 39241 } 39242 else if (isBindingElement(declaration) && isObjectBindingPattern(declaration.parent)) { 39243 // In `{ a, ...b }, `a` is considered used since it removes a property from `b`. `b` may still be unused though. 39244 const lastElement = last(declaration.parent.elements); 39245 if (declaration === lastElement || !last(declaration.parent.elements).dotDotDotToken) { 39246 addToGroup(unusedDestructures, declaration.parent, declaration, getNodeId); 39247 } 39248 } 39249 else if (isVariableDeclaration(declaration)) { 39250 addToGroup(unusedVariables, declaration.parent, declaration, getNodeId); 39251 } 39252 else { 39253 const parameter = local.valueDeclaration && tryGetRootParameterDeclaration(local.valueDeclaration); 39254 const name = local.valueDeclaration && getNameOfDeclaration(local.valueDeclaration); 39255 if (parameter && name) { 39256 if (!isParameterPropertyDeclaration(parameter, parameter.parent) && !parameterIsThisKeyword(parameter) && !isIdentifierThatStartsWithUnderscore(name)) { 39257 if (isBindingElement(declaration) && isArrayBindingPattern(declaration.parent)) { 39258 addToGroup(unusedDestructures, declaration.parent, declaration, getNodeId); 39259 } 39260 else { 39261 addDiagnostic(parameter, UnusedKind.Parameter, createDiagnosticForNode(name, Diagnostics._0_is_declared_but_its_value_is_never_read, symbolName(local))); 39262 } 39263 } 39264 } 39265 else { 39266 errorUnusedLocal(declaration, symbolName(local), addDiagnostic); 39267 } 39268 } 39269 } 39270 } 39271 }); 39272 unusedImports.forEach(([importClause, unuseds]) => { 39273 const importDecl = importClause.parent; 39274 const nDeclarations = (importClause.name ? 1 : 0) + 39275 (importClause.namedBindings ? 39276 (importClause.namedBindings.kind === SyntaxKind.NamespaceImport ? 1 : importClause.namedBindings.elements.length) 39277 : 0); 39278 if (nDeclarations === unuseds.length) { 39279 addDiagnostic(importDecl, UnusedKind.Local, unuseds.length === 1 39280 ? createDiagnosticForNode(importDecl, Diagnostics._0_is_declared_but_its_value_is_never_read, idText(first(unuseds).name!)) 39281 : createDiagnosticForNode(importDecl, Diagnostics.All_imports_in_import_declaration_are_unused)); 39282 } 39283 else { 39284 for (const unused of unuseds) errorUnusedLocal(unused, idText(unused.name!), addDiagnostic); 39285 } 39286 }); 39287 unusedDestructures.forEach(([bindingPattern, bindingElements]) => { 39288 const kind = tryGetRootParameterDeclaration(bindingPattern.parent) ? UnusedKind.Parameter : UnusedKind.Local; 39289 if (bindingPattern.elements.length === bindingElements.length) { 39290 if (bindingElements.length === 1 && bindingPattern.parent.kind === SyntaxKind.VariableDeclaration && bindingPattern.parent.parent.kind === SyntaxKind.VariableDeclarationList) { 39291 addToGroup(unusedVariables, bindingPattern.parent.parent, bindingPattern.parent, getNodeId); 39292 } 39293 else { 39294 addDiagnostic(bindingPattern, kind, bindingElements.length === 1 39295 ? createDiagnosticForNode(bindingPattern, Diagnostics._0_is_declared_but_its_value_is_never_read, bindingNameText(first(bindingElements).name)) 39296 : createDiagnosticForNode(bindingPattern, Diagnostics.All_destructured_elements_are_unused)); 39297 } 39298 } 39299 else { 39300 for (const e of bindingElements) { 39301 addDiagnostic(e, kind, createDiagnosticForNode(e, Diagnostics._0_is_declared_but_its_value_is_never_read, bindingNameText(e.name))); 39302 } 39303 } 39304 }); 39305 unusedVariables.forEach(([declarationList, declarations]) => { 39306 if (declarationList.declarations.length === declarations.length) { 39307 addDiagnostic(declarationList, UnusedKind.Local, declarations.length === 1 39308 ? createDiagnosticForNode(first(declarations).name, Diagnostics._0_is_declared_but_its_value_is_never_read, bindingNameText(first(declarations).name)) 39309 : createDiagnosticForNode(declarationList.parent.kind === SyntaxKind.VariableStatement ? declarationList.parent : declarationList, Diagnostics.All_variables_are_unused)); 39310 } 39311 else { 39312 for (const decl of declarations) { 39313 addDiagnostic(decl, UnusedKind.Local, createDiagnosticForNode(decl, Diagnostics._0_is_declared_but_its_value_is_never_read, bindingNameText(decl.name))); 39314 } 39315 } 39316 }); 39317 } 39318 39319 function checkPotentialUncheckedRenamedBindingElementsInTypes() { 39320 for (const node of potentialUnusedRenamedBindingElementsInTypes) { 39321 if (!getSymbolOfNode(node)?.isReferenced) { 39322 const wrappingDeclaration = walkUpBindingElementsAndPatterns(node); 39323 Debug.assert(isParameterDeclaration(wrappingDeclaration), "Only parameter declaration should be checked here"); 39324 const diagnostic = createDiagnosticForNode(node.name, Diagnostics._0_is_an_unused_renaming_of_1_Did_you_intend_to_use_it_as_a_type_annotation, declarationNameToString(node.name), declarationNameToString(node.propertyName)); 39325 if (!wrappingDeclaration.type) { 39326 // entire parameter does not have type annotation, suggest adding an annotation 39327 addRelatedInfo( 39328 diagnostic, 39329 createFileDiagnostic(getSourceFileOfNode(wrappingDeclaration), wrappingDeclaration.end, 1, Diagnostics.We_can_only_write_a_type_for_0_by_adding_a_type_for_the_entire_parameter_here, declarationNameToString(node.propertyName)) 39330 ); 39331 } 39332 diagnostics.add(diagnostic); 39333 } 39334 } 39335 } 39336 39337 function bindingNameText(name: BindingName): string { 39338 switch (name.kind) { 39339 case SyntaxKind.Identifier: 39340 return idText(name); 39341 case SyntaxKind.ArrayBindingPattern: 39342 case SyntaxKind.ObjectBindingPattern: 39343 return bindingNameText(cast(first(name.elements), isBindingElement).name); 39344 default: 39345 return Debug.assertNever(name); 39346 } 39347 } 39348 39349 type ImportedDeclaration = ImportClause | ImportSpecifier | NamespaceImport; 39350 function isImportedDeclaration(node: Node): node is ImportedDeclaration { 39351 return node.kind === SyntaxKind.ImportClause || node.kind === SyntaxKind.ImportSpecifier || node.kind === SyntaxKind.NamespaceImport; 39352 } 39353 function importClauseFromImported(decl: ImportedDeclaration): ImportClause { 39354 return decl.kind === SyntaxKind.ImportClause ? decl : decl.kind === SyntaxKind.NamespaceImport ? decl.parent : decl.parent.parent; 39355 } 39356 39357 function checkBlock(node: Block) { 39358 // Grammar checking for SyntaxKind.Block 39359 if (node.kind === SyntaxKind.Block) { 39360 checkGrammarStatementInAmbientContext(node); 39361 } 39362 if (isFunctionOrModuleBlock(node)) { 39363 const saveFlowAnalysisDisabled = flowAnalysisDisabled; 39364 forEach(node.statements, checkSourceElement); 39365 flowAnalysisDisabled = saveFlowAnalysisDisabled; 39366 } 39367 else { 39368 forEach(node.statements, checkSourceElement); 39369 } 39370 if (node.locals) { 39371 registerForUnusedIdentifiersCheck(node); 39372 } 39373 } 39374 39375 function checkCollisionWithArgumentsInGeneratedCode(node: SignatureDeclaration) { 39376 // no rest parameters \ declaration context \ overload - no codegen impact 39377 if (languageVersion >= ScriptTarget.ES2015 || !hasRestParameter(node) || node.flags & NodeFlags.Ambient || nodeIsMissing((node as FunctionLikeDeclaration).body)) { 39378 return; 39379 } 39380 39381 forEach(node.parameters, p => { 39382 if (p.name && !isBindingPattern(p.name) && p.name.escapedText === argumentsSymbol.escapedName) { 39383 errorSkippedOn("noEmit", p, Diagnostics.Duplicate_identifier_arguments_Compiler_uses_arguments_to_initialize_rest_parameters); 39384 } 39385 }); 39386 } 39387 39388 /** 39389 * Checks whether an {@link Identifier}, in the context of another {@link Node}, would collide with a runtime value 39390 * of {@link name} in an outer scope. This is used to check for collisions for downlevel transformations that 39391 * require names like `Object`, `Promise`, `Reflect`, `require`, `exports`, etc. 39392 */ 39393 function needCollisionCheckForIdentifier(node: Node, identifier: Identifier | undefined, name: string): boolean { 39394 if (identifier?.escapedText !== name) { 39395 return false; 39396 } 39397 39398 if (node.kind === SyntaxKind.PropertyDeclaration || 39399 node.kind === SyntaxKind.PropertySignature || 39400 node.kind === SyntaxKind.MethodDeclaration || 39401 node.kind === SyntaxKind.MethodSignature || 39402 node.kind === SyntaxKind.GetAccessor || 39403 node.kind === SyntaxKind.SetAccessor || 39404 node.kind === SyntaxKind.PropertyAssignment) { 39405 // it is ok to have member named '_super', '_this', `Promise`, etc. - member access is always qualified 39406 return false; 39407 } 39408 39409 if (node.flags & NodeFlags.Ambient) { 39410 // ambient context - no codegen impact 39411 return false; 39412 } 39413 39414 if (isImportClause(node) || isImportEqualsDeclaration(node) || isImportSpecifier(node)) { 39415 // type-only imports do not require collision checks against runtime values. 39416 if (isTypeOnlyImportOrExportDeclaration(node)) { 39417 return false; 39418 } 39419 } 39420 39421 const root = getRootDeclaration(node); 39422 if (isParameter(root) && nodeIsMissing((root.parent as FunctionLikeDeclaration).body)) { 39423 // just an overload - no codegen impact 39424 return false; 39425 } 39426 39427 return true; 39428 } 39429 39430 // this function will run after checking the source file so 'CaptureThis' is correct for all nodes 39431 function checkIfThisIsCapturedInEnclosingScope(node: Node): void { 39432 findAncestor(node, current => { 39433 if (getNodeCheckFlags(current) & NodeCheckFlags.CaptureThis) { 39434 const isDeclaration = node.kind !== SyntaxKind.Identifier; 39435 if (isDeclaration) { 39436 error(getNameOfDeclaration(node as Declaration), Diagnostics.Duplicate_identifier_this_Compiler_uses_variable_declaration_this_to_capture_this_reference); 39437 } 39438 else { 39439 error(node, Diagnostics.Expression_resolves_to_variable_declaration_this_that_compiler_uses_to_capture_this_reference); 39440 } 39441 return true; 39442 } 39443 return false; 39444 }); 39445 } 39446 39447 function checkIfNewTargetIsCapturedInEnclosingScope(node: Node): void { 39448 findAncestor(node, current => { 39449 if (getNodeCheckFlags(current) & NodeCheckFlags.CaptureNewTarget) { 39450 const isDeclaration = node.kind !== SyntaxKind.Identifier; 39451 if (isDeclaration) { 39452 error(getNameOfDeclaration(node as Declaration), Diagnostics.Duplicate_identifier_newTarget_Compiler_uses_variable_declaration_newTarget_to_capture_new_target_meta_property_reference); 39453 } 39454 else { 39455 error(node, Diagnostics.Expression_resolves_to_variable_declaration_newTarget_that_compiler_uses_to_capture_new_target_meta_property_reference); 39456 } 39457 return true; 39458 } 39459 return false; 39460 }); 39461 } 39462 39463 function checkCollisionWithRequireExportsInGeneratedCode(node: Node, name: Identifier | undefined) { 39464 // No need to check for require or exports for ES6 modules and later 39465 if (moduleKind >= ModuleKind.ES2015 && !(moduleKind >= ModuleKind.Node16 && getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS)) { 39466 return; 39467 } 39468 39469 if (!name || !needCollisionCheckForIdentifier(node, name, "require") && !needCollisionCheckForIdentifier(node, name, "exports")) { 39470 return; 39471 } 39472 39473 // Uninstantiated modules shouldnt do this check 39474 if (isModuleDeclaration(node) && getModuleInstanceState(node) !== ModuleInstanceState.Instantiated) { 39475 return; 39476 } 39477 39478 // In case of variable declaration, node.parent is variable statement so look at the variable statement's parent 39479 const parent = getDeclarationContainer(node); 39480 if (parent.kind === SyntaxKind.SourceFile && isExternalOrCommonJsModule(parent as SourceFile)) { 39481 // If the declaration happens to be in external module, report error that require and exports are reserved keywords 39482 errorSkippedOn("noEmit", name, Diagnostics.Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_a_module, 39483 declarationNameToString(name), declarationNameToString(name)); 39484 } 39485 } 39486 39487 function checkCollisionWithGlobalPromiseInGeneratedCode(node: Node, name: Identifier | undefined): void { 39488 if (!name || languageVersion >= ScriptTarget.ES2017 || !needCollisionCheckForIdentifier(node, name, "Promise")) { 39489 return; 39490 } 39491 39492 // Uninstantiated modules shouldnt do this check 39493 if (isModuleDeclaration(node) && getModuleInstanceState(node) !== ModuleInstanceState.Instantiated) { 39494 return; 39495 } 39496 39497 // In case of variable declaration, node.parent is variable statement so look at the variable statement's parent 39498 const parent = getDeclarationContainer(node); 39499 if (parent.kind === SyntaxKind.SourceFile && isExternalOrCommonJsModule(parent as SourceFile) && parent.flags & NodeFlags.HasAsyncFunctions) { 39500 // If the declaration happens to be in external module, report error that Promise is a reserved identifier. 39501 errorSkippedOn("noEmit", name, Diagnostics.Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_a_module_containing_async_functions, 39502 declarationNameToString(name), declarationNameToString(name)); 39503 } 39504 } 39505 39506 function recordPotentialCollisionWithWeakMapSetInGeneratedCode(node: Node, name: Identifier): void { 39507 if (languageVersion <= ScriptTarget.ES2021 39508 && (needCollisionCheckForIdentifier(node, name, "WeakMap") || needCollisionCheckForIdentifier(node, name, "WeakSet"))) { 39509 potentialWeakMapSetCollisions.push(node); 39510 } 39511 } 39512 39513 function checkWeakMapSetCollision(node: Node) { 39514 const enclosingBlockScope = getEnclosingBlockScopeContainer(node); 39515 if (getNodeCheckFlags(enclosingBlockScope) & NodeCheckFlags.ContainsClassWithPrivateIdentifiers) { 39516 Debug.assert(isNamedDeclaration(node) && isIdentifier(node.name) && typeof node.name.escapedText === "string", "The target of a WeakMap/WeakSet collision check should be an identifier"); 39517 errorSkippedOn("noEmit", node, Diagnostics.Compiler_reserves_name_0_when_emitting_private_identifier_downlevel, node.name.escapedText); 39518 } 39519 } 39520 39521 function recordPotentialCollisionWithReflectInGeneratedCode(node: Node, name: Identifier | undefined): void { 39522 if (name && languageVersion >= ScriptTarget.ES2015 && languageVersion <= ScriptTarget.ES2021 39523 && needCollisionCheckForIdentifier(node, name, "Reflect")) { 39524 potentialReflectCollisions.push(node); 39525 } 39526 } 39527 39528 function checkReflectCollision(node: Node) { 39529 let hasCollision = false; 39530 if (isClassExpression(node)) { 39531 // ClassExpression names don't contribute to their containers, but do matter for any of their block-scoped members. 39532 for (const member of node.members) { 39533 if (getNodeCheckFlags(member) & NodeCheckFlags.ContainsSuperPropertyInStaticInitializer) { 39534 hasCollision = true; 39535 break; 39536 } 39537 } 39538 } 39539 else if (isFunctionExpression(node)) { 39540 // FunctionExpression names don't contribute to their containers, but do matter for their contents 39541 if (getNodeCheckFlags(node) & NodeCheckFlags.ContainsSuperPropertyInStaticInitializer) { 39542 hasCollision = true; 39543 } 39544 } 39545 else { 39546 const container = getEnclosingBlockScopeContainer(node); 39547 if (container && getNodeCheckFlags(container) & NodeCheckFlags.ContainsSuperPropertyInStaticInitializer) { 39548 hasCollision = true; 39549 } 39550 } 39551 if (hasCollision) { 39552 Debug.assert(isNamedDeclaration(node) && isIdentifier(node.name), "The target of a Reflect collision check should be an identifier"); 39553 errorSkippedOn("noEmit", node, Diagnostics.Duplicate_identifier_0_Compiler_reserves_name_1_when_emitting_super_references_in_static_initializers, 39554 declarationNameToString(node.name), 39555 "Reflect"); 39556 } 39557 } 39558 39559 function checkCollisionsForDeclarationName(node: Node, name: Identifier | undefined) { 39560 if (!name) return; 39561 checkCollisionWithRequireExportsInGeneratedCode(node, name); 39562 checkCollisionWithGlobalPromiseInGeneratedCode(node, name); 39563 recordPotentialCollisionWithWeakMapSetInGeneratedCode(node, name); 39564 recordPotentialCollisionWithReflectInGeneratedCode(node, name); 39565 if (isClassLike(node)) { 39566 checkTypeNameIsReserved(name, Diagnostics.Class_name_cannot_be_0); 39567 if (!(node.flags & NodeFlags.Ambient)) { 39568 checkClassNameCollisionWithObject(name); 39569 } 39570 } 39571 else if (isEnumDeclaration(node)) { 39572 checkTypeNameIsReserved(name, Diagnostics.Enum_name_cannot_be_0); 39573 } 39574 else if (isAnnotationDeclaration(node)) { 39575 checkTypeNameIsReserved(name, Diagnostics.Annotation_name_cannot_be_0); 39576 if (!(node.flags & NodeFlags.Ambient)) { 39577 checkClassNameCollisionWithObject(name); 39578 } 39579 } 39580 } 39581 39582 function checkVarDeclaredNamesNotShadowed(node: VariableDeclaration | BindingElement) { 39583 // - ScriptBody : StatementList 39584 // It is a Syntax Error if any element of the LexicallyDeclaredNames of StatementList 39585 // also occurs in the VarDeclaredNames of StatementList. 39586 39587 // - Block : { StatementList } 39588 // It is a Syntax Error if any element of the LexicallyDeclaredNames of StatementList 39589 // also occurs in the VarDeclaredNames of StatementList. 39590 39591 // Variable declarations are hoisted to the top of their function scope. They can shadow 39592 // block scoped declarations, which bind tighter. this will not be flagged as duplicate definition 39593 // by the binder as the declaration scope is different. 39594 // A non-initialized declaration is a no-op as the block declaration will resolve before the var 39595 // declaration. the problem is if the declaration has an initializer. this will act as a write to the 39596 // block declared value. this is fine for let, but not const. 39597 // Only consider declarations with initializers, uninitialized const declarations will not 39598 // step on a let/const variable. 39599 // Do not consider const and const declarations, as duplicate block-scoped declarations 39600 // are handled by the binder. 39601 // We are only looking for const declarations that step on let\const declarations from a 39602 // different scope. e.g.: 39603 // { 39604 // const x = 0; // localDeclarationSymbol obtained after name resolution will correspond to this declaration 39605 // const x = 0; // symbol for this declaration will be 'symbol' 39606 // } 39607 39608 // skip block-scoped variables and parameters 39609 if ((getCombinedNodeFlags(node) & NodeFlags.BlockScoped) !== 0 || isParameterDeclaration(node)) { 39610 return; 39611 } 39612 39613 // skip variable declarations that don't have initializers 39614 // NOTE: in ES6 spec initializer is required in variable declarations where name is binding pattern 39615 // so we'll always treat binding elements as initialized 39616 if (node.kind === SyntaxKind.VariableDeclaration && !node.initializer) { 39617 return; 39618 } 39619 39620 const symbol = getSymbolOfNode(node); 39621 if (symbol.flags & SymbolFlags.FunctionScopedVariable) { 39622 if (!isIdentifier(node.name)) return Debug.fail(); 39623 const localDeclarationSymbol = resolveName(node, node.name.escapedText, SymbolFlags.Variable, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false); 39624 if (localDeclarationSymbol && 39625 localDeclarationSymbol !== symbol && 39626 localDeclarationSymbol.flags & SymbolFlags.BlockScopedVariable) { 39627 if (getDeclarationNodeFlagsFromSymbol(localDeclarationSymbol) & NodeFlags.BlockScoped) { 39628 const varDeclList = getAncestor(localDeclarationSymbol.valueDeclaration, SyntaxKind.VariableDeclarationList)!; 39629 const container = 39630 varDeclList.parent.kind === SyntaxKind.VariableStatement && varDeclList.parent.parent 39631 ? varDeclList.parent.parent 39632 : undefined; 39633 39634 // names of block-scoped and function scoped variables can collide only 39635 // if block scoped variable is defined in the function\module\source file scope (because of variable hoisting) 39636 const namesShareScope = 39637 container && 39638 (container.kind === SyntaxKind.Block && isFunctionLike(container.parent) || 39639 container.kind === SyntaxKind.ModuleBlock || 39640 container.kind === SyntaxKind.ModuleDeclaration || 39641 container.kind === SyntaxKind.SourceFile); 39642 39643 // here we know that function scoped variable is shadowed by block scoped one 39644 // if they are defined in the same scope - binder has already reported redeclaration error 39645 // otherwise if variable has an initializer - show error that initialization will fail 39646 // since LHS will be block scoped name instead of function scoped 39647 if (!namesShareScope) { 39648 const name = symbolToString(localDeclarationSymbol); 39649 error(node, Diagnostics.Cannot_initialize_outer_scoped_variable_0_in_the_same_scope_as_block_scoped_declaration_1, name, name); 39650 } 39651 } 39652 } 39653 } 39654 } 39655 39656 function convertAutoToAny(type: Type) { 39657 return type === autoType ? anyType : type === autoArrayType ? anyArrayType : type; 39658 } 39659 39660 // Check variable, parameter, or property declaration 39661 function checkVariableLikeDeclaration(node: ParameterDeclaration | PropertyDeclaration | PropertySignature | AnnotationPropertyDeclaration | VariableDeclaration | BindingElement) { 39662 checkDecorators(node); 39663 if (!isBindingElement(node)) { 39664 checkSourceElement(node.type); 39665 } 39666 39667 // JSDoc `function(string, string): string` syntax results in parameters with no name 39668 if (!node.name) { 39669 return; 39670 } 39671 39672 // For a computed property, just check the initializer and exit 39673 // Do not use hasDynamicName here, because that returns false for well known symbols. 39674 // We want to perform checkComputedPropertyName for all computed properties, including 39675 // well known symbols. 39676 if (node.name.kind === SyntaxKind.ComputedPropertyName) { 39677 checkComputedPropertyName(node.name); 39678 if (hasOnlyExpressionInitializer(node) && node.initializer) { 39679 checkExpressionCached(node.initializer); 39680 } 39681 } 39682 39683 if (isBindingElement(node)) { 39684 if ( 39685 node.propertyName && 39686 isIdentifier(node.name) && 39687 isParameterDeclaration(node) && 39688 nodeIsMissing((getContainingFunction(node) as FunctionLikeDeclaration).body)) { 39689 // type F = ({a: string}) => void; 39690 // ^^^^^^ 39691 // variable renaming in function type notation is confusing, 39692 // so we forbid it even if noUnusedLocals is not enabled 39693 potentialUnusedRenamedBindingElementsInTypes.push(node); 39694 return; 39695 } 39696 39697 if (isObjectBindingPattern(node.parent) && node.dotDotDotToken && languageVersion < ScriptTarget.ES2018) { 39698 checkExternalEmitHelpers(node, ExternalEmitHelpers.Rest); 39699 } 39700 // check computed properties inside property names of binding elements 39701 if (node.propertyName && node.propertyName.kind === SyntaxKind.ComputedPropertyName) { 39702 checkComputedPropertyName(node.propertyName); 39703 } 39704 39705 // check private/protected variable access 39706 const parent = node.parent.parent; 39707 const parentCheckMode = node.dotDotDotToken ? CheckMode.RestBindingElement : CheckMode.Normal; 39708 const parentType = getTypeForBindingElementParent(parent, parentCheckMode); 39709 const name = node.propertyName || node.name; 39710 if (parentType && !isBindingPattern(name)) { 39711 const exprType = getLiteralTypeFromPropertyName(name); 39712 if (isTypeUsableAsPropertyName(exprType)) { 39713 const nameText = getPropertyNameFromType(exprType); 39714 const property = getPropertyOfType(parentType, nameText); 39715 if (property) { 39716 markPropertyAsReferenced(property, /*nodeForCheckWriteOnly*/ undefined, /*isSelfTypeAccess*/ false); // A destructuring is never a write-only reference. 39717 checkPropertyAccessibility(node, !!parent.initializer && parent.initializer.kind === SyntaxKind.SuperKeyword, /*writing*/ false, parentType, property); 39718 } 39719 } 39720 } 39721 } 39722 39723 // For a binding pattern, check contained binding elements 39724 if (isBindingPattern(node.name)) { 39725 if (node.name.kind === SyntaxKind.ArrayBindingPattern && languageVersion < ScriptTarget.ES2015 && compilerOptions.downlevelIteration) { 39726 checkExternalEmitHelpers(node, ExternalEmitHelpers.Read); 39727 } 39728 39729 forEach(node.name.elements, checkSourceElement); 39730 } 39731 39732 // For a parameter declaration with an initializer, error and exit if the containing function doesn't have a body 39733 if (isParameter(node) && node.initializer && nodeIsMissing((getContainingFunction(node) as FunctionLikeDeclaration).body)) { 39734 error(node, Diagnostics.A_parameter_initializer_is_only_allowed_in_a_function_or_constructor_implementation); 39735 return; 39736 } 39737 // For a binding pattern, validate the initializer and exit 39738 if (isBindingPattern(node.name)) { 39739 const needCheckInitializer = hasOnlyExpressionInitializer(node) && node.initializer && node.parent.parent.kind !== SyntaxKind.ForInStatement; 39740 const needCheckWidenedType = !some(node.name.elements, not(isOmittedExpression)); 39741 if (needCheckInitializer || needCheckWidenedType) { 39742 // Don't validate for-in initializer as it is already an error 39743 const widenedType = getWidenedTypeForVariableLikeDeclaration(node); 39744 if (needCheckInitializer) { 39745 const initializerType = checkExpressionCached(node.initializer); 39746 if (strictNullChecks && needCheckWidenedType) { 39747 checkNonNullNonVoidType(initializerType, node); 39748 } 39749 else { 39750 checkTypeAssignableToAndOptionallyElaborate(initializerType, getWidenedTypeForVariableLikeDeclaration(node), node, node.initializer); 39751 } 39752 } 39753 // check the binding pattern with empty elements 39754 if (needCheckWidenedType) { 39755 if (isArrayBindingPattern(node.name)) { 39756 checkIteratedTypeOrElementType(IterationUse.Destructuring, widenedType, undefinedType, node); 39757 } 39758 else if (strictNullChecks) { 39759 checkNonNullNonVoidType(widenedType, node); 39760 } 39761 } 39762 } 39763 return; 39764 } 39765 // For a commonjs `const x = require`, validate the alias and exit 39766 const symbol = getSymbolOfNode(node); 39767 if (symbol.flags & SymbolFlags.Alias && isVariableDeclarationInitializedToBareOrAccessedRequire(node.kind === SyntaxKind.BindingElement ? node.parent.parent : node)) { 39768 checkAliasSymbol(node as BindingElement | VariableDeclaration); 39769 return; 39770 } 39771 39772 const type = convertAutoToAny(getTypeOfSymbol(symbol)); 39773 if (node === symbol.valueDeclaration) { 39774 // Node is the primary declaration of the symbol, just validate the initializer 39775 // Don't validate for-in initializer as it is already an error 39776 const initializer = hasOnlyExpressionInitializer(node) && getEffectiveInitializer(node); 39777 if (initializer) { 39778 const isJSObjectLiteralInitializer = isInJSFile(node) && 39779 isObjectLiteralExpression(initializer) && 39780 (initializer.properties.length === 0 || isPrototypeAccess(node.name)) && 39781 !!symbol.exports?.size; 39782 if (!isJSObjectLiteralInitializer && node.parent.parent.kind !== SyntaxKind.ForInStatement) { 39783 checkTypeAssignableToAndOptionallyElaborate(checkExpressionCached(initializer), type, node, initializer, /*headMessage*/ undefined); 39784 } 39785 } 39786 if (symbol.declarations && symbol.declarations.length > 1) { 39787 if (some(symbol.declarations, d => d !== node && isVariableLike(d) && !areDeclarationFlagsIdentical(d, node))) { 39788 error(node.name, Diagnostics.All_declarations_of_0_must_have_identical_modifiers, declarationNameToString(node.name)); 39789 } 39790 } 39791 } 39792 else { 39793 // Node is a secondary declaration, check that type is identical to primary declaration and check that 39794 // initializer is consistent with type associated with the node 39795 const declarationType = convertAutoToAny(getWidenedTypeForVariableLikeDeclaration(node)); 39796 39797 if (!isErrorType(type) && !isErrorType(declarationType) && 39798 !isTypeIdenticalTo(type, declarationType) && 39799 !(symbol.flags & SymbolFlags.Assignment)) { 39800 errorNextVariableOrPropertyDeclarationMustHaveSameType(symbol.valueDeclaration, type, node, declarationType); 39801 } 39802 if (hasOnlyExpressionInitializer(node) && node.initializer) { 39803 checkTypeAssignableToAndOptionallyElaborate(checkExpressionCached(node.initializer), declarationType, node, node.initializer, /*headMessage*/ undefined); 39804 } 39805 if (symbol.valueDeclaration && !areDeclarationFlagsIdentical(node, symbol.valueDeclaration)) { 39806 error(node.name, Diagnostics.All_declarations_of_0_must_have_identical_modifiers, declarationNameToString(node.name)); 39807 } 39808 } 39809 if (node.kind !== SyntaxKind.PropertyDeclaration && node.kind !== SyntaxKind.PropertySignature && node.kind !== SyntaxKind.AnnotationPropertyDeclaration) { 39810 // We know we don't have a binding pattern or computed name here 39811 checkExportsOnMergedDeclarations(node); 39812 if (node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement) { 39813 checkVarDeclaredNamesNotShadowed(node); 39814 } 39815 checkCollisionsForDeclarationName(node, node.name); 39816 } 39817 } 39818 39819 function errorNextVariableOrPropertyDeclarationMustHaveSameType(firstDeclaration: Declaration | undefined, firstType: Type, nextDeclaration: Declaration, nextType: Type): void { 39820 const nextDeclarationName = getNameOfDeclaration(nextDeclaration); 39821 const message = nextDeclaration.kind === SyntaxKind.PropertyDeclaration || nextDeclaration.kind === SyntaxKind.PropertySignature 39822 ? Diagnostics.Subsequent_property_declarations_must_have_the_same_type_Property_0_must_be_of_type_1_but_here_has_type_2 39823 : Diagnostics.Subsequent_variable_declarations_must_have_the_same_type_Variable_0_must_be_of_type_1_but_here_has_type_2; 39824 const declName = declarationNameToString(nextDeclarationName); 39825 const err = error( 39826 nextDeclarationName, 39827 message, 39828 declName, 39829 typeToString(firstType), 39830 typeToString(nextType) 39831 ); 39832 if (firstDeclaration) { 39833 addRelatedInfo(err, 39834 createDiagnosticForNode(firstDeclaration, Diagnostics._0_was_also_declared_here, declName) 39835 ); 39836 } 39837 } 39838 39839 function areDeclarationFlagsIdentical(left: Declaration, right: Declaration) { 39840 if ((left.kind === SyntaxKind.Parameter && right.kind === SyntaxKind.VariableDeclaration) || 39841 (left.kind === SyntaxKind.VariableDeclaration && right.kind === SyntaxKind.Parameter)) { 39842 // Differences in optionality between parameters and variables are allowed. 39843 return true; 39844 } 39845 39846 if (hasQuestionToken(left) !== hasQuestionToken(right)) { 39847 return false; 39848 } 39849 39850 const interestingFlags = ModifierFlags.Private | 39851 ModifierFlags.Protected | 39852 ModifierFlags.Async | 39853 ModifierFlags.Abstract | 39854 ModifierFlags.Readonly | 39855 ModifierFlags.Static; 39856 39857 return getSelectedEffectiveModifierFlags(left, interestingFlags) === getSelectedEffectiveModifierFlags(right, interestingFlags); 39858 } 39859 39860 function checkVariableDeclaration(node: VariableDeclaration) { 39861 tracing?.push(tracing.Phase.Check, "checkVariableDeclaration", { kind: node.kind, pos: node.pos, end: node.end, path: (node as TracingNode).tracingPath }); 39862 checkGrammarVariableDeclaration(node); 39863 checkVariableLikeDeclaration(node); 39864 tracing?.pop(); 39865 } 39866 39867 function checkBindingElement(node: BindingElement) { 39868 checkGrammarBindingElement(node); 39869 return checkVariableLikeDeclaration(node); 39870 } 39871 39872 function checkVariableStatement(node: VariableStatement) { 39873 // Grammar checking 39874 if (!checkGrammarDecoratorsAndModifiers(node) && !checkGrammarVariableDeclarationList(node.declarationList)) checkGrammarForDisallowedLetOrConstStatement(node); 39875 forEach(node.declarationList.declarations, checkSourceElement); 39876 } 39877 39878 function checkExpressionStatement(node: ExpressionStatement) { 39879 // Grammar checking 39880 checkGrammarStatementInAmbientContext(node); 39881 39882 checkExpression(node.expression); 39883 } 39884 39885 function checkIfStatement(node: IfStatement) { 39886 // Grammar checking 39887 checkGrammarStatementInAmbientContext(node); 39888 const type = checkTruthinessExpression(node.expression); 39889 checkTestingKnownTruthyCallableOrAwaitableType(node.expression, type, node.thenStatement); 39890 checkSourceElement(node.thenStatement); 39891 39892 if (node.thenStatement.kind === SyntaxKind.EmptyStatement) { 39893 error(node.thenStatement, Diagnostics.The_body_of_an_if_statement_cannot_be_the_empty_statement); 39894 } 39895 39896 checkSourceElement(node.elseStatement); 39897 } 39898 39899 function checkTestingKnownTruthyCallableOrAwaitableType(condExpr: Expression, condType: Type, body?: Statement | Expression) { 39900 if (!strictNullChecks) return; 39901 39902 helper(condExpr, body); 39903 while (isBinaryExpression(condExpr) && condExpr.operatorToken.kind === SyntaxKind.BarBarToken) { 39904 condExpr = condExpr.left; 39905 helper(condExpr, body); 39906 } 39907 39908 function helper(condExpr: Expression, body: Expression | Statement | undefined) { 39909 const location = isBinaryExpression(condExpr) && 39910 (condExpr.operatorToken.kind === SyntaxKind.BarBarToken || condExpr.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) 39911 ? condExpr.right 39912 : condExpr; 39913 if (isModuleExportsAccessExpression(location)) return; 39914 const type = location === condExpr ? condType : checkTruthinessExpression(location); 39915 const isPropertyExpressionCast = isPropertyAccessExpression(location) && isTypeAssertion(location.expression); 39916 if (!(getTypeFacts(type) & TypeFacts.Truthy) || isPropertyExpressionCast) return; 39917 39918 // While it technically should be invalid for any known-truthy value 39919 // to be tested, we de-scope to functions and Promises unreferenced in 39920 // the block as a heuristic to identify the most common bugs. There 39921 // are too many false positives for values sourced from type 39922 // definitions without strictNullChecks otherwise. 39923 const callSignatures = getSignaturesOfType(type, SignatureKind.Call); 39924 const isPromise = !!getAwaitedTypeOfPromise(type); 39925 if (callSignatures.length === 0 && !isPromise) { 39926 return; 39927 } 39928 39929 const testedNode = isIdentifier(location) ? location 39930 : isPropertyAccessExpression(location) ? location.name 39931 : isBinaryExpression(location) && isIdentifier(location.right) ? location.right 39932 : undefined; 39933 const testedSymbol = testedNode && getSymbolAtLocation(testedNode); 39934 if (!testedSymbol && !isPromise) { 39935 return; 39936 } 39937 39938 const isUsed = testedSymbol && isBinaryExpression(condExpr.parent) && isSymbolUsedInBinaryExpressionChain(condExpr.parent, testedSymbol) 39939 || testedSymbol && body && isSymbolUsedInConditionBody(condExpr, body, testedNode, testedSymbol); 39940 if (!isUsed) { 39941 if (isPromise) { 39942 errorAndMaybeSuggestAwait( 39943 location, 39944 /*maybeMissingAwait*/ true, 39945 Diagnostics.This_condition_will_always_return_true_since_this_0_is_always_defined, 39946 getTypeNameForErrorDisplay(type)); 39947 } 39948 else { 39949 error(location, Diagnostics.This_condition_will_always_return_true_since_this_function_is_always_defined_Did_you_mean_to_call_it_instead); 39950 } 39951 } 39952 } 39953 } 39954 39955 function isSymbolUsedInConditionBody(expr: Expression, body: Statement | Expression, testedNode: Node, testedSymbol: Symbol): boolean { 39956 return !!forEachChild(body, function check(childNode): boolean | undefined { 39957 if (isIdentifier(childNode)) { 39958 const childSymbol = getSymbolAtLocation(childNode); 39959 if (childSymbol && childSymbol === testedSymbol) { 39960 // If the test was a simple identifier, the above check is sufficient 39961 if (isIdentifier(expr) || isIdentifier(testedNode) && isBinaryExpression(testedNode.parent)) { 39962 return true; 39963 } 39964 // Otherwise we need to ensure the symbol is called on the same target 39965 let testedExpression = testedNode.parent; 39966 let childExpression = childNode.parent; 39967 while (testedExpression && childExpression) { 39968 if (isIdentifier(testedExpression) && isIdentifier(childExpression) || 39969 testedExpression.kind === SyntaxKind.ThisKeyword && childExpression.kind === SyntaxKind.ThisKeyword) { 39970 return getSymbolAtLocation(testedExpression) === getSymbolAtLocation(childExpression); 39971 } 39972 else if (isPropertyAccessExpression(testedExpression) && isPropertyAccessExpression(childExpression)) { 39973 if (getSymbolAtLocation(testedExpression.name) !== getSymbolAtLocation(childExpression.name)) { 39974 return false; 39975 } 39976 childExpression = childExpression.expression; 39977 testedExpression = testedExpression.expression; 39978 } 39979 else if (isCallExpression(testedExpression) && isCallExpression(childExpression)) { 39980 childExpression = childExpression.expression; 39981 testedExpression = testedExpression.expression; 39982 } 39983 else { 39984 return false; 39985 } 39986 } 39987 } 39988 } 39989 return forEachChild(childNode, check); 39990 }); 39991 } 39992 39993 function isSymbolUsedInBinaryExpressionChain(node: Node, testedSymbol: Symbol): boolean { 39994 while (isBinaryExpression(node) && node.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) { 39995 const isUsed = forEachChild(node.right, function visit(child): boolean | undefined { 39996 if (isIdentifier(child)) { 39997 const symbol = getSymbolAtLocation(child); 39998 if (symbol && symbol === testedSymbol) { 39999 return true; 40000 } 40001 } 40002 return forEachChild(child, visit); 40003 }); 40004 if (isUsed) { 40005 return true; 40006 } 40007 node = node.parent; 40008 } 40009 return false; 40010 } 40011 40012 function checkDoStatement(node: DoStatement) { 40013 // Grammar checking 40014 checkGrammarStatementInAmbientContext(node); 40015 40016 checkSourceElement(node.statement); 40017 checkTruthinessExpression(node.expression); 40018 } 40019 40020 function checkWhileStatement(node: WhileStatement) { 40021 // Grammar checking 40022 checkGrammarStatementInAmbientContext(node); 40023 40024 checkTruthinessExpression(node.expression); 40025 checkSourceElement(node.statement); 40026 } 40027 40028 function checkTruthinessOfType(type: Type, node: Node) { 40029 if (type.flags & TypeFlags.Void) { 40030 error(node, Diagnostics.An_expression_of_type_void_cannot_be_tested_for_truthiness); 40031 } 40032 return type; 40033 } 40034 40035 function checkTruthinessExpression(node: Expression, checkMode?: CheckMode) { 40036 return checkTruthinessOfType(checkExpression(node, checkMode), node); 40037 } 40038 40039 function checkForStatement(node: ForStatement) { 40040 // Grammar checking 40041 if (!checkGrammarStatementInAmbientContext(node)) { 40042 if (node.initializer && node.initializer.kind === SyntaxKind.VariableDeclarationList) { 40043 checkGrammarVariableDeclarationList(node.initializer as VariableDeclarationList); 40044 } 40045 } 40046 40047 if (node.initializer) { 40048 if (node.initializer.kind === SyntaxKind.VariableDeclarationList) { 40049 forEach((node.initializer as VariableDeclarationList).declarations, checkVariableDeclaration); 40050 } 40051 else { 40052 checkExpression(node.initializer); 40053 } 40054 } 40055 40056 if (node.condition) checkTruthinessExpression(node.condition); 40057 if (node.incrementor) checkExpression(node.incrementor); 40058 checkSourceElement(node.statement); 40059 if (node.locals) { 40060 registerForUnusedIdentifiersCheck(node); 40061 } 40062 } 40063 40064 function checkForOfStatement(node: ForOfStatement): void { 40065 checkGrammarForInOrForOfStatement(node); 40066 40067 const container = getContainingFunctionOrClassStaticBlock(node); 40068 if (node.awaitModifier) { 40069 if (container && isClassStaticBlockDeclaration(container)) { 40070 grammarErrorOnNode(node.awaitModifier, Diagnostics.For_await_loops_cannot_be_used_inside_a_class_static_block); 40071 } 40072 else { 40073 const functionFlags = getFunctionFlags(container); 40074 if ((functionFlags & (FunctionFlags.Invalid | FunctionFlags.Async)) === FunctionFlags.Async && languageVersion < ScriptTarget.ESNext) { 40075 // for..await..of in an async function or async generator function prior to ESNext requires the __asyncValues helper 40076 checkExternalEmitHelpers(node, ExternalEmitHelpers.ForAwaitOfIncludes); 40077 } 40078 } 40079 } 40080 else if (compilerOptions.downlevelIteration && languageVersion < ScriptTarget.ES2015) { 40081 // for..of prior to ES2015 requires the __values helper when downlevelIteration is enabled 40082 checkExternalEmitHelpers(node, ExternalEmitHelpers.ForOfIncludes); 40083 } 40084 40085 // Check the LHS and RHS 40086 // If the LHS is a declaration, just check it as a variable declaration, which will in turn check the RHS 40087 // via checkRightHandSideOfForOf. 40088 // If the LHS is an expression, check the LHS, as a destructuring assignment or as a reference. 40089 // Then check that the RHS is assignable to it. 40090 if (node.initializer.kind === SyntaxKind.VariableDeclarationList) { 40091 checkForInOrForOfVariableDeclaration(node); 40092 } 40093 else { 40094 const varExpr = node.initializer; 40095 const iteratedType = checkRightHandSideOfForOf(node); 40096 40097 // There may be a destructuring assignment on the left side 40098 if (varExpr.kind === SyntaxKind.ArrayLiteralExpression || varExpr.kind === SyntaxKind.ObjectLiteralExpression) { 40099 // iteratedType may be undefined. In this case, we still want to check the structure of 40100 // varExpr, in particular making sure it's a valid LeftHandSideExpression. But we'd like 40101 // to short circuit the type relation checking as much as possible, so we pass the unknownType. 40102 checkDestructuringAssignment(varExpr, iteratedType || errorType); 40103 } 40104 else { 40105 const leftType = checkExpression(varExpr); 40106 checkReferenceExpression( 40107 varExpr, 40108 Diagnostics.The_left_hand_side_of_a_for_of_statement_must_be_a_variable_or_a_property_access, 40109 Diagnostics.The_left_hand_side_of_a_for_of_statement_may_not_be_an_optional_property_access); 40110 40111 // iteratedType will be undefined if the rightType was missing properties/signatures 40112 // required to get its iteratedType (like [Symbol.iterator] or next). This may be 40113 // because we accessed properties from anyType, or it may have led to an error inside 40114 // getElementTypeOfIterable. 40115 if (iteratedType) { 40116 checkTypeAssignableToAndOptionallyElaborate(iteratedType, leftType, varExpr, node.expression); 40117 } 40118 } 40119 } 40120 40121 checkSourceElement(node.statement); 40122 if (node.locals) { 40123 registerForUnusedIdentifiersCheck(node); 40124 } 40125 } 40126 40127 function checkForInStatement(node: ForInStatement) { 40128 // Grammar checking 40129 checkGrammarForInOrForOfStatement(node); 40130 40131 const rightType = getNonNullableTypeIfNeeded(checkExpression(node.expression)); 40132 // TypeScript 1.0 spec (April 2014): 5.4 40133 // In a 'for-in' statement of the form 40134 // for (let VarDecl in Expr) Statement 40135 // VarDecl must be a variable declaration without a type annotation that declares a variable of type Any, 40136 // and Expr must be an expression of type Any, an object type, or a type parameter type. 40137 if (node.initializer.kind === SyntaxKind.VariableDeclarationList) { 40138 const variable = (node.initializer as VariableDeclarationList).declarations[0]; 40139 if (variable && isBindingPattern(variable.name)) { 40140 error(variable.name, Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_a_destructuring_pattern); 40141 } 40142 checkForInOrForOfVariableDeclaration(node); 40143 } 40144 else { 40145 // In a 'for-in' statement of the form 40146 // for (Var in Expr) Statement 40147 // Var must be an expression classified as a reference of type Any or the String primitive type, 40148 // and Expr must be an expression of type Any, an object type, or a type parameter type. 40149 const varExpr = node.initializer; 40150 const leftType = checkExpression(varExpr); 40151 if (varExpr.kind === SyntaxKind.ArrayLiteralExpression || varExpr.kind === SyntaxKind.ObjectLiteralExpression) { 40152 error(varExpr, Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_a_destructuring_pattern); 40153 } 40154 else if (!isTypeAssignableTo(getIndexTypeOrString(rightType), leftType)) { 40155 error(varExpr, Diagnostics.The_left_hand_side_of_a_for_in_statement_must_be_of_type_string_or_any); 40156 } 40157 else { 40158 // run check only former check succeeded to avoid cascading errors 40159 checkReferenceExpression( 40160 varExpr, 40161 Diagnostics.The_left_hand_side_of_a_for_in_statement_must_be_a_variable_or_a_property_access, 40162 Diagnostics.The_left_hand_side_of_a_for_in_statement_may_not_be_an_optional_property_access); 40163 } 40164 } 40165 40166 // unknownType is returned i.e. if node.expression is identifier whose name cannot be resolved 40167 // in this case error about missing name is already reported - do not report extra one 40168 if (rightType === neverType || !isTypeAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive)) { 40169 error(node.expression, Diagnostics.The_right_hand_side_of_a_for_in_statement_must_be_of_type_any_an_object_type_or_a_type_parameter_but_here_has_type_0, typeToString(rightType)); 40170 } 40171 40172 checkSourceElement(node.statement); 40173 if (node.locals) { 40174 registerForUnusedIdentifiersCheck(node); 40175 } 40176 } 40177 40178 function checkForInOrForOfVariableDeclaration(iterationStatement: ForInOrOfStatement): void { 40179 const variableDeclarationList = iterationStatement.initializer as VariableDeclarationList; 40180 // checkGrammarForInOrForOfStatement will check that there is exactly one declaration. 40181 if (variableDeclarationList.declarations.length >= 1) { 40182 const decl = variableDeclarationList.declarations[0]; 40183 checkVariableDeclaration(decl); 40184 } 40185 } 40186 40187 function checkRightHandSideOfForOf(statement: ForOfStatement): Type { 40188 const use = statement.awaitModifier ? IterationUse.ForAwaitOf : IterationUse.ForOf; 40189 return checkIteratedTypeOrElementType(use, checkNonNullExpression(statement.expression), undefinedType, statement.expression); 40190 } 40191 40192 function checkIteratedTypeOrElementType(use: IterationUse, inputType: Type, sentType: Type, errorNode: Node | undefined): Type { 40193 if (isTypeAny(inputType)) { 40194 return inputType; 40195 } 40196 return getIteratedTypeOrElementType(use, inputType, sentType, errorNode, /*checkAssignability*/ true) || anyType; 40197 } 40198 40199 /** 40200 * When consuming an iterable type in a for..of, spread, or iterator destructuring assignment 40201 * we want to get the iterated type of an iterable for ES2015 or later, or the iterated type 40202 * of a iterable (if defined globally) or element type of an array like for ES2015 or earlier. 40203 */ 40204 function getIteratedTypeOrElementType(use: IterationUse, inputType: Type, sentType: Type, errorNode: Node | undefined, checkAssignability: boolean): Type | undefined { 40205 const allowAsyncIterables = (use & IterationUse.AllowsAsyncIterablesFlag) !== 0; 40206 if (inputType === neverType) { 40207 reportTypeNotIterableError(errorNode!, inputType, allowAsyncIterables); // TODO: GH#18217 40208 return undefined; 40209 } 40210 40211 const uplevelIteration = languageVersion >= ScriptTarget.ES2015; 40212 const downlevelIteration = !uplevelIteration && compilerOptions.downlevelIteration; 40213 const possibleOutOfBounds = compilerOptions.noUncheckedIndexedAccess && !!(use & IterationUse.PossiblyOutOfBounds); 40214 40215 // Get the iterated type of an `Iterable<T>` or `IterableIterator<T>` only in ES2015 40216 // or higher, when inside of an async generator or for-await-if, or when 40217 // downlevelIteration is requested. 40218 if (uplevelIteration || downlevelIteration || allowAsyncIterables) { 40219 // We only report errors for an invalid iterable type in ES2015 or higher. 40220 const iterationTypes = getIterationTypesOfIterable(inputType, use, uplevelIteration ? errorNode : undefined); 40221 if (checkAssignability) { 40222 if (iterationTypes) { 40223 const diagnostic = 40224 use & IterationUse.ForOfFlag ? Diagnostics.Cannot_iterate_value_because_the_next_method_of_its_iterator_expects_type_1_but_for_of_will_always_send_0 : 40225 use & IterationUse.SpreadFlag ? Diagnostics.Cannot_iterate_value_because_the_next_method_of_its_iterator_expects_type_1_but_array_spread_will_always_send_0 : 40226 use & IterationUse.DestructuringFlag ? Diagnostics.Cannot_iterate_value_because_the_next_method_of_its_iterator_expects_type_1_but_array_destructuring_will_always_send_0 : 40227 use & IterationUse.YieldStarFlag ? Diagnostics.Cannot_delegate_iteration_to_value_because_the_next_method_of_its_iterator_expects_type_1_but_the_containing_generator_will_always_send_0 : 40228 undefined; 40229 if (diagnostic) { 40230 checkTypeAssignableTo(sentType, iterationTypes.nextType, errorNode, diagnostic); 40231 } 40232 } 40233 } 40234 if (iterationTypes || uplevelIteration) { 40235 return possibleOutOfBounds ? includeUndefinedInIndexSignature(iterationTypes && iterationTypes.yieldType) : (iterationTypes && iterationTypes.yieldType); 40236 } 40237 } 40238 40239 let arrayType = inputType; 40240 let reportedError = false; 40241 let hasStringConstituent = false; 40242 40243 // If strings are permitted, remove any string-like constituents from the array type. 40244 // This allows us to find other non-string element types from an array unioned with 40245 // a string. 40246 if (use & IterationUse.AllowsStringInputFlag) { 40247 if (arrayType.flags & TypeFlags.Union) { 40248 // After we remove all types that are StringLike, we will know if there was a string constituent 40249 // based on whether the result of filter is a new array. 40250 const arrayTypes = (inputType as UnionType).types; 40251 const filteredTypes = filter(arrayTypes, t => !(t.flags & TypeFlags.StringLike)); 40252 if (filteredTypes !== arrayTypes) { 40253 arrayType = getUnionType(filteredTypes, UnionReduction.Subtype); 40254 } 40255 } 40256 else if (arrayType.flags & TypeFlags.StringLike) { 40257 arrayType = neverType; 40258 } 40259 40260 hasStringConstituent = arrayType !== inputType; 40261 if (hasStringConstituent) { 40262 if (languageVersion < ScriptTarget.ES5) { 40263 if (errorNode) { 40264 error(errorNode, Diagnostics.Using_a_string_in_a_for_of_statement_is_only_supported_in_ECMAScript_5_and_higher); 40265 reportedError = true; 40266 } 40267 } 40268 40269 // Now that we've removed all the StringLike types, if no constituents remain, then the entire 40270 // arrayOrStringType was a string. 40271 if (arrayType.flags & TypeFlags.Never) { 40272 return possibleOutOfBounds ? includeUndefinedInIndexSignature(stringType) : stringType; 40273 } 40274 } 40275 } 40276 40277 if (!isArrayLikeType(arrayType)) { 40278 if (errorNode && !reportedError) { 40279 // Which error we report depends on whether we allow strings or if there was a 40280 // string constituent. For example, if the input type is number | string, we 40281 // want to say that number is not an array type. But if the input was just 40282 // number and string input is allowed, we want to say that number is not an 40283 // array type or a string type. 40284 const allowsStrings = !!(use & IterationUse.AllowsStringInputFlag) && !hasStringConstituent; 40285 const [defaultDiagnostic, maybeMissingAwait] = getIterationDiagnosticDetails(allowsStrings, downlevelIteration); 40286 errorAndMaybeSuggestAwait( 40287 errorNode, 40288 maybeMissingAwait && !!getAwaitedTypeOfPromise(arrayType), 40289 defaultDiagnostic, 40290 typeToString(arrayType)); 40291 } 40292 return hasStringConstituent ? possibleOutOfBounds ? includeUndefinedInIndexSignature(stringType) : stringType : undefined; 40293 } 40294 40295 const arrayElementType = getIndexTypeOfType(arrayType, numberType); 40296 if (hasStringConstituent && arrayElementType) { 40297 // This is just an optimization for the case where arrayOrStringType is string | string[] 40298 if (arrayElementType.flags & TypeFlags.StringLike && !compilerOptions.noUncheckedIndexedAccess) { 40299 return stringType; 40300 } 40301 40302 return getUnionType(possibleOutOfBounds ? [arrayElementType, stringType, undefinedType] : [arrayElementType, stringType], UnionReduction.Subtype); 40303 } 40304 40305 return (use & IterationUse.PossiblyOutOfBounds) ? includeUndefinedInIndexSignature(arrayElementType) : arrayElementType; 40306 40307 function getIterationDiagnosticDetails(allowsStrings: boolean, downlevelIteration: boolean | undefined): [error: DiagnosticMessage, maybeMissingAwait: boolean] { 40308 if (downlevelIteration) { 40309 return allowsStrings 40310 ? [Diagnostics.Type_0_is_not_an_array_type_or_a_string_type_or_does_not_have_a_Symbol_iterator_method_that_returns_an_iterator, true] 40311 : [Diagnostics.Type_0_is_not_an_array_type_or_does_not_have_a_Symbol_iterator_method_that_returns_an_iterator, true]; 40312 } 40313 40314 const yieldType = getIterationTypeOfIterable(use, IterationTypeKind.Yield, inputType, /*errorNode*/ undefined); 40315 40316 if (yieldType) { 40317 return [Diagnostics.Type_0_can_only_be_iterated_through_when_using_the_downlevelIteration_flag_or_with_a_target_of_es2015_or_higher, false]; 40318 } 40319 40320 if (isES2015OrLaterIterable(inputType.symbol?.escapedName)) { 40321 return [Diagnostics.Type_0_can_only_be_iterated_through_when_using_the_downlevelIteration_flag_or_with_a_target_of_es2015_or_higher, true]; 40322 } 40323 40324 return allowsStrings 40325 ? [Diagnostics.Type_0_is_not_an_array_type_or_a_string_type, true] 40326 : [Diagnostics.Type_0_is_not_an_array_type, true]; 40327 } 40328 } 40329 40330 function isES2015OrLaterIterable(n: __String) { 40331 switch (n) { 40332 case "Float32Array": 40333 case "Float64Array": 40334 case "Int16Array": 40335 case "Int32Array": 40336 case "Int8Array": 40337 case "NodeList": 40338 case "Uint16Array": 40339 case "Uint32Array": 40340 case "Uint8Array": 40341 case "Uint8ClampedArray": 40342 return true; 40343 } 40344 return false; 40345 } 40346 40347 /** 40348 * Gets the requested "iteration type" from an `Iterable`-like or `AsyncIterable`-like type. 40349 */ 40350 function getIterationTypeOfIterable(use: IterationUse, typeKind: IterationTypeKind, inputType: Type, errorNode: Node | undefined): Type | undefined { 40351 if (isTypeAny(inputType)) { 40352 return undefined; 40353 } 40354 40355 const iterationTypes = getIterationTypesOfIterable(inputType, use, errorNode); 40356 return iterationTypes && iterationTypes[getIterationTypesKeyFromIterationTypeKind(typeKind)]; 40357 } 40358 40359 function createIterationTypes(yieldType: Type = neverType, returnType: Type = neverType, nextType: Type = unknownType): IterationTypes { 40360 // `yieldType` and `returnType` are defaulted to `neverType` they each will be combined 40361 // via `getUnionType` when merging iteration types. `nextType` is defined as `unknownType` 40362 // as it is combined via `getIntersectionType` when merging iteration types. 40363 40364 // Use the cache only for intrinsic types to keep it small as they are likely to be 40365 // more frequently created (i.e. `Iterator<number, void, unknown>`). Iteration types 40366 // are also cached on the type they are requested for, so we shouldn't need to maintain 40367 // the cache for less-frequently used types. 40368 if (yieldType.flags & TypeFlags.Intrinsic && 40369 returnType.flags & (TypeFlags.Any | TypeFlags.Never | TypeFlags.Unknown | TypeFlags.Void | TypeFlags.Undefined) && 40370 nextType.flags & (TypeFlags.Any | TypeFlags.Never | TypeFlags.Unknown | TypeFlags.Void | TypeFlags.Undefined)) { 40371 const id = getTypeListId([yieldType, returnType, nextType]); 40372 let iterationTypes = iterationTypesCache.get(id); 40373 if (!iterationTypes) { 40374 iterationTypes = { yieldType, returnType, nextType }; 40375 iterationTypesCache.set(id, iterationTypes); 40376 } 40377 return iterationTypes; 40378 } 40379 return { yieldType, returnType, nextType }; 40380 } 40381 40382 /** 40383 * Combines multiple `IterationTypes` records. 40384 * 40385 * If `array` is empty or all elements are missing or are references to `noIterationTypes`, 40386 * then `noIterationTypes` is returned. Otherwise, an `IterationTypes` record is returned 40387 * for the combined iteration types. 40388 */ 40389 function combineIterationTypes(array: (IterationTypes | undefined)[]) { 40390 let yieldTypes: Type[] | undefined; 40391 let returnTypes: Type[] | undefined; 40392 let nextTypes: Type[] | undefined; 40393 for (const iterationTypes of array) { 40394 if (iterationTypes === undefined || iterationTypes === noIterationTypes) { 40395 continue; 40396 } 40397 if (iterationTypes === anyIterationTypes) { 40398 return anyIterationTypes; 40399 } 40400 yieldTypes = append(yieldTypes, iterationTypes.yieldType); 40401 returnTypes = append(returnTypes, iterationTypes.returnType); 40402 nextTypes = append(nextTypes, iterationTypes.nextType); 40403 } 40404 if (yieldTypes || returnTypes || nextTypes) { 40405 return createIterationTypes( 40406 yieldTypes && getUnionType(yieldTypes), 40407 returnTypes && getUnionType(returnTypes), 40408 nextTypes && getIntersectionType(nextTypes)); 40409 } 40410 return noIterationTypes; 40411 } 40412 40413 function getCachedIterationTypes(type: Type, cacheKey: MatchingKeys<IterableOrIteratorType, IterationTypes | undefined>) { 40414 return (type as IterableOrIteratorType)[cacheKey]; 40415 } 40416 40417 function setCachedIterationTypes(type: Type, cacheKey: MatchingKeys<IterableOrIteratorType, IterationTypes | undefined>, cachedTypes: IterationTypes) { 40418 return (type as IterableOrIteratorType)[cacheKey] = cachedTypes; 40419 } 40420 40421 /** 40422 * Gets the *yield*, *return*, and *next* types from an `Iterable`-like or `AsyncIterable`-like type. 40423 * 40424 * At every level that involves analyzing return types of signatures, we union the return types of all the signatures. 40425 * 40426 * Another thing to note is that at any step of this process, we could run into a dead end, 40427 * meaning either the property is missing, or we run into the anyType. If either of these things 40428 * happens, we return `undefined` to signal that we could not find the iteration type. If a property 40429 * is missing, and the previous step did not result in `any`, then we also give an error if the 40430 * caller requested it. Then the caller can decide what to do in the case where there is no iterated 40431 * type. 40432 * 40433 * For a **for-of** statement, `yield*` (in a normal generator), spread, array 40434 * destructuring, or normal generator we will only ever look for a `[Symbol.iterator]()` 40435 * method. 40436 * 40437 * For an async generator we will only ever look at the `[Symbol.asyncIterator]()` method. 40438 * 40439 * For a **for-await-of** statement or a `yield*` in an async generator we will look for 40440 * the `[Symbol.asyncIterator]()` method first, and then the `[Symbol.iterator]()` method. 40441 */ 40442 function getIterationTypesOfIterable(type: Type, use: IterationUse, errorNode: Node | undefined) { 40443 if (isTypeAny(type)) { 40444 return anyIterationTypes; 40445 } 40446 40447 if (!(type.flags & TypeFlags.Union)) { 40448 const errorOutputContainer: { errors: Diagnostic[] | undefined } | undefined = errorNode ? { errors: undefined } : undefined; 40449 const iterationTypes = getIterationTypesOfIterableWorker(type, use, errorNode, errorOutputContainer); 40450 if (iterationTypes === noIterationTypes) { 40451 if (errorNode) { 40452 const rootDiag = reportTypeNotIterableError(errorNode, type, !!(use & IterationUse.AllowsAsyncIterablesFlag)); 40453 if (errorOutputContainer?.errors) { 40454 addRelatedInfo(rootDiag, ...errorOutputContainer.errors); 40455 } 40456 } 40457 return undefined; 40458 } 40459 else if (errorOutputContainer?.errors?.length) { 40460 for (const diag of errorOutputContainer.errors) { 40461 diagnostics.add(diag); 40462 } 40463 } 40464 return iterationTypes; 40465 } 40466 40467 const cacheKey = use & IterationUse.AllowsAsyncIterablesFlag ? "iterationTypesOfAsyncIterable" : "iterationTypesOfIterable"; 40468 const cachedTypes = getCachedIterationTypes(type, cacheKey); 40469 if (cachedTypes) return cachedTypes === noIterationTypes ? undefined : cachedTypes; 40470 40471 let allIterationTypes: IterationTypes[] | undefined; 40472 for (const constituent of (type as UnionType).types) { 40473 const errorOutputContainer: { errors: Diagnostic[] | undefined } | undefined = errorNode ? { errors: undefined } : undefined; 40474 const iterationTypes = getIterationTypesOfIterableWorker(constituent, use, errorNode, errorOutputContainer); 40475 if (iterationTypes === noIterationTypes) { 40476 if (errorNode) { 40477 const rootDiag = reportTypeNotIterableError(errorNode, type, !!(use & IterationUse.AllowsAsyncIterablesFlag)); 40478 if (errorOutputContainer?.errors) { 40479 addRelatedInfo(rootDiag, ...errorOutputContainer.errors); 40480 } 40481 } 40482 setCachedIterationTypes(type, cacheKey, noIterationTypes); 40483 return undefined; 40484 } 40485 else if (errorOutputContainer?.errors?.length) { 40486 for (const diag of errorOutputContainer.errors) { 40487 diagnostics.add(diag); 40488 } 40489 } 40490 40491 allIterationTypes = append(allIterationTypes, iterationTypes); 40492 } 40493 40494 const iterationTypes = allIterationTypes ? combineIterationTypes(allIterationTypes) : noIterationTypes; 40495 setCachedIterationTypes(type, cacheKey, iterationTypes); 40496 return iterationTypes === noIterationTypes ? undefined : iterationTypes; 40497 } 40498 40499 function getAsyncFromSyncIterationTypes(iterationTypes: IterationTypes, errorNode: Node | undefined) { 40500 if (iterationTypes === noIterationTypes) return noIterationTypes; 40501 if (iterationTypes === anyIterationTypes) return anyIterationTypes; 40502 const { yieldType, returnType, nextType } = iterationTypes; 40503 // if we're requesting diagnostics, report errors for a missing `Awaited<T>`. 40504 if (errorNode) { 40505 getGlobalAwaitedSymbol(/*reportErrors*/ true); 40506 } 40507 return createIterationTypes( 40508 getAwaitedType(yieldType, errorNode) || anyType, 40509 getAwaitedType(returnType, errorNode) || anyType, 40510 nextType); 40511 } 40512 40513 /** 40514 * Gets the *yield*, *return*, and *next* types from a non-union type. 40515 * 40516 * If we are unable to find the *yield*, *return*, and *next* types, `noIterationTypes` is 40517 * returned to indicate to the caller that it should report an error. Otherwise, an 40518 * `IterationTypes` record is returned. 40519 * 40520 * NOTE: You probably don't want to call this directly and should be calling 40521 * `getIterationTypesOfIterable` instead. 40522 */ 40523 function getIterationTypesOfIterableWorker(type: Type, use: IterationUse, errorNode: Node | undefined, errorOutputContainer: { errors: Diagnostic[] | undefined } | undefined) { 40524 if (isTypeAny(type)) { 40525 return anyIterationTypes; 40526 } 40527 40528 // If we are reporting errors and encounter a cached `noIterationTypes`, we should ignore the cached value and continue as if nothing was cached. 40529 // In addition, we should not cache any new results for this call. 40530 let noCache = false; 40531 40532 if (use & IterationUse.AllowsAsyncIterablesFlag) { 40533 const iterationTypes = 40534 getIterationTypesOfIterableCached(type, asyncIterationTypesResolver) || 40535 getIterationTypesOfIterableFast(type, asyncIterationTypesResolver); 40536 if (iterationTypes) { 40537 if (iterationTypes === noIterationTypes && errorNode) { 40538 // ignore the cached value 40539 noCache = true; 40540 } 40541 else { 40542 return use & IterationUse.ForOfFlag ? 40543 getAsyncFromSyncIterationTypes(iterationTypes, errorNode) : 40544 iterationTypes; 40545 } 40546 } 40547 } 40548 40549 if (use & IterationUse.AllowsSyncIterablesFlag) { 40550 let iterationTypes = 40551 getIterationTypesOfIterableCached(type, syncIterationTypesResolver) || 40552 getIterationTypesOfIterableFast(type, syncIterationTypesResolver); 40553 if (iterationTypes) { 40554 if (iterationTypes === noIterationTypes && errorNode) { 40555 // ignore the cached value 40556 noCache = true; 40557 } 40558 else { 40559 if (use & IterationUse.AllowsAsyncIterablesFlag) { 40560 // for a sync iterable in an async context, only use the cached types if they are valid. 40561 if (iterationTypes !== noIterationTypes) { 40562 iterationTypes = getAsyncFromSyncIterationTypes(iterationTypes, errorNode); 40563 return noCache ? iterationTypes : setCachedIterationTypes(type, "iterationTypesOfAsyncIterable", iterationTypes); 40564 } 40565 } 40566 else { 40567 return iterationTypes; 40568 } 40569 } 40570 } 40571 } 40572 40573 if (use & IterationUse.AllowsAsyncIterablesFlag) { 40574 const iterationTypes = getIterationTypesOfIterableSlow(type, asyncIterationTypesResolver, errorNode, errorOutputContainer, noCache); 40575 if (iterationTypes !== noIterationTypes) { 40576 return iterationTypes; 40577 } 40578 } 40579 40580 if (use & IterationUse.AllowsSyncIterablesFlag) { 40581 let iterationTypes = getIterationTypesOfIterableSlow(type, syncIterationTypesResolver, errorNode, errorOutputContainer, noCache); 40582 if (iterationTypes !== noIterationTypes) { 40583 if (use & IterationUse.AllowsAsyncIterablesFlag) { 40584 iterationTypes = getAsyncFromSyncIterationTypes(iterationTypes, errorNode); 40585 return noCache ? iterationTypes : setCachedIterationTypes(type, "iterationTypesOfAsyncIterable", iterationTypes); 40586 } 40587 else { 40588 return iterationTypes; 40589 } 40590 } 40591 } 40592 40593 return noIterationTypes; 40594 } 40595 40596 /** 40597 * Gets the *yield*, *return*, and *next* types of an `Iterable`-like or 40598 * `AsyncIterable`-like type from the cache. 40599 * 40600 * NOTE: You probably don't want to call this directly and should be calling 40601 * `getIterationTypesOfIterable` instead. 40602 */ 40603 function getIterationTypesOfIterableCached(type: Type, resolver: IterationTypesResolver) { 40604 return getCachedIterationTypes(type, resolver.iterableCacheKey); 40605 } 40606 40607 function getIterationTypesOfGlobalIterableType(globalType: Type, resolver: IterationTypesResolver) { 40608 const globalIterationTypes = 40609 getIterationTypesOfIterableCached(globalType, resolver) || 40610 getIterationTypesOfIterableSlow(globalType, resolver, /*errorNode*/ undefined, /*errorOutputContainer*/ undefined, /*noCache*/ false); 40611 return globalIterationTypes === noIterationTypes ? defaultIterationTypes : globalIterationTypes; 40612 } 40613 40614 /** 40615 * Gets the *yield*, *return*, and *next* types of an `Iterable`-like or `AsyncIterable`-like 40616 * type from from common heuristics. 40617 * 40618 * If we previously analyzed this type and found no iteration types, `noIterationTypes` is 40619 * returned. If we found iteration types, an `IterationTypes` record is returned. 40620 * Otherwise, we return `undefined` to indicate to the caller it should perform a more 40621 * exhaustive analysis. 40622 * 40623 * NOTE: You probably don't want to call this directly and should be calling 40624 * `getIterationTypesOfIterable` instead. 40625 */ 40626 function getIterationTypesOfIterableFast(type: Type, resolver: IterationTypesResolver) { 40627 // As an optimization, if the type is an instantiation of one of the following global types, then 40628 // just grab its related type argument: 40629 // - `Iterable<T>` or `AsyncIterable<T>` 40630 // - `IterableIterator<T>` or `AsyncIterableIterator<T>` 40631 let globalType: Type; 40632 if (isReferenceToType(type, globalType = resolver.getGlobalIterableType(/*reportErrors*/ false)) || 40633 isReferenceToType(type, globalType = resolver.getGlobalIterableIteratorType(/*reportErrors*/ false))) { 40634 const [yieldType] = getTypeArguments(type as GenericType); 40635 // The "return" and "next" types of `Iterable` and `IterableIterator` are defined by the 40636 // iteration types of their `[Symbol.iterator]()` method. The same is true for their async cousins. 40637 // While we define these as `any` and `undefined` in our libs by default, a custom lib *could* use 40638 // different definitions. 40639 const { returnType, nextType } = getIterationTypesOfGlobalIterableType(globalType, resolver); 40640 return setCachedIterationTypes(type, resolver.iterableCacheKey, createIterationTypes(resolver.resolveIterationType(yieldType, /*errorNode*/ undefined) || yieldType, resolver.resolveIterationType(returnType, /*errorNode*/ undefined) || returnType, nextType)); 40641 } 40642 40643 // As an optimization, if the type is an instantiation of the following global type, then 40644 // just grab its related type arguments: 40645 // - `Generator<T, TReturn, TNext>` or `AsyncGenerator<T, TReturn, TNext>` 40646 if (isReferenceToType(type, resolver.getGlobalGeneratorType(/*reportErrors*/ false))) { 40647 const [yieldType, returnType, nextType] = getTypeArguments(type as GenericType); 40648 return setCachedIterationTypes(type, resolver.iterableCacheKey, createIterationTypes(resolver.resolveIterationType(yieldType, /*errorNode*/ undefined) || yieldType, resolver.resolveIterationType(returnType, /*errorNode*/ undefined) || returnType, nextType)); 40649 } 40650 } 40651 40652 function getPropertyNameForKnownSymbolName(symbolName: string): __String { 40653 const ctorType = getGlobalESSymbolConstructorSymbol(/*reportErrors*/ false); 40654 const uniqueType = ctorType && getTypeOfPropertyOfType(getTypeOfSymbol(ctorType), escapeLeadingUnderscores(symbolName)); 40655 return uniqueType && isTypeUsableAsPropertyName(uniqueType) ? getPropertyNameFromType(uniqueType) : `__@${symbolName}` as __String; 40656 } 40657 40658 /** 40659 * Gets the *yield*, *return*, and *next* types of an `Iterable`-like or `AsyncIterable`-like 40660 * type from its members. 40661 * 40662 * If we successfully found the *yield*, *return*, and *next* types, an `IterationTypes` 40663 * record is returned. Otherwise, `noIterationTypes` is returned. 40664 * 40665 * NOTE: You probably don't want to call this directly and should be calling 40666 * `getIterationTypesOfIterable` instead. 40667 */ 40668 function getIterationTypesOfIterableSlow(type: Type, resolver: IterationTypesResolver, errorNode: Node | undefined, errorOutputContainer: { errors: Diagnostic[] | undefined } | undefined, noCache: boolean) { 40669 const method = getPropertyOfType(type, getPropertyNameForKnownSymbolName(resolver.iteratorSymbolName)); 40670 const methodType = method && !(method.flags & SymbolFlags.Optional) ? getTypeOfSymbol(method) : undefined; 40671 if (isTypeAny(methodType)) { 40672 return noCache ? anyIterationTypes : setCachedIterationTypes(type, resolver.iterableCacheKey, anyIterationTypes); 40673 } 40674 40675 const signatures = methodType ? getSignaturesOfType(methodType, SignatureKind.Call) : undefined; 40676 if (!some(signatures)) { 40677 return noCache ? noIterationTypes : setCachedIterationTypes(type, resolver.iterableCacheKey, noIterationTypes); 40678 } 40679 40680 const iteratorType = getIntersectionType(map(signatures, getReturnTypeOfSignature)); 40681 const iterationTypes = getIterationTypesOfIteratorWorker(iteratorType, resolver, errorNode, errorOutputContainer, noCache) ?? noIterationTypes; 40682 return noCache ? iterationTypes : setCachedIterationTypes(type, resolver.iterableCacheKey, iterationTypes); 40683 } 40684 40685 function reportTypeNotIterableError(errorNode: Node, type: Type, allowAsyncIterables: boolean): Diagnostic { 40686 const message = allowAsyncIterables 40687 ? Diagnostics.Type_0_must_have_a_Symbol_asyncIterator_method_that_returns_an_async_iterator 40688 : Diagnostics.Type_0_must_have_a_Symbol_iterator_method_that_returns_an_iterator; 40689 const suggestAwait = 40690 // for (const x of Promise<...>) or [...Promise<...>] 40691 !!getAwaitedTypeOfPromise(type) 40692 // for (const x of AsyncIterable<...>) 40693 || ( 40694 !allowAsyncIterables && 40695 isForOfStatement(errorNode.parent) && 40696 errorNode.parent.expression === errorNode && 40697 getGlobalAsyncIterableType(/** reportErrors */ false) !== emptyGenericType && 40698 isTypeAssignableTo(type, getGlobalAsyncIterableType(/** reportErrors */ false) 40699 )); 40700 return errorAndMaybeSuggestAwait(errorNode, suggestAwait, message, typeToString(type)); 40701 } 40702 40703 /** 40704 * Gets the *yield*, *return*, and *next* types from an `Iterator`-like or `AsyncIterator`-like type. 40705 * 40706 * If we successfully found the *yield*, *return*, and *next* types, an `IterationTypes` 40707 * record is returned. Otherwise, `undefined` is returned. 40708 */ 40709 function getIterationTypesOfIterator(type: Type, resolver: IterationTypesResolver, errorNode: Node | undefined, errorOutputContainer: { errors: Diagnostic[] | undefined } | undefined) { 40710 return getIterationTypesOfIteratorWorker(type, resolver, errorNode, errorOutputContainer, /*noCache*/ false); 40711 } 40712 40713 /** 40714 * Gets the *yield*, *return*, and *next* types from an `Iterator`-like or `AsyncIterator`-like type. 40715 * 40716 * If we successfully found the *yield*, *return*, and *next* types, an `IterationTypes` 40717 * record is returned. Otherwise, `undefined` is returned. 40718 * 40719 * NOTE: You probably don't want to call this directly and should be calling 40720 * `getIterationTypesOfIterator` instead. 40721 */ 40722 function getIterationTypesOfIteratorWorker(type: Type, resolver: IterationTypesResolver, errorNode: Node | undefined, errorOutputContainer: { errors: Diagnostic[] | undefined } | undefined, noCache: boolean) { 40723 if (isTypeAny(type)) { 40724 return anyIterationTypes; 40725 } 40726 40727 let iterationTypes = 40728 getIterationTypesOfIteratorCached(type, resolver) || 40729 getIterationTypesOfIteratorFast(type, resolver); 40730 40731 if (iterationTypes === noIterationTypes && errorNode) { 40732 iterationTypes = undefined; 40733 noCache = true; 40734 } 40735 40736 iterationTypes ??= getIterationTypesOfIteratorSlow(type, resolver, errorNode, errorOutputContainer, noCache); 40737 return iterationTypes === noIterationTypes ? undefined : iterationTypes; 40738 } 40739 40740 /** 40741 * Gets the iteration types of an `Iterator`-like or `AsyncIterator`-like type from the 40742 * cache. 40743 * 40744 * NOTE: You probably don't want to call this directly and should be calling 40745 * `getIterationTypesOfIterator` instead. 40746 */ 40747 function getIterationTypesOfIteratorCached(type: Type, resolver: IterationTypesResolver) { 40748 return getCachedIterationTypes(type, resolver.iteratorCacheKey); 40749 } 40750 40751 /** 40752 * Gets the iteration types of an `Iterator`-like or `AsyncIterator`-like type from the 40753 * cache or from common heuristics. 40754 * 40755 * If we previously analyzed this type and found no iteration types, `noIterationTypes` is 40756 * returned. If we found iteration types, an `IterationTypes` record is returned. 40757 * Otherwise, we return `undefined` to indicate to the caller it should perform a more 40758 * exhaustive analysis. 40759 * 40760 * NOTE: You probably don't want to call this directly and should be calling 40761 * `getIterationTypesOfIterator` instead. 40762 */ 40763 function getIterationTypesOfIteratorFast(type: Type, resolver: IterationTypesResolver) { 40764 // As an optimization, if the type is an instantiation of one of the following global types, 40765 // then just grab its related type argument: 40766 // - `IterableIterator<T>` or `AsyncIterableIterator<T>` 40767 // - `Iterator<T, TReturn, TNext>` or `AsyncIterator<T, TReturn, TNext>` 40768 // - `Generator<T, TReturn, TNext>` or `AsyncGenerator<T, TReturn, TNext>` 40769 const globalType = resolver.getGlobalIterableIteratorType(/*reportErrors*/ false); 40770 if (isReferenceToType(type, globalType)) { 40771 const [yieldType] = getTypeArguments(type as GenericType); 40772 // The "return" and "next" types of `IterableIterator` and `AsyncIterableIterator` are defined by the 40773 // iteration types of their `next`, `return`, and `throw` methods. While we define these as `any` 40774 // and `undefined` in our libs by default, a custom lib *could* use different definitions. 40775 const globalIterationTypes = 40776 getIterationTypesOfIteratorCached(globalType, resolver) || 40777 getIterationTypesOfIteratorSlow(globalType, resolver, /*errorNode*/ undefined, /*errorOutputContainer*/ undefined, /*noCache*/ false); 40778 const { returnType, nextType } = globalIterationTypes === noIterationTypes ? defaultIterationTypes : globalIterationTypes; 40779 return setCachedIterationTypes(type, resolver.iteratorCacheKey, createIterationTypes(yieldType, returnType, nextType)); 40780 } 40781 if (isReferenceToType(type, resolver.getGlobalIteratorType(/*reportErrors*/ false)) || 40782 isReferenceToType(type, resolver.getGlobalGeneratorType(/*reportErrors*/ false))) { 40783 const [yieldType, returnType, nextType] = getTypeArguments(type as GenericType); 40784 return setCachedIterationTypes(type, resolver.iteratorCacheKey, createIterationTypes(yieldType, returnType, nextType)); 40785 } 40786 } 40787 40788 function isIteratorResult(type: Type, kind: IterationTypeKind.Yield | IterationTypeKind.Return) { 40789 // From https://tc39.github.io/ecma262/#sec-iteratorresult-interface: 40790 // > [done] is the result status of an iterator `next` method call. If the end of the iterator was reached `done` is `true`. 40791 // > If the end was not reached `done` is `false` and a value is available. 40792 // > If a `done` property (either own or inherited) does not exist, it is consider to have the value `false`. 40793 const doneType = getTypeOfPropertyOfType(type, "done" as __String) || falseType; 40794 return isTypeAssignableTo(kind === IterationTypeKind.Yield ? falseType : trueType, doneType); 40795 } 40796 40797 function isYieldIteratorResult(type: Type) { 40798 return isIteratorResult(type, IterationTypeKind.Yield); 40799 } 40800 40801 function isReturnIteratorResult(type: Type) { 40802 return isIteratorResult(type, IterationTypeKind.Return); 40803 } 40804 40805 /** 40806 * Gets the *yield* and *return* types of an `IteratorResult`-like type. 40807 * 40808 * If we are unable to determine a *yield* or a *return* type, `noIterationTypes` is 40809 * returned to indicate to the caller that it should handle the error. Otherwise, an 40810 * `IterationTypes` record is returned. 40811 */ 40812 function getIterationTypesOfIteratorResult(type: Type) { 40813 if (isTypeAny(type)) { 40814 return anyIterationTypes; 40815 } 40816 40817 const cachedTypes = getCachedIterationTypes(type, "iterationTypesOfIteratorResult"); 40818 if (cachedTypes) { 40819 return cachedTypes; 40820 } 40821 40822 // As an optimization, if the type is an instantiation of one of the global `IteratorYieldResult<T>` 40823 // or `IteratorReturnResult<TReturn>` types, then just grab its type argument. 40824 if (isReferenceToType(type, getGlobalIteratorYieldResultType(/*reportErrors*/ false))) { 40825 const yieldType = getTypeArguments(type as GenericType)[0]; 40826 return setCachedIterationTypes(type, "iterationTypesOfIteratorResult", createIterationTypes(yieldType, /*returnType*/ undefined, /*nextType*/ undefined)); 40827 } 40828 if (isReferenceToType(type, getGlobalIteratorReturnResultType(/*reportErrors*/ false))) { 40829 const returnType = getTypeArguments(type as GenericType)[0]; 40830 return setCachedIterationTypes(type, "iterationTypesOfIteratorResult", createIterationTypes(/*yieldType*/ undefined, returnType, /*nextType*/ undefined)); 40831 } 40832 40833 // Choose any constituents that can produce the requested iteration type. 40834 const yieldIteratorResult = filterType(type, isYieldIteratorResult); 40835 const yieldType = yieldIteratorResult !== neverType ? getTypeOfPropertyOfType(yieldIteratorResult, "value" as __String) : undefined; 40836 40837 const returnIteratorResult = filterType(type, isReturnIteratorResult); 40838 const returnType = returnIteratorResult !== neverType ? getTypeOfPropertyOfType(returnIteratorResult, "value" as __String) : undefined; 40839 40840 if (!yieldType && !returnType) { 40841 return setCachedIterationTypes(type, "iterationTypesOfIteratorResult", noIterationTypes); 40842 } 40843 40844 // From https://tc39.github.io/ecma262/#sec-iteratorresult-interface 40845 // > ... If the iterator does not have a return value, `value` is `undefined`. In that case, the 40846 // > `value` property may be absent from the conforming object if it does not inherit an explicit 40847 // > `value` property. 40848 return setCachedIterationTypes(type, "iterationTypesOfIteratorResult", createIterationTypes(yieldType, returnType || voidType, /*nextType*/ undefined)); 40849 } 40850 40851 /** 40852 * Gets the *yield*, *return*, and *next* types of a the `next()`, `return()`, or 40853 * `throw()` method of an `Iterator`-like or `AsyncIterator`-like type. 40854 * 40855 * If we successfully found the *yield*, *return*, and *next* types, an `IterationTypes` 40856 * record is returned. Otherwise, we return `undefined`. 40857 */ 40858 function getIterationTypesOfMethod(type: Type, resolver: IterationTypesResolver, methodName: "next" | "return" | "throw", errorNode: Node | undefined, errorOutputContainer: { errors: Diagnostic[] | undefined } | undefined): IterationTypes | undefined { 40859 const method = getPropertyOfType(type, methodName as __String); 40860 40861 // Ignore 'return' or 'throw' if they are missing. 40862 if (!method && methodName !== "next") { 40863 return undefined; 40864 } 40865 40866 const methodType = method && !(methodName === "next" && (method.flags & SymbolFlags.Optional)) 40867 ? methodName === "next" ? getTypeOfSymbol(method) : getTypeWithFacts(getTypeOfSymbol(method), TypeFacts.NEUndefinedOrNull) 40868 : undefined; 40869 40870 if (isTypeAny(methodType)) { 40871 // `return()` and `throw()` don't provide a *next* type. 40872 return methodName === "next" ? anyIterationTypes : anyIterationTypesExceptNext; 40873 } 40874 40875 // Both async and non-async iterators *must* have a `next` method. 40876 const methodSignatures = methodType ? getSignaturesOfType(methodType, SignatureKind.Call) : emptyArray; 40877 if (methodSignatures.length === 0) { 40878 if (errorNode) { 40879 const diagnostic = methodName === "next" 40880 ? resolver.mustHaveANextMethodDiagnostic 40881 : resolver.mustBeAMethodDiagnostic; 40882 if (errorOutputContainer) { 40883 errorOutputContainer.errors ??= []; 40884 errorOutputContainer.errors.push(createDiagnosticForNode(errorNode, diagnostic, methodName)); 40885 } 40886 else { 40887 error(errorNode, diagnostic, methodName); 40888 } 40889 } 40890 return methodName === "next" ? noIterationTypes : undefined; 40891 } 40892 40893 // If the method signature comes exclusively from the global iterator or generator type, 40894 // create iteration types from its type arguments like `getIterationTypesOfIteratorFast` 40895 // does (so as to remove `undefined` from the next and return types). We arrive here when 40896 // a contextual type for a generator was not a direct reference to one of those global types, 40897 // but looking up `methodType` referred to one of them (and nothing else). E.g., in 40898 // `interface SpecialIterator extends Iterator<number> {}`, `SpecialIterator` is not a 40899 // reference to `Iterator`, but its `next` member derives exclusively from `Iterator`. 40900 if (methodType?.symbol && methodSignatures.length === 1) { 40901 const globalGeneratorType = resolver.getGlobalGeneratorType(/*reportErrors*/ false); 40902 const globalIteratorType = resolver.getGlobalIteratorType(/*reportErrors*/ false); 40903 const isGeneratorMethod = globalGeneratorType.symbol?.members?.get(methodName as __String) === methodType.symbol; 40904 const isIteratorMethod = !isGeneratorMethod && globalIteratorType.symbol?.members?.get(methodName as __String) === methodType.symbol; 40905 if (isGeneratorMethod || isIteratorMethod) { 40906 const globalType = isGeneratorMethod ? globalGeneratorType : globalIteratorType; 40907 const { mapper } = methodType as AnonymousType; 40908 return createIterationTypes( 40909 getMappedType(globalType.typeParameters![0], mapper!), 40910 getMappedType(globalType.typeParameters![1], mapper!), 40911 methodName === "next" ? getMappedType(globalType.typeParameters![2], mapper!) : undefined); 40912 } 40913 } 40914 40915 // Extract the first parameter and return type of each signature. 40916 let methodParameterTypes: Type[] | undefined; 40917 let methodReturnTypes: Type[] | undefined; 40918 for (const signature of methodSignatures) { 40919 if (methodName !== "throw" && some(signature.parameters)) { 40920 methodParameterTypes = append(methodParameterTypes, getTypeAtPosition(signature, 0)); 40921 } 40922 methodReturnTypes = append(methodReturnTypes, getReturnTypeOfSignature(signature)); 40923 } 40924 40925 // Resolve the *next* or *return* type from the first parameter of a `next()` or 40926 // `return()` method, respectively. 40927 let returnTypes: Type[] | undefined; 40928 let nextType: Type | undefined; 40929 if (methodName !== "throw") { 40930 const methodParameterType = methodParameterTypes ? getUnionType(methodParameterTypes) : unknownType; 40931 if (methodName === "next") { 40932 // The value of `next(value)` is *not* awaited by async generators 40933 nextType = methodParameterType; 40934 } 40935 else if (methodName === "return") { 40936 // The value of `return(value)` *is* awaited by async generators 40937 const resolvedMethodParameterType = resolver.resolveIterationType(methodParameterType, errorNode) || anyType; 40938 returnTypes = append(returnTypes, resolvedMethodParameterType); 40939 } 40940 } 40941 40942 // Resolve the *yield* and *return* types from the return type of the method (i.e. `IteratorResult`) 40943 let yieldType: Type; 40944 const methodReturnType = methodReturnTypes ? getIntersectionType(methodReturnTypes) : neverType; 40945 const resolvedMethodReturnType = resolver.resolveIterationType(methodReturnType, errorNode) || anyType; 40946 const iterationTypes = getIterationTypesOfIteratorResult(resolvedMethodReturnType); 40947 if (iterationTypes === noIterationTypes) { 40948 if (errorNode) { 40949 if (errorOutputContainer) { 40950 errorOutputContainer.errors ??= []; 40951 errorOutputContainer.errors.push(createDiagnosticForNode(errorNode, resolver.mustHaveAValueDiagnostic, methodName)); 40952 } 40953 else { 40954 error(errorNode, resolver.mustHaveAValueDiagnostic, methodName); 40955 } 40956 } 40957 yieldType = anyType; 40958 returnTypes = append(returnTypes, anyType); 40959 } 40960 else { 40961 yieldType = iterationTypes.yieldType; 40962 returnTypes = append(returnTypes, iterationTypes.returnType); 40963 } 40964 40965 return createIterationTypes(yieldType, getUnionType(returnTypes), nextType); 40966 } 40967 40968 /** 40969 * Gets the *yield*, *return*, and *next* types of an `Iterator`-like or `AsyncIterator`-like 40970 * type from its members. 40971 * 40972 * If we successfully found the *yield*, *return*, and *next* types, an `IterationTypes` 40973 * record is returned. Otherwise, `noIterationTypes` is returned. 40974 * 40975 * NOTE: You probably don't want to call this directly and should be calling 40976 * `getIterationTypesOfIterator` instead. 40977 */ 40978 function getIterationTypesOfIteratorSlow(type: Type, resolver: IterationTypesResolver, errorNode: Node | undefined, errorOutputContainer: { errors: Diagnostic[] | undefined } | undefined, noCache: boolean) { 40979 const iterationTypes = combineIterationTypes([ 40980 getIterationTypesOfMethod(type, resolver, "next", errorNode, errorOutputContainer), 40981 getIterationTypesOfMethod(type, resolver, "return", errorNode, errorOutputContainer), 40982 getIterationTypesOfMethod(type, resolver, "throw", errorNode, errorOutputContainer), 40983 ]); 40984 return noCache ? iterationTypes : setCachedIterationTypes(type, resolver.iteratorCacheKey, iterationTypes); 40985 } 40986 40987 /** 40988 * Gets the requested "iteration type" from a type that is either `Iterable`-like, `Iterator`-like, 40989 * `IterableIterator`-like, or `Generator`-like (for a non-async generator); or `AsyncIterable`-like, 40990 * `AsyncIterator`-like, `AsyncIterableIterator`-like, or `AsyncGenerator`-like (for an async generator). 40991 */ 40992 function getIterationTypeOfGeneratorFunctionReturnType(kind: IterationTypeKind, returnType: Type, isAsyncGenerator: boolean): Type | undefined { 40993 if (isTypeAny(returnType)) { 40994 return undefined; 40995 } 40996 40997 const iterationTypes = getIterationTypesOfGeneratorFunctionReturnType(returnType, isAsyncGenerator); 40998 return iterationTypes && iterationTypes[getIterationTypesKeyFromIterationTypeKind(kind)]; 40999 } 41000 41001 function getIterationTypesOfGeneratorFunctionReturnType(type: Type, isAsyncGenerator: boolean) { 41002 if (isTypeAny(type)) { 41003 return anyIterationTypes; 41004 } 41005 41006 const use = isAsyncGenerator ? IterationUse.AsyncGeneratorReturnType : IterationUse.GeneratorReturnType; 41007 const resolver = isAsyncGenerator ? asyncIterationTypesResolver : syncIterationTypesResolver; 41008 return getIterationTypesOfIterable(type, use, /*errorNode*/ undefined) || 41009 getIterationTypesOfIterator(type, resolver, /*errorNode*/ undefined, /*errorOutputContainer*/ undefined); 41010 } 41011 41012 function checkBreakOrContinueStatement(node: BreakOrContinueStatement) { 41013 // Grammar checking 41014 if (!checkGrammarStatementInAmbientContext(node)) checkGrammarBreakOrContinueStatement(node); 41015 41016 // TODO: Check that target label is valid 41017 } 41018 41019 function unwrapReturnType(returnType: Type, functionFlags: FunctionFlags) { 41020 const isGenerator = !!(functionFlags & FunctionFlags.Generator); 41021 const isAsync = !!(functionFlags & FunctionFlags.Async); 41022 if (isGenerator) { 41023 const returnIterationType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, returnType, isAsync); 41024 if (!returnIterationType) { 41025 return errorType; 41026 } 41027 return isAsync ? getAwaitedTypeNoAlias(unwrapAwaitedType(returnIterationType)) : returnIterationType; 41028 } 41029 return isAsync ? getAwaitedTypeNoAlias(returnType) || errorType : returnType; 41030 } 41031 41032 function isUnwrappedReturnTypeVoidOrAny(func: SignatureDeclaration, returnType: Type): boolean { 41033 const unwrappedReturnType = unwrapReturnType(returnType, getFunctionFlags(func)); 41034 return !!unwrappedReturnType && maybeTypeOfKind(unwrappedReturnType, TypeFlags.Void | TypeFlags.AnyOrUnknown); 41035 } 41036 41037 function checkReturnStatement(node: ReturnStatement) { 41038 // Grammar checking 41039 if (checkGrammarStatementInAmbientContext(node)) { 41040 return; 41041 } 41042 41043 const container = getContainingFunctionOrClassStaticBlock(node); 41044 if(container && isClassStaticBlockDeclaration(container)) { 41045 grammarErrorOnFirstToken(node, Diagnostics.A_return_statement_cannot_be_used_inside_a_class_static_block); 41046 return; 41047 } 41048 41049 if (!container) { 41050 grammarErrorOnFirstToken(node, Diagnostics.A_return_statement_can_only_be_used_within_a_function_body); 41051 return; 41052 } 41053 41054 const signature = getSignatureFromDeclaration(container); 41055 const returnType = getReturnTypeOfSignature(signature); 41056 const functionFlags = getFunctionFlags(container); 41057 if (strictNullChecks || node.expression || returnType.flags & TypeFlags.Never) { 41058 const exprType = node.expression ? checkExpressionCached(node.expression) : undefinedType; 41059 if (container.kind === SyntaxKind.SetAccessor) { 41060 if (node.expression) { 41061 error(node, Diagnostics.Setters_cannot_return_a_value); 41062 } 41063 } 41064 else if (container.kind === SyntaxKind.Constructor) { 41065 if (node.expression && !checkTypeAssignableToAndOptionallyElaborate(exprType, returnType, node, node.expression)) { 41066 error(node, Diagnostics.Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class); 41067 } 41068 } 41069 else if (getReturnTypeFromAnnotation(container)) { 41070 const unwrappedReturnType = unwrapReturnType(returnType, functionFlags) ?? returnType; 41071 const unwrappedExprType = functionFlags & FunctionFlags.Async 41072 ? checkAwaitedType(exprType, /*withAlias*/ false, node, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member) 41073 : exprType; 41074 if (unwrappedReturnType) { 41075 // If the function has a return type, but promisedType is 41076 // undefined, an error will be reported in checkAsyncFunctionReturnType 41077 // so we don't need to report one here. 41078 checkTypeAssignableToAndOptionallyElaborate(unwrappedExprType, unwrappedReturnType, node, node.expression); 41079 } 41080 } 41081 } 41082 else if (container.kind !== SyntaxKind.Constructor && compilerOptions.noImplicitReturns && !isUnwrappedReturnTypeVoidOrAny(container, returnType)) { 41083 // The function has a return type, but the return statement doesn't have an expression. 41084 error(node, Diagnostics.Not_all_code_paths_return_a_value); 41085 } 41086 } 41087 41088 function checkWithStatement(node: WithStatement) { 41089 // Grammar checking for withStatement 41090 if (!checkGrammarStatementInAmbientContext(node)) { 41091 if (node.flags & NodeFlags.AwaitContext) { 41092 grammarErrorOnFirstToken(node, Diagnostics.with_statements_are_not_allowed_in_an_async_function_block); 41093 } 41094 } 41095 41096 checkExpression(node.expression); 41097 41098 const sourceFile = getSourceFileOfNode(node); 41099 if (!hasParseDiagnostics(sourceFile)) { 41100 const start = getSpanOfTokenAtPosition(sourceFile, node.pos).start; 41101 const end = node.statement.pos; 41102 grammarErrorAtPos(sourceFile, start, end - start, Diagnostics.The_with_statement_is_not_supported_All_symbols_in_a_with_block_will_have_type_any); 41103 } 41104 } 41105 41106 function checkSwitchStatement(node: SwitchStatement) { 41107 // Grammar checking 41108 checkGrammarStatementInAmbientContext(node); 41109 41110 let firstDefaultClause: CaseOrDefaultClause; 41111 let hasDuplicateDefaultClause = false; 41112 41113 const expressionType = checkExpression(node.expression); 41114 const expressionIsLiteral = isLiteralType(expressionType); 41115 forEach(node.caseBlock.clauses, clause => { 41116 // Grammar check for duplicate default clauses, skip if we already report duplicate default clause 41117 if (clause.kind === SyntaxKind.DefaultClause && !hasDuplicateDefaultClause) { 41118 if (firstDefaultClause === undefined) { 41119 firstDefaultClause = clause; 41120 } 41121 else { 41122 grammarErrorOnNode(clause, Diagnostics.A_default_clause_cannot_appear_more_than_once_in_a_switch_statement); 41123 hasDuplicateDefaultClause = true; 41124 } 41125 } 41126 41127 if (clause.kind === SyntaxKind.CaseClause) { 41128 addLazyDiagnostic(createLazyCaseClauseDiagnostics(clause)); 41129 } 41130 forEach(clause.statements, checkSourceElement); 41131 if (compilerOptions.noFallthroughCasesInSwitch && clause.fallthroughFlowNode && isReachableFlowNode(clause.fallthroughFlowNode)) { 41132 error(clause, Diagnostics.Fallthrough_case_in_switch); 41133 } 41134 41135 function createLazyCaseClauseDiagnostics(clause: CaseClause) { 41136 return () => { 41137 // TypeScript 1.0 spec (April 2014): 5.9 41138 // In a 'switch' statement, each 'case' expression must be of a type that is comparable 41139 // to or from the type of the 'switch' expression. 41140 let caseType = checkExpression(clause.expression); 41141 const caseIsLiteral = isLiteralType(caseType); 41142 let comparedExpressionType = expressionType; 41143 if (!caseIsLiteral || !expressionIsLiteral) { 41144 caseType = caseIsLiteral ? getBaseTypeOfLiteralType(caseType) : caseType; 41145 comparedExpressionType = getBaseTypeOfLiteralType(expressionType); 41146 } 41147 if (!isTypeEqualityComparableTo(comparedExpressionType, caseType)) { 41148 // expressionType is not comparable to caseType, try the reversed check and report errors if it fails 41149 checkTypeComparableTo(caseType, comparedExpressionType, clause.expression, /*headMessage*/ undefined); 41150 } 41151 }; 41152 } 41153 }); 41154 if (node.caseBlock.locals) { 41155 registerForUnusedIdentifiersCheck(node.caseBlock); 41156 } 41157 } 41158 41159 function checkLabeledStatement(node: LabeledStatement) { 41160 // Grammar checking 41161 if (!checkGrammarStatementInAmbientContext(node)) { 41162 findAncestor(node.parent, current => { 41163 if (isFunctionLike(current)) { 41164 return "quit"; 41165 } 41166 if (current.kind === SyntaxKind.LabeledStatement && (current as LabeledStatement).label.escapedText === node.label.escapedText) { 41167 grammarErrorOnNode(node.label, Diagnostics.Duplicate_label_0, getTextOfNode(node.label)); 41168 return true; 41169 } 41170 return false; 41171 }); 41172 } 41173 41174 // ensure that label is unique 41175 checkSourceElement(node.statement); 41176 } 41177 41178 function checkThrowStatement(node: ThrowStatement) { 41179 // Grammar checking 41180 if (!checkGrammarStatementInAmbientContext(node)) { 41181 if (isIdentifier(node.expression) && !node.expression.escapedText) { 41182 grammarErrorAfterFirstToken(node, Diagnostics.Line_break_not_permitted_here); 41183 } 41184 } 41185 41186 if (node.expression) { 41187 checkExpression(node.expression); 41188 } 41189 } 41190 41191 function checkTryStatement(node: TryStatement) { 41192 // Grammar checking 41193 checkGrammarStatementInAmbientContext(node); 41194 41195 checkBlock(node.tryBlock); 41196 const catchClause = node.catchClause; 41197 if (catchClause) { 41198 // Grammar checking 41199 if (catchClause.variableDeclaration) { 41200 const declaration = catchClause.variableDeclaration; 41201 const typeNode = getEffectiveTypeAnnotationNode(getRootDeclaration(declaration)); 41202 if (typeNode) { 41203 const type = getTypeForVariableLikeDeclaration(declaration, /*includeOptionality*/ false, CheckMode.Normal); 41204 if (type && !(type.flags & TypeFlags.AnyOrUnknown)) { 41205 grammarErrorOnFirstToken(typeNode, Diagnostics.Catch_clause_variable_type_annotation_must_be_any_or_unknown_if_specified); 41206 } 41207 } 41208 else if (declaration.initializer) { 41209 grammarErrorOnFirstToken(declaration.initializer, Diagnostics.Catch_clause_variable_cannot_have_an_initializer); 41210 } 41211 else { 41212 const blockLocals = catchClause.block.locals; 41213 if (blockLocals) { 41214 forEachKey(catchClause.locals!, caughtName => { 41215 const blockLocal = blockLocals.get(caughtName); 41216 if (blockLocal?.valueDeclaration && (blockLocal.flags & SymbolFlags.BlockScopedVariable) !== 0) { 41217 grammarErrorOnNode(blockLocal.valueDeclaration, Diagnostics.Cannot_redeclare_identifier_0_in_catch_clause, caughtName); 41218 } 41219 }); 41220 } 41221 } 41222 } 41223 41224 checkBlock(catchClause.block); 41225 } 41226 41227 if (node.finallyBlock) { 41228 checkBlock(node.finallyBlock); 41229 } 41230 } 41231 41232 function checkIndexConstraints(type: Type, symbol: Symbol, isStaticIndex?: boolean) { 41233 const indexInfos = getIndexInfosOfType(type); 41234 if (indexInfos.length === 0) { 41235 return; 41236 } 41237 for (const prop of getPropertiesOfObjectType(type)) { 41238 if (!(isStaticIndex && prop.flags & SymbolFlags.Prototype)) { 41239 checkIndexConstraintForProperty(type, prop, getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique, /*includeNonPublic*/ true), getNonMissingTypeOfSymbol(prop)); 41240 } 41241 } 41242 const typeDeclaration = symbol.valueDeclaration; 41243 if (typeDeclaration && isClassLike(typeDeclaration)) { 41244 for (const member of typeDeclaration.members) { 41245 // Only process instance properties with computed names here. Static properties cannot be in conflict with indexers, 41246 // and properties with literal names were already checked. 41247 if (!isStatic(member) && !hasBindableName(member)) { 41248 const symbol = getSymbolOfNode(member); 41249 checkIndexConstraintForProperty(type, symbol, getTypeOfExpression((member as DynamicNamedDeclaration).name.expression), getNonMissingTypeOfSymbol(symbol)); 41250 } 41251 } 41252 } 41253 if (indexInfos.length > 1) { 41254 for (const info of indexInfos) { 41255 checkIndexConstraintForIndexSignature(type, info); 41256 } 41257 } 41258 } 41259 41260 function checkIndexConstraintForProperty(type: Type, prop: Symbol, propNameType: Type, propType: Type) { 41261 const declaration = prop.valueDeclaration; 41262 const name = getNameOfDeclaration(declaration); 41263 if (name && isPrivateIdentifier(name)) { 41264 return; 41265 } 41266 const indexInfos = getApplicableIndexInfos(type, propNameType); 41267 const interfaceDeclaration = getObjectFlags(type) & ObjectFlags.Interface ? getDeclarationOfKind(type.symbol, SyntaxKind.InterfaceDeclaration) : undefined; 41268 const propDeclaration = declaration && declaration.kind === SyntaxKind.BinaryExpression || 41269 name && name.kind === SyntaxKind.ComputedPropertyName ? declaration : undefined; 41270 const localPropDeclaration = getParentOfSymbol(prop) === type.symbol ? declaration : undefined; 41271 for (const info of indexInfos) { 41272 const localIndexDeclaration = info.declaration && getParentOfSymbol(getSymbolOfNode(info.declaration)) === type.symbol ? info.declaration : undefined; 41273 // We check only when (a) the property is declared in the containing type, or (b) the applicable index signature is declared 41274 // in the containing type, or (c) the containing type is an interface and no base interface contains both the property and 41275 // the index signature (i.e. property and index signature are declared in separate inherited interfaces). 41276 const errorNode = localPropDeclaration || localIndexDeclaration || 41277 (interfaceDeclaration && !some(getBaseTypes(type as InterfaceType), base => !!getPropertyOfObjectType(base, prop.escapedName) && !!getIndexTypeOfType(base, info.keyType)) ? interfaceDeclaration : undefined); 41278 if (errorNode && !isTypeAssignableTo(propType, info.type)) { 41279 const diagnostic = createError(errorNode, Diagnostics.Property_0_of_type_1_is_not_assignable_to_2_index_type_3, 41280 symbolToString(prop), typeToString(propType), typeToString(info.keyType), typeToString(info.type)); 41281 if (propDeclaration && errorNode !== propDeclaration) { 41282 addRelatedInfo(diagnostic, createDiagnosticForNode(propDeclaration, Diagnostics._0_is_declared_here, symbolToString(prop))); 41283 } 41284 diagnostics.add(diagnostic); 41285 } 41286 } 41287 } 41288 41289 function checkIndexConstraintForIndexSignature(type: Type, checkInfo: IndexInfo) { 41290 const declaration = checkInfo.declaration; 41291 const indexInfos = getApplicableIndexInfos(type, checkInfo.keyType); 41292 const interfaceDeclaration = getObjectFlags(type) & ObjectFlags.Interface ? getDeclarationOfKind(type.symbol, SyntaxKind.InterfaceDeclaration) : undefined; 41293 const localCheckDeclaration = declaration && getParentOfSymbol(getSymbolOfNode(declaration)) === type.symbol ? declaration : undefined; 41294 for (const info of indexInfos) { 41295 if (info === checkInfo) continue; 41296 const localIndexDeclaration = info.declaration && getParentOfSymbol(getSymbolOfNode(info.declaration)) === type.symbol ? info.declaration : undefined; 41297 // We check only when (a) the check index signature is declared in the containing type, or (b) the applicable index 41298 // signature is declared in the containing type, or (c) the containing type is an interface and no base interface contains 41299 // both index signatures (i.e. the index signatures are declared in separate inherited interfaces). 41300 const errorNode = localCheckDeclaration || localIndexDeclaration || 41301 (interfaceDeclaration && !some(getBaseTypes(type as InterfaceType), base => !!getIndexInfoOfType(base, checkInfo.keyType) && !!getIndexTypeOfType(base, info.keyType)) ? interfaceDeclaration : undefined); 41302 if (errorNode && !isTypeAssignableTo(checkInfo.type, info.type)) { 41303 error(errorNode, Diagnostics._0_index_type_1_is_not_assignable_to_2_index_type_3, 41304 typeToString(checkInfo.keyType), typeToString(checkInfo.type), typeToString(info.keyType), typeToString(info.type)); 41305 } 41306 } 41307 } 41308 41309 function checkTypeNameIsReserved(name: Identifier, message: DiagnosticMessage): void { 41310 // TS 1.0 spec (April 2014): 3.6.1 41311 // The predefined type keywords are reserved and cannot be used as names of user defined types. 41312 switch (name.escapedText) { 41313 case "any": 41314 case "unknown": 41315 case "never": 41316 case "number": 41317 case "bigint": 41318 case "boolean": 41319 case "string": 41320 case "symbol": 41321 case "void": 41322 case "object": 41323 error(name, message, name.escapedText as string); 41324 } 41325 } 41326 41327 /** 41328 * The name cannot be used as 'Object' of user defined types with special target. 41329 */ 41330 function checkClassNameCollisionWithObject(name: Identifier): void { 41331 if (languageVersion >= ScriptTarget.ES5 && name.escapedText === "Object" 41332 && (moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(name).impliedNodeFormat === ModuleKind.CommonJS)) { 41333 error(name, Diagnostics.Class_name_cannot_be_Object_when_targeting_ES5_with_module_0, ModuleKind[moduleKind]); // https://github.com/Microsoft/TypeScript/issues/17494 41334 } 41335 } 41336 41337 function checkUnmatchedJSDocParameters(node: SignatureDeclaration) { 41338 const jsdocParameters = filter(getJSDocTags(node), isJSDocParameterTag); 41339 if (!length(jsdocParameters)) return; 41340 41341 const isJs = isInJSFile(node); 41342 const parameters = new Set<__String>(); 41343 const excludedParameters = new Set<number>(); 41344 forEach(node.parameters, ({ name }, index) => { 41345 if (isIdentifier(name)) { 41346 parameters.add(name.escapedText); 41347 } 41348 if (isBindingPattern(name)) { 41349 excludedParameters.add(index); 41350 } 41351 }); 41352 41353 const containsArguments = containsArgumentsReference(node); 41354 if (containsArguments) { 41355 const lastJSDocParam = lastOrUndefined(jsdocParameters); 41356 if (isJs && lastJSDocParam && isIdentifier(lastJSDocParam.name) && lastJSDocParam.typeExpression && 41357 lastJSDocParam.typeExpression.type && !parameters.has(lastJSDocParam.name.escapedText) && !isArrayType(getTypeFromTypeNode(lastJSDocParam.typeExpression.type))) { 41358 error(lastJSDocParam.name, Diagnostics.JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name_It_would_match_arguments_if_it_had_an_array_type, idText(lastJSDocParam.name)); 41359 } 41360 } 41361 else { 41362 forEach(jsdocParameters, ({ name, isNameFirst }, index) => { 41363 if (excludedParameters.has(index) || isIdentifier(name) && parameters.has(name.escapedText)) { 41364 return; 41365 } 41366 if (isQualifiedName(name)) { 41367 if (isJs) { 41368 error(name, Diagnostics.Qualified_name_0_is_not_allowed_without_a_leading_param_object_1, entityNameToString(name), entityNameToString(name.left)); 41369 } 41370 } 41371 else { 41372 if (!isNameFirst) { 41373 errorOrSuggestion(isJs, name, Diagnostics.JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name, idText(name)); 41374 } 41375 } 41376 }); 41377 } 41378 } 41379 41380 /** 41381 * Check each type parameter and check that type parameters have no duplicate type parameter declarations 41382 */ 41383 function checkTypeParameters(typeParameterDeclarations: readonly TypeParameterDeclaration[] | undefined) { 41384 let seenDefault = false; 41385 if (typeParameterDeclarations) { 41386 for (let i = 0; i < typeParameterDeclarations.length; i++) { 41387 const node = typeParameterDeclarations[i]; 41388 checkTypeParameter(node); 41389 41390 addLazyDiagnostic(createCheckTypeParameterDiagnostic(node, i)); 41391 } 41392 } 41393 41394 function createCheckTypeParameterDiagnostic(node: TypeParameterDeclaration, i: number) { 41395 return () => { 41396 if (node.default) { 41397 seenDefault = true; 41398 checkTypeParametersNotReferenced(node.default, typeParameterDeclarations!, i); 41399 } 41400 else if (seenDefault) { 41401 error(node, Diagnostics.Required_type_parameters_may_not_follow_optional_type_parameters); 41402 } 41403 for (let j = 0; j < i; j++) { 41404 if (typeParameterDeclarations![j].symbol === node.symbol) { 41405 error(node.name, Diagnostics.Duplicate_identifier_0, declarationNameToString(node.name)); 41406 } 41407 } 41408 }; 41409 } 41410 } 41411 41412 /** Check that type parameter defaults only reference previously declared type parameters */ 41413 function checkTypeParametersNotReferenced(root: TypeNode, typeParameters: readonly TypeParameterDeclaration[], index: number) { 41414 visit(root); 41415 function visit(node: Node) { 41416 if (node.kind === SyntaxKind.TypeReference) { 41417 const type = getTypeFromTypeReference(node as TypeReferenceNode); 41418 if (type.flags & TypeFlags.TypeParameter) { 41419 for (let i = index; i < typeParameters.length; i++) { 41420 if (type.symbol === getSymbolOfNode(typeParameters[i])) { 41421 error(node, Diagnostics.Type_parameter_defaults_can_only_reference_previously_declared_type_parameters); 41422 } 41423 } 41424 } 41425 } 41426 forEachChild(node, visit); 41427 } 41428 } 41429 41430 /** Check that type parameter lists are identical across multiple declarations */ 41431 function checkTypeParameterListsIdentical(symbol: Symbol) { 41432 if (symbol.declarations && symbol.declarations.length === 1) { 41433 return; 41434 } 41435 41436 const links = getSymbolLinks(symbol); 41437 if (!links.typeParametersChecked) { 41438 links.typeParametersChecked = true; 41439 const declarations = getClassOrInterfaceDeclarationsOfSymbol(symbol); 41440 if (!declarations || declarations.length <= 1) { 41441 return; 41442 } 41443 41444 const type = getDeclaredTypeOfSymbol(symbol) as InterfaceType; 41445 if (!areTypeParametersIdentical(declarations, type.localTypeParameters!, getEffectiveTypeParameterDeclarations)) { 41446 // Report an error on every conflicting declaration. 41447 const name = symbolToString(symbol); 41448 for (const declaration of declarations) { 41449 error(declaration.name, Diagnostics.All_declarations_of_0_must_have_identical_type_parameters, name); 41450 } 41451 } 41452 } 41453 } 41454 41455 function areTypeParametersIdentical<T extends DeclarationWithTypeParameters | TypeParameterDeclaration>(declarations: readonly T[], targetParameters: TypeParameter[], getTypeParameterDeclarations: (node: T) => readonly TypeParameterDeclaration[]) { 41456 const maxTypeArgumentCount = length(targetParameters); 41457 const minTypeArgumentCount = getMinTypeArgumentCount(targetParameters); 41458 41459 for (const declaration of declarations) { 41460 // If this declaration has too few or too many type parameters, we report an error 41461 const sourceParameters = getTypeParameterDeclarations(declaration); 41462 const numTypeParameters = sourceParameters.length; 41463 if (numTypeParameters < minTypeArgumentCount || numTypeParameters > maxTypeArgumentCount) { 41464 return false; 41465 } 41466 41467 for (let i = 0; i < numTypeParameters; i++) { 41468 const source = sourceParameters[i]; 41469 const target = targetParameters[i]; 41470 41471 // If the type parameter node does not have the same as the resolved type 41472 // parameter at this position, we report an error. 41473 if (source.name.escapedText !== target.symbol.escapedName) { 41474 return false; 41475 } 41476 41477 // If the type parameter node does not have an identical constraint as the resolved 41478 // type parameter at this position, we report an error. 41479 const constraint = getEffectiveConstraintOfTypeParameter(source); 41480 const sourceConstraint = constraint && getTypeFromTypeNode(constraint); 41481 const targetConstraint = getConstraintOfTypeParameter(target); 41482 // relax check if later interface augmentation has no constraint, it's more broad and is OK to merge with 41483 // a more constrained interface (this could be generalized to a full hierarchy check, but that's maybe overkill) 41484 if (sourceConstraint && targetConstraint && !isTypeIdenticalTo(sourceConstraint, targetConstraint)) { 41485 return false; 41486 } 41487 41488 // If the type parameter node has a default and it is not identical to the default 41489 // for the type parameter at this position, we report an error. 41490 const sourceDefault = source.default && getTypeFromTypeNode(source.default); 41491 const targetDefault = getDefaultFromTypeParameter(target); 41492 if (sourceDefault && targetDefault && !isTypeIdenticalTo(sourceDefault, targetDefault)) { 41493 return false; 41494 } 41495 } 41496 } 41497 41498 return true; 41499 } 41500 41501 function checkClassExpression(node: ClassExpression): Type { 41502 checkClassLikeDeclaration(node); 41503 checkNodeDeferred(node); 41504 return getTypeOfSymbol(getSymbolOfNode(node)); 41505 } 41506 41507 function checkClassExpressionDeferred(node: ClassExpression) { 41508 forEach(node.members, checkSourceElement); 41509 registerForUnusedIdentifiersCheck(node); 41510 } 41511 41512 function checkClassDeclaration(node: ClassDeclaration) { 41513 const firstDecorator = find(node.modifiers, isDecorator); 41514 if (firstDecorator && some(node.members, p => hasStaticModifier(p) && isPrivateIdentifierClassElementDeclaration(p))) { 41515 grammarErrorOnNode(firstDecorator, Diagnostics.Class_decorators_can_t_be_used_with_static_private_identifier_Consider_removing_the_experimental_decorator); 41516 } 41517 if (!node.name && !hasSyntacticModifier(node, ModifierFlags.Default)) { 41518 grammarErrorOnFirstToken(node, Diagnostics.A_class_declaration_without_the_default_modifier_must_have_a_name); 41519 } 41520 checkClassLikeDeclaration(node); 41521 forEach(node.members, checkSourceElement); 41522 41523 registerForUnusedIdentifiersCheck(node); 41524 } 41525 41526 function checkStructDeclaration(node: StructDeclaration) { 41527 if (!node.name && !hasSyntacticModifier(node, ModifierFlags.Default)) { 41528 grammarErrorOnFirstToken(node, Diagnostics.A_struct_declaration_without_the_default_modifier_must_have_a_name); 41529 } 41530 checkClassLikeDeclaration(node); 41531 checkStructName(node); 41532 forEach(node.members, checkSourceElement); 41533 41534 registerForUnusedIdentifiersCheck(node); 41535 } 41536 41537 function checkStructName(node: StructDeclaration) { 41538 if (host.getCompilerOptions().ets && node.name && isIdentifier(node.name)) { 41539 const arrReservedComponents = host.getCompilerOptions().ets?.components; 41540 if (arrReservedComponents!.includes(node.name.escapedText.toString())) { 41541 error(node.name, Diagnostics.The_struct_name_cannot_contain_reserved_tag_name_Colon_0, node.name.escapedText.toString()); 41542 } 41543 } 41544 } 41545 41546 function checkAnnotationDeclaration(node: AnnotationDeclaration) { 41547 checkGrammarAnnotationDeclaration(node); 41548 checkDecorators(node); 41549 41550 const firstDecorator = find(node.modifiers, isDecorator); 41551 if (firstDecorator) { 41552 grammarErrorOnNode(firstDecorator, Diagnostics.Decorators_are_not_valid_here); 41553 } 41554 const firstAnnotation = find(node.modifiers, isAnnotation); 41555 if (firstAnnotation) { 41556 grammarErrorOnNode(firstAnnotation, Diagnostics.Annotation_cannot_be_applied_for_annotation_declaration); 41557 } 41558 41559 checkCollisionsForDeclarationName(node, node.name); 41560 41561 checkExportsOnMergedDeclarations(node); 41562 const symbol = getSymbolOfNode(node); 41563 const type = getDeclaredTypeOfSymbol(symbol) as InterfaceType; 41564 const staticType = getTypeOfSymbol(symbol) as ObjectType; 41565 41566 checkClassForDuplicateDeclarations(node); 41567 41568 addLazyDiagnostic(() => { 41569 checkIndexConstraints(type, symbol); 41570 checkIndexConstraints(staticType, symbol, /*isStaticIndex*/ true); 41571 checkTypeForDuplicateIndexSignatures(node); 41572 checkPropertyInitialization(node); 41573 }); 41574 41575 forEach(node.members, checkSourceElement); 41576 } 41577 41578 function checkGrammarAnnotationDeclaration(node: AnnotationDeclaration) { 41579 Debug.assert(node.parent); 41580 if (!isSourceFile(node.parent)) { 41581 grammarErrorOnNode(node, Diagnostics.Annotation_must_be_defined_at_top_level_only); 41582 } 41583 checkGrammarDecoratorsAndModifiers(node); 41584 } 41585 41586 function checkClassLikeDeclaration(node: ClassLikeDeclaration) { 41587 checkGrammarClassLikeDeclaration(node); 41588 checkDecorators(node); 41589 checkCollisionsForDeclarationName(node, node.name); 41590 checkTypeParameters(getEffectiveTypeParameterDeclarations(node)); 41591 checkExportsOnMergedDeclarations(node); 41592 const symbol = getSymbolOfNode(node); 41593 const type = getDeclaredTypeOfSymbol(symbol) as InterfaceType; 41594 const typeWithThis = getTypeWithThisArgument(type); 41595 const staticType = getTypeOfSymbol(symbol) as ObjectType; 41596 checkTypeParameterListsIdentical(symbol); 41597 checkFunctionOrConstructorSymbol(symbol); 41598 checkClassForDuplicateDeclarations(node); 41599 41600 // Only check for reserved static identifiers on non-ambient context. 41601 const nodeInAmbientContext = !!(node.flags & NodeFlags.Ambient); 41602 if (!nodeInAmbientContext) { 41603 checkClassForStaticPropertyNameConflicts(node); 41604 } 41605 41606 const baseTypeNode = getEffectiveBaseTypeNode(node); 41607 if (baseTypeNode) { 41608 forEach(baseTypeNode.typeArguments, checkSourceElement); 41609 if (languageVersion < ScriptTarget.ES2015) { 41610 checkExternalEmitHelpers(baseTypeNode.parent, ExternalEmitHelpers.Extends); 41611 } 41612 // check both @extends and extends if both are specified. 41613 const extendsNode = getClassExtendsHeritageElement(node); 41614 if (extendsNode && extendsNode !== baseTypeNode) { 41615 checkExpression(extendsNode.expression); 41616 } 41617 41618 const baseTypes = getBaseTypes(type); 41619 if (baseTypes.length) { 41620 addLazyDiagnostic(() => { 41621 const baseType = baseTypes[0]; 41622 const baseConstructorType = getBaseConstructorTypeOfClass(type); 41623 const staticBaseType = getApparentType(baseConstructorType); 41624 checkBaseTypeAccessibility(staticBaseType, baseTypeNode); 41625 checkSourceElement(baseTypeNode.expression); 41626 if (some(baseTypeNode.typeArguments)) { 41627 forEach(baseTypeNode.typeArguments, checkSourceElement); 41628 for (const constructor of getConstructorsForTypeArguments(staticBaseType, baseTypeNode.typeArguments, baseTypeNode)) { 41629 if (!checkTypeArgumentConstraints(baseTypeNode, constructor.typeParameters!)) { 41630 break; 41631 } 41632 } 41633 } 41634 const baseWithThis = getTypeWithThisArgument(baseType, type.thisType); 41635 if (!checkTypeAssignableTo(typeWithThis, baseWithThis, /*errorNode*/ undefined)) { 41636 issueMemberSpecificError(node, typeWithThis, baseWithThis, Diagnostics.Class_0_incorrectly_extends_base_class_1); 41637 } 41638 else { 41639 // Report static side error only when instance type is assignable 41640 checkTypeAssignableTo(staticType, getTypeWithoutSignatures(staticBaseType), node.name || node, 41641 Diagnostics.Class_static_side_0_incorrectly_extends_base_class_static_side_1); 41642 } 41643 if (baseConstructorType.flags & TypeFlags.TypeVariable) { 41644 if (!isMixinConstructorType(staticType)) { 41645 error(node.name || node, Diagnostics.A_mixin_class_must_have_a_constructor_with_a_single_rest_parameter_of_type_any); 41646 } 41647 else { 41648 const constructSignatures = getSignaturesOfType(baseConstructorType, SignatureKind.Construct); 41649 if (constructSignatures.some(signature => signature.flags & SignatureFlags.Abstract) && !hasSyntacticModifier(node, ModifierFlags.Abstract)) { 41650 error(node.name || node, Diagnostics.A_mixin_class_that_extends_from_a_type_variable_containing_an_abstract_construct_signature_must_also_be_declared_abstract); 41651 } 41652 } 41653 } 41654 41655 if (!(staticBaseType.symbol && staticBaseType.symbol.flags & SymbolFlags.Class) && !(baseConstructorType.flags & TypeFlags.TypeVariable)) { 41656 // When the static base type is a "class-like" constructor function (but not actually a class), we verify 41657 // that all instantiated base constructor signatures return the same type. 41658 const constructors = getInstantiatedConstructorsForTypeArguments(staticBaseType, baseTypeNode.typeArguments, baseTypeNode); 41659 if (forEach(constructors, sig => !isJSConstructor(sig.declaration) && !isTypeIdenticalTo(getReturnTypeOfSignature(sig), baseType))) { 41660 error(baseTypeNode.expression, Diagnostics.Base_constructors_must_all_have_the_same_return_type); 41661 } 41662 } 41663 checkKindsOfPropertyMemberOverrides(type, baseType); 41664 }); 41665 } 41666 } 41667 41668 checkMembersForOverrideModifier(node, type, typeWithThis, staticType); 41669 41670 const implementedTypeNodes = getEffectiveImplementsTypeNodes(node); 41671 if (implementedTypeNodes) { 41672 for (const typeRefNode of implementedTypeNodes) { 41673 if (!isEntityNameExpression(typeRefNode.expression) || isOptionalChain(typeRefNode.expression)) { 41674 error(typeRefNode.expression, Diagnostics.A_class_can_only_implement_an_identifier_Slashqualified_name_with_optional_type_arguments); 41675 } 41676 checkTypeReferenceNode(typeRefNode); 41677 addLazyDiagnostic(createImplementsDiagnostics(typeRefNode)); 41678 } 41679 } 41680 41681 addLazyDiagnostic(() => { 41682 checkIndexConstraints(type, symbol); 41683 checkIndexConstraints(staticType, symbol, /*isStaticIndex*/ true); 41684 checkTypeForDuplicateIndexSignatures(node); 41685 checkPropertyInitialization(node); 41686 }); 41687 41688 function createImplementsDiagnostics(typeRefNode: ExpressionWithTypeArguments) { 41689 return () => { 41690 const t = getReducedType(getTypeFromTypeNode(typeRefNode)); 41691 if (!isErrorType(t)) { 41692 if (isValidBaseType(t)) { 41693 const genericDiag = t.symbol && t.symbol.flags & SymbolFlags.Class ? 41694 Diagnostics.Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass : 41695 Diagnostics.Class_0_incorrectly_implements_interface_1; 41696 const baseWithThis = getTypeWithThisArgument(t, type.thisType); 41697 if (!checkTypeAssignableTo(typeWithThis, baseWithThis, /*errorNode*/ undefined)) { 41698 issueMemberSpecificError(node, typeWithThis, baseWithThis, genericDiag); 41699 } 41700 } 41701 else { 41702 error(typeRefNode, Diagnostics.A_class_can_only_implement_an_object_type_or_intersection_of_object_types_with_statically_known_members); 41703 } 41704 } 41705 }; 41706 } 41707 } 41708 41709 function checkMembersForOverrideModifier(node: ClassLikeDeclaration, type: InterfaceType, typeWithThis: Type, staticType: ObjectType) { 41710 const baseTypeNode = getEffectiveBaseTypeNode(node); 41711 const baseTypes = baseTypeNode && getBaseTypes(type); 41712 const baseWithThis = baseTypes?.length ? getTypeWithThisArgument(first(baseTypes), type.thisType) : undefined; 41713 const baseStaticType = getBaseConstructorTypeOfClass(type); 41714 41715 for (const member of node.members) { 41716 if (hasAmbientModifier(member)) { 41717 continue; 41718 } 41719 41720 if (isConstructorDeclaration(member)) { 41721 forEach(member.parameters, param => { 41722 if (isParameterPropertyDeclaration(param, member)) { 41723 checkExistingMemberForOverrideModifier( 41724 node, 41725 staticType, 41726 baseStaticType, 41727 baseWithThis, 41728 type, 41729 typeWithThis, 41730 param, 41731 /* memberIsParameterProperty */ true 41732 ); 41733 } 41734 }); 41735 } 41736 checkExistingMemberForOverrideModifier( 41737 node, 41738 staticType, 41739 baseStaticType, 41740 baseWithThis, 41741 type, 41742 typeWithThis, 41743 member, 41744 /* memberIsParameterProperty */ false, 41745 ); 41746 } 41747 } 41748 41749 /** 41750 * @param member Existing member node to be checked. 41751 * Note: `member` cannot be a synthetic node. 41752 */ 41753 function checkExistingMemberForOverrideModifier( 41754 node: ClassLikeDeclaration, 41755 staticType: ObjectType, 41756 baseStaticType: Type, 41757 baseWithThis: Type | undefined, 41758 type: InterfaceType, 41759 typeWithThis: Type, 41760 member: ClassElement | ParameterPropertyDeclaration, 41761 memberIsParameterProperty: boolean, 41762 reportErrors = true, 41763 ): MemberOverrideStatus { 41764 const declaredProp = member.name 41765 && getSymbolAtLocation(member.name) 41766 || getSymbolAtLocation(member); 41767 if (!declaredProp) { 41768 return MemberOverrideStatus.Ok; 41769 } 41770 41771 return checkMemberForOverrideModifier( 41772 node, 41773 staticType, 41774 baseStaticType, 41775 baseWithThis, 41776 type, 41777 typeWithThis, 41778 hasOverrideModifier(member), 41779 hasAbstractModifier(member), 41780 isStatic(member), 41781 memberIsParameterProperty, 41782 symbolName(declaredProp), 41783 reportErrors ? member : undefined, 41784 ); 41785 } 41786 41787 /** 41788 * Checks a class member declaration for either a missing or an invalid `override` modifier. 41789 * Note: this function can be used for speculative checking, 41790 * i.e. checking a member that does not yet exist in the program. 41791 * An example of that would be to call this function in a completions scenario, 41792 * when offering a method declaration as completion. 41793 * @param errorNode The node where we should report an error, or undefined if we should not report errors. 41794 */ 41795 function checkMemberForOverrideModifier( 41796 node: ClassLikeDeclaration, 41797 staticType: ObjectType, 41798 baseStaticType: Type, 41799 baseWithThis: Type | undefined, 41800 type: InterfaceType, 41801 typeWithThis: Type, 41802 memberHasOverrideModifier: boolean, 41803 memberHasAbstractModifier: boolean, 41804 memberIsStatic: boolean, 41805 memberIsParameterProperty: boolean, 41806 memberName: string, 41807 errorNode?: Node, 41808 ): MemberOverrideStatus { 41809 const isJs = isInJSFile(node); 41810 const nodeInAmbientContext = !!(node.flags & NodeFlags.Ambient); 41811 if (baseWithThis && (memberHasOverrideModifier || compilerOptions.noImplicitOverride)) { 41812 const memberEscapedName = escapeLeadingUnderscores(memberName); 41813 const thisType = memberIsStatic ? staticType : typeWithThis; 41814 const baseType = memberIsStatic ? baseStaticType : baseWithThis; 41815 const prop = getPropertyOfType(thisType, memberEscapedName); 41816 const baseProp = getPropertyOfType(baseType, memberEscapedName); 41817 41818 const baseClassName = typeToString(baseWithThis); 41819 if (prop && !baseProp && memberHasOverrideModifier) { 41820 if (errorNode) { 41821 const suggestion = getSuggestedSymbolForNonexistentClassMember(memberName, baseType); // Again, using symbol name: note that's different from `symbol.escapedName` 41822 suggestion ? 41823 error( 41824 errorNode, 41825 isJs ? 41826 Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0_Did_you_mean_1 : 41827 Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0_Did_you_mean_1, 41828 baseClassName, 41829 symbolToString(suggestion)) : 41830 error( 41831 errorNode, 41832 isJs ? 41833 Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0 : 41834 Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0, 41835 baseClassName); 41836 } 41837 return MemberOverrideStatus.HasInvalidOverride; 41838 } 41839 else if (prop && baseProp?.declarations && compilerOptions.noImplicitOverride && !nodeInAmbientContext) { 41840 const baseHasAbstract = some(baseProp.declarations, hasAbstractModifier); 41841 if (memberHasOverrideModifier) { 41842 return MemberOverrideStatus.Ok; 41843 } 41844 41845 if (!baseHasAbstract) { 41846 if (errorNode) { 41847 const diag = memberIsParameterProperty ? 41848 isJs ? 41849 Diagnostics.This_parameter_property_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0 : 41850 Diagnostics.This_parameter_property_must_have_an_override_modifier_because_it_overrides_a_member_in_base_class_0 : 41851 isJs ? 41852 Diagnostics.This_member_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0 : 41853 Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_a_member_in_the_base_class_0; 41854 error(errorNode, diag, baseClassName); 41855 } 41856 return MemberOverrideStatus.NeedsOverride; 41857 } 41858 else if (memberHasAbstractModifier && baseHasAbstract) { 41859 if (errorNode) { 41860 error(errorNode, Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_an_abstract_method_that_is_declared_in_the_base_class_0, baseClassName); 41861 } 41862 return MemberOverrideStatus.NeedsOverride; 41863 } 41864 } 41865 } 41866 else if (memberHasOverrideModifier) { 41867 if (errorNode) { 41868 const className = typeToString(type); 41869 error( 41870 errorNode, 41871 isJs ? 41872 Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_its_containing_class_0_does_not_extend_another_class : 41873 Diagnostics.This_member_cannot_have_an_override_modifier_because_its_containing_class_0_does_not_extend_another_class, 41874 className); 41875 } 41876 return MemberOverrideStatus.HasInvalidOverride; 41877 } 41878 41879 return MemberOverrideStatus.Ok; 41880 } 41881 41882 function issueMemberSpecificError(node: ClassLikeDeclaration, typeWithThis: Type, baseWithThis: Type, broadDiag: DiagnosticMessage) { 41883 // iterate over all implemented properties and issue errors on each one which isn't compatible, rather than the class as a whole, if possible 41884 let issuedMemberError = false; 41885 for (const member of node.members) { 41886 if (isStatic(member)) { 41887 continue; 41888 } 41889 const declaredProp = member.name && getSymbolAtLocation(member.name) || getSymbolAtLocation(member); 41890 if (declaredProp) { 41891 const prop = getPropertyOfType(typeWithThis, declaredProp.escapedName); 41892 const baseProp = getPropertyOfType(baseWithThis, declaredProp.escapedName); 41893 if (prop && baseProp) { 41894 const rootChain = () => chainDiagnosticMessages( 41895 /*details*/ undefined, 41896 Diagnostics.Property_0_in_type_1_is_not_assignable_to_the_same_property_in_base_type_2, 41897 symbolToString(declaredProp), 41898 typeToString(typeWithThis), 41899 typeToString(baseWithThis) 41900 ); 41901 if (!checkTypeAssignableTo(getTypeOfSymbol(prop), getTypeOfSymbol(baseProp), member.name || member, /*message*/ undefined, rootChain)) { 41902 issuedMemberError = true; 41903 } 41904 } 41905 } 41906 } 41907 if (!issuedMemberError) { 41908 // check again with diagnostics to generate a less-specific error 41909 checkTypeAssignableTo(typeWithThis, baseWithThis, node.name || node, broadDiag); 41910 } 41911 } 41912 41913 function checkBaseTypeAccessibility(type: Type, node: ExpressionWithTypeArguments) { 41914 const signatures = getSignaturesOfType(type, SignatureKind.Construct); 41915 if (signatures.length) { 41916 const declaration = signatures[0].declaration; 41917 if (declaration && hasEffectiveModifier(declaration, ModifierFlags.Private)) { 41918 const typeClassDeclaration = getClassLikeDeclarationOfSymbol(type.symbol)!; 41919 if (!isNodeWithinClass(node, typeClassDeclaration)) { 41920 error(node, Diagnostics.Cannot_extend_a_class_0_Class_constructor_is_marked_as_private, getFullyQualifiedName(type.symbol)); 41921 } 41922 } 41923 } 41924 } 41925 41926 /** 41927 * Checks a member declaration node to see if has a missing or invalid `override` modifier. 41928 * @param node Class-like node where the member is declared. 41929 * @param member Member declaration node. 41930 * Note: `member` can be a synthetic node without a parent. 41931 */ 41932 function getMemberOverrideModifierStatus(node: ClassLikeDeclaration, member: ClassElement): MemberOverrideStatus { 41933 if (!member.name) { 41934 return MemberOverrideStatus.Ok; 41935 } 41936 41937 const symbol = getSymbolOfNode(node); 41938 const type = getDeclaredTypeOfSymbol(symbol) as InterfaceType; 41939 const typeWithThis = getTypeWithThisArgument(type); 41940 const staticType = getTypeOfSymbol(symbol) as ObjectType; 41941 41942 const baseTypeNode = getEffectiveBaseTypeNode(node); 41943 const baseTypes = baseTypeNode && getBaseTypes(type); 41944 const baseWithThis = baseTypes?.length ? getTypeWithThisArgument(first(baseTypes), type.thisType) : undefined; 41945 const baseStaticType = getBaseConstructorTypeOfClass(type); 41946 41947 const memberHasOverrideModifier = member.parent 41948 ? hasOverrideModifier(member) 41949 : hasSyntacticModifier(member, ModifierFlags.Override); 41950 41951 const memberName = unescapeLeadingUnderscores(getTextOfPropertyName(member.name)); 41952 41953 return checkMemberForOverrideModifier( 41954 node, 41955 staticType, 41956 baseStaticType, 41957 baseWithThis, 41958 type, 41959 typeWithThis, 41960 memberHasOverrideModifier, 41961 hasAbstractModifier(member), 41962 isStatic(member), 41963 /* memberIsParameterProperty */ false, 41964 memberName, 41965 ); 41966 } 41967 41968 function getTargetSymbol(s: Symbol) { 41969 // if symbol is instantiated its flags are not copied from the 'target' 41970 // so we'll need to get back original 'target' symbol to work with correct set of flags 41971 return getCheckFlags(s) & CheckFlags.Instantiated ? (s as TransientSymbol).target! : s; 41972 } 41973 41974 function getClassOrInterfaceDeclarationsOfSymbol(symbol: Symbol) { 41975 return filter(symbol.declarations, (d: Declaration): d is ClassDeclaration | InterfaceDeclaration => 41976 d.kind === SyntaxKind.ClassDeclaration || d.kind === SyntaxKind.InterfaceDeclaration); 41977 } 41978 41979 function checkKindsOfPropertyMemberOverrides(type: InterfaceType, baseType: BaseType): void { 41980 // TypeScript 1.0 spec (April 2014): 8.2.3 41981 // A derived class inherits all members from its base class it doesn't override. 41982 // Inheritance means that a derived class implicitly contains all non - overridden members of the base class. 41983 // Both public and private property members are inherited, but only public property members can be overridden. 41984 // A property member in a derived class is said to override a property member in a base class 41985 // when the derived class property member has the same name and kind(instance or static) 41986 // as the base class property member. 41987 // The type of an overriding property member must be assignable(section 3.8.4) 41988 // to the type of the overridden property member, or otherwise a compile - time error occurs. 41989 // Base class instance member functions can be overridden by derived class instance member functions, 41990 // but not by other kinds of members. 41991 // Base class instance member variables and accessors can be overridden by 41992 // derived class instance member variables and accessors, but not by other kinds of members. 41993 41994 // NOTE: assignability is checked in checkClassDeclaration 41995 const baseProperties = getPropertiesOfType(baseType); 41996 basePropertyCheck: for (const baseProperty of baseProperties) { 41997 const base = getTargetSymbol(baseProperty); 41998 41999 if (base.flags & SymbolFlags.Prototype) { 42000 continue; 42001 } 42002 const baseSymbol = getPropertyOfObjectType(type, base.escapedName); 42003 if (!baseSymbol) { 42004 continue; 42005 } 42006 const derived = getTargetSymbol(baseSymbol); 42007 const baseDeclarationFlags = getDeclarationModifierFlagsFromSymbol(base); 42008 42009 Debug.assert(!!derived, "derived should point to something, even if it is the base class' declaration."); 42010 42011 // In order to resolve whether the inherited method was overridden in the base class or not, 42012 // we compare the Symbols obtained. Since getTargetSymbol returns the symbol on the *uninstantiated* 42013 // type declaration, derived and base resolve to the same symbol even in the case of generic classes. 42014 if (derived === base) { 42015 // derived class inherits base without override/redeclaration 42016 const derivedClassDecl = getClassLikeDeclarationOfSymbol(type.symbol)!; 42017 42018 // It is an error to inherit an abstract member without implementing it or being declared abstract. 42019 // If there is no declaration for the derived class (as in the case of class expressions), 42020 // then the class cannot be declared abstract. 42021 if (baseDeclarationFlags & ModifierFlags.Abstract && (!derivedClassDecl || !hasSyntacticModifier(derivedClassDecl, ModifierFlags.Abstract))) { 42022 // Searches other base types for a declaration that would satisfy the inherited abstract member. 42023 // (The class may have more than one base type via declaration merging with an interface with the 42024 // same name.) 42025 for (const otherBaseType of getBaseTypes(type)) { 42026 if (otherBaseType === baseType) continue; 42027 const baseSymbol = getPropertyOfObjectType(otherBaseType, base.escapedName); 42028 const derivedElsewhere = baseSymbol && getTargetSymbol(baseSymbol); 42029 if (derivedElsewhere && derivedElsewhere !== base) { 42030 continue basePropertyCheck; 42031 } 42032 } 42033 42034 if (derivedClassDecl.kind === SyntaxKind.ClassExpression) { 42035 error(derivedClassDecl, Diagnostics.Non_abstract_class_expression_does_not_implement_inherited_abstract_member_0_from_class_1, 42036 symbolToString(baseProperty), typeToString(baseType)); 42037 } 42038 else { 42039 error(derivedClassDecl, Diagnostics.Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2, 42040 typeToString(type), symbolToString(baseProperty), typeToString(baseType)); 42041 } 42042 } 42043 } 42044 else { 42045 // derived overrides base. 42046 const derivedDeclarationFlags = getDeclarationModifierFlagsFromSymbol(derived); 42047 if (baseDeclarationFlags & ModifierFlags.Private || derivedDeclarationFlags & ModifierFlags.Private) { 42048 // either base or derived property is private - not override, skip it 42049 continue; 42050 } 42051 42052 let errorMessage: DiagnosticMessage; 42053 const basePropertyFlags = base.flags & SymbolFlags.PropertyOrAccessor; 42054 const derivedPropertyFlags = derived.flags & SymbolFlags.PropertyOrAccessor; 42055 if (basePropertyFlags && derivedPropertyFlags) { 42056 // property/accessor is overridden with property/accessor 42057 if ((getCheckFlags(base) & CheckFlags.Synthetic 42058 ? base.declarations?.some(d => isPropertyAbstractOrInterface(d, baseDeclarationFlags)) 42059 : base.declarations?.every(d => isPropertyAbstractOrInterface(d, baseDeclarationFlags))) 42060 || getCheckFlags(base) & CheckFlags.Mapped 42061 || derived.valueDeclaration && isBinaryExpression(derived.valueDeclaration)) { 42062 // when the base property is abstract or from an interface, base/derived flags don't need to match 42063 // for intersection properties, this must be true of *any* of the declarations, for others it must be true of *all* 42064 // same when the derived property is from an assignment 42065 continue; 42066 } 42067 42068 const overriddenInstanceProperty = basePropertyFlags !== SymbolFlags.Property && derivedPropertyFlags === SymbolFlags.Property; 42069 const overriddenInstanceAccessor = basePropertyFlags === SymbolFlags.Property && derivedPropertyFlags !== SymbolFlags.Property; 42070 if (overriddenInstanceProperty || overriddenInstanceAccessor) { 42071 const errorMessage = overriddenInstanceProperty ? 42072 Diagnostics._0_is_defined_as_an_accessor_in_class_1_but_is_overridden_here_in_2_as_an_instance_property : 42073 Diagnostics._0_is_defined_as_a_property_in_class_1_but_is_overridden_here_in_2_as_an_accessor; 42074 error(getNameOfDeclaration(derived.valueDeclaration) || derived.valueDeclaration, errorMessage, symbolToString(base), typeToString(baseType), typeToString(type)); 42075 } 42076 else if (useDefineForClassFields) { 42077 const uninitialized = derived.declarations?.find(d => d.kind === SyntaxKind.PropertyDeclaration && !(d as PropertyDeclaration).initializer); 42078 if (uninitialized 42079 && !(derived.flags & SymbolFlags.Transient) 42080 && !(baseDeclarationFlags & ModifierFlags.Abstract) 42081 && !(derivedDeclarationFlags & ModifierFlags.Abstract) 42082 && !derived.declarations?.some(d => !!(d.flags & NodeFlags.Ambient))) { 42083 const constructor = findConstructorDeclaration(getClassLikeDeclarationOfSymbol(type.symbol)!); 42084 const propName = (uninitialized as PropertyDeclaration).name; 42085 if ((uninitialized as PropertyDeclaration).exclamationToken 42086 || !constructor 42087 || !isIdentifier(propName) 42088 || !strictNullChecks 42089 || !isPropertyInitializedInConstructor(propName, type, constructor)) { 42090 const errorMessage = Diagnostics.Property_0_will_overwrite_the_base_property_in_1_If_this_is_intentional_add_an_initializer_Otherwise_add_a_declare_modifier_or_remove_the_redundant_declaration; 42091 error(getNameOfDeclaration(derived.valueDeclaration) || derived.valueDeclaration, errorMessage, symbolToString(base), typeToString(baseType)); 42092 } 42093 } 42094 } 42095 42096 // correct case 42097 continue; 42098 } 42099 else if (isPrototypeProperty(base)) { 42100 if (isPrototypeProperty(derived) || derived.flags & SymbolFlags.Property) { 42101 // method is overridden with method or property -- correct case 42102 continue; 42103 } 42104 else { 42105 Debug.assert(!!(derived.flags & SymbolFlags.Accessor)); 42106 errorMessage = Diagnostics.Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_accessor; 42107 } 42108 } 42109 else if (base.flags & SymbolFlags.Accessor) { 42110 errorMessage = Diagnostics.Class_0_defines_instance_member_accessor_1_but_extended_class_2_defines_it_as_instance_member_function; 42111 } 42112 else { 42113 errorMessage = Diagnostics.Class_0_defines_instance_member_property_1_but_extended_class_2_defines_it_as_instance_member_function; 42114 } 42115 42116 error(getNameOfDeclaration(derived.valueDeclaration) || derived.valueDeclaration, errorMessage, typeToString(baseType), symbolToString(base), typeToString(type)); 42117 } 42118 } 42119 } 42120 42121 function isPropertyAbstractOrInterface(declaration: Declaration, baseDeclarationFlags: ModifierFlags) { 42122 return baseDeclarationFlags & ModifierFlags.Abstract && (!isPropertyDeclaration(declaration) || !declaration.initializer) 42123 || isInterfaceDeclaration(declaration.parent); 42124 } 42125 42126 function getNonInheritedProperties(type: InterfaceType, baseTypes: BaseType[], properties: Symbol[]) { 42127 if (!length(baseTypes)) { 42128 return properties; 42129 } 42130 const seen = new Map<__String, Symbol>(); 42131 forEach(properties, p => { 42132 seen.set(p.escapedName, p); 42133 }); 42134 42135 for (const base of baseTypes) { 42136 const properties = getPropertiesOfType(getTypeWithThisArgument(base, type.thisType)); 42137 for (const prop of properties) { 42138 const existing = seen.get(prop.escapedName); 42139 if (existing && prop.parent === existing.parent) { 42140 seen.delete(prop.escapedName); 42141 } 42142 } 42143 } 42144 42145 return arrayFrom(seen.values()); 42146 } 42147 42148 function checkInheritedPropertiesAreIdentical(type: InterfaceType, typeNode: Node): boolean { 42149 const baseTypes = getBaseTypes(type); 42150 if (baseTypes.length < 2) { 42151 return true; 42152 } 42153 42154 interface InheritanceInfoMap { prop: Symbol; containingType: Type; } 42155 const seen = new Map<__String, InheritanceInfoMap>(); 42156 forEach(resolveDeclaredMembers(type).declaredProperties, p => { 42157 seen.set(p.escapedName, { prop: p, containingType: type }); 42158 }); 42159 let ok = true; 42160 42161 for (const base of baseTypes) { 42162 const properties = getPropertiesOfType(getTypeWithThisArgument(base, type.thisType)); 42163 for (const prop of properties) { 42164 const existing = seen.get(prop.escapedName); 42165 if (!existing) { 42166 seen.set(prop.escapedName, { prop, containingType: base }); 42167 } 42168 else { 42169 const isInheritedProperty = existing.containingType !== type; 42170 if (isInheritedProperty && !isPropertyIdenticalTo(existing.prop, prop)) { 42171 ok = false; 42172 42173 const typeName1 = typeToString(existing.containingType); 42174 const typeName2 = typeToString(base); 42175 42176 let errorInfo = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Named_property_0_of_types_1_and_2_are_not_identical, symbolToString(prop), typeName1, typeName2); 42177 errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Interface_0_cannot_simultaneously_extend_types_1_and_2, typeToString(type), typeName1, typeName2); 42178 diagnostics.add(createDiagnosticForNodeFromMessageChain(typeNode, errorInfo)); 42179 } 42180 } 42181 } 42182 } 42183 42184 return ok; 42185 } 42186 42187 function checkPropertyInitialization(node: ClassLikeDeclaration | AnnotationDeclaration) { 42188 if (!strictNullChecks || !strictPropertyInitialization || node.flags & NodeFlags.Ambient) { 42189 return; 42190 } 42191 const constructor = (!isAnnotationDeclaration(node)) ? findConstructorDeclaration(node) : undefined; 42192 for (const member of node.members) { 42193 if (getEffectiveModifierFlags(member) & ModifierFlags.Ambient) { 42194 continue; 42195 } 42196 if (!isStatic(member) && isPropertyWithoutInitializer(member)) { 42197 const propName = (member as PropertyDeclaration).name; 42198 if (isIdentifier(propName) || isPrivateIdentifier(propName) || isComputedPropertyName(propName)) { 42199 const type = getTypeOfSymbol(getSymbolOfNode(member)); 42200 if (!(type.flags & TypeFlags.AnyOrUnknown || containsUndefinedType(type))) { 42201 if (!constructor || !isPropertyInitializedInConstructor(propName, type, constructor)) { 42202 error(member.name, Diagnostics.Property_0_has_no_initializer_and_is_not_definitely_assigned_in_the_constructor, declarationNameToString(propName)); 42203 } 42204 } 42205 } 42206 } 42207 } 42208 } 42209 42210 function isPropertyWithoutInitializer(node: Node) { 42211 return node.kind === SyntaxKind.PropertyDeclaration && 42212 !hasAbstractModifier(node) && 42213 !(node as PropertyDeclaration).exclamationToken && 42214 !(node as PropertyDeclaration).initializer; 42215 } 42216 42217 function isPropertyInitializedInStaticBlocks(propName: Identifier | PrivateIdentifier, propType: Type, staticBlocks: readonly ClassStaticBlockDeclaration[], startPos: number, endPos: number) { 42218 for (const staticBlock of staticBlocks) { 42219 // static block must be within the provided range as they are evaluated in document order (unlike constructors) 42220 if (staticBlock.pos >= startPos && staticBlock.pos <= endPos) { 42221 const reference = factory.createPropertyAccessExpression(factory.createThis(), propName); 42222 setParent(reference.expression, reference); 42223 setParent(reference, staticBlock); 42224 reference.flowNode = staticBlock.returnFlowNode; 42225 const flowType = getFlowTypeOfReference(reference, propType, getOptionalType(propType)); 42226 if (!containsUndefinedType(flowType)) { 42227 return true; 42228 } 42229 } 42230 } 42231 return false; 42232 } 42233 42234 function isPropertyInitializedInConstructor(propName: Identifier | PrivateIdentifier | ComputedPropertyName, propType: Type, constructor: ConstructorDeclaration) { 42235 const reference = isComputedPropertyName(propName) 42236 ? factory.createElementAccessExpression(factory.createThis(), propName.expression) 42237 : factory.createPropertyAccessExpression(factory.createThis(), propName); 42238 setParent(reference.expression, reference); 42239 setParent(reference, constructor); 42240 reference.flowNode = constructor.returnFlowNode; 42241 const flowType = getFlowTypeOfReference(reference, propType, getOptionalType(propType)); 42242 return !containsUndefinedType(flowType); 42243 } 42244 42245 42246 function checkInterfaceDeclaration(node: InterfaceDeclaration) { 42247 // Grammar checking 42248 if (!checkGrammarDecoratorsAndModifiers(node)) checkGrammarInterfaceDeclaration(node); 42249 42250 checkTypeParameters(node.typeParameters); 42251 addLazyDiagnostic(() => { 42252 checkTypeNameIsReserved(node.name, Diagnostics.Interface_name_cannot_be_0); 42253 42254 checkExportsOnMergedDeclarations(node); 42255 const symbol = getSymbolOfNode(node); 42256 checkTypeParameterListsIdentical(symbol); 42257 42258 // Only check this symbol once 42259 const firstInterfaceDecl = getDeclarationOfKind<InterfaceDeclaration>(symbol, SyntaxKind.InterfaceDeclaration); 42260 if (node === firstInterfaceDecl) { 42261 const type = getDeclaredTypeOfSymbol(symbol) as InterfaceType; 42262 const typeWithThis = getTypeWithThisArgument(type); 42263 // run subsequent checks only if first set succeeded 42264 if (checkInheritedPropertiesAreIdentical(type, node.name)) { 42265 for (const baseType of getBaseTypes(type)) { 42266 checkTypeAssignableTo(typeWithThis, getTypeWithThisArgument(baseType, type.thisType), node.name, Diagnostics.Interface_0_incorrectly_extends_interface_1); 42267 } 42268 checkIndexConstraints(type, symbol); 42269 } 42270 } 42271 checkObjectTypeForDuplicateDeclarations(node); 42272 }); 42273 forEach(getInterfaceBaseTypeNodes(node), heritageElement => { 42274 if (!isEntityNameExpression(heritageElement.expression) || isOptionalChain(heritageElement.expression)) { 42275 error(heritageElement.expression, Diagnostics.An_interface_can_only_extend_an_identifier_Slashqualified_name_with_optional_type_arguments); 42276 } 42277 checkTypeReferenceNode(heritageElement); 42278 }); 42279 42280 forEach(node.members, checkSourceElement); 42281 42282 addLazyDiagnostic(() => { 42283 checkTypeForDuplicateIndexSignatures(node); 42284 registerForUnusedIdentifiersCheck(node); 42285 }); 42286 } 42287 42288 function checkTypeAliasDeclaration(node: TypeAliasDeclaration) { 42289 // Grammar checking 42290 checkGrammarDecoratorsAndModifiers(node); 42291 checkTypeNameIsReserved(node.name, Diagnostics.Type_alias_name_cannot_be_0); 42292 checkExportsOnMergedDeclarations(node); 42293 checkTypeParameters(node.typeParameters); 42294 if (node.type.kind === SyntaxKind.IntrinsicKeyword) { 42295 if (!intrinsicTypeKinds.has(node.name.escapedText as string) || length(node.typeParameters) !== 1) { 42296 error(node.type, Diagnostics.The_intrinsic_keyword_can_only_be_used_to_declare_compiler_provided_intrinsic_types); 42297 } 42298 } 42299 else { 42300 checkSourceElement(node.type); 42301 registerForUnusedIdentifiersCheck(node); 42302 } 42303 } 42304 42305 function computeEnumMemberValues(node: EnumDeclaration) { 42306 const nodeLinks = getNodeLinks(node); 42307 if (!(nodeLinks.flags & NodeCheckFlags.EnumValuesComputed)) { 42308 nodeLinks.flags |= NodeCheckFlags.EnumValuesComputed; 42309 let autoValue: number | undefined = 0; 42310 for (const member of node.members) { 42311 const value = computeMemberValue(member, autoValue); 42312 getNodeLinks(member).enumMemberValue = value; 42313 autoValue = typeof value === "number" ? value + 1 : undefined; 42314 } 42315 } 42316 } 42317 42318 function computeMemberValue(member: EnumMember, autoValue: number | undefined) { 42319 if (isComputedNonLiteralName(member.name)) { 42320 error(member.name, Diagnostics.Computed_property_names_are_not_allowed_in_enums); 42321 } 42322 else { 42323 const text = getTextOfPropertyName(member.name); 42324 if (isNumericLiteralName(text) && !isInfinityOrNaNString(text)) { 42325 error(member.name, Diagnostics.An_enum_member_cannot_have_a_numeric_name); 42326 } 42327 } 42328 if (member.initializer) { 42329 return computeConstantValue(member); 42330 } 42331 // In ambient non-const numeric enum declarations, enum members without initializers are 42332 // considered computed members (as opposed to having auto-incremented values). 42333 if (member.parent.flags & NodeFlags.Ambient && !isEnumConst(member.parent) && getEnumKind(getSymbolOfNode(member.parent)) === EnumKind.Numeric) { 42334 return undefined; 42335 } 42336 // If the member declaration specifies no value, the member is considered a constant enum member. 42337 // If the member is the first member in the enum declaration, it is assigned the value zero. 42338 // Otherwise, it is assigned the value of the immediately preceding member plus one, and an error 42339 // occurs if the immediately preceding member is not a constant enum member. 42340 if (autoValue !== undefined) { 42341 return autoValue; 42342 } 42343 error(member.name, Diagnostics.Enum_member_must_have_initializer); 42344 return undefined; 42345 } 42346 42347 function computeConstantValue(member: EnumMember): string | number | undefined { 42348 const enumKind = getEnumKind(getSymbolOfNode(member.parent)); 42349 const isConstEnum = isEnumConst(member.parent); 42350 const initializer = member.initializer!; 42351 const value = enumKind === EnumKind.Literal && !isLiteralEnumMember(member) ? undefined : evaluate(initializer); 42352 if (value !== undefined) { 42353 if (isConstEnum && typeof value === "number" && !isFinite(value)) { 42354 error(initializer, isNaN(value) ? 42355 Diagnostics.const_enum_member_initializer_was_evaluated_to_disallowed_value_NaN : 42356 Diagnostics.const_enum_member_initializer_was_evaluated_to_a_non_finite_value); 42357 } 42358 } 42359 else if (enumKind === EnumKind.Literal) { 42360 error(initializer, Diagnostics.Computed_values_are_not_permitted_in_an_enum_with_string_valued_members); 42361 return 0; 42362 } 42363 else if (isConstEnum) { 42364 error(initializer, Diagnostics.const_enum_member_initializers_can_only_contain_literal_values_and_other_computed_enum_values); 42365 } 42366 else if (member.parent.flags & NodeFlags.Ambient) { 42367 error(initializer, Diagnostics.In_ambient_enum_declarations_member_initializer_must_be_constant_expression); 42368 } 42369 else { 42370 // Only here do we need to check that the initializer is assignable to the enum type. 42371 const source = checkExpression(initializer); 42372 if (!isTypeAssignableToKind(source, TypeFlags.NumberLike)) { 42373 error(initializer, Diagnostics.Only_numeric_enums_can_have_computed_members_but_this_expression_has_type_0_If_you_do_not_need_exhaustiveness_checks_consider_using_an_object_literal_instead, typeToString(source)); 42374 } 42375 else { 42376 checkTypeAssignableTo(source, getDeclaredTypeOfSymbol(getSymbolOfNode(member.parent)), initializer, /*headMessage*/ undefined); 42377 } 42378 } 42379 return value; 42380 42381 function evaluate(expr: Expression): string | number | undefined { 42382 switch (expr.kind) { 42383 case SyntaxKind.PrefixUnaryExpression: 42384 const value = evaluate((expr as PrefixUnaryExpression).operand); 42385 if (typeof value === "number") { 42386 switch ((expr as PrefixUnaryExpression).operator) { 42387 case SyntaxKind.PlusToken: return value; 42388 case SyntaxKind.MinusToken: return -value; 42389 case SyntaxKind.TildeToken: return ~value; 42390 } 42391 } 42392 break; 42393 case SyntaxKind.BinaryExpression: 42394 const left = evaluate((expr as BinaryExpression).left); 42395 const right = evaluate((expr as BinaryExpression).right); 42396 if (typeof left === "number" && typeof right === "number") { 42397 switch ((expr as BinaryExpression).operatorToken.kind) { 42398 case SyntaxKind.BarToken: return left | right; 42399 case SyntaxKind.AmpersandToken: return left & right; 42400 case SyntaxKind.GreaterThanGreaterThanToken: return left >> right; 42401 case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: return left >>> right; 42402 case SyntaxKind.LessThanLessThanToken: return left << right; 42403 case SyntaxKind.CaretToken: return left ^ right; 42404 case SyntaxKind.AsteriskToken: return left * right; 42405 case SyntaxKind.SlashToken: return left / right; 42406 case SyntaxKind.PlusToken: return left + right; 42407 case SyntaxKind.MinusToken: return left - right; 42408 case SyntaxKind.PercentToken: return left % right; 42409 case SyntaxKind.AsteriskAsteriskToken: return left ** right; 42410 } 42411 } 42412 else if (typeof left === "string" && typeof right === "string" && (expr as BinaryExpression).operatorToken.kind === SyntaxKind.PlusToken) { 42413 return left + right; 42414 } 42415 break; 42416 case SyntaxKind.StringLiteral: 42417 case SyntaxKind.NoSubstitutionTemplateLiteral: 42418 return (expr as StringLiteralLike).text; 42419 case SyntaxKind.NumericLiteral: 42420 checkGrammarNumericLiteral(expr as NumericLiteral); 42421 return +(expr as NumericLiteral).text; 42422 case SyntaxKind.ParenthesizedExpression: 42423 return evaluate((expr as ParenthesizedExpression).expression); 42424 case SyntaxKind.Identifier: 42425 const identifier = expr as Identifier; 42426 if (isInfinityOrNaNString(identifier.escapedText)) { 42427 return +(identifier.escapedText); 42428 } 42429 return nodeIsMissing(expr) ? 0 : evaluateEnumMember(expr, getSymbolOfNode(member.parent), identifier.escapedText); 42430 case SyntaxKind.ElementAccessExpression: 42431 case SyntaxKind.PropertyAccessExpression: 42432 if (isConstantMemberAccess(expr)) { 42433 const type = getTypeOfExpression(expr.expression); 42434 if (type.symbol && type.symbol.flags & SymbolFlags.Enum) { 42435 let name: __String; 42436 if (expr.kind === SyntaxKind.PropertyAccessExpression) { 42437 name = expr.name.escapedText; 42438 } 42439 else { 42440 name = escapeLeadingUnderscores(cast(expr.argumentExpression, isLiteralExpression).text); 42441 } 42442 return evaluateEnumMember(expr, type.symbol, name); 42443 } 42444 } 42445 break; 42446 } 42447 return undefined; 42448 } 42449 42450 function evaluateEnumMember(expr: Expression, enumSymbol: Symbol, name: __String) { 42451 const memberSymbol = enumSymbol.exports!.get(name); 42452 if (memberSymbol) { 42453 const declaration = memberSymbol.valueDeclaration; 42454 if (declaration !== member) { 42455 if (declaration && isBlockScopedNameDeclaredBeforeUse(declaration, member) && isEnumDeclaration(declaration.parent)) { 42456 return getEnumMemberValue(declaration as EnumMember); 42457 } 42458 error(expr, Diagnostics.A_member_initializer_in_a_enum_declaration_cannot_reference_members_declared_after_it_including_members_defined_in_other_enums); 42459 return 0; 42460 } 42461 else { 42462 error(expr, Diagnostics.Property_0_is_used_before_being_assigned, symbolToString(memberSymbol)); 42463 } 42464 } 42465 return undefined; 42466 } 42467 } 42468 42469 function isConstantMemberAccess(node: Expression): node is AccessExpression { 42470 const type = getTypeOfExpression(node); 42471 if (type === errorType) { 42472 return false; 42473 } 42474 42475 return node.kind === SyntaxKind.Identifier || 42476 node.kind === SyntaxKind.PropertyAccessExpression && isConstantMemberAccess((node as PropertyAccessExpression).expression) || 42477 node.kind === SyntaxKind.ElementAccessExpression && isConstantMemberAccess((node as ElementAccessExpression).expression) && 42478 isStringLiteralLike((node as ElementAccessExpression).argumentExpression); 42479 } 42480 42481 function checkEnumDeclaration(node: EnumDeclaration) { 42482 addLazyDiagnostic(() => checkEnumDeclarationWorker(node)); 42483 } 42484 42485 function checkEnumDeclarationWorker(node: EnumDeclaration) { 42486 // Grammar checking 42487 checkGrammarDecoratorsAndModifiers(node); 42488 42489 checkCollisionsForDeclarationName(node, node.name); 42490 checkExportsOnMergedDeclarations(node); 42491 node.members.forEach(checkEnumMember); 42492 42493 computeEnumMemberValues(node); 42494 42495 // Spec 2014 - Section 9.3: 42496 // It isn't possible for one enum declaration to continue the automatic numbering sequence of another, 42497 // and when an enum type has multiple declarations, only one declaration is permitted to omit a value 42498 // for the first member. 42499 // 42500 // Only perform this check once per symbol 42501 const enumSymbol = getSymbolOfNode(node); 42502 const firstDeclaration = getDeclarationOfKind(enumSymbol, node.kind); 42503 if (node === firstDeclaration) { 42504 if (enumSymbol.declarations && enumSymbol.declarations.length > 1) { 42505 const enumIsConst = isEnumConst(node); 42506 // check that const is placed\omitted on all enum declarations 42507 forEach(enumSymbol.declarations, decl => { 42508 if (isEnumDeclaration(decl) && isEnumConst(decl) !== enumIsConst) { 42509 error(getNameOfDeclaration(decl), Diagnostics.Enum_declarations_must_all_be_const_or_non_const); 42510 } 42511 }); 42512 } 42513 42514 let seenEnumMissingInitialInitializer = false; 42515 forEach(enumSymbol.declarations, declaration => { 42516 // return true if we hit a violation of the rule, false otherwise 42517 if (declaration.kind !== SyntaxKind.EnumDeclaration) { 42518 return false; 42519 } 42520 42521 const enumDeclaration = declaration as EnumDeclaration; 42522 if (!enumDeclaration.members.length) { 42523 return false; 42524 } 42525 42526 const firstEnumMember = enumDeclaration.members[0]; 42527 if (!firstEnumMember.initializer) { 42528 if (seenEnumMissingInitialInitializer) { 42529 error(firstEnumMember.name, Diagnostics.In_an_enum_with_multiple_declarations_only_one_declaration_can_omit_an_initializer_for_its_first_enum_element); 42530 } 42531 else { 42532 seenEnumMissingInitialInitializer = true; 42533 } 42534 } 42535 }); 42536 } 42537 } 42538 42539 function checkEnumMember(node: EnumMember) { 42540 if (isPrivateIdentifier(node.name)) { 42541 error(node, Diagnostics.An_enum_member_cannot_be_named_with_a_private_identifier); 42542 } 42543 } 42544 42545 function getFirstNonAmbientClassOrFunctionDeclaration(symbol: Symbol): Declaration | undefined { 42546 const declarations = symbol.declarations; 42547 if (declarations) { 42548 for (const declaration of declarations) { 42549 if ((declaration.kind === SyntaxKind.ClassDeclaration || 42550 (declaration.kind === SyntaxKind.FunctionDeclaration && nodeIsPresent((declaration as FunctionLikeDeclaration).body))) && 42551 !(declaration.flags & NodeFlags.Ambient)) { 42552 return declaration; 42553 } 42554 } 42555 } 42556 return undefined; 42557 } 42558 42559 function inSameLexicalScope(node1: Node, node2: Node) { 42560 const container1 = getEnclosingBlockScopeContainer(node1); 42561 const container2 = getEnclosingBlockScopeContainer(node2); 42562 if (isGlobalSourceFile(container1)) { 42563 return isGlobalSourceFile(container2); 42564 } 42565 else if (isGlobalSourceFile(container2)) { 42566 return false; 42567 } 42568 else { 42569 return container1 === container2; 42570 } 42571 } 42572 42573 function checkModuleDeclaration(node: ModuleDeclaration) { 42574 if (node.body) { 42575 checkSourceElement(node.body); 42576 if (!isGlobalScopeAugmentation(node)) { 42577 registerForUnusedIdentifiersCheck(node); 42578 } 42579 } 42580 42581 addLazyDiagnostic(checkModuleDeclarationDiagnostics); 42582 42583 function checkModuleDeclarationDiagnostics() { 42584 // Grammar checking 42585 const isGlobalAugmentation = isGlobalScopeAugmentation(node); 42586 const inAmbientContext = node.flags & NodeFlags.Ambient; 42587 if (isGlobalAugmentation && !inAmbientContext) { 42588 error(node.name, Diagnostics.Augmentations_for_the_global_scope_should_have_declare_modifier_unless_they_appear_in_already_ambient_context); 42589 } 42590 42591 const isAmbientExternalModule: boolean = isAmbientModule(node); 42592 const contextErrorMessage = isAmbientExternalModule 42593 ? Diagnostics.An_ambient_module_declaration_is_only_allowed_at_the_top_level_in_a_file 42594 : Diagnostics.A_namespace_declaration_is_only_allowed_at_the_top_level_of_a_namespace_or_module; 42595 if (checkGrammarModuleElementContext(node, contextErrorMessage)) { 42596 // If we hit a module declaration in an illegal context, just bail out to avoid cascading errors. 42597 return; 42598 } 42599 42600 if (!checkGrammarDecoratorsAndModifiers(node)) { 42601 if (!inAmbientContext && node.name.kind === SyntaxKind.StringLiteral) { 42602 grammarErrorOnNode(node.name, Diagnostics.Only_ambient_modules_can_use_quoted_names); 42603 } 42604 } 42605 42606 if (isIdentifier(node.name)) { 42607 checkCollisionsForDeclarationName(node, node.name); 42608 } 42609 42610 checkExportsOnMergedDeclarations(node); 42611 const symbol = getSymbolOfNode(node); 42612 42613 // The following checks only apply on a non-ambient instantiated module declaration. 42614 if (symbol.flags & SymbolFlags.ValueModule 42615 && !inAmbientContext 42616 && symbol.declarations 42617 && symbol.declarations.length > 1 42618 && isInstantiatedModule(node, shouldPreserveConstEnums(compilerOptions))) { 42619 const firstNonAmbientClassOrFunc = getFirstNonAmbientClassOrFunctionDeclaration(symbol); 42620 if (firstNonAmbientClassOrFunc) { 42621 if (getSourceFileOfNode(node) !== getSourceFileOfNode(firstNonAmbientClassOrFunc)) { 42622 error(node.name, Diagnostics.A_namespace_declaration_cannot_be_in_a_different_file_from_a_class_or_function_with_which_it_is_merged); 42623 } 42624 else if (node.pos < firstNonAmbientClassOrFunc.pos) { 42625 error(node.name, Diagnostics.A_namespace_declaration_cannot_be_located_prior_to_a_class_or_function_with_which_it_is_merged); 42626 } 42627 } 42628 42629 // if the module merges with a class declaration in the same lexical scope, 42630 // we need to track this to ensure the correct emit. 42631 const mergedClass = getDeclarationOfKind(symbol, SyntaxKind.ClassDeclaration); 42632 if (mergedClass && 42633 inSameLexicalScope(node, mergedClass)) { 42634 getNodeLinks(node).flags |= NodeCheckFlags.LexicalModuleMergesWithClass; 42635 } 42636 } 42637 42638 if (isAmbientExternalModule) { 42639 if (isExternalModuleAugmentation(node)) { 42640 // body of the augmentation should be checked for consistency only if augmentation was applied to its target (either global scope or module) 42641 // otherwise we'll be swamped in cascading errors. 42642 // We can detect if augmentation was applied using following rules: 42643 // - augmentation for a global scope is always applied 42644 // - augmentation for some external module is applied if symbol for augmentation is merged (it was combined with target module). 42645 const checkBody = isGlobalAugmentation || (getSymbolOfNode(node).flags & SymbolFlags.Transient); 42646 if (checkBody && node.body) { 42647 for (const statement of node.body.statements) { 42648 checkModuleAugmentationElement(statement, isGlobalAugmentation); 42649 } 42650 } 42651 } 42652 else if (isGlobalSourceFile(node.parent)) { 42653 if (isGlobalAugmentation) { 42654 error(node.name, Diagnostics.Augmentations_for_the_global_scope_can_only_be_directly_nested_in_external_modules_or_ambient_module_declarations); 42655 } 42656 else if (isExternalModuleNameRelative(getTextOfIdentifierOrLiteral(node.name))) { 42657 error(node.name, Diagnostics.Ambient_module_declaration_cannot_specify_relative_module_name); 42658 } 42659 } 42660 else { 42661 if (isGlobalAugmentation) { 42662 error(node.name, Diagnostics.Augmentations_for_the_global_scope_can_only_be_directly_nested_in_external_modules_or_ambient_module_declarations); 42663 } 42664 else { 42665 // Node is not an augmentation and is not located on the script level. 42666 // This means that this is declaration of ambient module that is located in other module or namespace which is prohibited. 42667 error(node.name, Diagnostics.Ambient_modules_cannot_be_nested_in_other_modules_or_namespaces); 42668 } 42669 } 42670 } 42671 } 42672 } 42673 42674 function checkModuleAugmentationElement(node: Node, isGlobalAugmentation: boolean): void { 42675 switch (node.kind) { 42676 case SyntaxKind.VariableStatement: 42677 // error each individual name in variable statement instead of marking the entire variable statement 42678 for (const decl of (node as VariableStatement).declarationList.declarations) { 42679 checkModuleAugmentationElement(decl, isGlobalAugmentation); 42680 } 42681 break; 42682 case SyntaxKind.ExportAssignment: 42683 case SyntaxKind.ExportDeclaration: 42684 grammarErrorOnFirstToken(node, Diagnostics.Exports_and_export_assignments_are_not_permitted_in_module_augmentations); 42685 break; 42686 case SyntaxKind.ImportEqualsDeclaration: 42687 case SyntaxKind.ImportDeclaration: 42688 grammarErrorOnFirstToken(node, Diagnostics.Imports_are_not_permitted_in_module_augmentations_Consider_moving_them_to_the_enclosing_external_module); 42689 break; 42690 case SyntaxKind.BindingElement: 42691 case SyntaxKind.VariableDeclaration: 42692 const name = (node as VariableDeclaration | BindingElement).name; 42693 if (isBindingPattern(name)) { 42694 for (const el of name.elements) { 42695 // mark individual names in binding pattern 42696 checkModuleAugmentationElement(el, isGlobalAugmentation); 42697 } 42698 break; 42699 } 42700 // falls through 42701 case SyntaxKind.ClassDeclaration: 42702 case SyntaxKind.EnumDeclaration: 42703 case SyntaxKind.FunctionDeclaration: 42704 case SyntaxKind.InterfaceDeclaration: 42705 case SyntaxKind.ModuleDeclaration: 42706 case SyntaxKind.TypeAliasDeclaration: 42707 if (isGlobalAugmentation) { 42708 return; 42709 } 42710 break; 42711 } 42712 } 42713 42714 function getFirstNonModuleExportsIdentifier(node: EntityNameOrEntityNameExpression): Identifier { 42715 switch (node.kind) { 42716 case SyntaxKind.Identifier: 42717 return node; 42718 case SyntaxKind.QualifiedName: 42719 do { 42720 node = node.left; 42721 } while (node.kind !== SyntaxKind.Identifier); 42722 return node; 42723 case SyntaxKind.PropertyAccessExpression: 42724 do { 42725 if (isModuleExportsAccessExpression(node.expression) && !isPrivateIdentifier(node.name)) { 42726 return node.name; 42727 } 42728 node = node.expression; 42729 } while (node.kind !== SyntaxKind.Identifier); 42730 return node; 42731 } 42732 } 42733 42734 function checkExternalImportOrExportDeclaration(node: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration): boolean { 42735 const moduleName = getExternalModuleName(node); 42736 if (!moduleName || nodeIsMissing(moduleName)) { 42737 // Should be a parse error. 42738 return false; 42739 } 42740 if (!isStringLiteral(moduleName)) { 42741 error(moduleName, Diagnostics.String_literal_expected); 42742 return false; 42743 } 42744 const inAmbientExternalModule = node.parent.kind === SyntaxKind.ModuleBlock && isAmbientModule(node.parent.parent); 42745 if (node.parent.kind !== SyntaxKind.SourceFile && !inAmbientExternalModule) { 42746 error(moduleName, node.kind === SyntaxKind.ExportDeclaration ? 42747 Diagnostics.Export_declarations_are_not_permitted_in_a_namespace : 42748 Diagnostics.Import_declarations_in_a_namespace_cannot_reference_a_module); 42749 return false; 42750 } 42751 if (inAmbientExternalModule && isExternalModuleNameRelative(moduleName.text)) { 42752 // we have already reported errors on top level imports/exports in external module augmentations in checkModuleDeclaration 42753 // no need to do this again. 42754 if (!isTopLevelInExternalModuleAugmentation(node)) { 42755 // TypeScript 1.0 spec (April 2013): 12.1.6 42756 // An ExternalImportDeclaration in an AmbientExternalModuleDeclaration may reference 42757 // other external modules only through top - level external module names. 42758 // Relative external module names are not permitted. 42759 error(node, Diagnostics.Import_or_export_declaration_in_an_ambient_module_declaration_cannot_reference_module_through_relative_module_name); 42760 return false; 42761 } 42762 } 42763 if (!isImportEqualsDeclaration(node) && node.assertClause) { 42764 let hasError = false; 42765 for (const clause of node.assertClause.elements) { 42766 if (!isStringLiteral(clause.value)) { 42767 hasError = true; 42768 error(clause.value, Diagnostics.Import_assertion_values_must_be_string_literal_expressions); 42769 } 42770 } 42771 return !hasError; 42772 } 42773 return true; 42774 } 42775 42776 function checkAliasSymbol(node: ImportEqualsDeclaration | VariableDeclaration | ImportClause | NamespaceImport | ImportSpecifier | ExportSpecifier | NamespaceExport | BindingElement) { 42777 let symbol = getSymbolOfNode(node); 42778 const target = resolveAlias(symbol); 42779 42780 if (target !== unknownSymbol) { 42781 // For external modules, `symbol` represents the local symbol for an alias. 42782 // This local symbol will merge any other local declarations (excluding other aliases) 42783 // and symbol.flags will contains combined representation for all merged declaration. 42784 // Based on symbol.flags we can compute a set of excluded meanings (meaning that resolved alias should not have, 42785 // otherwise it will conflict with some local declaration). Note that in addition to normal flags we include matching SymbolFlags.Export* 42786 // in order to prevent collisions with declarations that were exported from the current module (they still contribute to local names). 42787 symbol = getMergedSymbol(symbol.exportSymbol || symbol); 42788 42789 // A type-only import/export will already have a grammar error in a JS file, so no need to issue more errors within 42790 if (isInJSFile(node) && !(target.flags & SymbolFlags.Value) && !isTypeOnlyImportOrExportDeclaration(node)) { 42791 const errorNode = 42792 isImportOrExportSpecifier(node) ? node.propertyName || node.name : 42793 isNamedDeclaration(node) ? node.name : 42794 node; 42795 42796 Debug.assert(node.kind !== SyntaxKind.NamespaceExport); 42797 if (node.kind === SyntaxKind.ExportSpecifier) { 42798 const diag = error(errorNode, Diagnostics.Types_cannot_appear_in_export_declarations_in_JavaScript_files); 42799 const alreadyExportedSymbol = getSourceFileOfNode(node).symbol?.exports?.get((node.propertyName || node.name).escapedText); 42800 if (alreadyExportedSymbol === target) { 42801 const exportingDeclaration = alreadyExportedSymbol.declarations?.find(isJSDocNode); 42802 if (exportingDeclaration) { 42803 addRelatedInfo(diag, createDiagnosticForNode( 42804 exportingDeclaration, 42805 Diagnostics._0_is_automatically_exported_here, 42806 unescapeLeadingUnderscores(alreadyExportedSymbol.escapedName))); 42807 } 42808 } 42809 } 42810 else { 42811 Debug.assert(node.kind !== SyntaxKind.VariableDeclaration); 42812 const importDeclaration = findAncestor(node, or(isImportDeclaration, isImportEqualsDeclaration)); 42813 const moduleSpecifier = (importDeclaration && tryGetModuleSpecifierFromDeclaration(importDeclaration)?.text) ?? "..."; 42814 const importedIdentifier = unescapeLeadingUnderscores(isIdentifier(errorNode) ? errorNode.escapedText : symbol.escapedName); 42815 error( 42816 errorNode, 42817 Diagnostics._0_is_a_type_and_cannot_be_imported_in_JavaScript_files_Use_1_in_a_JSDoc_type_annotation, 42818 importedIdentifier, 42819 `import("${moduleSpecifier}").${importedIdentifier}`); 42820 } 42821 return; 42822 } 42823 42824 const targetFlags = getAllSymbolFlags(target); 42825 const excludedMeanings = 42826 (symbol.flags & (SymbolFlags.Value | SymbolFlags.ExportValue) ? SymbolFlags.Value : 0) | 42827 (symbol.flags & SymbolFlags.Type ? SymbolFlags.Type : 0) | 42828 (symbol.flags & SymbolFlags.Namespace ? SymbolFlags.Namespace : 0); 42829 if (targetFlags & excludedMeanings) { 42830 const message = node.kind === SyntaxKind.ExportSpecifier ? 42831 Diagnostics.Export_declaration_conflicts_with_exported_declaration_of_0 : 42832 Diagnostics.Import_declaration_conflicts_with_local_declaration_of_0; 42833 error(node, message, symbolToString(symbol)); 42834 } 42835 42836 if (compilerOptions.isolatedModules 42837 && !isTypeOnlyImportOrExportDeclaration(node) 42838 && !(node.flags & NodeFlags.Ambient)) { 42839 const typeOnlyAlias = getTypeOnlyAliasDeclaration(symbol); 42840 const isType = !(targetFlags & SymbolFlags.Value); 42841 if (isType || typeOnlyAlias) { 42842 switch (node.kind) { 42843 case SyntaxKind.ImportClause: 42844 case SyntaxKind.ImportSpecifier: 42845 case SyntaxKind.ImportEqualsDeclaration: { 42846 if (compilerOptions.preserveValueImports) { 42847 Debug.assertIsDefined(node.name, "An ImportClause with a symbol should have a name"); 42848 const message = isType 42849 ? Diagnostics._0_is_a_type_and_must_be_imported_using_a_type_only_import_when_preserveValueImports_and_isolatedModules_are_both_enabled 42850 : Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_imported_using_a_type_only_import_when_preserveValueImports_and_isolatedModules_are_both_enabled; 42851 const name = idText(node.kind === SyntaxKind.ImportSpecifier ? node.propertyName || node.name : node.name); 42852 addTypeOnlyDeclarationRelatedInfo( 42853 error(node, message, name), 42854 isType ? undefined : typeOnlyAlias, 42855 name 42856 ); 42857 } 42858 if (isType && node.kind === SyntaxKind.ImportEqualsDeclaration && hasEffectiveModifier(node, ModifierFlags.Export)) { 42859 error(node, Diagnostics.Cannot_use_export_import_on_a_type_or_type_only_namespace_when_the_isolatedModules_flag_is_provided); 42860 } 42861 break; 42862 } 42863 case SyntaxKind.ExportSpecifier: { 42864 // Don't allow re-exporting an export that will be elided when `--isolatedModules` is set. 42865 // The exception is that `import type { A } from './a'; export { A }` is allowed 42866 // because single-file analysis can determine that the export should be dropped. 42867 if (getSourceFileOfNode(typeOnlyAlias) !== getSourceFileOfNode(node)) { 42868 const message = isType 42869 ? Diagnostics.Re_exporting_a_type_when_the_isolatedModules_flag_is_provided_requires_using_export_type 42870 : Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_re_exported_using_a_type_only_re_export_when_isolatedModules_is_enabled; 42871 const name = idText(node.propertyName || node.name); 42872 addTypeOnlyDeclarationRelatedInfo( 42873 error(node, message, name), 42874 isType ? undefined : typeOnlyAlias, 42875 name 42876 ); 42877 return; 42878 } 42879 } 42880 } 42881 } 42882 } 42883 42884 if (isImportSpecifier(node)) { 42885 const targetSymbol = checkDeprecatedAliasedSymbol(symbol, node); 42886 if (isDeprecatedAliasedSymbol(targetSymbol) && targetSymbol.declarations) { 42887 addDeprecatedSuggestion(node, targetSymbol.declarations, targetSymbol.escapedName as string); 42888 } 42889 } 42890 42891 if ((isImportSpecifier(node) || isExportSpecifier(node))) { 42892 if (targetFlags & SymbolFlags.Annotation) { 42893 getNodeLinks(node).exportOrImportRefersToAnnotation = true; 42894 if (node.propertyName) { 42895 error(node, Diagnostics.Annotation_cannot_be_renamed_in_import_or_export); 42896 } 42897 } 42898 } 42899 42900 if (!isVariableDeclaration(node) && !isBindingElement(node)) { 42901 if (targetFlags & SymbolFlags.ConstEnum) { 42902 checkConstEnumRelate(node, target); 42903 } 42904 } 42905 } 42906 } 42907 42908 function isDeprecatedAliasedSymbol(symbol: Symbol) { 42909 return !!symbol.declarations && every(symbol.declarations, d => !!(getCombinedNodeFlags(d) & NodeFlags.Deprecated)); 42910 } 42911 42912 function checkDeprecatedAliasedSymbol(symbol: Symbol, location: Node) { 42913 if (!(symbol.flags & SymbolFlags.Alias)) return symbol; 42914 42915 const targetSymbol = resolveAlias(symbol); 42916 if (targetSymbol === unknownSymbol) return targetSymbol; 42917 42918 while (symbol.flags & SymbolFlags.Alias) { 42919 const target = getImmediateAliasedSymbol(symbol); 42920 if (target) { 42921 if (target === targetSymbol) break; 42922 if (target.declarations && length(target.declarations)) { 42923 if (isDeprecatedAliasedSymbol(target)) { 42924 addDeprecatedSuggestion(location, target.declarations, target.escapedName as string); 42925 break; 42926 } 42927 else { 42928 if (symbol === targetSymbol) break; 42929 symbol = target; 42930 } 42931 } 42932 } 42933 else { 42934 break; 42935 } 42936 } 42937 return targetSymbol; 42938 } 42939 42940 function checkImportBinding(node: ImportEqualsDeclaration | ImportClause | NamespaceImport | ImportSpecifier) { 42941 checkCollisionsForDeclarationName(node, node.name); 42942 checkAliasSymbol(node); 42943 if (node.kind === SyntaxKind.ImportSpecifier && 42944 idText(node.propertyName || node.name) === "default" && 42945 getESModuleInterop(compilerOptions) && 42946 moduleKind !== ModuleKind.System && (moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS)) { 42947 checkExternalEmitHelpers(node, ExternalEmitHelpers.ImportDefault); 42948 } 42949 } 42950 42951 function checkAssertClause(declaration: ImportDeclaration | ExportDeclaration) { 42952 if (declaration.assertClause) { 42953 const validForTypeAssertions = isExclusivelyTypeOnlyImportOrExport(declaration); 42954 const override = getResolutionModeOverrideForClause(declaration.assertClause, validForTypeAssertions ? grammarErrorOnNode : undefined); 42955 if (validForTypeAssertions && override) { 42956 if (!isNightly()) { 42957 grammarErrorOnNode(declaration.assertClause, Diagnostics.resolution_mode_assertions_are_unstable_Use_nightly_TypeScript_to_silence_this_error_Try_updating_with_npm_install_D_typescript_next); 42958 } 42959 42960 if (getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Node16 && getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeNext) { 42961 return grammarErrorOnNode(declaration.assertClause, Diagnostics.resolution_mode_assertions_are_only_supported_when_moduleResolution_is_node16_or_nodenext); 42962 } 42963 return; // Other grammar checks do not apply to type-only imports with resolution mode assertions 42964 } 42965 42966 const mode = (moduleKind === ModuleKind.NodeNext) && declaration.moduleSpecifier && getUsageModeForExpression(declaration.moduleSpecifier); 42967 if (mode !== ModuleKind.ESNext && moduleKind !== ModuleKind.ESNext) { 42968 return grammarErrorOnNode(declaration.assertClause, 42969 moduleKind === ModuleKind.NodeNext 42970 ? Diagnostics.Import_assertions_are_not_allowed_on_statements_that_transpile_to_commonjs_require_calls 42971 : Diagnostics.Import_assertions_are_only_supported_when_the_module_option_is_set_to_esnext_or_nodenext); 42972 } 42973 42974 if (isImportDeclaration(declaration) ? declaration.importClause?.isTypeOnly : declaration.isTypeOnly) { 42975 return grammarErrorOnNode(declaration.assertClause, Diagnostics.Import_assertions_cannot_be_used_with_type_only_imports_or_exports); 42976 } 42977 42978 if (override) { 42979 return grammarErrorOnNode(declaration.assertClause, Diagnostics.resolution_mode_can_only_be_set_for_type_only_imports); 42980 } 42981 } 42982 } 42983 42984 function checkImportDeclaration(node: ImportDeclaration) { 42985 if (checkGrammarModuleElementContext(node, isInJSFile(node) ? Diagnostics.An_import_declaration_can_only_be_used_at_the_top_level_of_a_module : Diagnostics.An_import_declaration_can_only_be_used_at_the_top_level_of_a_namespace_or_module)) { 42986 // If we hit an import declaration in an illegal context, just bail out to avoid cascading errors. 42987 return; 42988 } 42989 if (!checkGrammarDecoratorsAndModifiers(node) && hasEffectiveModifiers(node)) { 42990 grammarErrorOnFirstToken(node, Diagnostics.An_import_declaration_cannot_have_modifiers); 42991 } 42992 if (checkExternalImportOrExportDeclaration(node)) { 42993 const importClause = node.importClause; 42994 if (importClause && !checkGrammarImportClause(importClause)) { 42995 if (importClause.name) { 42996 checkImportBinding(importClause); 42997 } 42998 if (importClause.namedBindings) { 42999 if (importClause.namedBindings.kind === SyntaxKind.NamespaceImport) { 43000 checkImportBinding(importClause.namedBindings); 43001 if (moduleKind !== ModuleKind.System && (moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) && getESModuleInterop(compilerOptions)) { 43002 // import * as ns from "foo"; 43003 checkExternalEmitHelpers(node, ExternalEmitHelpers.ImportStar); 43004 } 43005 } 43006 else { 43007 const moduleExisted = resolveExternalModuleName(node, node.moduleSpecifier); 43008 if (moduleExisted) { 43009 forEach(importClause.namedBindings.elements, checkImportBinding); 43010 } 43011 } 43012 } 43013 } 43014 } 43015 checkAssertClause(node); 43016 } 43017 43018 function checkImportEqualsDeclaration(node: ImportEqualsDeclaration) { 43019 if (checkGrammarModuleElementContext(node, isInJSFile(node) ? Diagnostics.An_import_declaration_can_only_be_used_at_the_top_level_of_a_module : Diagnostics.An_import_declaration_can_only_be_used_at_the_top_level_of_a_namespace_or_module)) { 43020 // If we hit an import declaration in an illegal context, just bail out to avoid cascading errors. 43021 return; 43022 } 43023 43024 checkGrammarDecoratorsAndModifiers(node); 43025 if (isInternalModuleImportEqualsDeclaration(node) || checkExternalImportOrExportDeclaration(node)) { 43026 checkImportBinding(node); 43027 if (hasSyntacticModifier(node, ModifierFlags.Export)) { 43028 markExportAsReferenced(node); 43029 } 43030 if (node.moduleReference.kind !== SyntaxKind.ExternalModuleReference) { 43031 const target = resolveAlias(getSymbolOfNode(node)); 43032 if (target !== unknownSymbol) { 43033 const targetFlags = getAllSymbolFlags(target); 43034 if (targetFlags & SymbolFlags.Value) { 43035 // Target is a value symbol, check that it is not hidden by a local declaration with the same name 43036 const moduleName = getFirstIdentifier(node.moduleReference); 43037 if (!(resolveEntityName(moduleName, SymbolFlags.Value | SymbolFlags.Namespace)!.flags & SymbolFlags.Namespace)) { 43038 error(moduleName, Diagnostics.Module_0_is_hidden_by_a_local_declaration_with_the_same_name, declarationNameToString(moduleName)); 43039 } 43040 } 43041 if (targetFlags & SymbolFlags.Type) { 43042 checkTypeNameIsReserved(node.name, Diagnostics.Import_name_cannot_be_0); 43043 } 43044 } 43045 if (node.isTypeOnly) { 43046 grammarErrorOnNode(node, Diagnostics.An_import_alias_cannot_use_import_type); 43047 } 43048 } 43049 else { 43050 if (moduleKind >= ModuleKind.ES2015 && getSourceFileOfNode(node).impliedNodeFormat === undefined && !node.isTypeOnly && !(node.flags & NodeFlags.Ambient)) { 43051 // Import equals declaration is deprecated in es6 or above 43052 grammarErrorOnNode(node, Diagnostics.Import_assignment_cannot_be_used_when_targeting_ECMAScript_modules_Consider_using_import_Asterisk_as_ns_from_mod_import_a_from_mod_import_d_from_mod_or_another_module_format_instead); 43053 } 43054 } 43055 } 43056 } 43057 43058 function checkExportDeclaration(node: ExportDeclaration) { 43059 if (checkGrammarModuleElementContext(node, isInJSFile(node) ? Diagnostics.An_export_declaration_can_only_be_used_at_the_top_level_of_a_module : Diagnostics.An_export_declaration_can_only_be_used_at_the_top_level_of_a_namespace_or_module)) { 43060 // If we hit an export in an illegal context, just bail out to avoid cascading errors. 43061 return; 43062 } 43063 43064 if (!checkGrammarDecoratorsAndModifiers(node) && hasSyntacticModifiers(node)) { 43065 grammarErrorOnFirstToken(node, Diagnostics.An_export_declaration_cannot_have_modifiers); 43066 } 43067 43068 if (node.moduleSpecifier && node.exportClause && isNamedExports(node.exportClause) && length(node.exportClause.elements) && languageVersion === ScriptTarget.ES3) { 43069 checkExternalEmitHelpers(node, ExternalEmitHelpers.CreateBinding); 43070 } 43071 43072 checkGrammarExportDeclaration(node); 43073 if (!node.moduleSpecifier || checkExternalImportOrExportDeclaration(node)) { 43074 if (node.exportClause && !isNamespaceExport(node.exportClause)) { 43075 // export { x, y } 43076 // export { x, y } from "foo" 43077 forEach(node.exportClause.elements, checkExportSpecifier); 43078 const inAmbientExternalModule = node.parent.kind === SyntaxKind.ModuleBlock && isAmbientModule(node.parent.parent); 43079 const inAmbientNamespaceDeclaration = !inAmbientExternalModule && node.parent.kind === SyntaxKind.ModuleBlock && 43080 !node.moduleSpecifier && node.flags & NodeFlags.Ambient; 43081 if (node.parent.kind !== SyntaxKind.SourceFile && !inAmbientExternalModule && !inAmbientNamespaceDeclaration) { 43082 error(node, Diagnostics.Export_declarations_are_not_permitted_in_a_namespace); 43083 } 43084 } 43085 else { 43086 // export * from "foo" 43087 // export * as ns from "foo"; 43088 const moduleSymbol = resolveExternalModuleName(node, node.moduleSpecifier!); 43089 if (moduleSymbol && hasExportAssignmentSymbol(moduleSymbol)) { 43090 error(node.moduleSpecifier, Diagnostics.Module_0_uses_export_and_cannot_be_used_with_export_Asterisk, symbolToString(moduleSymbol)); 43091 } 43092 else if (node.exportClause) { 43093 checkAliasSymbol(node.exportClause); 43094 } 43095 if (moduleKind !== ModuleKind.System && (moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS)) { 43096 if (node.exportClause) { 43097 // export * as ns from "foo"; 43098 // For ES2015 modules, we emit it as a pair of `import * as a_1 ...; export { a_1 as ns }` and don't need the helper. 43099 // We only use the helper here when in esModuleInterop 43100 if (getESModuleInterop(compilerOptions)) { 43101 checkExternalEmitHelpers(node, ExternalEmitHelpers.ImportStar); 43102 } 43103 } 43104 else { 43105 // export * from "foo" 43106 checkExternalEmitHelpers(node, ExternalEmitHelpers.ExportStar); 43107 } 43108 } 43109 } 43110 } 43111 checkAssertClause(node); 43112 } 43113 43114 function checkGrammarExportDeclaration(node: ExportDeclaration): boolean { 43115 if (node.isTypeOnly) { 43116 if (node.exportClause?.kind === SyntaxKind.NamedExports) { 43117 return checkGrammarNamedImportsOrExports(node.exportClause); 43118 } 43119 else { 43120 return grammarErrorOnNode(node, Diagnostics.Only_named_exports_may_use_export_type); 43121 } 43122 } 43123 return false; 43124 } 43125 43126 function checkGrammarModuleElementContext(node: Statement, errorMessage: DiagnosticMessage): boolean { 43127 const isInAppropriateContext = node.parent.kind === SyntaxKind.SourceFile || node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.ModuleDeclaration; 43128 if (!isInAppropriateContext) { 43129 grammarErrorOnFirstToken(node, errorMessage); 43130 } 43131 return !isInAppropriateContext; 43132 } 43133 43134 function importClauseContainsReferencedImport(importClause: ImportClause) { 43135 return forEachImportClauseDeclaration(importClause, declaration => { 43136 return !!getSymbolOfNode(declaration).isReferenced; 43137 }); 43138 } 43139 43140 function importClauseContainsConstEnumUsedAsValue(importClause: ImportClause) { 43141 return forEachImportClauseDeclaration(importClause, declaration => { 43142 return !!getSymbolLinks(getSymbolOfNode(declaration)).constEnumReferenced; 43143 }); 43144 } 43145 43146 function canConvertImportDeclarationToTypeOnly(statement: Statement) { 43147 return isImportDeclaration(statement) && 43148 statement.importClause && 43149 !statement.importClause.isTypeOnly && 43150 importClauseContainsReferencedImport(statement.importClause) && 43151 !isReferencedAliasDeclaration(statement.importClause, /*checkChildren*/ true) && 43152 !importClauseContainsConstEnumUsedAsValue(statement.importClause); 43153 } 43154 43155 function canConvertImportEqualsDeclarationToTypeOnly(statement: Statement) { 43156 return isImportEqualsDeclaration(statement) && 43157 isExternalModuleReference(statement.moduleReference) && 43158 !statement.isTypeOnly && 43159 getSymbolOfNode(statement).isReferenced && 43160 !isReferencedAliasDeclaration(statement, /*checkChildren*/ false) && 43161 !getSymbolLinks(getSymbolOfNode(statement)).constEnumReferenced; 43162 } 43163 43164 function checkImportsForTypeOnlyConversion(sourceFile: SourceFile) { 43165 for (const statement of sourceFile.statements) { 43166 if (canConvertImportDeclarationToTypeOnly(statement) || canConvertImportEqualsDeclarationToTypeOnly(statement)) { 43167 error( 43168 statement, 43169 Diagnostics.This_import_is_never_used_as_a_value_and_must_use_import_type_because_importsNotUsedAsValues_is_set_to_error); 43170 } 43171 } 43172 } 43173 43174 function checkExportSpecifier(node: ExportSpecifier) { 43175 checkAliasSymbol(node); 43176 if (getEmitDeclarations(compilerOptions)) { 43177 collectLinkedAliases(node.propertyName || node.name, /*setVisibility*/ true); 43178 } 43179 if (!node.parent.parent.moduleSpecifier) { 43180 const exportedName = node.propertyName || node.name; 43181 // find immediate value referenced by exported name (SymbolFlags.Alias is set so we don't chase down aliases) 43182 const symbol = resolveName(exportedName, exportedName.escapedText, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, 43183 /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ true); 43184 if (symbol && (symbol === undefinedSymbol || symbol === globalThisSymbol || symbol.declarations && isGlobalSourceFile(getDeclarationContainer(symbol.declarations[0])))) { 43185 error(exportedName, Diagnostics.Cannot_export_0_Only_local_declarations_can_be_exported_from_a_module, idText(exportedName)); 43186 } 43187 else { 43188 if (!node.isTypeOnly && !node.parent.parent.isTypeOnly) { 43189 markExportAsReferenced(node); 43190 } 43191 const target = symbol && (symbol.flags & SymbolFlags.Alias ? resolveAlias(symbol) : symbol); 43192 if (!target || getAllSymbolFlags(target) & SymbolFlags.Value) { 43193 checkExpressionCached(node.propertyName || node.name); 43194 } 43195 } 43196 } 43197 else { 43198 if (getESModuleInterop(compilerOptions) && 43199 moduleKind !== ModuleKind.System && 43200 (moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) && 43201 idText(node.propertyName || node.name) === "default") { 43202 checkExternalEmitHelpers(node, ExternalEmitHelpers.ImportDefault); 43203 } 43204 } 43205 } 43206 43207 function checkAnnotationInExportAssignment(node: ExportAssignment) { 43208 let ident; 43209 switch (node.expression.kind) { 43210 case SyntaxKind.Identifier: 43211 ident = node.expression as Identifier; 43212 break; 43213 case SyntaxKind.PropertyAccessExpression: 43214 ident = node.expression as PropertyAccessExpression; 43215 break; 43216 default: 43217 return; 43218 } 43219 if (!ident) { 43220 return; 43221 } 43222 const symbol = getSymbolOfNameOrPropertyAccessExpression(ident, /*ignoreErrors*/ true); 43223 if (!symbol) { 43224 return; 43225 } 43226 if (getAllSymbolFlags(symbol) & SymbolFlags.Annotation) { 43227 getNodeLinks(node).exportOrImportRefersToAnnotation = true; 43228 if (node.isExportEquals === undefined) { 43229 error(node, Diagnostics.Annotation_cannot_be_exported_as_default); 43230 } 43231 } 43232 } 43233 43234 function checkExportAssignment(node: ExportAssignment) { 43235 const illegalContextMessage = node.isExportEquals 43236 ? Diagnostics.An_export_assignment_must_be_at_the_top_level_of_a_file_or_module_declaration 43237 : Diagnostics.A_default_export_must_be_at_the_top_level_of_a_file_or_module_declaration; 43238 if (checkGrammarModuleElementContext(node, illegalContextMessage)) { 43239 // If we hit an export assignment in an illegal context, just bail out to avoid cascading errors. 43240 return; 43241 } 43242 43243 const container = node.parent.kind === SyntaxKind.SourceFile ? node.parent : node.parent.parent as ModuleDeclaration; 43244 if (container.kind === SyntaxKind.ModuleDeclaration && !isAmbientModule(container)) { 43245 if (node.isExportEquals) { 43246 error(node, Diagnostics.An_export_assignment_cannot_be_used_in_a_namespace); 43247 } 43248 else { 43249 error(node, Diagnostics.A_default_export_can_only_be_used_in_an_ECMAScript_style_module); 43250 } 43251 43252 return; 43253 } 43254 // Grammar checking 43255 if (!checkGrammarDecoratorsAndModifiers(node) && hasEffectiveModifiers(node)) { 43256 grammarErrorOnFirstToken(node, Diagnostics.An_export_assignment_cannot_have_modifiers); 43257 } 43258 43259 const typeAnnotationNode = getEffectiveTypeAnnotationNode(node); 43260 if (typeAnnotationNode) { 43261 checkTypeAssignableTo(checkExpressionCached(node.expression), getTypeFromTypeNode(typeAnnotationNode), node.expression); 43262 } 43263 43264 if (node.expression.kind === SyntaxKind.Identifier) { 43265 const id = node.expression as Identifier; 43266 const sym = resolveEntityName(id, SymbolFlags.All, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, node); 43267 if (sym) { 43268 markAliasReferenced(sym, id); 43269 // If not a value, we're interpreting the identifier as a type export, along the lines of (`export { Id as default }`) 43270 const target = sym.flags & SymbolFlags.Alias ? resolveAlias(sym) : sym; 43271 if (getAllSymbolFlags(target) & SymbolFlags.Value) { 43272 // However if it is a value, we need to check it's being used correctly 43273 checkExpressionCached(node.expression); 43274 } 43275 } 43276 else { 43277 checkExpressionCached(node.expression); // doesn't resolve, check as expression to mark as error 43278 } 43279 43280 if (getEmitDeclarations(compilerOptions)) { 43281 collectLinkedAliases(node.expression as Identifier, /*setVisibility*/ true); 43282 } 43283 } 43284 else { 43285 checkExpressionCached(node.expression); 43286 } 43287 43288 checkAnnotationInExportAssignment(node); 43289 43290 checkExternalModuleExports(container); 43291 43292 if ((node.flags & NodeFlags.Ambient) && !isEntityNameExpression(node.expression)) { 43293 grammarErrorOnNode(node.expression, Diagnostics.The_expression_of_an_export_assignment_must_be_an_identifier_or_qualified_name_in_an_ambient_context); 43294 } 43295 43296 if (node.isExportEquals && !(node.flags & NodeFlags.Ambient)) { 43297 if (moduleKind >= ModuleKind.ES2015 && getSourceFileOfNode(node).impliedNodeFormat !== ModuleKind.CommonJS) { 43298 // export assignment is not supported in es6 modules 43299 grammarErrorOnNode(node, Diagnostics.Export_assignment_cannot_be_used_when_targeting_ECMAScript_modules_Consider_using_export_default_or_another_module_format_instead); 43300 } 43301 else if (moduleKind === ModuleKind.System) { 43302 // system modules does not support export assignment 43303 grammarErrorOnNode(node, Diagnostics.Export_assignment_is_not_supported_when_module_flag_is_system); 43304 } 43305 } 43306 } 43307 43308 function hasExportedMembers(moduleSymbol: Symbol) { 43309 return forEachEntry(moduleSymbol.exports!, (_, id) => id !== "export="); 43310 } 43311 43312 function checkExternalModuleExports(node: SourceFile | ModuleDeclaration) { 43313 const moduleSymbol = getSymbolOfNode(node); 43314 const links = getSymbolLinks(moduleSymbol); 43315 if (!links.exportsChecked) { 43316 const exportEqualsSymbol = moduleSymbol.exports!.get("export=" as __String); 43317 if (exportEqualsSymbol && hasExportedMembers(moduleSymbol)) { 43318 const declaration = getDeclarationOfAliasSymbol(exportEqualsSymbol) || exportEqualsSymbol.valueDeclaration; 43319 if (declaration && !isTopLevelInExternalModuleAugmentation(declaration) && !isInJSFile(declaration)) { 43320 error(declaration, Diagnostics.An_export_assignment_cannot_be_used_in_a_module_with_other_exported_elements); 43321 } 43322 } 43323 // Checks for export * conflicts 43324 const exports = getExportsOfModule(moduleSymbol); 43325 if (exports) { 43326 exports.forEach(({ declarations, flags }, id) => { 43327 if (id === "__export") { 43328 return; 43329 } 43330 // ECMA262: 15.2.1.1 It is a Syntax Error if the ExportedNames of ModuleItemList contains any duplicate entries. 43331 // (TS Exceptions: namespaces, function overloads, enums, and interfaces) 43332 if (flags & (SymbolFlags.Namespace | SymbolFlags.Enum)) { 43333 return; 43334 } 43335 const exportedDeclarationsCount = countWhere(declarations, and(isNotOverloadAndNotAccessor, not(isInterfaceDeclaration))); 43336 if (flags & SymbolFlags.TypeAlias && exportedDeclarationsCount <= 2) { 43337 // it is legal to merge type alias with other values 43338 // so count should be either 1 (just type alias) or 2 (type alias + merged value) 43339 return; 43340 } 43341 if (exportedDeclarationsCount > 1) { 43342 if (!isDuplicatedCommonJSExport(declarations)) { 43343 for (const declaration of declarations!) { 43344 if (isNotOverload(declaration)) { 43345 diagnostics.add(createDiagnosticForNode(declaration, Diagnostics.Cannot_redeclare_exported_variable_0, unescapeLeadingUnderscores(id))); 43346 } 43347 } 43348 } 43349 } 43350 }); 43351 } 43352 links.exportsChecked = true; 43353 } 43354 } 43355 43356 function isDuplicatedCommonJSExport(declarations: Declaration[] | undefined) { 43357 return declarations 43358 && declarations.length > 1 43359 && declarations.every(d => isInJSFile(d) && isAccessExpression(d) && (isExportsIdentifier(d.expression) || isModuleExportsAccessExpression(d.expression))); 43360 } 43361 43362 function checkSourceElement(node: Node | undefined): void { 43363 if (node) { 43364 const saveCurrentNode = currentNode; 43365 currentNode = node; 43366 instantiationCount = 0; 43367 checkSourceElementWorker(node); 43368 currentNode = saveCurrentNode; 43369 } 43370 } 43371 43372 function checkSourceElementWorker(node: Node): void { 43373 forEach((node as JSDocContainer).jsDoc, ({ comment, tags }) => { 43374 checkJSDocCommentWorker(comment); 43375 forEach(tags, tag => { 43376 checkJSDocCommentWorker(tag.comment); 43377 if (isInJSFile(node)) { 43378 checkSourceElement(tag); 43379 } 43380 }); 43381 }); 43382 43383 const kind = node.kind; 43384 if (cancellationToken) { 43385 // Only bother checking on a few construct kinds. We don't want to be excessively 43386 // hitting the cancellation token on every node we check. 43387 switch (kind) { 43388 case SyntaxKind.ModuleDeclaration: 43389 case SyntaxKind.ClassDeclaration: 43390 case SyntaxKind.InterfaceDeclaration: 43391 case SyntaxKind.FunctionDeclaration: 43392 cancellationToken.throwIfCancellationRequested(); 43393 } 43394 } 43395 if (kind >= SyntaxKind.FirstStatement && kind <= SyntaxKind.LastStatement && node.flowNode && !isReachableFlowNode(node.flowNode)) { 43396 errorOrSuggestion(compilerOptions.allowUnreachableCode === false, node, Diagnostics.Unreachable_code_detected); 43397 } 43398 43399 switch (kind) { 43400 case SyntaxKind.TypeParameter: 43401 return checkTypeParameter(node as TypeParameterDeclaration); 43402 case SyntaxKind.Parameter: 43403 return checkParameter(node as ParameterDeclaration); 43404 case SyntaxKind.PropertyDeclaration: 43405 return checkPropertyDeclaration(node as PropertyDeclaration); 43406 case SyntaxKind.PropertySignature: 43407 return checkPropertySignature(node as PropertySignature); 43408 case SyntaxKind.AnnotationPropertyDeclaration: 43409 return checkPropertyDeclaration(node as AnnotationPropertyDeclaration); 43410 case SyntaxKind.ConstructorType: 43411 case SyntaxKind.FunctionType: 43412 case SyntaxKind.CallSignature: 43413 case SyntaxKind.ConstructSignature: 43414 case SyntaxKind.IndexSignature: 43415 return checkSignatureDeclaration(node as SignatureDeclaration); 43416 case SyntaxKind.MethodDeclaration: 43417 case SyntaxKind.MethodSignature: 43418 return checkMethodDeclaration(node as MethodDeclaration | MethodSignature); 43419 case SyntaxKind.ClassStaticBlockDeclaration: 43420 return checkClassStaticBlockDeclaration(node as ClassStaticBlockDeclaration); 43421 case SyntaxKind.Constructor: 43422 return checkConstructorDeclaration(node as ConstructorDeclaration); 43423 case SyntaxKind.GetAccessor: 43424 case SyntaxKind.SetAccessor: 43425 return checkAccessorDeclaration(node as AccessorDeclaration); 43426 case SyntaxKind.TypeReference: 43427 return checkTypeReferenceNode(node as TypeReferenceNode); 43428 case SyntaxKind.TypePredicate: 43429 return checkTypePredicate(node as TypePredicateNode); 43430 case SyntaxKind.TypeQuery: 43431 return checkTypeQuery(node as TypeQueryNode); 43432 case SyntaxKind.TypeLiteral: 43433 return checkTypeLiteral(node as TypeLiteralNode); 43434 case SyntaxKind.ArrayType: 43435 return checkArrayType(node as ArrayTypeNode); 43436 case SyntaxKind.TupleType: 43437 return checkTupleType(node as TupleTypeNode); 43438 case SyntaxKind.UnionType: 43439 case SyntaxKind.IntersectionType: 43440 return checkUnionOrIntersectionType(node as UnionOrIntersectionTypeNode); 43441 case SyntaxKind.ParenthesizedType: 43442 case SyntaxKind.OptionalType: 43443 case SyntaxKind.RestType: 43444 return checkSourceElement((node as ParenthesizedTypeNode | OptionalTypeNode | RestTypeNode).type); 43445 case SyntaxKind.ThisType: 43446 return checkThisType(node as ThisTypeNode); 43447 case SyntaxKind.TypeOperator: 43448 return checkTypeOperator(node as TypeOperatorNode); 43449 case SyntaxKind.ConditionalType: 43450 return checkConditionalType(node as ConditionalTypeNode); 43451 case SyntaxKind.InferType: 43452 return checkInferType(node as InferTypeNode); 43453 case SyntaxKind.TemplateLiteralType: 43454 return checkTemplateLiteralType(node as TemplateLiteralTypeNode); 43455 case SyntaxKind.ImportType: 43456 return checkImportType(node as ImportTypeNode); 43457 case SyntaxKind.NamedTupleMember: 43458 return checkNamedTupleMember(node as NamedTupleMember); 43459 case SyntaxKind.JSDocAugmentsTag: 43460 return checkJSDocAugmentsTag(node as JSDocAugmentsTag); 43461 case SyntaxKind.JSDocImplementsTag: 43462 return checkJSDocImplementsTag(node as JSDocImplementsTag); 43463 case SyntaxKind.JSDocTypedefTag: 43464 case SyntaxKind.JSDocCallbackTag: 43465 case SyntaxKind.JSDocEnumTag: 43466 return checkJSDocTypeAliasTag(node as JSDocTypedefTag); 43467 case SyntaxKind.JSDocTemplateTag: 43468 return checkJSDocTemplateTag(node as JSDocTemplateTag); 43469 case SyntaxKind.JSDocTypeTag: 43470 return checkJSDocTypeTag(node as JSDocTypeTag); 43471 case SyntaxKind.JSDocLink: 43472 case SyntaxKind.JSDocLinkCode: 43473 case SyntaxKind.JSDocLinkPlain: 43474 return checkJSDocLinkLikeTag(node as JSDocLink | JSDocLinkCode | JSDocLinkPlain); 43475 case SyntaxKind.JSDocParameterTag: 43476 return checkJSDocParameterTag(node as JSDocParameterTag); 43477 case SyntaxKind.JSDocPropertyTag: 43478 return checkJSDocPropertyTag(node as JSDocPropertyTag); 43479 case SyntaxKind.JSDocFunctionType: 43480 checkJSDocFunctionType(node as JSDocFunctionType); 43481 // falls through 43482 case SyntaxKind.JSDocNonNullableType: 43483 case SyntaxKind.JSDocNullableType: 43484 case SyntaxKind.JSDocAllType: 43485 case SyntaxKind.JSDocUnknownType: 43486 case SyntaxKind.JSDocTypeLiteral: 43487 checkJSDocTypeIsInJsFile(node); 43488 forEachChild(node, checkSourceElement); 43489 return; 43490 case SyntaxKind.JSDocVariadicType: 43491 checkJSDocVariadicType(node as JSDocVariadicType); 43492 return; 43493 case SyntaxKind.JSDocTypeExpression: 43494 return checkSourceElement((node as JSDocTypeExpression).type); 43495 case SyntaxKind.JSDocPublicTag: 43496 case SyntaxKind.JSDocProtectedTag: 43497 case SyntaxKind.JSDocPrivateTag: 43498 return checkJSDocAccessibilityModifiers(node as JSDocPublicTag | JSDocProtectedTag | JSDocPrivateTag); 43499 case SyntaxKind.IndexedAccessType: 43500 return checkIndexedAccessType(node as IndexedAccessTypeNode); 43501 case SyntaxKind.MappedType: 43502 return checkMappedType(node as MappedTypeNode); 43503 case SyntaxKind.FunctionDeclaration: 43504 return checkFunctionDeclaration(node as FunctionDeclaration); 43505 case SyntaxKind.Block: 43506 case SyntaxKind.ModuleBlock: 43507 return checkBlock(node as Block); 43508 case SyntaxKind.VariableStatement: 43509 return checkVariableStatement(node as VariableStatement); 43510 case SyntaxKind.ExpressionStatement: 43511 return checkExpressionStatement(node as ExpressionStatement); 43512 case SyntaxKind.IfStatement: 43513 return checkIfStatement(node as IfStatement); 43514 case SyntaxKind.DoStatement: 43515 return checkDoStatement(node as DoStatement); 43516 case SyntaxKind.WhileStatement: 43517 return checkWhileStatement(node as WhileStatement); 43518 case SyntaxKind.ForStatement: 43519 return checkForStatement(node as ForStatement); 43520 case SyntaxKind.ForInStatement: 43521 return checkForInStatement(node as ForInStatement); 43522 case SyntaxKind.ForOfStatement: 43523 return checkForOfStatement(node as ForOfStatement); 43524 case SyntaxKind.ContinueStatement: 43525 case SyntaxKind.BreakStatement: 43526 return checkBreakOrContinueStatement(node as BreakOrContinueStatement); 43527 case SyntaxKind.ReturnStatement: 43528 return checkReturnStatement(node as ReturnStatement); 43529 case SyntaxKind.WithStatement: 43530 return checkWithStatement(node as WithStatement); 43531 case SyntaxKind.SwitchStatement: 43532 return checkSwitchStatement(node as SwitchStatement); 43533 case SyntaxKind.LabeledStatement: 43534 return checkLabeledStatement(node as LabeledStatement); 43535 case SyntaxKind.ThrowStatement: 43536 return checkThrowStatement(node as ThrowStatement); 43537 case SyntaxKind.TryStatement: 43538 return checkTryStatement(node as TryStatement); 43539 case SyntaxKind.VariableDeclaration: 43540 return checkVariableDeclaration(node as VariableDeclaration); 43541 case SyntaxKind.BindingElement: 43542 return checkBindingElement(node as BindingElement); 43543 case SyntaxKind.ClassDeclaration: 43544 return checkClassDeclaration(node as ClassDeclaration); 43545 case SyntaxKind.StructDeclaration: 43546 return checkStructDeclaration(node as StructDeclaration); 43547 case SyntaxKind.AnnotationDeclaration: 43548 return checkAnnotationDeclaration(node as AnnotationDeclaration); 43549 case SyntaxKind.InterfaceDeclaration: 43550 return checkInterfaceDeclaration(node as InterfaceDeclaration); 43551 case SyntaxKind.TypeAliasDeclaration: 43552 return checkTypeAliasDeclaration(node as TypeAliasDeclaration); 43553 case SyntaxKind.EnumDeclaration: 43554 return checkEnumDeclaration(node as EnumDeclaration); 43555 case SyntaxKind.ModuleDeclaration: 43556 return checkModuleDeclaration(node as ModuleDeclaration); 43557 case SyntaxKind.ImportDeclaration: 43558 return checkImportDeclaration(node as ImportDeclaration); 43559 case SyntaxKind.ImportEqualsDeclaration: 43560 return checkImportEqualsDeclaration(node as ImportEqualsDeclaration); 43561 case SyntaxKind.ExportDeclaration: 43562 return checkExportDeclaration(node as ExportDeclaration); 43563 case SyntaxKind.ExportAssignment: 43564 return checkExportAssignment(node as ExportAssignment); 43565 case SyntaxKind.EmptyStatement: 43566 case SyntaxKind.DebuggerStatement: 43567 checkGrammarStatementInAmbientContext(node); 43568 return; 43569 case SyntaxKind.MissingDeclaration: 43570 return checkMissingDeclaration(node); 43571 } 43572 } 43573 43574 function checkJSDocCommentWorker(node: string | readonly JSDocComment[] | undefined) { 43575 if (isArray(node)) { 43576 forEach(node, tag => { 43577 if (isJSDocLinkLike(tag)) { 43578 checkSourceElement(tag); 43579 } 43580 }); 43581 } 43582 } 43583 43584 function checkJSDocTypeIsInJsFile(node: Node): void { 43585 if (!isInJSFile(node)) { 43586 grammarErrorOnNode(node, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments); 43587 } 43588 } 43589 43590 function checkJSDocVariadicType(node: JSDocVariadicType): void { 43591 checkJSDocTypeIsInJsFile(node); 43592 checkSourceElement(node.type); 43593 43594 // Only legal location is in the *last* parameter tag or last parameter of a JSDoc function. 43595 const { parent } = node; 43596 if (isParameter(parent) && isJSDocFunctionType(parent.parent)) { 43597 if (last(parent.parent.parameters) !== parent) { 43598 error(node, Diagnostics.A_rest_parameter_must_be_last_in_a_parameter_list); 43599 } 43600 return; 43601 } 43602 43603 if (!isJSDocTypeExpression(parent)) { 43604 error(node, Diagnostics.JSDoc_may_only_appear_in_the_last_parameter_of_a_signature); 43605 } 43606 43607 const paramTag = node.parent.parent; 43608 if (!isJSDocParameterTag(paramTag)) { 43609 error(node, Diagnostics.JSDoc_may_only_appear_in_the_last_parameter_of_a_signature); 43610 return; 43611 } 43612 43613 const param = getParameterSymbolFromJSDoc(paramTag); 43614 if (!param) { 43615 // We will error in `checkJSDocParameterTag`. 43616 return; 43617 } 43618 43619 const host = getHostSignatureFromJSDoc(paramTag); 43620 if (!host || last(host.parameters).symbol !== param) { 43621 error(node, Diagnostics.A_rest_parameter_must_be_last_in_a_parameter_list); 43622 } 43623 } 43624 43625 function getTypeFromJSDocVariadicType(node: JSDocVariadicType): Type { 43626 const type = getTypeFromTypeNode(node.type); 43627 const { parent } = node; 43628 const paramTag = node.parent.parent; 43629 if (isJSDocTypeExpression(node.parent) && isJSDocParameterTag(paramTag)) { 43630 // Else we will add a diagnostic, see `checkJSDocVariadicType`. 43631 const host = getHostSignatureFromJSDoc(paramTag); 43632 const isCallbackTag = isJSDocCallbackTag(paramTag.parent.parent); 43633 if (host || isCallbackTag) { 43634 /* 43635 Only return an array type if the corresponding parameter is marked as a rest parameter, or if there are no parameters. 43636 So in the following situation we will not create an array type: 43637 /** @param {...number} a * / 43638 function f(a) {} 43639 Because `a` will just be of type `number | undefined`. A synthetic `...args` will also be added, which *will* get an array type. 43640 */ 43641 const lastParamDeclaration = isCallbackTag 43642 ? lastOrUndefined((paramTag.parent.parent as unknown as JSDocCallbackTag).typeExpression.parameters) 43643 : lastOrUndefined(host!.parameters); 43644 const symbol = getParameterSymbolFromJSDoc(paramTag); 43645 if (!lastParamDeclaration || 43646 symbol && lastParamDeclaration.symbol === symbol && isRestParameter(lastParamDeclaration)) { 43647 return createArrayType(type); 43648 } 43649 } 43650 } 43651 if (isParameter(parent) && isJSDocFunctionType(parent.parent)) { 43652 return createArrayType(type); 43653 } 43654 return addOptionality(type); 43655 } 43656 43657 // Function and class expression bodies are checked after all statements in the enclosing body. This is 43658 // to ensure constructs like the following are permitted: 43659 // const foo = function () { 43660 // const s = foo(); 43661 // return "hello"; 43662 // } 43663 // Here, performing a full type check of the body of the function expression whilst in the process of 43664 // determining the type of foo would cause foo to be given type any because of the recursive reference. 43665 // Delaying the type check of the body ensures foo has been assigned a type. 43666 function checkNodeDeferred(node: Node) { 43667 const enclosingFile = getSourceFileOfNode(node); 43668 const links = getNodeLinks(enclosingFile); 43669 if (!(links.flags & NodeCheckFlags.TypeChecked)) { 43670 links.deferredNodes ||= new Set(); 43671 links.deferredNodes.add(node); 43672 } 43673 } 43674 43675 function checkDeferredNodes(context: SourceFile) { 43676 const links = getNodeLinks(context); 43677 if (links.deferredNodes) { 43678 links.deferredNodes.forEach(checkDeferredNode); 43679 } 43680 } 43681 43682 function checkDeferredNode(node: Node) { 43683 tracing?.push(tracing.Phase.Check, "checkDeferredNode", { kind: node.kind, pos: node.pos, end: node.end, path: (node as TracingNode).tracingPath }); 43684 const saveCurrentNode = currentNode; 43685 currentNode = node; 43686 instantiationCount = 0; 43687 switch (node.kind) { 43688 case SyntaxKind.CallExpression: 43689 case SyntaxKind.NewExpression: 43690 case SyntaxKind.TaggedTemplateExpression: 43691 case SyntaxKind.Decorator: 43692 case SyntaxKind.JsxOpeningElement: 43693 // These node kinds are deferred checked when overload resolution fails 43694 // To save on work, we ensure the arguments are checked just once, in 43695 // a deferred way 43696 resolveUntypedCall(node as CallLikeExpression); 43697 break; 43698 case SyntaxKind.FunctionExpression: 43699 case SyntaxKind.ArrowFunction: 43700 case SyntaxKind.MethodDeclaration: 43701 case SyntaxKind.MethodSignature: 43702 checkFunctionExpressionOrObjectLiteralMethodDeferred(node as FunctionExpression); 43703 break; 43704 case SyntaxKind.GetAccessor: 43705 case SyntaxKind.SetAccessor: 43706 checkAccessorDeclaration(node as AccessorDeclaration); 43707 break; 43708 case SyntaxKind.ClassExpression: 43709 checkClassExpressionDeferred(node as ClassExpression); 43710 break; 43711 case SyntaxKind.TypeParameter: 43712 checkTypeParameterDeferred(node as TypeParameterDeclaration); 43713 break; 43714 case SyntaxKind.JsxSelfClosingElement: 43715 checkJsxSelfClosingElementDeferred(node as JsxSelfClosingElement); 43716 break; 43717 case SyntaxKind.JsxElement: 43718 checkJsxElementDeferred(node as JsxElement); 43719 break; 43720 } 43721 currentNode = saveCurrentNode; 43722 tracing?.pop(); 43723 } 43724 43725 function checkSourceFile(node: SourceFile) { 43726 tracing?.push(tracing.Phase.Check, "checkSourceFile", { path: node.path }, /*separateBeginAndEnd*/ true); 43727 const recordInfo = MemoryDotting.recordStage(MemoryDotting.CHECK_SOURCE_FILE); 43728 performance.mark("beforeCheck"); 43729 if (host.getFileCheckedModuleInfo) { 43730 jsDocFileCheckInfo = host.getFileCheckedModuleInfo(node.fileName); 43731 jsDocFileCheckInfo.currentFileName = node.fileName; 43732 } 43733 checkSourceFileWorker(node); 43734 performance.mark("afterCheck"); 43735 MemoryDotting.stopRecordStage(recordInfo); 43736 performance.measure("Check", "beforeCheck", "afterCheck"); 43737 tracing?.pop(); 43738 } 43739 43740 function unusedIsError(kind: UnusedKind, isAmbient: boolean): boolean { 43741 if (isAmbient) { 43742 return false; 43743 } 43744 switch (kind) { 43745 case UnusedKind.Local: 43746 return !!compilerOptions.noUnusedLocals; 43747 case UnusedKind.Parameter: 43748 return !!compilerOptions.noUnusedParameters; 43749 default: 43750 return Debug.assertNever(kind); 43751 } 43752 } 43753 43754 function getPotentiallyUnusedIdentifiers(sourceFile: SourceFile): readonly PotentiallyUnusedIdentifier[] { 43755 return allPotentiallyUnusedIdentifiers.get(sourceFile.path) || emptyArray; 43756 } 43757 43758 // Fully type check a source file and collect the relevant diagnostics. 43759 function checkSourceFileWorker(node: SourceFile) { 43760 const links = getNodeLinks(node); 43761 if (!(links.flags & NodeCheckFlags.TypeChecked)) { 43762 if (skipTypeChecking(node, compilerOptions, host)) { 43763 return; 43764 } 43765 43766 // clear constEnumRelate 43767 constEnumRelate.set(node.resolvedPath, new Map()); 43768 43769 // Grammar checking 43770 checkGrammarSourceFile(node); 43771 43772 clear(potentialThisCollisions); 43773 clear(potentialNewTargetCollisions); 43774 clear(potentialWeakMapSetCollisions); 43775 clear(potentialReflectCollisions); 43776 clear(potentialUnusedRenamedBindingElementsInTypes); 43777 43778 forEach(node.statements, node => { 43779 if (!node.skipCheck) { 43780 checkSourceElement(node); 43781 } 43782 }); 43783 checkSourceElement(node.endOfFileToken); 43784 43785 checkDeferredNodes(node); 43786 43787 if (isExternalOrCommonJsModule(node)) { 43788 registerForUnusedIdentifiersCheck(node); 43789 } 43790 43791 addLazyDiagnostic(() => { 43792 // This relies on the results of other lazy diagnostics, so must be computed after them 43793 if (!node.isDeclarationFile && (compilerOptions.noUnusedLocals || compilerOptions.noUnusedParameters)) { 43794 checkUnusedIdentifiers(getPotentiallyUnusedIdentifiers(node), (containingNode, kind, diag) => { 43795 if (!containsParseError(containingNode) && unusedIsError(kind, !!(containingNode.flags & NodeFlags.Ambient))) { 43796 diagnostics.add(diag); 43797 } 43798 }); 43799 } 43800 if (!node.isDeclarationFile) { 43801 checkPotentialUncheckedRenamedBindingElementsInTypes(); 43802 } 43803 }); 43804 43805 if (compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Error && 43806 !node.isDeclarationFile && 43807 isExternalModule(node) 43808 ) { 43809 checkImportsForTypeOnlyConversion(node); 43810 } 43811 43812 if (isExternalOrCommonJsModule(node)) { 43813 checkExternalModuleExports(node); 43814 } 43815 43816 if (potentialThisCollisions.length) { 43817 forEach(potentialThisCollisions, checkIfThisIsCapturedInEnclosingScope); 43818 clear(potentialThisCollisions); 43819 } 43820 43821 if (potentialNewTargetCollisions.length) { 43822 forEach(potentialNewTargetCollisions, checkIfNewTargetIsCapturedInEnclosingScope); 43823 clear(potentialNewTargetCollisions); 43824 } 43825 43826 if (potentialWeakMapSetCollisions.length) { 43827 forEach(potentialWeakMapSetCollisions, checkWeakMapSetCollision); 43828 clear(potentialWeakMapSetCollisions); 43829 } 43830 43831 if (potentialReflectCollisions.length) { 43832 forEach(potentialReflectCollisions, checkReflectCollision); 43833 clear(potentialReflectCollisions); 43834 } 43835 43836 links.flags |= NodeCheckFlags.TypeChecked; 43837 } 43838 } 43839 43840 function getDiagnostics(sourceFile: SourceFile, ct: CancellationToken): Diagnostic[] { 43841 try { 43842 // Record the cancellation token so it can be checked later on during checkSourceElement. 43843 // Do this in a finally block so we can ensure that it gets reset back to nothing after 43844 // this call is done. 43845 cancellationToken = ct; 43846 return getDiagnosticsWorker(sourceFile); 43847 } 43848 finally { 43849 cancellationToken = undefined; 43850 } 43851 } 43852 43853 function ensurePendingDiagnosticWorkComplete() { 43854 // Invoke any existing lazy diagnostics to add them, clear the backlog of diagnostics 43855 for (const cb of deferredDiagnosticsCallbacks) { 43856 cb(); 43857 } 43858 deferredDiagnosticsCallbacks = []; 43859 } 43860 43861 function checkSourceFileWithEagerDiagnostics(sourceFile: SourceFile) { 43862 ensurePendingDiagnosticWorkComplete(); 43863 // then setup diagnostics for immediate invocation (as we are about to collect them, and 43864 // this avoids the overhead of longer-lived callbacks we don't need to allocate) 43865 // This also serves to make the shift to possibly lazy diagnostics transparent to serial command-line scenarios 43866 // (as in those cases, all the diagnostics will still be computed as the appropriate place in the tree, 43867 // thus much more likely retaining the same union ordering as before we had lazy diagnostics) 43868 const oldAddLazyDiagnostics = addLazyDiagnostic; 43869 addLazyDiagnostic = cb => cb(); 43870 checkSourceFile(sourceFile); 43871 addLazyDiagnostic = oldAddLazyDiagnostics; 43872 } 43873 43874 function getDiagnosticsWorker(sourceFile: SourceFile): Diagnostic[] { 43875 if (sourceFile) { 43876 ensurePendingDiagnosticWorkComplete(); 43877 // Some global diagnostics are deferred until they are needed and 43878 // may not be reported in the first call to getGlobalDiagnostics. 43879 // We should catch these changes and report them. 43880 const previousGlobalDiagnostics = diagnostics.getGlobalDiagnostics(); 43881 const previousGlobalDiagnosticsSize = previousGlobalDiagnostics.length; 43882 43883 checkSourceFileWithEagerDiagnostics(sourceFile); 43884 43885 const semanticDiagnostics = diagnostics.getDiagnostics(sourceFile.fileName); 43886 const currentGlobalDiagnostics = diagnostics.getGlobalDiagnostics(); 43887 if (currentGlobalDiagnostics !== previousGlobalDiagnostics) { 43888 // If the arrays are not the same reference, new diagnostics were added. 43889 const deferredGlobalDiagnostics = relativeComplement(previousGlobalDiagnostics, currentGlobalDiagnostics, compareDiagnostics); 43890 return concatenate(deferredGlobalDiagnostics, semanticDiagnostics); 43891 } 43892 else if (previousGlobalDiagnosticsSize === 0 && currentGlobalDiagnostics.length > 0) { 43893 // If the arrays are the same reference, but the length has changed, a single 43894 // new diagnostic was added as DiagnosticCollection attempts to reuse the 43895 // same array. 43896 return concatenate(currentGlobalDiagnostics, semanticDiagnostics); 43897 } 43898 43899 return semanticDiagnostics; 43900 } 43901 43902 // Global diagnostics are always added when a file is not provided to 43903 // getDiagnostics 43904 forEach(host.getSourceFiles(), checkSourceFileWithEagerDiagnostics); 43905 return diagnostics.getDiagnostics(); 43906 } 43907 43908 function getGlobalDiagnostics(): Diagnostic[] { 43909 ensurePendingDiagnosticWorkComplete(); 43910 return diagnostics.getGlobalDiagnostics(); 43911 } 43912 43913 // Language service support 43914 43915 function getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[] { 43916 if (location.flags & NodeFlags.InWithStatement) { 43917 // We cannot answer semantic questions within a with block, do not proceed any further 43918 return []; 43919 } 43920 43921 const symbols = createSymbolTable(); 43922 let isStaticSymbol = false; 43923 43924 populateSymbols(); 43925 43926 symbols.delete(InternalSymbolName.This); // Not a symbol, a keyword 43927 return symbolsToArray(symbols); 43928 43929 function populateSymbols() { 43930 while (location) { 43931 if (location.locals && !isGlobalSourceFile(location)) { 43932 copySymbols(location.locals, meaning); 43933 } 43934 43935 switch (location.kind) { 43936 case SyntaxKind.SourceFile: 43937 if (!isExternalModule(location as SourceFile)) break; 43938 // falls through 43939 case SyntaxKind.ModuleDeclaration: 43940 copyLocallyVisibleExportSymbols(getSymbolOfNode(location as ModuleDeclaration | SourceFile).exports!, meaning & SymbolFlags.ModuleMember); 43941 break; 43942 case SyntaxKind.EnumDeclaration: 43943 copySymbols(getSymbolOfNode(location as EnumDeclaration).exports!, meaning & SymbolFlags.EnumMember); 43944 break; 43945 case SyntaxKind.ClassExpression: 43946 const className = (location as ClassExpression).name; 43947 if (className) { 43948 copySymbol(location.symbol, meaning); 43949 } 43950 43951 // this fall-through is necessary because we would like to handle 43952 // type parameter inside class expression similar to how we handle it in classDeclaration and interface Declaration. 43953 // falls through 43954 case SyntaxKind.ClassDeclaration: 43955 case SyntaxKind.InterfaceDeclaration: 43956 // If we didn't come from static member of class or interface, 43957 // add the type parameters into the symbol table 43958 // (type parameters of classDeclaration/classExpression and interface are in member property of the symbol. 43959 // Note: that the memberFlags come from previous iteration. 43960 if (!isStaticSymbol) { 43961 copySymbols(getMembersOfSymbol(getSymbolOfNode(location as ClassDeclaration | InterfaceDeclaration)), meaning & SymbolFlags.Type); 43962 } 43963 break; 43964 case SyntaxKind.FunctionExpression: 43965 const funcName = (location as FunctionExpression).name; 43966 if (funcName) { 43967 copySymbol(location.symbol, meaning); 43968 } 43969 break; 43970 } 43971 43972 if (introducesArgumentsExoticObject(location)) { 43973 copySymbol(argumentsSymbol, meaning); 43974 } 43975 43976 isStaticSymbol = isStatic(location); 43977 location = location.parent; 43978 } 43979 43980 copySymbols(globals, meaning); 43981 } 43982 43983 /** 43984 * Copy the given symbol into symbol tables if the symbol has the given meaning 43985 * and it doesn't already existed in the symbol table 43986 * @param key a key for storing in symbol table; if undefined, use symbol.name 43987 * @param symbol the symbol to be added into symbol table 43988 * @param meaning meaning of symbol to filter by before adding to symbol table 43989 */ 43990 function copySymbol(symbol: Symbol, meaning: SymbolFlags): void { 43991 if (getCombinedLocalAndExportSymbolFlags(symbol) & meaning) { 43992 const id = symbol.escapedName; 43993 // We will copy all symbol regardless of its reserved name because 43994 // symbolsToArray will check whether the key is a reserved name and 43995 // it will not copy symbol with reserved name to the array 43996 if (!symbols.has(id)) { 43997 symbols.set(id, symbol); 43998 } 43999 } 44000 } 44001 44002 function copySymbols(source: SymbolTable, meaning: SymbolFlags): void { 44003 if (meaning) { 44004 source.forEach(symbol => { 44005 copySymbol(symbol, meaning); 44006 }); 44007 } 44008 } 44009 44010 function copyLocallyVisibleExportSymbols(source: SymbolTable, meaning: SymbolFlags): void { 44011 if (meaning) { 44012 source.forEach(symbol => { 44013 // Similar condition as in `resolveNameHelper` 44014 if (!getDeclarationOfKind(symbol, SyntaxKind.ExportSpecifier) && !getDeclarationOfKind(symbol, SyntaxKind.NamespaceExport)) { 44015 copySymbol(symbol, meaning); 44016 } 44017 }); 44018 } 44019 } 44020 } 44021 44022 function isTypeDeclarationName(name: Node): boolean { 44023 return name.kind === SyntaxKind.Identifier && 44024 isTypeDeclaration(name.parent) && 44025 getNameOfDeclaration(name.parent) === name; 44026 } 44027 44028 // True if the given identifier is part of a type reference 44029 function isTypeReferenceIdentifier(node: EntityName): boolean { 44030 while (node.parent.kind === SyntaxKind.QualifiedName) { 44031 node = node.parent as QualifiedName; 44032 } 44033 44034 return node.parent.kind === SyntaxKind.TypeReference; 44035 } 44036 44037 function isHeritageClauseElementIdentifier(node: Node): boolean { 44038 while (node.parent.kind === SyntaxKind.PropertyAccessExpression) { 44039 node = node.parent; 44040 } 44041 44042 return node.parent.kind === SyntaxKind.ExpressionWithTypeArguments; 44043 } 44044 44045 function forEachEnclosingClass<T>(node: Node, callback: (node: Node) => T | undefined): T | undefined { 44046 let result: T | undefined; 44047 44048 while (true) { 44049 node = getContainingClass(node)!; 44050 if (!node) break; 44051 if (result = callback(node)) break; 44052 } 44053 44054 return result; 44055 } 44056 44057 function isNodeUsedDuringClassInitialization(node: Node) { 44058 return !!findAncestor(node, element => { 44059 if (isConstructorDeclaration(element) && nodeIsPresent(element.body) || isPropertyDeclaration(element)) { 44060 return true; 44061 } 44062 else if (isClassLike(element) || isFunctionLikeDeclaration(element)) { 44063 return "quit"; 44064 } 44065 44066 return false; 44067 }); 44068 } 44069 44070 function isNodeWithinClass(node: Node, classDeclaration: ClassLikeDeclaration) { 44071 return !!forEachEnclosingClass(node, n => n === classDeclaration); 44072 } 44073 44074 function getLeftSideOfImportEqualsOrExportAssignment(nodeOnRightSide: EntityName): ImportEqualsDeclaration | ExportAssignment | undefined { 44075 while (nodeOnRightSide.parent.kind === SyntaxKind.QualifiedName) { 44076 nodeOnRightSide = nodeOnRightSide.parent as QualifiedName; 44077 } 44078 44079 if (nodeOnRightSide.parent.kind === SyntaxKind.ImportEqualsDeclaration) { 44080 return (nodeOnRightSide.parent as ImportEqualsDeclaration).moduleReference === nodeOnRightSide ? nodeOnRightSide.parent as ImportEqualsDeclaration : undefined; 44081 } 44082 44083 if (nodeOnRightSide.parent.kind === SyntaxKind.ExportAssignment) { 44084 return (nodeOnRightSide.parent as ExportAssignment).expression === nodeOnRightSide as Node ? nodeOnRightSide.parent as ExportAssignment : undefined; 44085 } 44086 44087 return undefined; 44088 } 44089 44090 function isInRightSideOfImportOrExportAssignment(node: EntityName) { 44091 return getLeftSideOfImportEqualsOrExportAssignment(node) !== undefined; 44092 } 44093 44094 function getSpecialPropertyAssignmentSymbolFromEntityName(entityName: EntityName | PropertyAccessExpression) { 44095 const specialPropertyAssignmentKind = getAssignmentDeclarationKind(entityName.parent.parent as BinaryExpression); 44096 switch (specialPropertyAssignmentKind) { 44097 case AssignmentDeclarationKind.ExportsProperty: 44098 case AssignmentDeclarationKind.PrototypeProperty: 44099 return getSymbolOfNode(entityName.parent); 44100 case AssignmentDeclarationKind.ThisProperty: 44101 case AssignmentDeclarationKind.ModuleExports: 44102 case AssignmentDeclarationKind.Property: 44103 return getSymbolOfNode(entityName.parent.parent); 44104 } 44105 } 44106 44107 function isImportTypeQualifierPart(node: EntityName): ImportTypeNode | undefined { 44108 let parent = node.parent; 44109 while (isQualifiedName(parent)) { 44110 node = parent; 44111 parent = parent.parent; 44112 } 44113 if (parent && parent.kind === SyntaxKind.ImportType && (parent as ImportTypeNode).qualifier === node) { 44114 return parent as ImportTypeNode; 44115 } 44116 return undefined; 44117 } 44118 44119 function getSymbolOfNameOrPropertyAccessExpression(name: EntityName | PrivateIdentifier | PropertyAccessExpression | JSDocMemberName, ignoreErrors?: boolean): Symbol | undefined { 44120 if (isDeclarationName(name)) { 44121 return getSymbolOfNode(name.parent); 44122 } 44123 44124 if (isInJSFile(name) && 44125 name.parent.kind === SyntaxKind.PropertyAccessExpression && 44126 name.parent === (name.parent.parent as BinaryExpression).left) { 44127 // Check if this is a special property assignment 44128 if (!isPrivateIdentifier(name) && !isJSDocMemberName(name)) { 44129 const specialPropertyAssignmentSymbol = getSpecialPropertyAssignmentSymbolFromEntityName(name); 44130 if (specialPropertyAssignmentSymbol) { 44131 return specialPropertyAssignmentSymbol; 44132 } 44133 } 44134 } 44135 44136 if (name.parent.kind === SyntaxKind.ExportAssignment && isEntityNameExpression(name)) { 44137 // Even an entity name expression that doesn't resolve as an entityname may still typecheck as a property access expression 44138 const success = resolveEntityName(name, 44139 /*all meanings*/ SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, /*ignoreErrors*/ true); 44140 if (success && success !== unknownSymbol) { 44141 return success; 44142 } 44143 } 44144 else if (isEntityName(name) && isInRightSideOfImportOrExportAssignment(name)) { 44145 // Since we already checked for ExportAssignment, this really could only be an Import 44146 const importEqualsDeclaration = getAncestor(name, SyntaxKind.ImportEqualsDeclaration); 44147 Debug.assert(importEqualsDeclaration !== undefined); 44148 return getSymbolOfPartOfRightHandSideOfImportEquals(name, /*dontResolveAlias*/ true); 44149 } 44150 44151 if (isEntityName(name)) { 44152 const possibleImportNode = isImportTypeQualifierPart(name); 44153 if (possibleImportNode) { 44154 getTypeFromTypeNode(possibleImportNode); 44155 const sym = getNodeLinks(name).resolvedSymbol; 44156 return sym === unknownSymbol ? undefined : sym; 44157 } 44158 } 44159 44160 while (isRightSideOfQualifiedNameOrPropertyAccessOrJSDocMemberName(name)) { 44161 name = name.parent as QualifiedName | PropertyAccessEntityNameExpression | JSDocMemberName; 44162 } 44163 44164 if (isHeritageClauseElementIdentifier(name)) { 44165 let meaning = SymbolFlags.None; 44166 // In an interface or class, we're definitely interested in a type. 44167 if (name.parent.kind === SyntaxKind.ExpressionWithTypeArguments) { 44168 meaning = SymbolFlags.Type; 44169 44170 // In a class 'extends' clause we are also looking for a value. 44171 if (isExpressionWithTypeArgumentsInClassExtendsClause(name.parent)) { 44172 meaning |= SymbolFlags.Value; 44173 } 44174 } 44175 else { 44176 meaning = SymbolFlags.Namespace; 44177 } 44178 44179 meaning |= SymbolFlags.Alias; 44180 const entityNameSymbol = isEntityNameExpression(name) ? resolveEntityName(name, meaning) : undefined; 44181 if (entityNameSymbol) { 44182 return entityNameSymbol; 44183 } 44184 } 44185 44186 if (name.parent.kind === SyntaxKind.JSDocParameterTag) { 44187 return getParameterSymbolFromJSDoc(name.parent as JSDocParameterTag); 44188 } 44189 44190 if (name.parent.kind === SyntaxKind.TypeParameter && name.parent.parent.kind === SyntaxKind.JSDocTemplateTag) { 44191 Debug.assert(!isInJSFile(name)); // Otherwise `isDeclarationName` would have been true. 44192 const typeParameter = getTypeParameterFromJsDoc(name.parent as TypeParameterDeclaration & { parent: JSDocTemplateTag }); 44193 return typeParameter && typeParameter.symbol; 44194 } 44195 44196 if (isExpressionNode(name)) { 44197 if (nodeIsMissing(name)) { 44198 // Missing entity name. 44199 return undefined; 44200 } 44201 44202 const isJSDoc = findAncestor(name, or(isJSDocLinkLike, isJSDocNameReference, isJSDocMemberName)); 44203 const meaning = isJSDoc ? SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Value : SymbolFlags.Value; 44204 if (name.kind === SyntaxKind.Identifier) { 44205 if (isJSXTagName(name) && isJsxIntrinsicIdentifier(name)) { 44206 const symbol = getIntrinsicTagSymbol(name.parent as JsxOpeningLikeElement); 44207 return symbol === unknownSymbol ? undefined : symbol; 44208 } 44209 const result = resolveEntityName(name, meaning, /*ignoreErrors*/ ignoreErrors, /* dontResolveAlias */ true, getHostSignatureFromJSDoc(name)); 44210 if (!result && isJSDoc) { 44211 const container = findAncestor(name, or(isClassLike, isInterfaceDeclaration)); 44212 if (container) { 44213 return resolveJSDocMemberName(name, /*ignoreErrors*/ false, getSymbolOfNode(container)); 44214 } 44215 } 44216 if (result && isJSDoc) { 44217 const container = getJSDocHost(name); 44218 if (container && isEnumMember(container) && container === result.valueDeclaration) { 44219 return resolveEntityName(name, meaning, /*ignoreErrors*/ true, /* dontResolveAlias */ true, getSourceFileOfNode(container)) || result; 44220 } 44221 } 44222 return result; 44223 } 44224 else if (isPrivateIdentifier(name)) { 44225 return getSymbolForPrivateIdentifierExpression(name); 44226 } 44227 else if (name.kind === SyntaxKind.PropertyAccessExpression || name.kind === SyntaxKind.QualifiedName) { 44228 const links = getNodeLinks(name); 44229 if (links.resolvedSymbol) { 44230 return links.resolvedSymbol; 44231 } 44232 44233 if (name.kind === SyntaxKind.PropertyAccessExpression) { 44234 checkPropertyAccessExpression(name, CheckMode.Normal); 44235 if (!links.resolvedSymbol) { 44236 const expressionType = checkExpressionCached(name.expression); 44237 const infos = getApplicableIndexInfos(expressionType, getLiteralTypeFromPropertyName(name.name)); 44238 if (infos.length && (expressionType as ObjectType).members) { 44239 const resolved = resolveStructuredTypeMembers(expressionType as ObjectType); 44240 const symbol = resolved.members.get(InternalSymbolName.Index); 44241 if (infos === getIndexInfosOfType(expressionType)) { 44242 links.resolvedSymbol = symbol; 44243 } 44244 else if (symbol) { 44245 const symbolLinks = getSymbolLinks(symbol); 44246 const declarationList = mapDefined(infos, i => i.declaration); 44247 const nodeListId = map(declarationList, getNodeId).join(","); 44248 if (!symbolLinks.filteredIndexSymbolCache) { 44249 symbolLinks.filteredIndexSymbolCache = new Map(); 44250 } 44251 if (symbolLinks.filteredIndexSymbolCache.has(nodeListId)) { 44252 links.resolvedSymbol = symbolLinks.filteredIndexSymbolCache.get(nodeListId)!; 44253 } 44254 else { 44255 const copy = createSymbol(SymbolFlags.Signature, InternalSymbolName.Index); 44256 copy.declarations = mapDefined(infos, i => i.declaration); 44257 copy.parent = expressionType.aliasSymbol ? expressionType.aliasSymbol : expressionType.symbol ? expressionType.symbol : getSymbolAtLocation(copy.declarations[0].parent); 44258 symbolLinks.filteredIndexSymbolCache.set(nodeListId, copy); 44259 links.resolvedSymbol = symbolLinks.filteredIndexSymbolCache.get(nodeListId)!; 44260 } 44261 } 44262 } 44263 } 44264 } 44265 else { 44266 checkQualifiedName(name, CheckMode.Normal); 44267 } 44268 if (!links.resolvedSymbol && isJSDoc && isQualifiedName(name)) { 44269 return resolveJSDocMemberName(name); 44270 } 44271 return links.resolvedSymbol; 44272 } 44273 else if (isJSDocMemberName(name)) { 44274 return resolveJSDocMemberName(name); 44275 } 44276 } 44277 else if (isTypeReferenceIdentifier(name as EntityName)) { 44278 const meaning = name.parent.kind === SyntaxKind.TypeReference ? SymbolFlags.Type : SymbolFlags.Namespace; 44279 const symbol = resolveEntityName(name as EntityName, meaning, /*ignoreErrors*/ false, /*dontResolveAlias*/ true); 44280 return symbol && symbol !== unknownSymbol ? symbol : getUnresolvedSymbolForEntityName(name as EntityName); 44281 } 44282 if (name.parent.kind === SyntaxKind.TypePredicate) { 44283 return resolveEntityName(name as Identifier, /*meaning*/ SymbolFlags.FunctionScopedVariable); 44284 } 44285 44286 return undefined; 44287 } 44288 44289 /** 44290 * Recursively resolve entity names and jsdoc instance references: 44291 * 1. K#m as K.prototype.m for a class (or other value) K 44292 * 2. K.m as K.prototype.m 44293 * 3. I.m as I.m for a type I, or any other I.m that fails to resolve in (1) or (2) 44294 * 44295 * For unqualified names, a container K may be provided as a second argument. 44296 */ 44297 function resolveJSDocMemberName(name: EntityName | JSDocMemberName, ignoreErrors?: boolean, container?: Symbol): Symbol | undefined { 44298 if (isEntityName(name)) { 44299 // resolve static values first 44300 const meaning = SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Value; 44301 let symbol = resolveEntityName(name, meaning, ignoreErrors, /*dontResolveAlias*/ true, getHostSignatureFromJSDoc(name)); 44302 if (!symbol && isIdentifier(name) && container) { 44303 symbol = getMergedSymbol(getSymbol(getExportsOfSymbol(container), name.escapedText, meaning)); 44304 } 44305 if (symbol) { 44306 return symbol; 44307 } 44308 } 44309 const left = isIdentifier(name) ? container : resolveJSDocMemberName(name.left, ignoreErrors, container); 44310 const right = isIdentifier(name) ? name.escapedText : name.right.escapedText; 44311 if (left) { 44312 const proto = left.flags & SymbolFlags.Value && getPropertyOfType(getTypeOfSymbol(left), "prototype" as __String); 44313 const t = proto ? getTypeOfSymbol(proto) : getDeclaredTypeOfSymbol(left); 44314 return getPropertyOfType(t, right); 44315 } 44316 } 44317 44318 function getSymbolAtLocation(node: Node, ignoreErrors?: boolean): Symbol | undefined { 44319 if (node.kind === SyntaxKind.SourceFile) { 44320 return isExternalModule(node as SourceFile) ? getMergedSymbol(node.symbol) : undefined; 44321 } 44322 const { parent } = node; 44323 const grandParent = parent.parent; 44324 44325 if (node.flags & NodeFlags.InWithStatement) { 44326 // We cannot answer semantic questions within a with block, do not proceed any further 44327 return undefined; 44328 } 44329 44330 if (isDeclarationNameOrImportPropertyName(node)) { 44331 // This is a declaration, call getSymbolOfNode 44332 const parentSymbol = getSymbolOfNode(parent)!; 44333 return isImportOrExportSpecifier(node.parent) && node.parent.propertyName === node 44334 ? getImmediateAliasedSymbol(parentSymbol) 44335 : parentSymbol; 44336 } 44337 else if (isLiteralComputedPropertyDeclarationName(node)) { 44338 return getSymbolOfNode(parent.parent); 44339 } 44340 44341 if (node.kind === SyntaxKind.Identifier) { 44342 if (isInRightSideOfImportOrExportAssignment(node as Identifier)) { 44343 return getSymbolOfNameOrPropertyAccessExpression(node as Identifier); 44344 } 44345 else if (parent.kind === SyntaxKind.BindingElement && 44346 grandParent.kind === SyntaxKind.ObjectBindingPattern && 44347 node === (parent as BindingElement).propertyName) { 44348 const typeOfPattern = getTypeOfNode(grandParent); 44349 const propertyDeclaration = getPropertyOfType(typeOfPattern, (node as Identifier).escapedText); 44350 44351 if (propertyDeclaration) { 44352 return propertyDeclaration; 44353 } 44354 } 44355 else if (isMetaProperty(parent) && parent.name === node) { 44356 if (parent.keywordToken === SyntaxKind.NewKeyword && idText(node as Identifier) === "target") { 44357 // `target` in `new.target` 44358 return checkNewTargetMetaProperty(parent).symbol; 44359 } 44360 // The `meta` in `import.meta` could be given `getTypeOfNode(parent).symbol` (the `ImportMeta` interface symbol), but 44361 // we have a fake expression type made for other reasons already, whose transient `meta` 44362 // member should more exactly be the kind of (declarationless) symbol we want. 44363 // (See #44364 and #45031 for relevant implementation PRs) 44364 if (parent.keywordToken === SyntaxKind.ImportKeyword && idText(node as Identifier) === "meta") { 44365 return getGlobalImportMetaExpressionType().members!.get("meta" as __String); 44366 } 44367 // no other meta properties are valid syntax, thus no others should have symbols 44368 return undefined; 44369 } 44370 } 44371 44372 switch (node.kind) { 44373 case SyntaxKind.Identifier: 44374 case SyntaxKind.PrivateIdentifier: 44375 case SyntaxKind.PropertyAccessExpression: 44376 case SyntaxKind.QualifiedName: 44377 if (!isThisInTypeQuery(node)) { 44378 return getSymbolOfNameOrPropertyAccessExpression(node as EntityName | PrivateIdentifier | PropertyAccessExpression); 44379 } 44380 // falls through 44381 44382 case SyntaxKind.ThisKeyword: 44383 const container = getThisContainer(node, /*includeArrowFunctions*/ false); 44384 if (isFunctionLike(container)) { 44385 const sig = getSignatureFromDeclaration(container); 44386 if (sig.thisParameter) { 44387 return sig.thisParameter; 44388 } 44389 } 44390 if (isInExpressionContext(node)) { 44391 return checkExpression(node as Expression).symbol; 44392 } 44393 // falls through 44394 44395 case SyntaxKind.ThisType: 44396 return getTypeFromThisTypeNode(node as ThisExpression | ThisTypeNode).symbol; 44397 44398 case SyntaxKind.SuperKeyword: 44399 return checkExpression(node as Expression).symbol; 44400 44401 case SyntaxKind.ConstructorKeyword: 44402 // constructor keyword for an overload, should take us to the definition if it exist 44403 const constructorDeclaration = node.parent; 44404 if (constructorDeclaration && constructorDeclaration.kind === SyntaxKind.Constructor) { 44405 return (constructorDeclaration.parent as ClassDeclaration).symbol; 44406 } 44407 return undefined; 44408 44409 case SyntaxKind.StringLiteral: 44410 case SyntaxKind.NoSubstitutionTemplateLiteral: 44411 // 1). import x = require("./mo/*gotToDefinitionHere*/d") 44412 // 2). External module name in an import declaration 44413 // 3). Dynamic import call or require in javascript 44414 // 4). type A = import("./f/*gotToDefinitionHere*/oo") 44415 if ((isExternalModuleImportEqualsDeclaration(node.parent.parent) && getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node) || 44416 ((node.parent.kind === SyntaxKind.ImportDeclaration || node.parent.kind === SyntaxKind.ExportDeclaration) && (node.parent as ImportDeclaration).moduleSpecifier === node) || 44417 ((isInJSFile(node) && isRequireCall(node.parent, /*checkArgumentIsStringLiteralLike*/ false)) || isImportCall(node.parent)) || 44418 (isLiteralTypeNode(node.parent) && isLiteralImportTypeNode(node.parent.parent) && node.parent.parent.argument === node.parent) 44419 ) { 44420 return resolveExternalModuleName(node, node as LiteralExpression, ignoreErrors); 44421 } 44422 if (isCallExpression(parent) && isBindableObjectDefinePropertyCall(parent) && parent.arguments[1] === node) { 44423 return getSymbolOfNode(parent); 44424 } 44425 // falls through 44426 44427 case SyntaxKind.NumericLiteral: 44428 // index access 44429 const objectType = isElementAccessExpression(parent) 44430 ? parent.argumentExpression === node ? getTypeOfExpression(parent.expression) : undefined 44431 : isLiteralTypeNode(parent) && isIndexedAccessTypeNode(grandParent) 44432 ? getTypeFromTypeNode(grandParent.objectType) 44433 : undefined; 44434 return objectType && getPropertyOfType(objectType, escapeLeadingUnderscores((node as StringLiteral | NumericLiteral).text)); 44435 44436 case SyntaxKind.DefaultKeyword: 44437 case SyntaxKind.FunctionKeyword: 44438 case SyntaxKind.EqualsGreaterThanToken: 44439 case SyntaxKind.ClassKeyword: 44440 return getSymbolOfNode(node.parent); 44441 case SyntaxKind.ImportType: 44442 return isLiteralImportTypeNode(node) ? getSymbolAtLocation(node.argument.literal, ignoreErrors) : undefined; 44443 44444 case SyntaxKind.ExportKeyword: 44445 return isExportAssignment(node.parent) ? Debug.checkDefined(node.parent.symbol) : undefined; 44446 44447 case SyntaxKind.ImportKeyword: 44448 case SyntaxKind.NewKeyword: 44449 return isMetaProperty(node.parent) ? checkMetaPropertyKeyword(node.parent).symbol : undefined; 44450 case SyntaxKind.MetaProperty: 44451 return checkExpression(node as Expression).symbol; 44452 44453 default: 44454 return undefined; 44455 } 44456 } 44457 44458 function getIndexInfosAtLocation(node: Node): readonly IndexInfo[] | undefined { 44459 if (isIdentifier(node) && isPropertyAccessExpression(node.parent) && node.parent.name === node) { 44460 const keyType = getLiteralTypeFromPropertyName(node); 44461 const objectType = getTypeOfExpression(node.parent.expression); 44462 const objectTypes = objectType.flags & TypeFlags.Union ? (objectType as UnionType).types : [objectType]; 44463 return flatMap(objectTypes, t => filter(getIndexInfosOfType(t), info => isApplicableIndexType(keyType, info.keyType))); 44464 } 44465 return undefined; 44466 } 44467 44468 function getShorthandAssignmentValueSymbol(location: Node | undefined): Symbol | undefined { 44469 if (location && location.kind === SyntaxKind.ShorthandPropertyAssignment) { 44470 return resolveEntityName((location as ShorthandPropertyAssignment).name, SymbolFlags.Value | SymbolFlags.Alias); 44471 } 44472 return undefined; 44473 } 44474 44475 /** Returns the target of an export specifier without following aliases */ 44476 function getExportSpecifierLocalTargetSymbol(node: ExportSpecifier | Identifier): Symbol | undefined { 44477 if (isExportSpecifier(node)) { 44478 return node.parent.parent.moduleSpecifier ? 44479 getExternalModuleMember(node.parent.parent, node) : 44480 resolveEntityName(node.propertyName || node.name, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias); 44481 } 44482 else { 44483 return resolveEntityName(node, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias); 44484 } 44485 } 44486 44487 function getTypeOfNode(node: Node): Type { 44488 if (isSourceFile(node) && !isExternalModule(node)) { 44489 return errorType; 44490 } 44491 44492 if (node.flags & NodeFlags.InWithStatement) { 44493 // We cannot answer semantic questions within a with block, do not proceed any further 44494 return errorType; 44495 } 44496 44497 const classDecl = tryGetClassImplementingOrExtendingExpressionWithTypeArguments(node); 44498 const classType = classDecl && getDeclaredTypeOfClassOrInterface(getSymbolOfNode(classDecl.class)); 44499 if (isPartOfTypeNode(node)) { 44500 const typeFromTypeNode = getTypeFromTypeNode(node as TypeNode); 44501 return classType ? getTypeWithThisArgument(typeFromTypeNode, classType.thisType) : typeFromTypeNode; 44502 } 44503 44504 if (isExpressionNode(node)) { 44505 return getRegularTypeOfExpression(node as Expression); 44506 } 44507 44508 if (classType && !classDecl.isImplements) { 44509 // A SyntaxKind.ExpressionWithTypeArguments is considered a type node, except when it occurs in the 44510 // extends clause of a class. We handle that case here. 44511 const baseType = firstOrUndefined(getBaseTypes(classType)); 44512 return baseType ? getTypeWithThisArgument(baseType, classType.thisType) : errorType; 44513 } 44514 44515 if (isTypeDeclaration(node)) { 44516 // In this case, we call getSymbolOfNode instead of getSymbolAtLocation because it is a declaration 44517 const symbol = getSymbolOfNode(node); 44518 return getDeclaredTypeOfSymbol(symbol); 44519 } 44520 44521 if (isTypeDeclarationName(node)) { 44522 const symbol = getSymbolAtLocation(node); 44523 return symbol ? getDeclaredTypeOfSymbol(symbol) : errorType; 44524 } 44525 44526 if (isDeclaration(node)) { 44527 // In this case, we call getSymbolOfNode instead of getSymbolAtLocation because it is a declaration 44528 const symbol = getSymbolOfNode(node); 44529 return symbol ? getTypeOfSymbol(symbol) : errorType; 44530 } 44531 44532 if (isDeclarationNameOrImportPropertyName(node)) { 44533 const symbol = getSymbolAtLocation(node); 44534 if (symbol) { 44535 return getTypeOfSymbol(symbol); 44536 } 44537 return errorType; 44538 } 44539 44540 if (isBindingPattern(node)) { 44541 return getTypeForVariableLikeDeclaration(node.parent, /*includeOptionality*/ true, CheckMode.Normal) || errorType; 44542 } 44543 44544 if (isInRightSideOfImportOrExportAssignment(node as Identifier)) { 44545 const symbol = getSymbolAtLocation(node); 44546 if (symbol) { 44547 const declaredType = getDeclaredTypeOfSymbol(symbol); 44548 return !isErrorType(declaredType) ? declaredType : getTypeOfSymbol(symbol); 44549 } 44550 } 44551 44552 if (isMetaProperty(node.parent) && node.parent.keywordToken === node.kind) { 44553 return checkMetaPropertyKeyword(node.parent); 44554 } 44555 44556 return errorType; 44557 } 44558 44559 function tryGetTypeOfNodeWithoutCheck(node: Node): Type { 44560 if (isSourceFile(node) && !isExternalModule(node)) { 44561 return errorType; 44562 } 44563 44564 if (node.flags & NodeFlags.InWithStatement) { 44565 // We cannot answer semantic questions within a with block, do not proceed any further 44566 return errorType; 44567 } 44568 44569 const classDecl = tryGetClassImplementingOrExtendingExpressionWithTypeArguments(node); 44570 const classType = classDecl && getDeclaredTypeOfClassOrInterface(getSymbolOfNode(classDecl.class)); 44571 if (isPartOfTypeNode(node)) { 44572 const typeFromTypeNode = getTypeFromTypeNode(<TypeNode>node); 44573 return classType ? getTypeWithThisArgument(typeFromTypeNode, classType.thisType) : typeFromTypeNode; 44574 } 44575 44576 if (isExpressionNode(node)) { 44577 return getRegularTypeOfExpression(<Expression>node, CheckMode.SkipEtsComponentBody); 44578 } 44579 44580 return getTypeOfNode(node); 44581 } 44582 44583 // Gets the type of object literal or array literal of destructuring assignment. 44584 // { a } from 44585 // for ( { a } of elems) { 44586 // } 44587 // [ a ] from 44588 // [a] = [ some array ...] 44589 function getTypeOfAssignmentPattern(expr: AssignmentPattern): Type | undefined { 44590 Debug.assert(expr.kind === SyntaxKind.ObjectLiteralExpression || expr.kind === SyntaxKind.ArrayLiteralExpression); 44591 // If this is from "for of" 44592 // for ( { a } of elems) { 44593 // } 44594 if (expr.parent.kind === SyntaxKind.ForOfStatement) { 44595 const iteratedType = checkRightHandSideOfForOf(expr.parent as ForOfStatement); 44596 return checkDestructuringAssignment(expr, iteratedType || errorType); 44597 } 44598 // If this is from "for" initializer 44599 // for ({a } = elems[0];.....) { } 44600 if (expr.parent.kind === SyntaxKind.BinaryExpression) { 44601 const iteratedType = getTypeOfExpression((expr.parent as BinaryExpression).right); 44602 return checkDestructuringAssignment(expr, iteratedType || errorType); 44603 } 44604 // If this is from nested object binding pattern 44605 // for ({ skills: { primary, secondary } } = multiRobot, i = 0; i < 1; i++) { 44606 if (expr.parent.kind === SyntaxKind.PropertyAssignment) { 44607 const node = cast(expr.parent.parent, isObjectLiteralExpression); 44608 const typeOfParentObjectLiteral = getTypeOfAssignmentPattern(node) || errorType; 44609 const propertyIndex = indexOfNode(node.properties, expr.parent); 44610 return checkObjectLiteralDestructuringPropertyAssignment(node, typeOfParentObjectLiteral, propertyIndex); 44611 } 44612 // Array literal assignment - array destructuring pattern 44613 const node = cast(expr.parent, isArrayLiteralExpression); 44614 // [{ property1: p1, property2 }] = elems; 44615 const typeOfArrayLiteral = getTypeOfAssignmentPattern(node) || errorType; 44616 const elementType = checkIteratedTypeOrElementType(IterationUse.Destructuring, typeOfArrayLiteral, undefinedType, expr.parent) || errorType; 44617 return checkArrayLiteralDestructuringElementAssignment(node, typeOfArrayLiteral, node.elements.indexOf(expr), elementType); 44618 } 44619 44620 // Gets the property symbol corresponding to the property in destructuring assignment 44621 // 'property1' from 44622 // for ( { property1: a } of elems) { 44623 // } 44624 // 'property1' at location 'a' from: 44625 // [a] = [ property1, property2 ] 44626 function getPropertySymbolOfDestructuringAssignment(location: Identifier) { 44627 // Get the type of the object or array literal and then look for property of given name in the type 44628 const typeOfObjectLiteral = getTypeOfAssignmentPattern(cast(location.parent.parent, isAssignmentPattern)); 44629 return typeOfObjectLiteral && getPropertyOfType(typeOfObjectLiteral, location.escapedText); 44630 } 44631 44632 function getRegularTypeOfExpression(expr: Expression, checkMode?: CheckMode): Type { 44633 if (isRightSideOfQualifiedNameOrPropertyAccess(expr)) { 44634 expr = expr.parent as Expression; 44635 } 44636 return getRegularTypeOfLiteralType(getTypeOfExpression(expr, checkMode)); 44637 } 44638 44639 /** 44640 * Gets either the static or instance type of a class element, based on 44641 * whether the element is declared as "static". 44642 */ 44643 function getParentTypeOfClassElement(node: ClassElement) { 44644 const classSymbol = getSymbolOfNode(node.parent)!; 44645 return isStatic(node) 44646 ? getTypeOfSymbol(classSymbol) 44647 : getDeclaredTypeOfSymbol(classSymbol); 44648 } 44649 44650 function getClassElementPropertyKeyType(element: ClassElement) { 44651 const name = element.name!; 44652 switch (name.kind) { 44653 case SyntaxKind.Identifier: 44654 return getStringLiteralType(idText(name)); 44655 case SyntaxKind.NumericLiteral: 44656 case SyntaxKind.StringLiteral: 44657 return getStringLiteralType(name.text); 44658 case SyntaxKind.ComputedPropertyName: 44659 const nameType = checkComputedPropertyName(name); 44660 return isTypeAssignableToKind(nameType, TypeFlags.ESSymbolLike) ? nameType : stringType; 44661 default: 44662 return Debug.fail("Unsupported property name."); 44663 } 44664 } 44665 44666 // Return the list of properties of the given type, augmented with properties from Function 44667 // if the type has call or construct signatures 44668 function getAugmentedPropertiesOfType(type: Type): Symbol[] { 44669 type = getApparentType(type); 44670 const propsByName = createSymbolTable(getPropertiesOfType(type)); 44671 const functionType = getSignaturesOfType(type, SignatureKind.Call).length ? globalCallableFunctionType : 44672 getSignaturesOfType(type, SignatureKind.Construct).length ? globalNewableFunctionType : 44673 undefined; 44674 if (functionType) { 44675 forEach(getPropertiesOfType(functionType), p => { 44676 if (!propsByName.has(p.escapedName)) { 44677 propsByName.set(p.escapedName, p); 44678 } 44679 }); 44680 } 44681 return getNamedMembers(propsByName); 44682 } 44683 44684 function typeHasCallOrConstructSignatures(type: Type): boolean { 44685 return ts.typeHasCallOrConstructSignatures(type, checker); 44686 } 44687 44688 function getRootSymbols(symbol: Symbol): readonly Symbol[] { 44689 const roots = getImmediateRootSymbols(symbol); 44690 return roots ? flatMap(roots, getRootSymbols) : [symbol]; 44691 } 44692 function getImmediateRootSymbols(symbol: Symbol): readonly Symbol[] | undefined { 44693 if (getCheckFlags(symbol) & CheckFlags.Synthetic) { 44694 return mapDefined(getSymbolLinks(symbol).containingType!.types, type => getPropertyOfType(type, symbol.escapedName)); 44695 } 44696 else if (symbol.flags & SymbolFlags.Transient) { 44697 const { leftSpread, rightSpread, syntheticOrigin } = symbol as TransientSymbol; 44698 return leftSpread ? [leftSpread, rightSpread!] 44699 : syntheticOrigin ? [syntheticOrigin] 44700 : singleElementArray(tryGetTarget(symbol)); 44701 } 44702 return undefined; 44703 } 44704 function tryGetTarget(symbol: Symbol): Symbol | undefined { 44705 let target: Symbol | undefined; 44706 let next: Symbol | undefined = symbol; 44707 while (next = getSymbolLinks(next).target) { 44708 target = next; 44709 } 44710 return target; 44711 } 44712 44713 // Emitter support 44714 44715 function isArgumentsLocalBinding(nodeIn: Identifier): boolean { 44716 // Note: does not handle isShorthandPropertyAssignment (and probably a few more) 44717 if (isGeneratedIdentifier(nodeIn)) return false; 44718 const node = getParseTreeNode(nodeIn, isIdentifier); 44719 if (!node) return false; 44720 const parent = node.parent; 44721 if (!parent) return false; 44722 const isPropertyName = ((isPropertyAccessExpression(parent) 44723 || isPropertyAssignment(parent)) 44724 && parent.name === node); 44725 return !isPropertyName && getReferencedValueSymbol(node) === argumentsSymbol; 44726 } 44727 44728 function moduleExportsSomeValue(moduleReferenceExpression: Expression): boolean { 44729 let moduleSymbol = resolveExternalModuleName(moduleReferenceExpression.parent, moduleReferenceExpression); 44730 if (!moduleSymbol || isShorthandAmbientModuleSymbol(moduleSymbol)) { 44731 // If the module is not found or is shorthand, assume that it may export a value. 44732 return true; 44733 } 44734 44735 const hasExportAssignment = hasExportAssignmentSymbol(moduleSymbol); 44736 // if module has export assignment then 'resolveExternalModuleSymbol' will return resolved symbol for export assignment 44737 // otherwise it will return moduleSymbol itself 44738 moduleSymbol = resolveExternalModuleSymbol(moduleSymbol); 44739 44740 const symbolLinks = getSymbolLinks(moduleSymbol); 44741 if (symbolLinks.exportsSomeValue === undefined) { 44742 // for export assignments - check if resolved symbol for RHS is itself a value 44743 // otherwise - check if at least one export is value 44744 symbolLinks.exportsSomeValue = hasExportAssignment 44745 ? !!(moduleSymbol.flags & SymbolFlags.Value) 44746 : forEachEntry(getExportsOfModule(moduleSymbol), isValue); 44747 } 44748 44749 return symbolLinks.exportsSomeValue!; 44750 44751 function isValue(s: Symbol): boolean { 44752 s = resolveSymbol(s); 44753 return s && !!(getAllSymbolFlags(s) & SymbolFlags.Value); 44754 } 44755 } 44756 44757 function isNameOfModuleOrEnumDeclaration(node: Identifier) { 44758 return isModuleOrEnumDeclaration(node.parent) && node === node.parent.name; 44759 } 44760 44761 // When resolved as an expression identifier, if the given node references an exported entity, return the declaration 44762 // node of the exported entity's container. Otherwise, return undefined. 44763 function getReferencedExportContainer(nodeIn: Identifier, prefixLocals?: boolean): SourceFile | ModuleDeclaration | EnumDeclaration | undefined { 44764 const node = getParseTreeNode(nodeIn, isIdentifier); 44765 if (node) { 44766 // When resolving the export container for the name of a module or enum 44767 // declaration, we need to start resolution at the declaration's container. 44768 // Otherwise, we could incorrectly resolve the export container as the 44769 // declaration if it contains an exported member with the same name. 44770 let symbol = getReferencedValueSymbol(node, /*startInDeclarationContainer*/ isNameOfModuleOrEnumDeclaration(node)); 44771 if (symbol) { 44772 if (symbol.flags & SymbolFlags.ExportValue) { 44773 // If we reference an exported entity within the same module declaration, then whether 44774 // we prefix depends on the kind of entity. SymbolFlags.ExportHasLocal encompasses all the 44775 // kinds that we do NOT prefix. 44776 const exportSymbol = getMergedSymbol(symbol.exportSymbol!); 44777 if (!prefixLocals && exportSymbol.flags & SymbolFlags.ExportHasLocal && !(exportSymbol.flags & SymbolFlags.Variable)) { 44778 return undefined; 44779 } 44780 symbol = exportSymbol; 44781 } 44782 const parentSymbol = getParentOfSymbol(symbol); 44783 if (parentSymbol) { 44784 if (parentSymbol.flags & SymbolFlags.ValueModule && parentSymbol.valueDeclaration?.kind === SyntaxKind.SourceFile) { 44785 const symbolFile = parentSymbol.valueDeclaration as SourceFile; 44786 const referenceFile = getSourceFileOfNode(node); 44787 // If `node` accesses an export and that export isn't in the same file, then symbol is a namespace export, so return undefined. 44788 const symbolIsUmdExport = symbolFile !== referenceFile; 44789 return symbolIsUmdExport ? undefined : symbolFile; 44790 } 44791 return findAncestor(node.parent, (n): n is ModuleDeclaration | EnumDeclaration => isModuleOrEnumDeclaration(n) && getSymbolOfNode(n) === parentSymbol); 44792 } 44793 } 44794 } 44795 } 44796 44797 // When resolved as an expression identifier, if the given node references an import, return the declaration of 44798 // that import. Otherwise, return undefined. 44799 function getReferencedImportDeclaration(nodeIn: Identifier): Declaration | undefined { 44800 if (nodeIn.generatedImportReference) { 44801 return nodeIn.generatedImportReference; 44802 } 44803 const node = getParseTreeNode(nodeIn, isIdentifier); 44804 if (node) { 44805 const symbol = getReferencedValueOrAliasSymbol(node); 44806 44807 // We should only get the declaration of an alias if there isn't a local value 44808 // declaration for the symbol 44809 if (isNonLocalAlias(symbol, /*excludes*/ SymbolFlags.Value) && !getTypeOnlyAliasDeclaration(symbol, SymbolFlags.Value)) { 44810 return getDeclarationOfAliasSymbol(symbol); 44811 } 44812 } 44813 44814 return undefined; 44815 } 44816 44817 function isSymbolOfDestructuredElementOfCatchBinding(symbol: Symbol) { 44818 return symbol.valueDeclaration 44819 && isBindingElement(symbol.valueDeclaration) 44820 && walkUpBindingElementsAndPatterns(symbol.valueDeclaration).parent.kind === SyntaxKind.CatchClause; 44821 } 44822 44823 function isSymbolOfDeclarationWithCollidingName(symbol: Symbol): boolean { 44824 if (symbol.flags & SymbolFlags.BlockScoped && symbol.valueDeclaration && !isSourceFile(symbol.valueDeclaration)) { 44825 const links = getSymbolLinks(symbol); 44826 if (links.isDeclarationWithCollidingName === undefined) { 44827 const container = getEnclosingBlockScopeContainer(symbol.valueDeclaration); 44828 if (isStatementWithLocals(container) || isSymbolOfDestructuredElementOfCatchBinding(symbol)) { 44829 const nodeLinks = getNodeLinks(symbol.valueDeclaration); 44830 if (resolveName(container.parent, symbol.escapedName, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false)) { 44831 // redeclaration - always should be renamed 44832 links.isDeclarationWithCollidingName = true; 44833 } 44834 else if (nodeLinks.flags & NodeCheckFlags.CapturedBlockScopedBinding) { 44835 // binding is captured in the function 44836 // should be renamed if: 44837 // - binding is not top level - top level bindings never collide with anything 44838 // AND 44839 // - binding is not declared in loop, should be renamed to avoid name reuse across siblings 44840 // let a, b 44841 // { let x = 1; a = () => x; } 44842 // { let x = 100; b = () => x; } 44843 // console.log(a()); // should print '1' 44844 // console.log(b()); // should print '100' 44845 // OR 44846 // - binding is declared inside loop but not in inside initializer of iteration statement or directly inside loop body 44847 // * variables from initializer are passed to rewritten loop body as parameters so they are not captured directly 44848 // * variables that are declared immediately in loop body will become top level variable after loop is rewritten and thus 44849 // they will not collide with anything 44850 const isDeclaredInLoop = nodeLinks.flags & NodeCheckFlags.BlockScopedBindingInLoop; 44851 const inLoopInitializer = isIterationStatement(container, /*lookInLabeledStatements*/ false); 44852 const inLoopBodyBlock = container.kind === SyntaxKind.Block && isIterationStatement(container.parent, /*lookInLabeledStatements*/ false); 44853 44854 links.isDeclarationWithCollidingName = !isBlockScopedContainerTopLevel(container) && (!isDeclaredInLoop || (!inLoopInitializer && !inLoopBodyBlock)); 44855 } 44856 else { 44857 links.isDeclarationWithCollidingName = false; 44858 } 44859 } 44860 } 44861 return links.isDeclarationWithCollidingName!; 44862 } 44863 return false; 44864 } 44865 44866 // When resolved as an expression identifier, if the given node references a nested block scoped entity with 44867 // a name that either hides an existing name or might hide it when compiled downlevel, 44868 // return the declaration of that entity. Otherwise, return undefined. 44869 function getReferencedDeclarationWithCollidingName(nodeIn: Identifier): Declaration | undefined { 44870 if (!isGeneratedIdentifier(nodeIn)) { 44871 const node = getParseTreeNode(nodeIn, isIdentifier); 44872 if (node) { 44873 const symbol = getReferencedValueSymbol(node); 44874 if (symbol && isSymbolOfDeclarationWithCollidingName(symbol)) { 44875 return symbol.valueDeclaration; 44876 } 44877 } 44878 } 44879 44880 return undefined; 44881 } 44882 44883 // Return true if the given node is a declaration of a nested block scoped entity with a name that either hides an 44884 // existing name or might hide a name when compiled downlevel 44885 function isDeclarationWithCollidingName(nodeIn: Declaration): boolean { 44886 const node = getParseTreeNode(nodeIn, isDeclaration); 44887 if (node) { 44888 const symbol = getSymbolOfNode(node); 44889 if (symbol) { 44890 return isSymbolOfDeclarationWithCollidingName(symbol); 44891 } 44892 } 44893 44894 return false; 44895 } 44896 44897 function isValueAliasDeclaration(node: Node): boolean { 44898 switch (node.kind) { 44899 case SyntaxKind.ImportEqualsDeclaration: 44900 return isAliasResolvedToValue(getSymbolOfNode(node)); 44901 case SyntaxKind.ImportClause: 44902 case SyntaxKind.NamespaceImport: 44903 case SyntaxKind.ImportSpecifier: 44904 case SyntaxKind.ExportSpecifier: 44905 const symbol = getSymbolOfNode(node); 44906 return !!symbol && isAliasResolvedToValue(symbol) && !getTypeOnlyAliasDeclaration(symbol, SymbolFlags.Value); 44907 case SyntaxKind.ExportDeclaration: 44908 const exportClause = (node as ExportDeclaration).exportClause; 44909 return !!exportClause && ( 44910 isNamespaceExport(exportClause) || 44911 some(exportClause.elements, isValueAliasDeclaration) 44912 ); 44913 case SyntaxKind.ExportAssignment: 44914 return (node as ExportAssignment).expression && (node as ExportAssignment).expression.kind === SyntaxKind.Identifier ? 44915 isAliasResolvedToValue(getSymbolOfNode(node)) : 44916 true; 44917 } 44918 return false; 44919 } 44920 44921 function isTopLevelValueImportEqualsWithEntityName(nodeIn: ImportEqualsDeclaration): boolean { 44922 const node = getParseTreeNode(nodeIn, isImportEqualsDeclaration); 44923 if (node === undefined || node.parent.kind !== SyntaxKind.SourceFile || !isInternalModuleImportEqualsDeclaration(node)) { 44924 // parent is not source file or it is not reference to internal module 44925 return false; 44926 } 44927 44928 const isValue = isAliasResolvedToValue(getSymbolOfNode(node)); 44929 return isValue && node.moduleReference && !nodeIsMissing(node.moduleReference); 44930 } 44931 44932 function isAliasResolvedToValue(symbol: Symbol | undefined): boolean { 44933 if (!symbol) { 44934 return false; 44935 } 44936 const target = getExportSymbolOfValueSymbolIfExported(resolveAlias(symbol)); 44937 if (target === unknownSymbol) { 44938 return true; 44939 } 44940 // const enums and modules that contain only const enums are not considered values from the emit perspective 44941 // unless 'preserveConstEnums' option is set to true 44942 return !!((getAllSymbolFlags(target) ?? -1) & SymbolFlags.Value) && 44943 (shouldPreserveConstEnums(compilerOptions) || !isConstEnumOrConstEnumOnlyModule(target)); 44944 } 44945 44946 function isConstEnumOrConstEnumOnlyModule(s: Symbol): boolean { 44947 return isConstEnumSymbol(s) || !!s.constEnumOnlyModule; 44948 } 44949 44950 function isReferencedAliasDeclaration(node: Node, checkChildren?: boolean): boolean { 44951 if (isAliasSymbolDeclaration(node)) { 44952 const symbol = getSymbolOfNode(node); 44953 const links = symbol && getSymbolLinks(symbol); 44954 if (links?.referenced) { 44955 return true; 44956 } 44957 const target = getSymbolLinks(symbol!).aliasTarget; // TODO: GH#18217 44958 if (target && getEffectiveModifierFlags(node) & ModifierFlags.Export && 44959 getAllSymbolFlags(target) & SymbolFlags.Value && 44960 (shouldPreserveConstEnums(compilerOptions) || !isConstEnumOrConstEnumOnlyModule(target))) { 44961 // An `export import ... =` of a value symbol is always considered referenced 44962 return true; 44963 } 44964 } 44965 44966 if (checkChildren) { 44967 return !!forEachChild(node, node => isReferencedAliasDeclaration(node, checkChildren)); 44968 } 44969 return false; 44970 } 44971 44972 function isReferenced(node: Node): boolean { 44973 const symbol = getSymbolOfNode(node); 44974 return !!symbol?.isReferenced; 44975 } 44976 44977 function isImplementationOfOverload(node: SignatureDeclaration) { 44978 if (nodeIsPresent((node as FunctionLikeDeclaration).body)) { 44979 if (isGetAccessor(node) || isSetAccessor(node)) return false; // Get or set accessors can never be overload implementations, but can have up to 2 signatures 44980 const symbol = getSymbolOfNode(node); 44981 const signaturesOfSymbol = getSignaturesOfSymbol(symbol); 44982 // If this function body corresponds to function with multiple signature, it is implementation of overload 44983 // e.g.: function foo(a: string): string; 44984 // function foo(a: number): number; 44985 // function foo(a: any) { // This is implementation of the overloads 44986 // return a; 44987 // } 44988 return signaturesOfSymbol.length > 1 || 44989 // If there is single signature for the symbol, it is overload if that signature isn't coming from the node 44990 // e.g.: function foo(a: string): string; 44991 // function foo(a: any) { // This is implementation of the overloads 44992 // return a; 44993 // } 44994 (signaturesOfSymbol.length === 1 && signaturesOfSymbol[0].declaration !== node); 44995 } 44996 return false; 44997 } 44998 44999 function isRequiredInitializedParameter(parameter: ParameterDeclaration | JSDocParameterTag): boolean { 45000 return !!strictNullChecks && 45001 !isOptionalParameter(parameter) && 45002 !isJSDocParameterTag(parameter) && 45003 !!parameter.initializer && 45004 !hasSyntacticModifier(parameter, ModifierFlags.ParameterPropertyModifier); 45005 } 45006 45007 function isOptionalUninitializedParameterProperty(parameter: ParameterDeclaration) { 45008 return strictNullChecks && 45009 isOptionalParameter(parameter) && 45010 !parameter.initializer && 45011 hasSyntacticModifier(parameter, ModifierFlags.ParameterPropertyModifier); 45012 } 45013 45014 function isExpandoFunctionDeclaration(node: Declaration): boolean { 45015 const declaration = getParseTreeNode(node, isFunctionDeclaration); 45016 if (!declaration) { 45017 return false; 45018 } 45019 const symbol = getSymbolOfNode(declaration); 45020 if (!symbol || !(symbol.flags & SymbolFlags.Function)) { 45021 return false; 45022 } 45023 return !!forEachEntry(getExportsOfSymbol(symbol), p => p.flags & SymbolFlags.Value && p.valueDeclaration && isPropertyAccessExpression(p.valueDeclaration)); 45024 } 45025 45026 function getPropertiesOfContainerFunction(node: Declaration): Symbol[] { 45027 const declaration = getParseTreeNode(node, isFunctionDeclaration); 45028 if (!declaration) { 45029 return emptyArray; 45030 } 45031 const symbol = getSymbolOfNode(declaration); 45032 return symbol && getPropertiesOfType(getTypeOfSymbol(symbol)) || emptyArray; 45033 } 45034 45035 function getNodeCheckFlags(node: Node): NodeCheckFlags { 45036 const nodeId = node.id || 0; 45037 if (nodeId < 0 || nodeId >= nodeLinks.length) return 0; 45038 return nodeLinks[nodeId]?.flags || 0; 45039 } 45040 45041 function getEnumMemberValue(node: EnumMember): string | number | undefined { 45042 computeEnumMemberValues(node.parent); 45043 return getNodeLinks(node).enumMemberValue; 45044 } 45045 45046 function canHaveConstantValue(node: Node): node is EnumMember | AccessExpression { 45047 switch (node.kind) { 45048 case SyntaxKind.EnumMember: 45049 case SyntaxKind.PropertyAccessExpression: 45050 case SyntaxKind.ElementAccessExpression: 45051 return true; 45052 } 45053 return false; 45054 } 45055 45056 function getConstantValue(node: EnumMember | AccessExpression): string | number | undefined { 45057 if (node.kind === SyntaxKind.EnumMember) { 45058 return getEnumMemberValue(node); 45059 } 45060 45061 const symbol = getNodeLinks(node).resolvedSymbol; 45062 if (symbol && (symbol.flags & SymbolFlags.EnumMember)) { 45063 // inline property\index accesses only for const enums 45064 const member = symbol.valueDeclaration as EnumMember; 45065 if (isEnumConst(member.parent)) { 45066 return getEnumMemberValue(member); 45067 } 45068 } 45069 45070 return undefined; 45071 } 45072 45073 function isFunctionType(type: Type): boolean { 45074 return !!(type.flags & TypeFlags.Object) && getSignaturesOfType(type, SignatureKind.Call).length > 0; 45075 } 45076 45077 function getTypeReferenceSerializationKind(typeNameIn: EntityName, location?: Node): TypeReferenceSerializationKind { 45078 // ensure both `typeName` and `location` are parse tree nodes. 45079 const typeName = getParseTreeNode(typeNameIn, isEntityName); 45080 if (!typeName) return TypeReferenceSerializationKind.Unknown; 45081 45082 if (location) { 45083 location = getParseTreeNode(location); 45084 if (!location) return TypeReferenceSerializationKind.Unknown; 45085 } 45086 45087 // Resolve the symbol as a value to ensure the type can be reached at runtime during emit. 45088 let isTypeOnly = false; 45089 if (isQualifiedName(typeName)) { 45090 const rootValueSymbol = resolveEntityName(getFirstIdentifier(typeName), SymbolFlags.Value, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, location); 45091 isTypeOnly = !!rootValueSymbol?.declarations?.every(isTypeOnlyImportOrExportDeclaration); 45092 } 45093 const valueSymbol = resolveEntityName(typeName, SymbolFlags.Value, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, location); 45094 const resolvedSymbol = valueSymbol && valueSymbol.flags & SymbolFlags.Alias ? resolveAlias(valueSymbol) : valueSymbol; 45095 isTypeOnly ||= !!valueSymbol?.declarations?.every(isTypeOnlyImportOrExportDeclaration); 45096 45097 // Resolve the symbol as a type so that we can provide a more useful hint for the type serializer. 45098 const typeSymbol = resolveEntityName(typeName, SymbolFlags.Type, /*ignoreErrors*/ true, /*dontResolveAlias*/ false, location); 45099 if (resolvedSymbol && resolvedSymbol === typeSymbol) { 45100 const globalPromiseSymbol = getGlobalPromiseConstructorSymbol(/*reportErrors*/ false); 45101 if (globalPromiseSymbol && resolvedSymbol === globalPromiseSymbol) { 45102 return TypeReferenceSerializationKind.Promise; 45103 } 45104 45105 const constructorType = getTypeOfSymbol(resolvedSymbol); 45106 if (constructorType && isConstructorType(constructorType)) { 45107 return isTypeOnly ? TypeReferenceSerializationKind.TypeWithCallSignature : TypeReferenceSerializationKind.TypeWithConstructSignatureAndValue; 45108 } 45109 } 45110 45111 // We might not be able to resolve type symbol so use unknown type in that case (eg error case) 45112 if (!typeSymbol) { 45113 return isTypeOnly ? TypeReferenceSerializationKind.ObjectType : TypeReferenceSerializationKind.Unknown; 45114 } 45115 const type = getDeclaredTypeOfSymbol(typeSymbol); 45116 if (isErrorType(type)) { 45117 return isTypeOnly ? TypeReferenceSerializationKind.ObjectType : TypeReferenceSerializationKind.Unknown; 45118 } 45119 else if (type.flags & TypeFlags.AnyOrUnknown) { 45120 return TypeReferenceSerializationKind.ObjectType; 45121 } 45122 else if (isTypeAssignableToKind(type, TypeFlags.Void | TypeFlags.Nullable | TypeFlags.Never)) { 45123 return TypeReferenceSerializationKind.VoidNullableOrNeverType; 45124 } 45125 else if (isTypeAssignableToKind(type, TypeFlags.BooleanLike)) { 45126 return TypeReferenceSerializationKind.BooleanType; 45127 } 45128 else if (isTypeAssignableToKind(type, TypeFlags.NumberLike)) { 45129 return TypeReferenceSerializationKind.NumberLikeType; 45130 } 45131 else if (isTypeAssignableToKind(type, TypeFlags.BigIntLike)) { 45132 return TypeReferenceSerializationKind.BigIntLikeType; 45133 } 45134 else if (isTypeAssignableToKind(type, TypeFlags.StringLike)) { 45135 return TypeReferenceSerializationKind.StringLikeType; 45136 } 45137 else if (isTupleType(type)) { 45138 return TypeReferenceSerializationKind.ArrayLikeType; 45139 } 45140 else if (isTypeAssignableToKind(type, TypeFlags.ESSymbolLike)) { 45141 return TypeReferenceSerializationKind.ESSymbolType; 45142 } 45143 else if (isFunctionType(type)) { 45144 return TypeReferenceSerializationKind.TypeWithCallSignature; 45145 } 45146 else if (isArrayType(type)) { 45147 return TypeReferenceSerializationKind.ArrayLikeType; 45148 } 45149 else { 45150 return TypeReferenceSerializationKind.ObjectType; 45151 } 45152 } 45153 45154 function createTypeOfDeclaration(declarationIn: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean) { 45155 const declaration = getParseTreeNode(declarationIn, isVariableLikeOrAccessor); 45156 if (!declaration) { 45157 return factory.createToken(SyntaxKind.AnyKeyword) as KeywordTypeNode; 45158 } 45159 // Get type of the symbol if this is the valid symbol otherwise get type at location 45160 const symbol = getSymbolOfNode(declaration); 45161 let type = symbol && !(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.Signature)) 45162 ? getWidenedLiteralType(getTypeOfSymbol(symbol)) 45163 : errorType; 45164 if (type.flags & TypeFlags.UniqueESSymbol && 45165 type.symbol === symbol) { 45166 flags |= NodeBuilderFlags.AllowUniqueESSymbolType; 45167 } 45168 if (addUndefined) { 45169 type = getOptionalType(type); 45170 } 45171 return nodeBuilder.typeToTypeNode(type, enclosingDeclaration, flags | NodeBuilderFlags.MultilineObjectLiterals, tracker); 45172 } 45173 45174 function createReturnTypeOfSignatureDeclaration(signatureDeclarationIn: SignatureDeclaration, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker) { 45175 const signatureDeclaration = getParseTreeNode(signatureDeclarationIn, isFunctionLike); 45176 if (!signatureDeclaration) { 45177 return factory.createToken(SyntaxKind.AnyKeyword) as KeywordTypeNode; 45178 } 45179 const signature = getSignatureFromDeclaration(signatureDeclaration); 45180 return nodeBuilder.typeToTypeNode(getReturnTypeOfSignature(signature), enclosingDeclaration, flags | NodeBuilderFlags.MultilineObjectLiterals, tracker); 45181 } 45182 45183 function createTypeOfExpression(exprIn: Expression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker) { 45184 const expr = getParseTreeNode(exprIn, isExpression); 45185 if (!expr) { 45186 return factory.createToken(SyntaxKind.AnyKeyword) as KeywordTypeNode; 45187 } 45188 const type = getWidenedType(getRegularTypeOfExpression(expr)); 45189 return nodeBuilder.typeToTypeNode(type, enclosingDeclaration, flags | NodeBuilderFlags.MultilineObjectLiterals, tracker); 45190 } 45191 45192 function hasGlobalName(name: string): boolean { 45193 return globals.has(escapeLeadingUnderscores(name)); 45194 } 45195 45196 function getReferencedValueSymbol(reference: Identifier, startInDeclarationContainer?: boolean): Symbol | undefined { 45197 const resolvedSymbol = getNodeLinks(reference).resolvedSymbol; 45198 if (resolvedSymbol) { 45199 return resolvedSymbol; 45200 } 45201 45202 let location: Node = reference; 45203 if (startInDeclarationContainer) { 45204 // When resolving the name of a declaration as a value, we need to start resolution 45205 // at a point outside of the declaration. 45206 const parent = reference.parent; 45207 if (isDeclaration(parent) && reference === parent.name) { 45208 location = getDeclarationContainer(parent); 45209 } 45210 } 45211 45212 return resolveName(location, reference.escapedText, SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias, /*nodeNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ true); 45213 } 45214 45215 /** 45216 * Get either a value-meaning symbol or an alias symbol. 45217 * Unlike `getReferencedValueSymbol`, if the cached resolved symbol is the unknown symbol, 45218 * we call `resolveName` to find a symbol. 45219 * This is because when caching the resolved symbol, we only consider value symbols, but here 45220 * we want to also get an alias symbol if one exists. 45221 */ 45222 function getReferencedValueOrAliasSymbol(reference: Identifier): Symbol | undefined { 45223 const resolvedSymbol = getNodeLinks(reference).resolvedSymbol; 45224 if (resolvedSymbol && resolvedSymbol !== unknownSymbol) { 45225 return resolvedSymbol; 45226 } 45227 45228 return resolveName( 45229 reference, 45230 reference.escapedText, 45231 SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias, 45232 /*nodeNotFoundMessage*/ undefined, 45233 /*nameArg*/ undefined, 45234 /*isUse*/ true, 45235 /*excludeGlobals*/ undefined, 45236 /*getSpellingSuggestions*/ undefined); 45237 } 45238 45239 function getReferencedValueDeclaration(referenceIn: Identifier): Declaration | undefined { 45240 if (!isGeneratedIdentifier(referenceIn)) { 45241 const reference = getParseTreeNode(referenceIn, isIdentifier); 45242 if (reference) { 45243 const symbol = getReferencedValueSymbol(reference); 45244 if (symbol) { 45245 return getExportSymbolOfValueSymbolIfExported(symbol).valueDeclaration; 45246 } 45247 } 45248 } 45249 45250 return undefined; 45251 } 45252 45253 function isLiteralConstDeclaration(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration): boolean { 45254 if (isDeclarationReadonly(node) || isVariableDeclaration(node) && isVarConst(node)) { 45255 return isFreshLiteralType(getTypeOfSymbol(getSymbolOfNode(node))); 45256 } 45257 return false; 45258 } 45259 45260 function literalTypeToNode(type: FreshableType, enclosing: Node, tracker: SymbolTracker): Expression { 45261 const enumResult = type.flags & TypeFlags.EnumLiteral ? nodeBuilder.symbolToExpression(type.symbol, SymbolFlags.Value, enclosing, /*flags*/ undefined, tracker) 45262 : type === trueType ? factory.createTrue() : type === falseType && factory.createFalse(); 45263 if (enumResult) return enumResult; 45264 const literalValue = (type as LiteralType).value; 45265 return typeof literalValue === "object" ? factory.createBigIntLiteral(literalValue) : 45266 typeof literalValue === "number" ? factory.createNumericLiteral(literalValue) : 45267 factory.createStringLiteral(literalValue); 45268 } 45269 45270 function createLiteralConstValue(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration, tracker: SymbolTracker) { 45271 const type = getTypeOfSymbol(getSymbolOfNode(node)); 45272 return literalTypeToNode(type as FreshableType, node, tracker); 45273 } 45274 45275 function getJsxFactoryEntity(location: Node): EntityName | undefined { 45276 return location ? (getJsxNamespace(location), (getSourceFileOfNode(location).localJsxFactory || _jsxFactoryEntity)) : _jsxFactoryEntity; 45277 } 45278 45279 function getJsxFragmentFactoryEntity(location: Node): EntityName | undefined { 45280 if (location) { 45281 const file = getSourceFileOfNode(location); 45282 if (file) { 45283 if (file.localJsxFragmentFactory) { 45284 return file.localJsxFragmentFactory; 45285 } 45286 const jsxFragPragmas = file.pragmas.get("jsxfrag"); 45287 const jsxFragPragma = isArray(jsxFragPragmas) ? jsxFragPragmas[0] : jsxFragPragmas; 45288 if (jsxFragPragma) { 45289 file.localJsxFragmentFactory = parseIsolatedEntityName(jsxFragPragma.arguments.factory, languageVersion); 45290 return file.localJsxFragmentFactory; 45291 } 45292 } 45293 } 45294 45295 if (compilerOptions.jsxFragmentFactory) { 45296 return parseIsolatedEntityName(compilerOptions.jsxFragmentFactory, languageVersion); 45297 } 45298 } 45299 45300 function createResolver(): EmitResolver { 45301 // this variable and functions that use it are deliberately moved here from the outer scope 45302 // to avoid scope pollution 45303 const resolvedTypeReferenceDirectives = host.getResolvedTypeReferenceDirectives(); 45304 let fileToDirective: ESMap<string, [specifier: string, mode: SourceFile["impliedNodeFormat"] | undefined]>; 45305 if (resolvedTypeReferenceDirectives) { 45306 // populate reverse mapping: file path -> type reference directive that was resolved to this file 45307 fileToDirective = new Map<string, [specifier: string, mode: SourceFile["impliedNodeFormat"] | undefined]>(); 45308 resolvedTypeReferenceDirectives.forEach((resolvedDirective, key, mode) => { 45309 if (!resolvedDirective || !resolvedDirective.resolvedFileName) { 45310 return; 45311 } 45312 const file = host.getSourceFile(resolvedDirective.resolvedFileName); 45313 if (file) { 45314 // Add the transitive closure of path references loaded by this file (as long as they are not) 45315 // part of an existing type reference. 45316 addReferencedFilesToTypeDirective(file, key, mode); 45317 } 45318 }); 45319 } 45320 45321 return { 45322 getReferencedExportContainer, 45323 getReferencedImportDeclaration, 45324 getReferencedDeclarationWithCollidingName, 45325 isDeclarationWithCollidingName, 45326 isValueAliasDeclaration: nodeIn => { 45327 const node = getParseTreeNode(nodeIn); 45328 // Synthesized nodes are always treated like values. 45329 return node ? isValueAliasDeclaration(node) : true; 45330 }, 45331 hasGlobalName, 45332 isReferencedAliasDeclaration: (nodeIn, checkChildren?) => { 45333 const node = getParseTreeNode(nodeIn); 45334 // Synthesized nodes are always treated as referenced. 45335 return node ? isReferencedAliasDeclaration(node, checkChildren) : true; 45336 }, 45337 isReferenced: (nodeIn: Node | undefined): boolean => { 45338 const node = getParseTreeNode(nodeIn); 45339 return node ? isReferenced(node) : false; 45340 }, 45341 getNodeCheckFlags: nodeIn => { 45342 const node = getParseTreeNode(nodeIn); 45343 return node ? getNodeCheckFlags(node) : 0; 45344 }, 45345 isTopLevelValueImportEqualsWithEntityName, 45346 isDeclarationVisible, 45347 isImplementationOfOverload, 45348 isRequiredInitializedParameter, 45349 isOptionalUninitializedParameterProperty, 45350 isExpandoFunctionDeclaration, 45351 getPropertiesOfContainerFunction, 45352 createTypeOfDeclaration, 45353 createReturnTypeOfSignatureDeclaration, 45354 createTypeOfExpression, 45355 createLiteralConstValue, 45356 isSymbolAccessible, 45357 isEntityNameVisible, 45358 getConstantValue: nodeIn => { 45359 const node = getParseTreeNode(nodeIn, canHaveConstantValue); 45360 return node ? getConstantValue(node) : undefined; 45361 }, 45362 collectLinkedAliases, 45363 getReferencedValueDeclaration, 45364 getTypeReferenceSerializationKind, 45365 isOptionalParameter, 45366 moduleExportsSomeValue, 45367 isArgumentsLocalBinding, 45368 getExternalModuleFileFromDeclaration: nodeIn => { 45369 const node = getParseTreeNode(nodeIn, hasPossibleExternalModuleReference); 45370 return node && getExternalModuleFileFromDeclaration(node); 45371 }, 45372 getTypeReferenceDirectivesForEntityName, 45373 getTypeReferenceDirectivesForSymbol, 45374 isLiteralConstDeclaration, 45375 isLateBound: (nodeIn: Declaration): nodeIn is LateBoundDeclaration => { 45376 const node = getParseTreeNode(nodeIn, isDeclaration); 45377 const symbol = node && getSymbolOfNode(node); 45378 return !!(symbol && getCheckFlags(symbol) & CheckFlags.Late); 45379 }, 45380 getJsxFactoryEntity, 45381 getJsxFragmentFactoryEntity, 45382 getAllAccessorDeclarations(accessor: AccessorDeclaration): AllAccessorDeclarations { 45383 accessor = getParseTreeNode(accessor, isGetOrSetAccessorDeclaration)!; // TODO: GH#18217 45384 const otherKind = accessor.kind === SyntaxKind.SetAccessor ? SyntaxKind.GetAccessor : SyntaxKind.SetAccessor; 45385 const otherAccessor = getDeclarationOfKind<AccessorDeclaration>(getSymbolOfNode(accessor), otherKind); 45386 const firstAccessor = otherAccessor && (otherAccessor.pos < accessor.pos) ? otherAccessor : accessor; 45387 const secondAccessor = otherAccessor && (otherAccessor.pos < accessor.pos) ? accessor : otherAccessor; 45388 const setAccessor = accessor.kind === SyntaxKind.SetAccessor ? accessor : otherAccessor as SetAccessorDeclaration; 45389 const getAccessor = accessor.kind === SyntaxKind.GetAccessor ? accessor : otherAccessor as GetAccessorDeclaration; 45390 return { 45391 firstAccessor, 45392 secondAccessor, 45393 setAccessor, 45394 getAccessor 45395 }; 45396 }, 45397 getSymbolOfExternalModuleSpecifier: moduleName => resolveExternalModuleNameWorker(moduleName, moduleName, /*moduleNotFoundError*/ undefined), 45398 isBindingCapturedByNode: (node, decl) => { 45399 const parseNode = getParseTreeNode(node); 45400 const parseDecl = getParseTreeNode(decl); 45401 return !!parseNode && !!parseDecl && (isVariableDeclaration(parseDecl) || isBindingElement(parseDecl)) && isBindingCapturedByNode(parseNode, parseDecl); 45402 }, 45403 getDeclarationStatementsForSourceFile: (node, flags, tracker, bundled) => { 45404 const n = getParseTreeNode(node) as SourceFile; 45405 Debug.assert(n && n.kind === SyntaxKind.SourceFile, "Non-sourcefile node passed into getDeclarationsForSourceFile"); 45406 const sym = getSymbolOfNode(node); 45407 if (!sym) { 45408 return !node.locals ? [] : nodeBuilder.symbolTableToDeclarationStatements(node.locals, node, flags, tracker, bundled); 45409 } 45410 return !sym.exports ? [] : nodeBuilder.symbolTableToDeclarationStatements(sym.exports, node, flags, tracker, bundled); 45411 }, 45412 isImportRequiredByAugmentation, 45413 getAnnotationObjectLiteralEvaluatedProps: (node: Annotation): ESMap<__String, Expression> | undefined => { 45414 return getNodeLinks(node).annotationObjectLiteralEvaluatedProps; 45415 }, 45416 getAnnotationPropertyEvaluatedInitializer: (node: AnnotationPropertyDeclaration): Expression | undefined => { 45417 return getNodeLinks(node).annotationPropertyEvaluatedInitializer; 45418 }, 45419 getAnnotationPropertyInferredType: (node: AnnotationPropertyDeclaration): TypeNode | undefined => { 45420 return getNodeLinks(node).annotationPropertyInferredType; 45421 }, 45422 isReferredToAnnotation: (node: ImportSpecifier | ExportSpecifier | ExportAssignment): boolean | undefined => { 45423 return getNodeLinks(node).exportOrImportRefersToAnnotation; 45424 } 45425 }; 45426 45427 function isImportRequiredByAugmentation(node: ImportDeclaration) { 45428 const file = getSourceFileOfNode(node); 45429 if (!file.symbol) return false; 45430 const importTarget = getExternalModuleFileFromDeclaration(node); 45431 if (!importTarget) return false; 45432 if (importTarget === file) return false; 45433 const exports = getExportsOfModule(file.symbol); 45434 for (const s of arrayFrom(exports.values())) { 45435 if (s.mergeId) { 45436 const merged = getMergedSymbol(s); 45437 if (merged.declarations) { 45438 for (const d of merged.declarations) { 45439 const declFile = getSourceFileOfNode(d); 45440 if (declFile === importTarget) { 45441 return true; 45442 } 45443 } 45444 } 45445 } 45446 } 45447 return false; 45448 } 45449 45450 function isInHeritageClause(node: PropertyAccessEntityNameExpression) { 45451 return node.parent && node.parent.kind === SyntaxKind.ExpressionWithTypeArguments && node.parent.parent && node.parent.parent.kind === SyntaxKind.HeritageClause; 45452 } 45453 45454 // defined here to avoid outer scope pollution 45455 function getTypeReferenceDirectivesForEntityName(node: EntityNameOrEntityNameExpression): [specifier: string, mode: SourceFile["impliedNodeFormat"] | undefined][] | undefined { 45456 // program does not have any files with type reference directives - bail out 45457 if (!fileToDirective) { 45458 return undefined; 45459 } 45460 // computed property name should use node as value 45461 // property access can only be used as values, or types when within an expression with type arguments inside a heritage clause 45462 // qualified names can only be used as types\namespaces 45463 // identifiers are treated as values only if they appear in type queries 45464 let meaning; 45465 if (node.parent.kind === SyntaxKind.ComputedPropertyName) { 45466 meaning = SymbolFlags.Value | SymbolFlags.ExportValue; 45467 } 45468 else { 45469 meaning = SymbolFlags.Type | SymbolFlags.Namespace; 45470 if ((node.kind === SyntaxKind.Identifier && isInTypeQuery(node)) || (node.kind === SyntaxKind.PropertyAccessExpression && !isInHeritageClause(node))) { 45471 meaning = SymbolFlags.Value | SymbolFlags.ExportValue; 45472 } 45473 } 45474 45475 const symbol = resolveEntityName(node, meaning, /*ignoreErrors*/ true); 45476 return symbol && symbol !== unknownSymbol ? getTypeReferenceDirectivesForSymbol(symbol, meaning) : undefined; 45477 } 45478 45479 // defined here to avoid outer scope pollution 45480 function getTypeReferenceDirectivesForSymbol(symbol: Symbol, meaning?: SymbolFlags): [specifier: string, mode: SourceFile["impliedNodeFormat"] | undefined][] | undefined { 45481 // program does not have any files with type reference directives - bail out 45482 if (!fileToDirective || !isSymbolFromTypeDeclarationFile(symbol)) { 45483 return undefined; 45484 } 45485 // check what declarations in the symbol can contribute to the target meaning 45486 let typeReferenceDirectives: [specifier: string, mode: SourceFile["impliedNodeFormat"] | undefined][] | undefined; 45487 for (const decl of symbol.declarations!) { 45488 // check meaning of the local symbol to see if declaration needs to be analyzed further 45489 if (decl.symbol && decl.symbol.flags & meaning!) { 45490 const file = getSourceFileOfNode(decl); 45491 const typeReferenceDirective = fileToDirective.get(file.path); 45492 if (typeReferenceDirective) { 45493 (typeReferenceDirectives || (typeReferenceDirectives = [])).push(typeReferenceDirective); 45494 } 45495 else { 45496 // found at least one entry that does not originate from type reference directive 45497 return undefined; 45498 } 45499 } 45500 } 45501 return typeReferenceDirectives; 45502 } 45503 45504 function isSymbolFromTypeDeclarationFile(symbol: Symbol): boolean { 45505 // bail out if symbol does not have associated declarations (i.e. this is transient symbol created for property in binding pattern) 45506 if (!symbol.declarations) { 45507 return false; 45508 } 45509 45510 // walk the parent chain for symbols to make sure that top level parent symbol is in the global scope 45511 // external modules cannot define or contribute to type declaration files 45512 let current = symbol; 45513 while (true) { 45514 const parent = getParentOfSymbol(current); 45515 if (parent) { 45516 current = parent; 45517 } 45518 else { 45519 break; 45520 } 45521 } 45522 45523 if (current.valueDeclaration && current.valueDeclaration.kind === SyntaxKind.SourceFile && current.flags & SymbolFlags.ValueModule) { 45524 return false; 45525 } 45526 45527 // check that at least one declaration of top level symbol originates from type declaration file 45528 for (const decl of symbol.declarations) { 45529 const file = getSourceFileOfNode(decl); 45530 if (fileToDirective.has(file.path)) { 45531 return true; 45532 } 45533 } 45534 return false; 45535 } 45536 45537 function addReferencedFilesToTypeDirective(file: SourceFile, key: string, mode: SourceFile["impliedNodeFormat"] | undefined) { 45538 if (fileToDirective.has(file.path)) return; 45539 fileToDirective.set(file.path, [key, mode]); 45540 for (const { fileName, resolutionMode } of file.referencedFiles) { 45541 const resolvedFile = resolveTripleslashReference(fileName, file.fileName); 45542 const referencedFile = host.getSourceFile(resolvedFile); 45543 if (referencedFile) { 45544 addReferencedFilesToTypeDirective(referencedFile, key, resolutionMode || file.impliedNodeFormat); 45545 } 45546 } 45547 } 45548 } 45549 45550 function getExternalModuleFileFromDeclaration(declaration: AnyImportOrReExport | ModuleDeclaration | ImportTypeNode | ImportCall): SourceFile | undefined { 45551 const specifier = declaration.kind === SyntaxKind.ModuleDeclaration ? tryCast(declaration.name, isStringLiteral) : getExternalModuleName(declaration); 45552 const moduleSymbol = resolveExternalModuleNameWorker(specifier!, specifier!, /*moduleNotFoundError*/ undefined); // TODO: GH#18217 45553 if (!moduleSymbol) { 45554 return undefined; 45555 } 45556 return getDeclarationOfKind(moduleSymbol, SyntaxKind.SourceFile); 45557 } 45558 45559 function initializeTypeChecker() { 45560 // Bind all source files and propagate errors 45561 for (const file of host.getSourceFiles()) { 45562 bindSourceFile(file, compilerOptions); 45563 } 45564 45565 amalgamatedDuplicates = new Map(); 45566 45567 // Initialize global symbol table 45568 let augmentations: (readonly (StringLiteral | Identifier)[])[] | undefined; 45569 for (const file of host.getSourceFiles()) { 45570 if (file.redirectInfo) { 45571 continue; 45572 } 45573 if (!isExternalOrCommonJsModule(file)) { 45574 // It is an error for a non-external-module (i.e. script) to declare its own `globalThis`. 45575 // We can't use `builtinGlobals` for this due to synthetic expando-namespace generation in JS files. 45576 const fileGlobalThisSymbol = file.locals!.get("globalThis" as __String); 45577 if (fileGlobalThisSymbol?.declarations) { 45578 for (const declaration of fileGlobalThisSymbol.declarations) { 45579 diagnostics.add(createDiagnosticForNode(declaration, Diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0, "globalThis")); 45580 } 45581 } 45582 mergeSymbolTable(globals, file.locals!); 45583 } 45584 if (file.jsGlobalAugmentations) { 45585 mergeSymbolTable(globals, file.jsGlobalAugmentations); 45586 } 45587 if (file.patternAmbientModules && file.patternAmbientModules.length) { 45588 patternAmbientModules = concatenate(patternAmbientModules, file.patternAmbientModules); 45589 } 45590 if (file.moduleAugmentations.length) { 45591 (augmentations || (augmentations = [])).push(file.moduleAugmentations); 45592 } 45593 if (file.symbol && file.symbol.globalExports) { 45594 // Merge in UMD exports with first-in-wins semantics (see #9771) 45595 const source = file.symbol.globalExports; 45596 source.forEach((sourceSymbol, id) => { 45597 if (!globals.has(id)) { 45598 globals.set(id, sourceSymbol); 45599 } 45600 }); 45601 } 45602 } 45603 45604 // We do global augmentations separately from module augmentations (and before creating global types) because they 45605 // 1. Affect global types. We won't have the correct global types until global augmentations are merged. Also, 45606 // 2. Module augmentation instantiation requires creating the type of a module, which, in turn, can require 45607 // checking for an export or property on the module (if export=) which, in turn, can fall back to the 45608 // apparent type of the module - either globalObjectType or globalFunctionType - which wouldn't exist if we 45609 // did module augmentations prior to finalizing the global types. 45610 if (augmentations) { 45611 // merge _global_ module augmentations. 45612 // this needs to be done after global symbol table is initialized to make sure that all ambient modules are indexed 45613 for (const list of augmentations) { 45614 for (const augmentation of list) { 45615 if (!isGlobalScopeAugmentation(augmentation.parent as ModuleDeclaration)) continue; 45616 mergeModuleAugmentation(augmentation); 45617 } 45618 } 45619 } 45620 45621 // Setup global builtins 45622 addToSymbolTable(globals, builtinGlobals, Diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0); 45623 45624 getSymbolLinks(undefinedSymbol).type = undefinedWideningType; 45625 getSymbolLinks(argumentsSymbol).type = getGlobalType("IArguments" as __String, /*arity*/ 0, /*reportErrors*/ true); 45626 getSymbolLinks(unknownSymbol).type = errorType; 45627 getSymbolLinks(globalThisSymbol).type = createObjectType(ObjectFlags.Anonymous, globalThisSymbol); 45628 45629 // Initialize special types 45630 globalArrayType = getGlobalType("Array" as __String, /*arity*/ 1, /*reportErrors*/ true); 45631 globalObjectType = getGlobalType("Object" as __String, /*arity*/ 0, /*reportErrors*/ true); 45632 globalFunctionType = getGlobalType("Function" as __String, /*arity*/ 0, /*reportErrors*/ true); 45633 globalCallableFunctionType = strictBindCallApply && getGlobalType("CallableFunction" as __String, /*arity*/ 0, /*reportErrors*/ true) || globalFunctionType; 45634 globalNewableFunctionType = strictBindCallApply && getGlobalType("NewableFunction" as __String, /*arity*/ 0, /*reportErrors*/ true) || globalFunctionType; 45635 globalStringType = getGlobalType("String" as __String, /*arity*/ 0, /*reportErrors*/ true); 45636 globalNumberType = getGlobalType("Number" as __String, /*arity*/ 0, /*reportErrors*/ true); 45637 globalBooleanType = getGlobalType("Boolean" as __String, /*arity*/ 0, /*reportErrors*/ true); 45638 globalRegExpType = getGlobalType("RegExp" as __String, /*arity*/ 0, /*reportErrors*/ true); 45639 anyArrayType = createArrayType(anyType); 45640 45641 autoArrayType = createArrayType(autoType); 45642 if (autoArrayType === emptyObjectType) { 45643 // autoArrayType is used as a marker, so even if global Array type is not defined, it needs to be a unique type 45644 autoArrayType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, emptyArray); 45645 } 45646 45647 globalReadonlyArrayType = getGlobalTypeOrUndefined("ReadonlyArray" as __String, /*arity*/ 1) as GenericType || globalArrayType; 45648 anyReadonlyArrayType = globalReadonlyArrayType ? createTypeFromGenericGlobalType(globalReadonlyArrayType, [anyType]) : anyArrayType; 45649 globalThisType = getGlobalTypeOrUndefined("ThisType" as __String, /*arity*/ 1) as GenericType; 45650 45651 if (augmentations) { 45652 // merge _nonglobal_ module augmentations. 45653 // this needs to be done after global symbol table is initialized to make sure that all ambient modules are indexed 45654 for (const list of augmentations) { 45655 for (const augmentation of list) { 45656 if (isGlobalScopeAugmentation(augmentation.parent as ModuleDeclaration)) continue; 45657 mergeModuleAugmentation(augmentation); 45658 } 45659 } 45660 } 45661 45662 amalgamatedDuplicates.forEach(({ firstFile, secondFile, conflictingSymbols }) => { 45663 // If not many things conflict, issue individual errors 45664 if (conflictingSymbols.size < 8) { 45665 conflictingSymbols.forEach(({ isBlockScoped, firstFileLocations, secondFileLocations }, symbolName) => { 45666 const message = isBlockScoped ? Diagnostics.Cannot_redeclare_block_scoped_variable_0 : Diagnostics.Duplicate_identifier_0; 45667 for (const node of firstFileLocations) { 45668 addDuplicateDeclarationError(node, message, symbolName, secondFileLocations); 45669 } 45670 for (const node of secondFileLocations) { 45671 addDuplicateDeclarationError(node, message, symbolName, firstFileLocations); 45672 } 45673 }); 45674 } 45675 else { 45676 // Otherwise issue top-level error since the files appear very identical in terms of what they contain 45677 const list = arrayFrom(conflictingSymbols.keys()).join(", "); 45678 diagnostics.add(addRelatedInfo( 45679 createDiagnosticForNode(firstFile, Diagnostics.Definitions_of_the_following_identifiers_conflict_with_those_in_another_file_Colon_0, list), 45680 createDiagnosticForNode(secondFile, Diagnostics.Conflicts_are_in_this_file) 45681 )); 45682 diagnostics.add(addRelatedInfo( 45683 createDiagnosticForNode(secondFile, Diagnostics.Definitions_of_the_following_identifiers_conflict_with_those_in_another_file_Colon_0, list), 45684 createDiagnosticForNode(firstFile, Diagnostics.Conflicts_are_in_this_file) 45685 )); 45686 } 45687 }); 45688 amalgamatedDuplicates = undefined; 45689 } 45690 45691 function checkExternalEmitHelpers(location: Node, helpers: ExternalEmitHelpers) { 45692 if ((requestedExternalEmitHelpers & helpers) !== helpers && compilerOptions.importHelpers) { 45693 const sourceFile = getSourceFileOfNode(location); 45694 if (isEffectiveExternalModule(sourceFile, compilerOptions) && !(location.flags & NodeFlags.Ambient)) { 45695 const helpersModule = resolveHelpersModule(sourceFile, location); 45696 if (helpersModule !== unknownSymbol) { 45697 const uncheckedHelpers = helpers & ~requestedExternalEmitHelpers; 45698 for (let helper = ExternalEmitHelpers.FirstEmitHelper; helper <= ExternalEmitHelpers.LastEmitHelper; helper <<= 1) { 45699 if (uncheckedHelpers & helper) { 45700 const name = getHelperName(helper); 45701 const symbol = getSymbol(helpersModule.exports!, escapeLeadingUnderscores(name), SymbolFlags.Value); 45702 if (!symbol) { 45703 error(location, Diagnostics.This_syntax_requires_an_imported_helper_named_1_which_does_not_exist_in_0_Consider_upgrading_your_version_of_0, externalHelpersModuleNameText, name); 45704 } 45705 else if (helper & ExternalEmitHelpers.ClassPrivateFieldGet) { 45706 if (!some(getSignaturesOfSymbol(symbol), signature => getParameterCount(signature) > 3)) { 45707 error(location, Diagnostics.This_syntax_requires_an_imported_helper_named_1_with_2_parameters_which_is_not_compatible_with_the_one_in_0_Consider_upgrading_your_version_of_0, externalHelpersModuleNameText, name, 4); 45708 } 45709 } 45710 else if (helper & ExternalEmitHelpers.ClassPrivateFieldSet) { 45711 if (!some(getSignaturesOfSymbol(symbol), signature => getParameterCount(signature) > 4)) { 45712 error(location, Diagnostics.This_syntax_requires_an_imported_helper_named_1_with_2_parameters_which_is_not_compatible_with_the_one_in_0_Consider_upgrading_your_version_of_0, externalHelpersModuleNameText, name, 5); 45713 } 45714 } 45715 else if (helper & ExternalEmitHelpers.SpreadArray) { 45716 if (!some(getSignaturesOfSymbol(symbol), signature => getParameterCount(signature) > 2)) { 45717 error(location, Diagnostics.This_syntax_requires_an_imported_helper_named_1_with_2_parameters_which_is_not_compatible_with_the_one_in_0_Consider_upgrading_your_version_of_0, externalHelpersModuleNameText, name, 3); 45718 } 45719 } 45720 } 45721 } 45722 } 45723 requestedExternalEmitHelpers |= helpers; 45724 } 45725 } 45726 } 45727 45728 function getHelperName(helper: ExternalEmitHelpers) { 45729 switch (helper) { 45730 case ExternalEmitHelpers.Extends: return "__extends"; 45731 case ExternalEmitHelpers.Assign: return "__assign"; 45732 case ExternalEmitHelpers.Rest: return "__rest"; 45733 case ExternalEmitHelpers.Decorate: return "__decorate"; 45734 case ExternalEmitHelpers.Metadata: return "__metadata"; 45735 case ExternalEmitHelpers.Param: return "__param"; 45736 case ExternalEmitHelpers.Awaiter: return "__awaiter"; 45737 case ExternalEmitHelpers.Generator: return "__generator"; 45738 case ExternalEmitHelpers.Values: return "__values"; 45739 case ExternalEmitHelpers.Read: return "__read"; 45740 case ExternalEmitHelpers.SpreadArray: return "__spreadArray"; 45741 case ExternalEmitHelpers.Await: return "__await"; 45742 case ExternalEmitHelpers.AsyncGenerator: return "__asyncGenerator"; 45743 case ExternalEmitHelpers.AsyncDelegator: return "__asyncDelegator"; 45744 case ExternalEmitHelpers.AsyncValues: return "__asyncValues"; 45745 case ExternalEmitHelpers.ExportStar: return "__exportStar"; 45746 case ExternalEmitHelpers.ImportStar: return "__importStar"; 45747 case ExternalEmitHelpers.ImportDefault: return "__importDefault"; 45748 case ExternalEmitHelpers.MakeTemplateObject: return "__makeTemplateObject"; 45749 case ExternalEmitHelpers.ClassPrivateFieldGet: return "__classPrivateFieldGet"; 45750 case ExternalEmitHelpers.ClassPrivateFieldSet: return "__classPrivateFieldSet"; 45751 case ExternalEmitHelpers.ClassPrivateFieldIn: return "__classPrivateFieldIn"; 45752 case ExternalEmitHelpers.CreateBinding: return "__createBinding"; 45753 default: return Debug.fail("Unrecognized helper"); 45754 } 45755 } 45756 45757 function resolveHelpersModule(node: SourceFile, errorNode: Node) { 45758 if (!externalHelpersModule) { 45759 externalHelpersModule = resolveExternalModule(node, externalHelpersModuleNameText, Diagnostics.This_syntax_requires_an_imported_helper_but_module_0_cannot_be_found, errorNode) || unknownSymbol; 45760 } 45761 return externalHelpersModule; 45762 } 45763 45764 // GRAMMAR CHECKING 45765 function checkGrammarDecoratorsAndModifiers(node: HasModifiers | HasDecorators | HasIllegalModifiers | HasIllegalDecorators): boolean { 45766 return checkGrammarDecorators(node) || checkGrammarModifiers(node); 45767 } 45768 45769 function checkGrammarDecorators(node: Node): boolean { 45770 if (canHaveIllegalDecorators(node) && some(node.illegalDecorators) && !isArkTsDecorator(node, compilerOptions)) { 45771 if (isSendableFunctionOrType(node)) { 45772 return false; 45773 } 45774 return grammarErrorOnFirstToken(node, Diagnostics.Decorators_are_not_valid_here); 45775 } 45776 if (!canHaveDecorators(node) || !hasDecorators(node) && !(isFunctionDeclaration(node) && !isArkTsDecorator(node, compilerOptions))) { 45777 return false; 45778 } 45779 const decorators = getAllDecorators(node); 45780 if (getSourceFileOfNode(node).scriptKind === ScriptKind.ETS) { 45781 if (isTokenInsideBuilder(decorators, compilerOptions) && !isConstructorDeclaration(node)) { 45782 return false; 45783 } 45784 if (hasEtsStylesDecoratorNames(decorators, compilerOptions) && !isConstructorDeclaration(node)) { 45785 return true; 45786 } 45787 // const etsComponentDecoratorNames = getEtsExtendDecoratorsComponentNames(decorators, compilerOptions); 45788 // if (etsComponentDecoratorNames.length) { 45789 // const filtedEtsComponentNames = filterEtsExtendDecoratorComponentNamesByOptions(etsComponentDecoratorNames, compilerOptions); 45790 // if (filtedEtsComponentNames.length) { 45791 // return false; 45792 // } 45793 // const sourceFile = getSourceFileOfNode(node); 45794 // const span = getSpanOfTokenAtPosition(sourceFile, node.pos); 45795 // diagnostics.add(createFileDiagnostic(sourceFile, span.start, span.length, Diagnostics.Decorator_name_must_be_one_of_ETS_Components)); 45796 // return true; 45797 // } 45798 } 45799 45800 if (!nodeCanBeDecorated(node, node.parent, node.parent.parent, compilerOptions)) { 45801 const isMethodDeclarationAndNodeIsNotPresent = node.kind === SyntaxKind.MethodDeclaration && ! nodeIsPresent(node.body); 45802 const message = isMethodDeclarationAndNodeIsNotPresent ? Diagnostics.A_decorator_can_only_decorate_a_method_implementation_not_an_overload : Diagnostics.Decorators_are_not_valid_here; 45803 for (const decorator of decorators) { 45804 if (!grammarErrorOnNode(decorator, message)) { 45805 return false; 45806 } 45807 } 45808 return true; 45809 } 45810 else if (node.kind === SyntaxKind.GetAccessor || node.kind === SyntaxKind.SetAccessor) { 45811 const accessors = getAllAccessorDeclarations((node.parent as ClassDeclaration).members, node as AccessorDeclaration); 45812 if (hasDecorators(accessors.firstAccessor) && node === accessors.secondAccessor) { 45813 return grammarErrorOnFirstToken(node, Diagnostics.Decorators_cannot_be_applied_to_multiple_get_Slashset_accessors_of_the_same_name); 45814 } 45815 } 45816 return false; 45817 } 45818 45819 function checkGrammarModifiers(node: HasModifiers | HasIllegalModifiers): boolean { 45820 const quickResult = reportObviousModifierErrors(node); 45821 if (quickResult !== undefined) { 45822 return quickResult; 45823 } 45824 45825 let lastStatic: Node | undefined, lastDeclare: Node | undefined, lastAsync: Node | undefined, lastOverride: Node | undefined; 45826 let flags = ModifierFlags.None; 45827 for (const modifier of node.modifiers!) { 45828 if (isDecorator(modifier)) continue; 45829 if (modifier.kind !== SyntaxKind.ReadonlyKeyword) { 45830 if (node.kind === SyntaxKind.PropertySignature || node.kind === SyntaxKind.MethodSignature) { 45831 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_type_member, tokenToString(modifier.kind)); 45832 } 45833 if (node.kind === SyntaxKind.IndexSignature && (modifier.kind !== SyntaxKind.StaticKeyword || !isClassLike(node.parent))) { 45834 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_an_index_signature, tokenToString(modifier.kind)); 45835 } 45836 } 45837 if (modifier.kind !== SyntaxKind.InKeyword && modifier.kind !== SyntaxKind.OutKeyword) { 45838 if (node.kind === SyntaxKind.TypeParameter) { 45839 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_type_parameter, tokenToString(modifier.kind)); 45840 } 45841 } 45842 switch (modifier.kind) { 45843 case SyntaxKind.ConstKeyword: 45844 if (node.kind !== SyntaxKind.EnumDeclaration) { 45845 return grammarErrorOnNode(node, Diagnostics.A_class_member_cannot_have_the_0_keyword, tokenToString(SyntaxKind.ConstKeyword)); 45846 } 45847 break; 45848 case SyntaxKind.OverrideKeyword: 45849 // If node.kind === SyntaxKind.Parameter, checkParameter reports an error if it's not a parameter property. 45850 if (flags & ModifierFlags.Override) { 45851 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "override"); 45852 } 45853 else if (flags & ModifierFlags.Ambient) { 45854 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "override", "declare"); 45855 } 45856 else if (flags & ModifierFlags.Readonly) { 45857 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "override", "readonly"); 45858 } 45859 else if (flags & ModifierFlags.Accessor) { 45860 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "override", "accessor"); 45861 } 45862 else if (flags & ModifierFlags.Async) { 45863 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "override", "async"); 45864 } 45865 flags |= ModifierFlags.Override; 45866 lastOverride = modifier; 45867 break; 45868 45869 case SyntaxKind.PublicKeyword: 45870 case SyntaxKind.ProtectedKeyword: 45871 case SyntaxKind.PrivateKeyword: 45872 const text = visibilityToString(modifierToFlag(modifier.kind)); 45873 45874 if (flags & ModifierFlags.AccessibilityModifier) { 45875 return grammarErrorOnNode(modifier, Diagnostics.Accessibility_modifier_already_seen); 45876 } 45877 else if (flags & ModifierFlags.Override) { 45878 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "override"); 45879 } 45880 else if (flags & ModifierFlags.Static) { 45881 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "static"); 45882 } 45883 else if (flags & ModifierFlags.Accessor) { 45884 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "accessor"); 45885 } 45886 else if (flags & ModifierFlags.Readonly) { 45887 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "readonly"); 45888 } 45889 else if (flags & ModifierFlags.Async) { 45890 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "async"); 45891 } 45892 else if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) { 45893 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element, text); 45894 } 45895 else if (flags & ModifierFlags.Abstract) { 45896 if (modifier.kind === SyntaxKind.PrivateKeyword) { 45897 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, text, "abstract"); 45898 } 45899 else { 45900 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "abstract"); 45901 } 45902 } 45903 else if (isPrivateIdentifierClassElementDeclaration(node)) { 45904 return grammarErrorOnNode(modifier, Diagnostics.An_accessibility_modifier_cannot_be_used_with_a_private_identifier); 45905 } 45906 flags |= modifierToFlag(modifier.kind); 45907 break; 45908 45909 case SyntaxKind.StaticKeyword: 45910 if (flags & ModifierFlags.Static) { 45911 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "static"); 45912 } 45913 else if (flags & ModifierFlags.Readonly) { 45914 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "static", "readonly"); 45915 } 45916 else if (flags & ModifierFlags.Async) { 45917 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "static", "async"); 45918 } 45919 else if (flags & ModifierFlags.Accessor) { 45920 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "static", "accessor"); 45921 } 45922 else if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) { 45923 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element, "static"); 45924 } 45925 else if (node.kind === SyntaxKind.Parameter) { 45926 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "static"); 45927 } 45928 else if (flags & ModifierFlags.Abstract) { 45929 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "static", "abstract"); 45930 } 45931 else if (flags & ModifierFlags.Override) { 45932 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "static", "override"); 45933 } 45934 flags |= ModifierFlags.Static; 45935 lastStatic = modifier; 45936 break; 45937 45938 case SyntaxKind.AccessorKeyword: 45939 if (flags & ModifierFlags.Accessor) { 45940 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "accessor"); 45941 } 45942 else if (flags & ModifierFlags.Readonly) { 45943 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "accessor", "readonly"); 45944 } 45945 else if (flags & ModifierFlags.Ambient) { 45946 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "accessor", "declare"); 45947 } 45948 else if (node.kind !== SyntaxKind.PropertyDeclaration) { 45949 return grammarErrorOnNode(modifier, Diagnostics.accessor_modifier_can_only_appear_on_a_property_declaration); 45950 } 45951 45952 flags |= ModifierFlags.Accessor; 45953 break; 45954 45955 case SyntaxKind.ReadonlyKeyword: 45956 if (flags & ModifierFlags.Readonly) { 45957 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "readonly"); 45958 } 45959 else if (node.kind !== SyntaxKind.PropertyDeclaration && node.kind !== SyntaxKind.PropertySignature && node.kind !== SyntaxKind.IndexSignature && node.kind !== SyntaxKind.Parameter) { 45960 // If node.kind === SyntaxKind.Parameter, checkParameter reports an error if it's not a parameter property. 45961 return grammarErrorOnNode(modifier, Diagnostics.readonly_modifier_can_only_appear_on_a_property_declaration_or_index_signature); 45962 } 45963 flags |= ModifierFlags.Readonly; 45964 break; 45965 45966 case SyntaxKind.ExportKeyword: 45967 if (flags & ModifierFlags.Export) { 45968 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "export"); 45969 } 45970 else if (flags & ModifierFlags.Ambient) { 45971 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "export", "declare"); 45972 } 45973 else if (flags & ModifierFlags.Abstract) { 45974 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "export", "abstract"); 45975 } 45976 else if (flags & ModifierFlags.Async) { 45977 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "export", "async"); 45978 } 45979 else if (isClassLike(node.parent)) { 45980 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_class_elements_of_this_kind, "export"); 45981 } 45982 else if (node.kind === SyntaxKind.Parameter) { 45983 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "export"); 45984 } 45985 flags |= ModifierFlags.Export; 45986 break; 45987 case SyntaxKind.DefaultKeyword: 45988 const container = node.parent.kind === SyntaxKind.SourceFile ? node.parent : node.parent.parent; 45989 if (container.kind === SyntaxKind.ModuleDeclaration && !isAmbientModule(container)) { 45990 return grammarErrorOnNode(modifier, Diagnostics.A_default_export_can_only_be_used_in_an_ECMAScript_style_module); 45991 } 45992 else if (!(flags & ModifierFlags.Export)) { 45993 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "export", "default"); 45994 } 45995 45996 flags |= ModifierFlags.Default; 45997 break; 45998 case SyntaxKind.DeclareKeyword: 45999 if (flags & ModifierFlags.Ambient) { 46000 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "declare"); 46001 } 46002 else if (flags & ModifierFlags.Async) { 46003 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, "async"); 46004 } 46005 else if (flags & ModifierFlags.Override) { 46006 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, "override"); 46007 } 46008 else if (isClassLike(node.parent) && !isPropertyDeclaration(node)) { 46009 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_class_elements_of_this_kind, "declare"); 46010 } 46011 else if (node.kind === SyntaxKind.Parameter) { 46012 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "declare"); 46013 } 46014 else if ((node.parent.flags & NodeFlags.Ambient) && node.parent.kind === SyntaxKind.ModuleBlock) { 46015 return grammarErrorOnNode(modifier, Diagnostics.A_declare_modifier_cannot_be_used_in_an_already_ambient_context); 46016 } 46017 else if (isPrivateIdentifierClassElementDeclaration(node)) { 46018 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_a_private_identifier, "declare"); 46019 } 46020 flags |= ModifierFlags.Ambient; 46021 lastDeclare = modifier; 46022 break; 46023 46024 case SyntaxKind.AbstractKeyword: 46025 if (flags & ModifierFlags.Abstract) { 46026 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "abstract"); 46027 } 46028 if (node.kind !== SyntaxKind.ClassDeclaration && 46029 node.kind !== SyntaxKind.ConstructorType) { 46030 if (node.kind !== SyntaxKind.MethodDeclaration && 46031 node.kind !== SyntaxKind.PropertyDeclaration && 46032 node.kind !== SyntaxKind.GetAccessor && 46033 node.kind !== SyntaxKind.SetAccessor) { 46034 return grammarErrorOnNode(modifier, Diagnostics.abstract_modifier_can_only_appear_on_a_class_method_or_property_declaration); 46035 } 46036 if (!(node.parent.kind === SyntaxKind.ClassDeclaration && hasSyntacticModifier(node.parent, ModifierFlags.Abstract))) { 46037 return grammarErrorOnNode(modifier, Diagnostics.Abstract_methods_can_only_appear_within_an_abstract_class); 46038 } 46039 if (flags & ModifierFlags.Static) { 46040 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "static", "abstract"); 46041 } 46042 if (flags & ModifierFlags.Private) { 46043 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "private", "abstract"); 46044 } 46045 if (flags & ModifierFlags.Async && lastAsync) { 46046 return grammarErrorOnNode(lastAsync, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "async", "abstract"); 46047 } 46048 if (flags & ModifierFlags.Override) { 46049 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "abstract", "override"); 46050 } 46051 if (flags & ModifierFlags.Accessor) { 46052 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "abstract", "accessor"); 46053 } 46054 } 46055 if (isNamedDeclaration(node) && node.name.kind === SyntaxKind.PrivateIdentifier) { 46056 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_a_private_identifier, "abstract"); 46057 } 46058 46059 flags |= ModifierFlags.Abstract; 46060 break; 46061 46062 case SyntaxKind.AsyncKeyword: 46063 if (flags & ModifierFlags.Async) { 46064 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "async"); 46065 } 46066 else if (flags & ModifierFlags.Ambient || node.parent.flags & NodeFlags.Ambient) { 46067 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, "async"); 46068 } 46069 else if (node.kind === SyntaxKind.Parameter) { 46070 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "async"); 46071 } 46072 if (flags & ModifierFlags.Abstract) { 46073 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "async", "abstract"); 46074 } 46075 flags |= ModifierFlags.Async; 46076 lastAsync = modifier; 46077 break; 46078 46079 case SyntaxKind.InKeyword: 46080 case SyntaxKind.OutKeyword: 46081 const inOutFlag = modifier.kind === SyntaxKind.InKeyword ? ModifierFlags.In : ModifierFlags.Out; 46082 const inOutText = modifier.kind === SyntaxKind.InKeyword ? "in" : "out"; 46083 if (node.kind !== SyntaxKind.TypeParameter || !(isInterfaceDeclaration(node.parent) || isClassLike(node.parent) || isTypeAliasDeclaration(node.parent))) { 46084 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_can_only_appear_on_a_type_parameter_of_a_class_interface_or_type_alias, inOutText); 46085 } 46086 if (flags & inOutFlag) { 46087 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, inOutText); 46088 } 46089 if (inOutFlag & ModifierFlags.In && flags & ModifierFlags.Out) { 46090 return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "in", "out"); 46091 } 46092 flags |= inOutFlag; 46093 break; 46094 } 46095 } 46096 46097 if (node.kind === SyntaxKind.Constructor) { 46098 if (flags & ModifierFlags.Static) { 46099 return grammarErrorOnNode(lastStatic!, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "static"); 46100 } 46101 if (flags & ModifierFlags.Override) { 46102 return grammarErrorOnNode(lastOverride!, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "override"); // TODO: GH#18217 46103 } 46104 if (flags & ModifierFlags.Async) { 46105 return grammarErrorOnNode(lastAsync!, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "async"); 46106 } 46107 return false; 46108 } 46109 else if ((node.kind === SyntaxKind.ImportDeclaration || node.kind === SyntaxKind.ImportEqualsDeclaration) && flags & ModifierFlags.Ambient) { 46110 return grammarErrorOnNode(lastDeclare!, Diagnostics.A_0_modifier_cannot_be_used_with_an_import_declaration, "declare"); 46111 } 46112 else if (node.kind === SyntaxKind.Parameter && (flags & ModifierFlags.ParameterPropertyModifier) && isBindingPattern(node.name)) { 46113 return grammarErrorOnNode(node, Diagnostics.A_parameter_property_may_not_be_declared_using_a_binding_pattern); 46114 } 46115 else if (node.kind === SyntaxKind.Parameter && (flags & ModifierFlags.ParameterPropertyModifier) && node.dotDotDotToken) { 46116 return grammarErrorOnNode(node, Diagnostics.A_parameter_property_cannot_be_declared_using_a_rest_parameter); 46117 } 46118 if (flags & ModifierFlags.Async) { 46119 return checkGrammarAsyncModifier(node, lastAsync!); 46120 } 46121 return false; 46122 } 46123 46124 /** 46125 * true | false: Early return this value from checkGrammarModifiers. 46126 * undefined: Need to do full checking on the modifiers. 46127 */ 46128 function reportObviousModifierErrors(node: HasModifiers | HasIllegalModifiers): boolean | undefined { 46129 return !node.modifiers 46130 ? false 46131 : shouldReportBadModifier(node) 46132 ? grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here) 46133 : undefined; 46134 } 46135 46136 function shouldReportBadModifier(node: HasModifiers | HasIllegalModifiers): boolean { 46137 switch (node.kind) { 46138 case SyntaxKind.GetAccessor: 46139 case SyntaxKind.SetAccessor: 46140 case SyntaxKind.Constructor: 46141 case SyntaxKind.PropertyDeclaration: 46142 case SyntaxKind.PropertySignature: 46143 case SyntaxKind.MethodDeclaration: 46144 case SyntaxKind.MethodSignature: 46145 case SyntaxKind.IndexSignature: 46146 case SyntaxKind.ModuleDeclaration: 46147 case SyntaxKind.ImportDeclaration: 46148 case SyntaxKind.ImportEqualsDeclaration: 46149 case SyntaxKind.ExportDeclaration: 46150 case SyntaxKind.ExportAssignment: 46151 case SyntaxKind.FunctionExpression: 46152 case SyntaxKind.ArrowFunction: 46153 case SyntaxKind.Parameter: 46154 case SyntaxKind.TypeParameter: 46155 return false; 46156 case SyntaxKind.ClassStaticBlockDeclaration: 46157 case SyntaxKind.PropertyAssignment: 46158 case SyntaxKind.ShorthandPropertyAssignment: 46159 case SyntaxKind.NamespaceExportDeclaration: 46160 case SyntaxKind.FunctionType: 46161 case SyntaxKind.MissingDeclaration: 46162 return true; 46163 default: 46164 if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) { 46165 return false; 46166 } 46167 switch (node.kind) { 46168 case SyntaxKind.FunctionDeclaration: 46169 return nodeHasAnyModifiersExcept(node, SyntaxKind.AsyncKeyword); 46170 case SyntaxKind.ClassDeclaration: 46171 case SyntaxKind.StructDeclaration: 46172 case SyntaxKind.AnnotationDeclaration: 46173 case SyntaxKind.ConstructorType: 46174 return nodeHasAnyModifiersExcept(node, SyntaxKind.AbstractKeyword); 46175 case SyntaxKind.ClassExpression: 46176 case SyntaxKind.InterfaceDeclaration: 46177 case SyntaxKind.VariableStatement: 46178 case SyntaxKind.TypeAliasDeclaration: 46179 return true; 46180 case SyntaxKind.EnumDeclaration: 46181 return nodeHasAnyModifiersExcept(node, SyntaxKind.ConstKeyword); 46182 default: 46183 Debug.assertNever(node); 46184 } 46185 } 46186 } 46187 46188 function nodeHasAnyModifiersExcept(node: HasModifiers, allowedModifier: SyntaxKind): boolean { 46189 for (const modifier of node.modifiers!) { 46190 if (isDecorator(modifier)) continue; 46191 return modifier.kind !== allowedModifier; 46192 } 46193 return false; 46194 } 46195 46196 function checkGrammarAsyncModifier(node: Node, asyncModifier: Node): boolean { 46197 switch (node.kind) { 46198 case SyntaxKind.MethodDeclaration: 46199 case SyntaxKind.FunctionDeclaration: 46200 case SyntaxKind.FunctionExpression: 46201 case SyntaxKind.ArrowFunction: 46202 return false; 46203 } 46204 46205 return grammarErrorOnNode(asyncModifier, Diagnostics._0_modifier_cannot_be_used_here, "async"); 46206 } 46207 46208 function checkGrammarForDisallowedTrailingComma(list: NodeArray<Node> | undefined, diag = Diagnostics.Trailing_comma_not_allowed): boolean { 46209 if (list && list.hasTrailingComma) { 46210 return grammarErrorAtPos(list[0], list.end - ",".length, ",".length, diag); 46211 } 46212 return false; 46213 } 46214 46215 function checkGrammarTypeParameterList(typeParameters: NodeArray<TypeParameterDeclaration> | undefined, file: SourceFile): boolean { 46216 if (typeParameters && typeParameters.length === 0) { 46217 const start = typeParameters.pos - "<".length; 46218 const end = skipTrivia(file.text, typeParameters.end) + ">".length; 46219 return grammarErrorAtPos(file, start, end - start, Diagnostics.Type_parameter_list_cannot_be_empty); 46220 } 46221 return false; 46222 } 46223 46224 function checkGrammarParameterList(parameters: NodeArray<ParameterDeclaration>) { 46225 let seenOptionalParameter = false; 46226 const parameterCount = parameters.length; 46227 46228 for (let i = 0; i < parameterCount; i++) { 46229 const parameter = parameters[i]; 46230 if (parameter.dotDotDotToken) { 46231 if (i !== (parameterCount - 1)) { 46232 return grammarErrorOnNode(parameter.dotDotDotToken, Diagnostics.A_rest_parameter_must_be_last_in_a_parameter_list); 46233 } 46234 if (!(parameter.flags & NodeFlags.Ambient)) { // Allow `...foo,` in ambient declarations; see GH#23070 46235 checkGrammarForDisallowedTrailingComma(parameters, Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma); 46236 } 46237 46238 if (parameter.questionToken) { 46239 return grammarErrorOnNode(parameter.questionToken, Diagnostics.A_rest_parameter_cannot_be_optional); 46240 } 46241 46242 if (parameter.initializer) { 46243 return grammarErrorOnNode(parameter.name, Diagnostics.A_rest_parameter_cannot_have_an_initializer); 46244 } 46245 } 46246 else if (isOptionalParameter(parameter)) { 46247 seenOptionalParameter = true; 46248 if (parameter.questionToken && parameter.initializer) { 46249 return grammarErrorOnNode(parameter.name, Diagnostics.Parameter_cannot_have_question_mark_and_initializer); 46250 } 46251 } 46252 else if (seenOptionalParameter && !parameter.initializer) { 46253 return grammarErrorOnNode(parameter.name, Diagnostics.A_required_parameter_cannot_follow_an_optional_parameter); 46254 } 46255 } 46256 } 46257 46258 function getNonSimpleParameters(parameters: readonly ParameterDeclaration[]): readonly ParameterDeclaration[] { 46259 return filter(parameters, parameter => !!parameter.initializer || isBindingPattern(parameter.name) || isRestParameter(parameter)); 46260 } 46261 46262 function checkGrammarForUseStrictSimpleParameterList(node: FunctionLikeDeclaration): boolean { 46263 if (languageVersion >= ScriptTarget.ES2016) { 46264 const useStrictDirective = node.body && isBlock(node.body) && findUseStrictPrologue(node.body.statements); 46265 if (useStrictDirective) { 46266 const nonSimpleParameters = getNonSimpleParameters(node.parameters); 46267 if (length(nonSimpleParameters)) { 46268 forEach(nonSimpleParameters, parameter => { 46269 addRelatedInfo( 46270 error(parameter, Diagnostics.This_parameter_is_not_allowed_with_use_strict_directive), 46271 createDiagnosticForNode(useStrictDirective, Diagnostics.use_strict_directive_used_here) 46272 ); 46273 }); 46274 46275 const diagnostics = nonSimpleParameters.map((parameter, index) => ( 46276 index === 0 ? createDiagnosticForNode(parameter, Diagnostics.Non_simple_parameter_declared_here) : createDiagnosticForNode(parameter, Diagnostics.and_here) 46277 )) as [DiagnosticWithLocation, ...DiagnosticWithLocation[]]; 46278 addRelatedInfo(error(useStrictDirective, Diagnostics.use_strict_directive_cannot_be_used_with_non_simple_parameter_list), ...diagnostics); 46279 return true; 46280 } 46281 } 46282 } 46283 return false; 46284 } 46285 46286 function checkGrammarFunctionLikeDeclaration(node: FunctionLikeDeclaration | MethodSignature): boolean { 46287 // Prevent cascading error by short-circuit 46288 const file = getSourceFileOfNode(node); 46289 return checkGrammarDecoratorsAndModifiers(node) || 46290 checkGrammarTypeParameterList(node.typeParameters, file) || 46291 checkGrammarParameterList(node.parameters) || 46292 checkGrammarArrowFunction(node, file) || 46293 (isFunctionLikeDeclaration(node) && checkGrammarForUseStrictSimpleParameterList(node)); 46294 } 46295 46296 function checkGrammarClassLikeDeclaration(node: ClassLikeDeclaration): boolean { 46297 const file = getSourceFileOfNode(node); 46298 return checkGrammarClassDeclarationHeritageClauses(node) || 46299 checkGrammarTypeParameterList(node.typeParameters, file); 46300 } 46301 46302 function checkGrammarArrowFunction(node: Node, file: SourceFile): boolean { 46303 if (!isArrowFunction(node)) { 46304 return false; 46305 } 46306 46307 if (node.typeParameters && !(length(node.typeParameters) > 1 || node.typeParameters.hasTrailingComma || node.typeParameters[0].constraint)) { 46308 if (file && fileExtensionIsOneOf(file.fileName, [Extension.Mts, Extension.Cts])) { 46309 grammarErrorOnNode(node.typeParameters[0], Diagnostics.This_syntax_is_reserved_in_files_with_the_mts_or_cts_extension_Add_a_trailing_comma_or_explicit_constraint); 46310 } 46311 } 46312 46313 const { equalsGreaterThanToken } = node; 46314 const startLine = getLineAndCharacterOfPosition(file, equalsGreaterThanToken.pos).line; 46315 const endLine = getLineAndCharacterOfPosition(file, equalsGreaterThanToken.end).line; 46316 return startLine !== endLine && grammarErrorOnNode(equalsGreaterThanToken, Diagnostics.Line_terminator_not_permitted_before_arrow); 46317 } 46318 46319 function checkGrammarIndexSignatureParameters(node: SignatureDeclaration): boolean { 46320 const parameter = node.parameters[0]; 46321 if (node.parameters.length !== 1) { 46322 if (parameter) { 46323 return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_must_have_exactly_one_parameter); 46324 } 46325 else { 46326 return grammarErrorOnNode(node, Diagnostics.An_index_signature_must_have_exactly_one_parameter); 46327 } 46328 } 46329 checkGrammarForDisallowedTrailingComma(node.parameters, Diagnostics.An_index_signature_cannot_have_a_trailing_comma); 46330 if (parameter.dotDotDotToken) { 46331 return grammarErrorOnNode(parameter.dotDotDotToken, Diagnostics.An_index_signature_cannot_have_a_rest_parameter); 46332 } 46333 if (hasEffectiveModifiers(parameter)) { 46334 return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_cannot_have_an_accessibility_modifier); 46335 } 46336 if (parameter.questionToken) { 46337 return grammarErrorOnNode(parameter.questionToken, Diagnostics.An_index_signature_parameter_cannot_have_a_question_mark); 46338 } 46339 if (parameter.initializer) { 46340 return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_cannot_have_an_initializer); 46341 } 46342 if (!parameter.type) { 46343 return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_must_have_a_type_annotation); 46344 } 46345 const type = getTypeFromTypeNode(parameter.type); 46346 if (someType(type, t => !!(t.flags & TypeFlags.StringOrNumberLiteralOrUnique)) || isGenericType(type)) { 46347 return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_type_cannot_be_a_literal_type_or_generic_type_Consider_using_a_mapped_object_type_instead); 46348 } 46349 if (!everyType(type, isValidIndexKeyType)) { 46350 return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_type_must_be_string_number_symbol_or_a_template_literal_type); 46351 } 46352 if (!node.type) { 46353 return grammarErrorOnNode(node, Diagnostics.An_index_signature_must_have_a_type_annotation); 46354 } 46355 return false; 46356 } 46357 46358 function checkGrammarIndexSignature(node: IndexSignatureDeclaration) { 46359 // Prevent cascading error by short-circuit 46360 return checkGrammarDecoratorsAndModifiers(node) || checkGrammarIndexSignatureParameters(node); 46361 } 46362 46363 function checkGrammarForAtLeastOneTypeArgument(node: Node, typeArguments: NodeArray<TypeNode> | undefined): boolean { 46364 if (typeArguments && typeArguments.length === 0) { 46365 const sourceFile = getSourceFileOfNode(node); 46366 const start = typeArguments.pos - "<".length; 46367 const end = skipTrivia(sourceFile.text, typeArguments.end) + ">".length; 46368 return grammarErrorAtPos(sourceFile, start, end - start, Diagnostics.Type_argument_list_cannot_be_empty); 46369 } 46370 return false; 46371 } 46372 46373 function checkGrammarTypeArguments(node: Node, typeArguments: NodeArray<TypeNode> | undefined): boolean { 46374 return checkGrammarForDisallowedTrailingComma(typeArguments) || 46375 checkGrammarForAtLeastOneTypeArgument(node, typeArguments); 46376 } 46377 46378 function checkGrammarTaggedTemplateChain(node: TaggedTemplateExpression): boolean { 46379 if (node.questionDotToken || node.flags & NodeFlags.OptionalChain) { 46380 return grammarErrorOnNode(node.template, Diagnostics.Tagged_template_expressions_are_not_permitted_in_an_optional_chain); 46381 } 46382 return false; 46383 } 46384 46385 function checkGrammarHeritageClause(node: HeritageClause): boolean { 46386 const types = node.types; 46387 if (checkGrammarForDisallowedTrailingComma(types)) { 46388 return true; 46389 } 46390 if (types && types.length === 0) { 46391 const listType = tokenToString(node.token); 46392 return grammarErrorAtPos(node, types.pos, 0, Diagnostics._0_list_cannot_be_empty, listType); 46393 } 46394 return some(types, checkGrammarExpressionWithTypeArguments); 46395 } 46396 46397 function checkGrammarExpressionWithTypeArguments(node: ExpressionWithTypeArguments | TypeQueryNode) { 46398 if (isExpressionWithTypeArguments(node) && isImportKeyword(node.expression) && node.typeArguments) { 46399 return grammarErrorOnNode(node, Diagnostics.This_use_of_import_is_invalid_import_calls_can_be_written_but_they_must_have_parentheses_and_cannot_have_type_arguments); 46400 } 46401 return checkGrammarTypeArguments(node, node.typeArguments); 46402 } 46403 46404 function checkGrammarClassDeclarationHeritageClauses(node: ClassLikeDeclaration) { 46405 let seenExtendsClause = false; 46406 let seenImplementsClause = false; 46407 46408 if (!checkGrammarDecoratorsAndModifiers(node) && node.heritageClauses) { 46409 for (const heritageClause of node.heritageClauses) { 46410 if (heritageClause.token === SyntaxKind.ExtendsKeyword) { 46411 if (seenExtendsClause) { 46412 return grammarErrorOnFirstToken(heritageClause, Diagnostics.extends_clause_already_seen); 46413 } 46414 46415 if (seenImplementsClause) { 46416 return grammarErrorOnFirstToken(heritageClause, Diagnostics.extends_clause_must_precede_implements_clause); 46417 } 46418 46419 if (heritageClause.types.length > 1) { 46420 return grammarErrorOnFirstToken(heritageClause.types[1], Diagnostics.Classes_can_only_extend_a_single_class); 46421 } 46422 46423 seenExtendsClause = true; 46424 } 46425 else { 46426 Debug.assert(heritageClause.token === SyntaxKind.ImplementsKeyword); 46427 if (seenImplementsClause) { 46428 return grammarErrorOnFirstToken(heritageClause, Diagnostics.implements_clause_already_seen); 46429 } 46430 46431 seenImplementsClause = true; 46432 } 46433 46434 // Grammar checking heritageClause inside class declaration 46435 checkGrammarHeritageClause(heritageClause); 46436 } 46437 } 46438 } 46439 46440 function checkGrammarInterfaceDeclaration(node: InterfaceDeclaration) { 46441 let seenExtendsClause = false; 46442 46443 if (node.heritageClauses) { 46444 for (const heritageClause of node.heritageClauses) { 46445 if (heritageClause.token === SyntaxKind.ExtendsKeyword) { 46446 if (seenExtendsClause) { 46447 return grammarErrorOnFirstToken(heritageClause, Diagnostics.extends_clause_already_seen); 46448 } 46449 46450 seenExtendsClause = true; 46451 } 46452 else { 46453 Debug.assert(heritageClause.token === SyntaxKind.ImplementsKeyword); 46454 return grammarErrorOnFirstToken(heritageClause, Diagnostics.Interface_declaration_cannot_have_implements_clause); 46455 } 46456 46457 // Grammar checking heritageClause inside class declaration 46458 checkGrammarHeritageClause(heritageClause); 46459 } 46460 } 46461 return false; 46462 } 46463 46464 function checkGrammarComputedPropertyName(node: Node): boolean { 46465 // If node is not a computedPropertyName, just skip the grammar checking 46466 if (node.kind !== SyntaxKind.ComputedPropertyName) { 46467 return false; 46468 } 46469 46470 const computedPropertyName = node as ComputedPropertyName; 46471 if (computedPropertyName.expression.kind === SyntaxKind.BinaryExpression && (computedPropertyName.expression as BinaryExpression).operatorToken.kind === SyntaxKind.CommaToken) { 46472 return grammarErrorOnNode(computedPropertyName.expression, Diagnostics.A_comma_expression_is_not_allowed_in_a_computed_property_name); 46473 } 46474 return false; 46475 } 46476 46477 function checkGrammarForGenerator(node: FunctionLikeDeclaration) { 46478 if (node.asteriskToken) { 46479 Debug.assert( 46480 node.kind === SyntaxKind.FunctionDeclaration || 46481 node.kind === SyntaxKind.FunctionExpression || 46482 node.kind === SyntaxKind.MethodDeclaration); 46483 if (node.flags & NodeFlags.Ambient) { 46484 return grammarErrorOnNode(node.asteriskToken, Diagnostics.Generators_are_not_allowed_in_an_ambient_context); 46485 } 46486 if (!node.body) { 46487 return grammarErrorOnNode(node.asteriskToken, Diagnostics.An_overload_signature_cannot_be_declared_as_a_generator); 46488 } 46489 } 46490 } 46491 46492 function checkGrammarForInvalidQuestionMark(questionToken: QuestionToken | undefined, message: DiagnosticMessage): boolean { 46493 return !!questionToken && grammarErrorOnNode(questionToken, message); 46494 } 46495 46496 function checkGrammarForInvalidExclamationToken(exclamationToken: ExclamationToken | undefined, message: DiagnosticMessage): boolean { 46497 return !!exclamationToken && grammarErrorOnNode(exclamationToken, message); 46498 } 46499 46500 function checkGrammarObjectLiteralExpression(node: ObjectLiteralExpression, inDestructuring: boolean) { 46501 const seen = new Map<__String, DeclarationMeaning>(); 46502 46503 for (const prop of node.properties) { 46504 if (prop.kind === SyntaxKind.SpreadAssignment) { 46505 if (inDestructuring) { 46506 // a rest property cannot be destructured any further 46507 const expression = skipParentheses(prop.expression); 46508 if (isArrayLiteralExpression(expression) || isObjectLiteralExpression(expression)) { 46509 return grammarErrorOnNode(prop.expression, Diagnostics.A_rest_element_cannot_contain_a_binding_pattern); 46510 } 46511 } 46512 continue; 46513 } 46514 const name = prop.name; 46515 if (name.kind === SyntaxKind.ComputedPropertyName) { 46516 // If the name is not a ComputedPropertyName, the grammar checking will skip it 46517 checkGrammarComputedPropertyName(name); 46518 } 46519 46520 if (prop.kind === SyntaxKind.ShorthandPropertyAssignment && !inDestructuring && prop.objectAssignmentInitializer) { 46521 // having objectAssignmentInitializer is only valid in ObjectAssignmentPattern 46522 // outside of destructuring it is a syntax error 46523 grammarErrorOnNode(prop.equalsToken!, Diagnostics.Did_you_mean_to_use_a_Colon_An_can_only_follow_a_property_name_when_the_containing_object_literal_is_part_of_a_destructuring_pattern); 46524 } 46525 46526 if (name.kind === SyntaxKind.PrivateIdentifier) { 46527 grammarErrorOnNode(name, Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies); 46528 } 46529 46530 // Modifiers are never allowed on properties except for 'async' on a method declaration 46531 if (canHaveModifiers(prop) && prop.modifiers) { 46532 for (const mod of prop.modifiers) { 46533 if (isModifier(mod) && (mod.kind !== SyntaxKind.AsyncKeyword || prop.kind !== SyntaxKind.MethodDeclaration)) { 46534 grammarErrorOnNode(mod, Diagnostics._0_modifier_cannot_be_used_here, getTextOfNode(mod)); 46535 } 46536 } 46537 } 46538 else if (canHaveIllegalModifiers(prop) && prop.modifiers) { 46539 for (const mod of prop.modifiers) { 46540 grammarErrorOnNode(mod, Diagnostics._0_modifier_cannot_be_used_here, getTextOfNode(mod)); 46541 } 46542 } 46543 46544 // ECMA-262 11.1.5 Object Initializer 46545 // If previous is not undefined then throw a SyntaxError exception if any of the following conditions are true 46546 // a.This production is contained in strict code and IsDataDescriptor(previous) is true and 46547 // IsDataDescriptor(propId.descriptor) is true. 46548 // b.IsDataDescriptor(previous) is true and IsAccessorDescriptor(propId.descriptor) is true. 46549 // c.IsAccessorDescriptor(previous) is true and IsDataDescriptor(propId.descriptor) is true. 46550 // d.IsAccessorDescriptor(previous) is true and IsAccessorDescriptor(propId.descriptor) is true 46551 // and either both previous and propId.descriptor have[[Get]] fields or both previous and propId.descriptor have[[Set]] fields 46552 let currentKind: DeclarationMeaning; 46553 switch (prop.kind) { 46554 case SyntaxKind.ShorthandPropertyAssignment: 46555 case SyntaxKind.PropertyAssignment: 46556 // Grammar checking for computedPropertyName and shorthandPropertyAssignment 46557 checkGrammarForInvalidExclamationToken(prop.exclamationToken, Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context); 46558 checkGrammarForInvalidQuestionMark(prop.questionToken, Diagnostics.An_object_member_cannot_be_declared_optional); 46559 if (name.kind === SyntaxKind.NumericLiteral) { 46560 checkGrammarNumericLiteral(name); 46561 } 46562 currentKind = DeclarationMeaning.PropertyAssignment; 46563 break; 46564 case SyntaxKind.MethodDeclaration: 46565 currentKind = DeclarationMeaning.Method; 46566 break; 46567 case SyntaxKind.GetAccessor: 46568 currentKind = DeclarationMeaning.GetAccessor; 46569 break; 46570 case SyntaxKind.SetAccessor: 46571 currentKind = DeclarationMeaning.SetAccessor; 46572 break; 46573 default: 46574 throw Debug.assertNever(prop, "Unexpected syntax kind:" + (prop as Node).kind); 46575 } 46576 46577 if (!inDestructuring) { 46578 const effectiveName = getPropertyNameForPropertyNameNode(name); 46579 if (effectiveName === undefined) { 46580 continue; 46581 } 46582 46583 const existingKind = seen.get(effectiveName); 46584 if (!existingKind) { 46585 seen.set(effectiveName, currentKind); 46586 } 46587 else { 46588 if ((currentKind & DeclarationMeaning.Method) && (existingKind & DeclarationMeaning.Method)) { 46589 grammarErrorOnNode(name, Diagnostics.Duplicate_identifier_0, getTextOfNode(name)); 46590 } 46591 else if ((currentKind & DeclarationMeaning.PropertyAssignment) && (existingKind & DeclarationMeaning.PropertyAssignment)) { 46592 grammarErrorOnNode(name, Diagnostics.An_object_literal_cannot_have_multiple_properties_with_the_same_name, getTextOfNode(name)); 46593 } 46594 else if ((currentKind & DeclarationMeaning.GetOrSetAccessor) && (existingKind & DeclarationMeaning.GetOrSetAccessor)) { 46595 if (existingKind !== DeclarationMeaning.GetOrSetAccessor && currentKind !== existingKind) { 46596 seen.set(effectiveName, currentKind | existingKind); 46597 } 46598 else { 46599 return grammarErrorOnNode(name, Diagnostics.An_object_literal_cannot_have_multiple_get_Slashset_accessors_with_the_same_name); 46600 } 46601 } 46602 else { 46603 return grammarErrorOnNode(name, Diagnostics.An_object_literal_cannot_have_property_and_accessor_with_the_same_name); 46604 } 46605 } 46606 } 46607 } 46608 } 46609 46610 function checkGrammarJsxElement(node: JsxOpeningLikeElement) { 46611 checkGrammarJsxName(node.tagName); 46612 checkGrammarTypeArguments(node, node.typeArguments); 46613 const seen = new Map<__String, boolean>(); 46614 46615 for (const attr of node.attributes.properties) { 46616 if (attr.kind === SyntaxKind.JsxSpreadAttribute) { 46617 continue; 46618 } 46619 46620 const { name, initializer } = attr; 46621 if (!seen.get(name.escapedText)) { 46622 seen.set(name.escapedText, true); 46623 } 46624 else { 46625 return grammarErrorOnNode(name, Diagnostics.JSX_elements_cannot_have_multiple_attributes_with_the_same_name); 46626 } 46627 46628 if (initializer && initializer.kind === SyntaxKind.JsxExpression && !initializer.expression) { 46629 return grammarErrorOnNode(initializer, Diagnostics.JSX_attributes_must_only_be_assigned_a_non_empty_expression); 46630 } 46631 } 46632 } 46633 46634 function checkGrammarJsxName(node: JsxTagNameExpression) { 46635 if (isPropertyAccessExpression(node)) { 46636 let propName: JsxTagNameExpression = node; 46637 do { 46638 const check = checkGrammarJsxNestedIdentifier(propName.name); 46639 if (check) { 46640 return check; 46641 } 46642 propName = propName.expression; 46643 } while (isPropertyAccessExpression(propName)); 46644 const check = checkGrammarJsxNestedIdentifier(propName); 46645 if (check) { 46646 return check; 46647 } 46648 } 46649 46650 function checkGrammarJsxNestedIdentifier(name: MemberName | ThisExpression) { 46651 if (isIdentifier(name) && idText(name).indexOf(":") !== -1) { 46652 return grammarErrorOnNode(name, Diagnostics.JSX_property_access_expressions_cannot_include_JSX_namespace_names); 46653 } 46654 } 46655 } 46656 46657 function checkGrammarJsxExpression(node: JsxExpression) { 46658 if (node.expression && isCommaSequence(node.expression)) { 46659 return grammarErrorOnNode(node.expression, Diagnostics.JSX_expressions_may_not_use_the_comma_operator_Did_you_mean_to_write_an_array); 46660 } 46661 } 46662 46663 function checkGrammarForInOrForOfStatement(forInOrOfStatement: ForInOrOfStatement): boolean { 46664 if (checkGrammarStatementInAmbientContext(forInOrOfStatement)) { 46665 return true; 46666 } 46667 46668 if (forInOrOfStatement.kind === SyntaxKind.ForOfStatement && forInOrOfStatement.awaitModifier) { 46669 if (!(forInOrOfStatement.flags & NodeFlags.AwaitContext)) { 46670 const sourceFile = getSourceFileOfNode(forInOrOfStatement); 46671 if (isInTopLevelContext(forInOrOfStatement)) { 46672 if (!hasParseDiagnostics(sourceFile)) { 46673 if (!isEffectiveExternalModule(sourceFile, compilerOptions)) { 46674 diagnostics.add(createDiagnosticForNode(forInOrOfStatement.awaitModifier, 46675 Diagnostics.for_await_loops_are_only_allowed_at_the_top_level_of_a_file_when_that_file_is_a_module_but_this_file_has_no_imports_or_exports_Consider_adding_an_empty_export_to_make_this_file_a_module)); 46676 } 46677 switch (moduleKind) { 46678 case ModuleKind.Node16: 46679 case ModuleKind.NodeNext: 46680 if (sourceFile.impliedNodeFormat === ModuleKind.CommonJS) { 46681 diagnostics.add( 46682 createDiagnosticForNode(forInOrOfStatement.awaitModifier, Diagnostics.The_current_file_is_a_CommonJS_module_and_cannot_use_await_at_the_top_level) 46683 ); 46684 break; 46685 } 46686 // fallthrough 46687 case ModuleKind.ES2022: 46688 case ModuleKind.ESNext: 46689 case ModuleKind.System: 46690 if (languageVersion >= ScriptTarget.ES2017) { 46691 break; 46692 } 46693 // fallthrough 46694 default: 46695 diagnostics.add( 46696 createDiagnosticForNode(forInOrOfStatement.awaitModifier, 46697 Diagnostics.Top_level_for_await_loops_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_or_nodenext_and_the_target_option_is_set_to_es2017_or_higher 46698 ) 46699 ); 46700 break; 46701 } 46702 } 46703 } 46704 else { 46705 // use of 'for-await-of' in non-async function 46706 if (!hasParseDiagnostics(sourceFile)) { 46707 const diagnostic = createDiagnosticForNode(forInOrOfStatement.awaitModifier, Diagnostics.for_await_loops_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules); 46708 const func = getContainingFunction(forInOrOfStatement); 46709 if (func && func.kind !== SyntaxKind.Constructor) { 46710 Debug.assert((getFunctionFlags(func) & FunctionFlags.Async) === 0, "Enclosing function should never be an async function."); 46711 const relatedInfo = createDiagnosticForNode(func, Diagnostics.Did_you_mean_to_mark_this_function_as_async); 46712 addRelatedInfo(diagnostic, relatedInfo); 46713 } 46714 diagnostics.add(diagnostic); 46715 return true; 46716 } 46717 } 46718 return false; 46719 } 46720 } 46721 46722 if (isForOfStatement(forInOrOfStatement) && !(forInOrOfStatement.flags & NodeFlags.AwaitContext) && 46723 isIdentifier(forInOrOfStatement.initializer) && forInOrOfStatement.initializer.escapedText === "async") { 46724 grammarErrorOnNode(forInOrOfStatement.initializer, Diagnostics.The_left_hand_side_of_a_for_of_statement_may_not_be_async); 46725 return false; 46726 } 46727 46728 if (forInOrOfStatement.initializer.kind === SyntaxKind.VariableDeclarationList) { 46729 const variableList = forInOrOfStatement.initializer as VariableDeclarationList; 46730 if (!checkGrammarVariableDeclarationList(variableList)) { 46731 const declarations = variableList.declarations; 46732 46733 // declarations.length can be zero if there is an error in variable declaration in for-of or for-in 46734 // See http://www.ecma-international.org/ecma-262/6.0/#sec-for-in-and-for-of-statements for details 46735 // For example: 46736 // var let = 10; 46737 // for (let of [1,2,3]) {} // this is invalid ES6 syntax 46738 // for (let in [1,2,3]) {} // this is invalid ES6 syntax 46739 // We will then want to skip on grammar checking on variableList declaration 46740 if (!declarations.length) { 46741 return false; 46742 } 46743 46744 if (declarations.length > 1) { 46745 const diagnostic = forInOrOfStatement.kind === SyntaxKind.ForInStatement 46746 ? Diagnostics.Only_a_single_variable_declaration_is_allowed_in_a_for_in_statement 46747 : Diagnostics.Only_a_single_variable_declaration_is_allowed_in_a_for_of_statement; 46748 return grammarErrorOnFirstToken(variableList.declarations[1], diagnostic); 46749 } 46750 const firstDeclaration = declarations[0]; 46751 46752 if (firstDeclaration.initializer) { 46753 const diagnostic = forInOrOfStatement.kind === SyntaxKind.ForInStatement 46754 ? Diagnostics.The_variable_declaration_of_a_for_in_statement_cannot_have_an_initializer 46755 : Diagnostics.The_variable_declaration_of_a_for_of_statement_cannot_have_an_initializer; 46756 return grammarErrorOnNode(firstDeclaration.name, diagnostic); 46757 } 46758 if (firstDeclaration.type) { 46759 const diagnostic = forInOrOfStatement.kind === SyntaxKind.ForInStatement 46760 ? Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_use_a_type_annotation 46761 : Diagnostics.The_left_hand_side_of_a_for_of_statement_cannot_use_a_type_annotation; 46762 return grammarErrorOnNode(firstDeclaration, diagnostic); 46763 } 46764 } 46765 } 46766 46767 return false; 46768 } 46769 46770 function checkGrammarAccessor(accessor: AccessorDeclaration): boolean { 46771 if (!(accessor.flags & NodeFlags.Ambient) && (accessor.parent.kind !== SyntaxKind.TypeLiteral) && (accessor.parent.kind !== SyntaxKind.InterfaceDeclaration)) { 46772 if (languageVersion < ScriptTarget.ES5) { 46773 return grammarErrorOnNode(accessor.name, Diagnostics.Accessors_are_only_available_when_targeting_ECMAScript_5_and_higher); 46774 } 46775 if (languageVersion < ScriptTarget.ES2015 && isPrivateIdentifier(accessor.name)) { 46776 return grammarErrorOnNode(accessor.name, Diagnostics.Private_identifiers_are_only_available_when_targeting_ECMAScript_2015_and_higher); 46777 } 46778 if (accessor.body === undefined && !hasSyntacticModifier(accessor, ModifierFlags.Abstract)) { 46779 return grammarErrorAtPos(accessor, accessor.end - 1, ";".length, Diagnostics._0_expected, "{"); 46780 } 46781 } 46782 if (accessor.body) { 46783 if (hasSyntacticModifier(accessor, ModifierFlags.Abstract)) { 46784 return grammarErrorOnNode(accessor, Diagnostics.An_abstract_accessor_cannot_have_an_implementation); 46785 } 46786 if (accessor.parent.kind === SyntaxKind.TypeLiteral || accessor.parent.kind === SyntaxKind.InterfaceDeclaration) { 46787 return grammarErrorOnNode(accessor.body, Diagnostics.An_implementation_cannot_be_declared_in_ambient_contexts); 46788 } 46789 } 46790 if (accessor.typeParameters) { 46791 return grammarErrorOnNode(accessor.name, Diagnostics.An_accessor_cannot_have_type_parameters); 46792 } 46793 if (!doesAccessorHaveCorrectParameterCount(accessor)) { 46794 return grammarErrorOnNode(accessor.name, 46795 accessor.kind === SyntaxKind.GetAccessor ? 46796 Diagnostics.A_get_accessor_cannot_have_parameters : 46797 Diagnostics.A_set_accessor_must_have_exactly_one_parameter); 46798 } 46799 if (accessor.kind === SyntaxKind.SetAccessor) { 46800 if (accessor.type) { 46801 return grammarErrorOnNode(accessor.name, Diagnostics.A_set_accessor_cannot_have_a_return_type_annotation); 46802 } 46803 const parameter = Debug.checkDefined(getSetAccessorValueParameter(accessor), "Return value does not match parameter count assertion."); 46804 if (parameter.dotDotDotToken) { 46805 return grammarErrorOnNode(parameter.dotDotDotToken, Diagnostics.A_set_accessor_cannot_have_rest_parameter); 46806 } 46807 if (parameter.questionToken) { 46808 return grammarErrorOnNode(parameter.questionToken, Diagnostics.A_set_accessor_cannot_have_an_optional_parameter); 46809 } 46810 if (parameter.initializer) { 46811 return grammarErrorOnNode(accessor.name, Diagnostics.A_set_accessor_parameter_cannot_have_an_initializer); 46812 } 46813 } 46814 return false; 46815 } 46816 46817 /** Does the accessor have the right number of parameters? 46818 * A get accessor has no parameters or a single `this` parameter. 46819 * A set accessor has one parameter or a `this` parameter and one more parameter. 46820 */ 46821 function doesAccessorHaveCorrectParameterCount(accessor: AccessorDeclaration) { 46822 return getAccessorThisParameter(accessor) || accessor.parameters.length === (accessor.kind === SyntaxKind.GetAccessor ? 0 : 1); 46823 } 46824 46825 function getAccessorThisParameter(accessor: AccessorDeclaration): ParameterDeclaration | undefined { 46826 if (accessor.parameters.length === (accessor.kind === SyntaxKind.GetAccessor ? 1 : 2)) { 46827 return getThisParameter(accessor); 46828 } 46829 } 46830 46831 function checkGrammarTypeOperatorNode(node: TypeOperatorNode) { 46832 if (node.operator === SyntaxKind.UniqueKeyword) { 46833 if (node.type.kind !== SyntaxKind.SymbolKeyword) { 46834 return grammarErrorOnNode(node.type, Diagnostics._0_expected, tokenToString(SyntaxKind.SymbolKeyword)); 46835 } 46836 let parent = walkUpParenthesizedTypes(node.parent); 46837 if (isInJSFile(parent) && isJSDocTypeExpression(parent)) { 46838 const host = getJSDocHost(parent); 46839 if (host) { 46840 parent = getSingleVariableOfVariableStatement(host) || host; 46841 } 46842 } 46843 switch (parent.kind) { 46844 case SyntaxKind.VariableDeclaration: 46845 const decl = parent as VariableDeclaration; 46846 if (decl.name.kind !== SyntaxKind.Identifier) { 46847 return grammarErrorOnNode(node, Diagnostics.unique_symbol_types_may_not_be_used_on_a_variable_declaration_with_a_binding_name); 46848 } 46849 if (!isVariableDeclarationInVariableStatement(decl)) { 46850 return grammarErrorOnNode(node, Diagnostics.unique_symbol_types_are_only_allowed_on_variables_in_a_variable_statement); 46851 } 46852 if (!(decl.parent.flags & NodeFlags.Const)) { 46853 return grammarErrorOnNode((parent as VariableDeclaration).name, Diagnostics.A_variable_whose_type_is_a_unique_symbol_type_must_be_const); 46854 } 46855 break; 46856 46857 case SyntaxKind.PropertyDeclaration: 46858 if (!isStatic(parent) || 46859 !hasEffectiveReadonlyModifier(parent)) { 46860 return grammarErrorOnNode((parent as PropertyDeclaration).name, Diagnostics.A_property_of_a_class_whose_type_is_a_unique_symbol_type_must_be_both_static_and_readonly); 46861 } 46862 break; 46863 46864 case SyntaxKind.PropertySignature: 46865 if (!hasSyntacticModifier(parent, ModifierFlags.Readonly)) { 46866 return grammarErrorOnNode((parent as PropertySignature).name, Diagnostics.A_property_of_an_interface_or_type_literal_whose_type_is_a_unique_symbol_type_must_be_readonly); 46867 } 46868 break; 46869 46870 default: 46871 return grammarErrorOnNode(node, Diagnostics.unique_symbol_types_are_not_allowed_here); 46872 } 46873 } 46874 else if (node.operator === SyntaxKind.ReadonlyKeyword) { 46875 if (node.type.kind !== SyntaxKind.ArrayType && node.type.kind !== SyntaxKind.TupleType) { 46876 return grammarErrorOnFirstToken(node, Diagnostics.readonly_type_modifier_is_only_permitted_on_array_and_tuple_literal_types, tokenToString(SyntaxKind.SymbolKeyword)); 46877 } 46878 } 46879 } 46880 46881 function checkGrammarForInvalidDynamicName(node: DeclarationName, message: DiagnosticMessage) { 46882 if (isNonBindableDynamicName(node)) { 46883 return grammarErrorOnNode(node, message); 46884 } 46885 } 46886 46887 function checkGrammarMethod(node: MethodDeclaration | MethodSignature) { 46888 if (checkGrammarFunctionLikeDeclaration(node)) { 46889 return true; 46890 } 46891 46892 if (node.kind === SyntaxKind.MethodDeclaration) { 46893 if (node.parent.kind === SyntaxKind.ObjectLiteralExpression) { 46894 // We only disallow modifier on a method declaration if it is a property of object-literal-expression 46895 if (node.modifiers && !(node.modifiers.length === 1 && first(node.modifiers).kind === SyntaxKind.AsyncKeyword)) { 46896 return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here); 46897 } 46898 else if (checkGrammarForInvalidQuestionMark(node.questionToken, Diagnostics.An_object_member_cannot_be_declared_optional)) { 46899 return true; 46900 } 46901 else if (checkGrammarForInvalidExclamationToken(node.exclamationToken, Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context)) { 46902 return true; 46903 } 46904 else if (node.body === undefined) { 46905 return grammarErrorAtPos(node, node.end - 1, ";".length, Diagnostics._0_expected, "{"); 46906 } 46907 } 46908 if (checkGrammarForGenerator(node)) { 46909 return true; 46910 } 46911 } 46912 46913 if (isClassLike(node.parent)) { 46914 if (languageVersion < ScriptTarget.ES2015 && isPrivateIdentifier(node.name)) { 46915 return grammarErrorOnNode(node.name, Diagnostics.Private_identifiers_are_only_available_when_targeting_ECMAScript_2015_and_higher); 46916 } 46917 // Technically, computed properties in ambient contexts is disallowed 46918 // for property declarations and accessors too, not just methods. 46919 // However, property declarations disallow computed names in general, 46920 // and accessors are not allowed in ambient contexts in general, 46921 // so this error only really matters for methods. 46922 if (node.flags & NodeFlags.Ambient) { 46923 return checkGrammarForInvalidDynamicName(node.name, Diagnostics.A_computed_property_name_in_an_ambient_context_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type); 46924 } 46925 else if (node.kind === SyntaxKind.MethodDeclaration && !node.body) { 46926 return checkGrammarForInvalidDynamicName(node.name, Diagnostics.A_computed_property_name_in_a_method_overload_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type); 46927 } 46928 } 46929 else if (node.parent.kind === SyntaxKind.InterfaceDeclaration) { 46930 return checkGrammarForInvalidDynamicName(node.name, Diagnostics.A_computed_property_name_in_an_interface_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type); 46931 } 46932 else if (node.parent.kind === SyntaxKind.TypeLiteral) { 46933 return checkGrammarForInvalidDynamicName(node.name, Diagnostics.A_computed_property_name_in_a_type_literal_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type); 46934 } 46935 } 46936 46937 function checkGrammarBreakOrContinueStatement(node: BreakOrContinueStatement): boolean { 46938 let current: Node = node; 46939 while (current) { 46940 if (isFunctionLikeOrClassStaticBlockDeclaration(current)) { 46941 return grammarErrorOnNode(node, Diagnostics.Jump_target_cannot_cross_function_boundary); 46942 } 46943 46944 switch (current.kind) { 46945 case SyntaxKind.LabeledStatement: 46946 if (node.label && (current as LabeledStatement).label.escapedText === node.label.escapedText) { 46947 // found matching label - verify that label usage is correct 46948 // continue can only target labels that are on iteration statements 46949 const isMisplacedContinueLabel = node.kind === SyntaxKind.ContinueStatement 46950 && !isIterationStatement((current as LabeledStatement).statement, /*lookInLabeledStatement*/ true); 46951 46952 if (isMisplacedContinueLabel) { 46953 return grammarErrorOnNode(node, Diagnostics.A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement); 46954 } 46955 46956 return false; 46957 } 46958 break; 46959 case SyntaxKind.SwitchStatement: 46960 if (node.kind === SyntaxKind.BreakStatement && !node.label) { 46961 // unlabeled break within switch statement - ok 46962 return false; 46963 } 46964 break; 46965 default: 46966 if (isIterationStatement(current, /*lookInLabeledStatement*/ false) && !node.label) { 46967 // unlabeled break or continue within iteration statement - ok 46968 return false; 46969 } 46970 break; 46971 } 46972 46973 current = current.parent; 46974 } 46975 46976 if (node.label) { 46977 const message = node.kind === SyntaxKind.BreakStatement 46978 ? Diagnostics.A_break_statement_can_only_jump_to_a_label_of_an_enclosing_statement 46979 : Diagnostics.A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement; 46980 46981 return grammarErrorOnNode(node, message); 46982 } 46983 else { 46984 const message = node.kind === SyntaxKind.BreakStatement 46985 ? Diagnostics.A_break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement 46986 : Diagnostics.A_continue_statement_can_only_be_used_within_an_enclosing_iteration_statement; 46987 return grammarErrorOnNode(node, message); 46988 } 46989 } 46990 46991 function checkGrammarBindingElement(node: BindingElement) { 46992 if (node.dotDotDotToken) { 46993 const elements = node.parent.elements; 46994 if (node !== last(elements)) { 46995 return grammarErrorOnNode(node, Diagnostics.A_rest_element_must_be_last_in_a_destructuring_pattern); 46996 } 46997 checkGrammarForDisallowedTrailingComma(elements, Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma); 46998 46999 if (node.propertyName) { 47000 return grammarErrorOnNode(node.name, Diagnostics.A_rest_element_cannot_have_a_property_name); 47001 } 47002 } 47003 47004 if (node.dotDotDotToken && node.initializer) { 47005 // Error on equals token which immediately precedes the initializer 47006 return grammarErrorAtPos(node, node.initializer.pos - 1, 1, Diagnostics.A_rest_element_cannot_have_an_initializer); 47007 } 47008 } 47009 47010 function isStringOrNumberLiteralExpression(expr: Expression) { 47011 return isStringOrNumericLiteralLike(expr) || 47012 expr.kind === SyntaxKind.PrefixUnaryExpression && (expr as PrefixUnaryExpression).operator === SyntaxKind.MinusToken && 47013 (expr as PrefixUnaryExpression).operand.kind === SyntaxKind.NumericLiteral; 47014 } 47015 47016 function isBigIntLiteralExpression(expr: Expression) { 47017 return expr.kind === SyntaxKind.BigIntLiteral || 47018 expr.kind === SyntaxKind.PrefixUnaryExpression && (expr as PrefixUnaryExpression).operator === SyntaxKind.MinusToken && 47019 (expr as PrefixUnaryExpression).operand.kind === SyntaxKind.BigIntLiteral; 47020 } 47021 47022 function isSimpleLiteralEnumReference(expr: Expression) { 47023 if ((isPropertyAccessExpression(expr) || (isElementAccessExpression(expr) && isStringOrNumberLiteralExpression(expr.argumentExpression))) && 47024 isEntityNameExpression(expr.expression)) { 47025 return !!(checkExpressionCached(expr).flags & TypeFlags.EnumLiteral); 47026 } 47027 } 47028 47029 function checkAmbientInitializer(node: VariableDeclaration | PropertyDeclaration | PropertySignature) { 47030 const initializer = node.initializer; 47031 if (initializer) { 47032 const isInvalidInitializer = !( 47033 isStringOrNumberLiteralExpression(initializer) || 47034 isSimpleLiteralEnumReference(initializer) || 47035 initializer.kind === SyntaxKind.TrueKeyword || initializer.kind === SyntaxKind.FalseKeyword || 47036 isBigIntLiteralExpression(initializer) 47037 ); 47038 const isConstOrReadonly = isDeclarationReadonly(node) || isVariableDeclaration(node) && isVarConst(node); 47039 if (isConstOrReadonly && !node.type) { 47040 if (isInvalidInitializer) { 47041 return grammarErrorOnNode(initializer, Diagnostics.A_const_initializer_in_an_ambient_context_must_be_a_string_or_numeric_literal_or_literal_enum_reference); 47042 } 47043 } 47044 else { 47045 return grammarErrorOnNode(initializer, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts); 47046 } 47047 } 47048 } 47049 47050 function checkGrammarVariableDeclaration(node: VariableDeclaration) { 47051 if (node.parent.parent.kind !== SyntaxKind.ForInStatement && node.parent.parent.kind !== SyntaxKind.ForOfStatement) { 47052 if (node.flags & NodeFlags.Ambient) { 47053 checkAmbientInitializer(node); 47054 } 47055 else if (!node.initializer) { 47056 if (isBindingPattern(node.name) && !isBindingPattern(node.parent)) { 47057 return grammarErrorOnNode(node, Diagnostics.A_destructuring_declaration_must_have_an_initializer); 47058 } 47059 if (isVarConst(node)) { 47060 return grammarErrorOnNode(node, Diagnostics.const_declarations_must_be_initialized); 47061 } 47062 } 47063 } 47064 47065 if (node.exclamationToken && (node.parent.parent.kind !== SyntaxKind.VariableStatement || !node.type || node.initializer || node.flags & NodeFlags.Ambient)) { 47066 const message = node.initializer 47067 ? Diagnostics.Declarations_with_initializers_cannot_also_have_definite_assignment_assertions 47068 : !node.type 47069 ? Diagnostics.Declarations_with_definite_assignment_assertions_must_also_have_type_annotations 47070 : Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context; 47071 return grammarErrorOnNode(node.exclamationToken, message); 47072 } 47073 47074 if ((moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) && moduleKind !== ModuleKind.System && 47075 !(node.parent.parent.flags & NodeFlags.Ambient) && hasSyntacticModifier(node.parent.parent, ModifierFlags.Export)) { 47076 checkESModuleMarker(node.name); 47077 } 47078 47079 const checkLetConstNames = (isLet(node) || isVarConst(node)); 47080 47081 // 1. LexicalDeclaration : LetOrConst BindingList ; 47082 // It is a Syntax Error if the BoundNames of BindingList contains "let". 47083 // 2. ForDeclaration: ForDeclaration : LetOrConst ForBinding 47084 // It is a Syntax Error if the BoundNames of ForDeclaration contains "let". 47085 47086 // It is a SyntaxError if a VariableDeclaration or VariableDeclarationNoIn occurs within strict code 47087 // and its Identifier is eval or arguments 47088 return checkLetConstNames && checkGrammarNameInLetOrConstDeclarations(node.name); 47089 } 47090 47091 function checkESModuleMarker(name: Identifier | BindingPattern): boolean { 47092 if (name.kind === SyntaxKind.Identifier) { 47093 if (idText(name) === "__esModule") { 47094 return grammarErrorOnNodeSkippedOn("noEmit", name, Diagnostics.Identifier_expected_esModule_is_reserved_as_an_exported_marker_when_transforming_ECMAScript_modules); 47095 } 47096 } 47097 else { 47098 const elements = name.elements; 47099 for (const element of elements) { 47100 if (!isOmittedExpression(element)) { 47101 return checkESModuleMarker(element.name); 47102 } 47103 } 47104 } 47105 return false; 47106 } 47107 47108 function checkGrammarNameInLetOrConstDeclarations(name: Identifier | BindingPattern): boolean { 47109 if (name.kind === SyntaxKind.Identifier) { 47110 if (name.originalKeywordKind === SyntaxKind.LetKeyword) { 47111 return grammarErrorOnNode(name, Diagnostics.let_is_not_allowed_to_be_used_as_a_name_in_let_or_const_declarations); 47112 } 47113 } 47114 else { 47115 const elements = name.elements; 47116 for (const element of elements) { 47117 if (!isOmittedExpression(element)) { 47118 checkGrammarNameInLetOrConstDeclarations(element.name); 47119 } 47120 } 47121 } 47122 return false; 47123 } 47124 47125 function checkGrammarVariableDeclarationList(declarationList: VariableDeclarationList): boolean { 47126 const declarations = declarationList.declarations; 47127 if (checkGrammarForDisallowedTrailingComma(declarationList.declarations)) { 47128 return true; 47129 } 47130 47131 if (!declarationList.declarations.length) { 47132 return grammarErrorAtPos(declarationList, declarations.pos, declarations.end - declarations.pos, Diagnostics.Variable_declaration_list_cannot_be_empty); 47133 } 47134 return false; 47135 } 47136 47137 function allowLetAndConstDeclarations(parent: Node): boolean { 47138 switch (parent.kind) { 47139 case SyntaxKind.IfStatement: 47140 case SyntaxKind.DoStatement: 47141 case SyntaxKind.WhileStatement: 47142 case SyntaxKind.WithStatement: 47143 case SyntaxKind.ForStatement: 47144 case SyntaxKind.ForInStatement: 47145 case SyntaxKind.ForOfStatement: 47146 return false; 47147 case SyntaxKind.LabeledStatement: 47148 return allowLetAndConstDeclarations(parent.parent); 47149 } 47150 47151 return true; 47152 } 47153 47154 function checkGrammarForDisallowedLetOrConstStatement(node: VariableStatement) { 47155 if (!allowLetAndConstDeclarations(node.parent)) { 47156 if (isLet(node.declarationList)) { 47157 return grammarErrorOnNode(node, Diagnostics.let_declarations_can_only_be_declared_inside_a_block); 47158 } 47159 else if (isVarConst(node.declarationList)) { 47160 return grammarErrorOnNode(node, Diagnostics.const_declarations_can_only_be_declared_inside_a_block); 47161 } 47162 } 47163 } 47164 47165 function checkGrammarMetaProperty(node: MetaProperty) { 47166 const escapedText = node.name.escapedText; 47167 switch (node.keywordToken) { 47168 case SyntaxKind.NewKeyword: 47169 if (escapedText !== "target") { 47170 return grammarErrorOnNode(node.name, Diagnostics._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, node.name.escapedText, tokenToString(node.keywordToken), "target"); 47171 } 47172 break; 47173 case SyntaxKind.ImportKeyword: 47174 if (escapedText !== "meta") { 47175 return grammarErrorOnNode(node.name, Diagnostics._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, node.name.escapedText, tokenToString(node.keywordToken), "meta"); 47176 } 47177 break; 47178 } 47179 } 47180 47181 function hasParseDiagnostics(sourceFile: SourceFile): boolean { 47182 return sourceFile.parseDiagnostics.length > 0; 47183 } 47184 47185 function grammarErrorOnFirstToken(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean { 47186 const sourceFile = getSourceFileOfNode(node); 47187 if (!hasParseDiagnostics(sourceFile)) { 47188 const span = getSpanOfTokenAtPosition(sourceFile, node.pos); 47189 diagnostics.add(createFileDiagnostic(sourceFile, span.start, span.length, message, arg0, arg1, arg2)); 47190 return true; 47191 } 47192 return false; 47193 } 47194 47195 function grammarErrorAtPos(nodeForSourceFile: Node, start: number, length: number, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean { 47196 const sourceFile = getSourceFileOfNode(nodeForSourceFile); 47197 if (!hasParseDiagnostics(sourceFile)) { 47198 diagnostics.add(createFileDiagnostic(sourceFile, start, length, message, arg0, arg1, arg2)); 47199 return true; 47200 } 47201 return false; 47202 } 47203 47204 function grammarErrorOnNodeSkippedOn(key: keyof CompilerOptions, node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean { 47205 const sourceFile = getSourceFileOfNode(node); 47206 if (!hasParseDiagnostics(sourceFile)) { 47207 errorSkippedOn(key, node, message, arg0, arg1, arg2); 47208 return true; 47209 } 47210 return false; 47211 } 47212 47213 function grammarErrorOnNode(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean { 47214 const sourceFile = getSourceFileOfNode(node); 47215 if (!hasParseDiagnostics(sourceFile)) { 47216 diagnostics.add(createDiagnosticForNode(node, message, arg0, arg1, arg2)); 47217 return true; 47218 } 47219 return false; 47220 } 47221 47222 function checkGrammarConstructorTypeParameters(node: ConstructorDeclaration) { 47223 const jsdocTypeParameters = isInJSFile(node) ? getJSDocTypeParameterDeclarations(node) : undefined; 47224 const range = node.typeParameters || jsdocTypeParameters && firstOrUndefined(jsdocTypeParameters); 47225 if (range) { 47226 const pos = range.pos === range.end ? range.pos : skipTrivia(getSourceFileOfNode(node).text, range.pos); 47227 return grammarErrorAtPos(node, pos, range.end - pos, Diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration); 47228 } 47229 } 47230 47231 function checkGrammarConstructorTypeAnnotation(node: ConstructorDeclaration) { 47232 const type = node.type || getEffectiveReturnTypeNode(node); 47233 if (type) { 47234 return grammarErrorOnNode(type, Diagnostics.Type_annotation_cannot_appear_on_a_constructor_declaration); 47235 } 47236 } 47237 47238 function checkGrammarProperty(node: PropertyDeclaration | PropertySignature) { 47239 if (isComputedPropertyName(node.name) && isBinaryExpression(node.name.expression) && node.name.expression.operatorToken.kind === SyntaxKind.InKeyword) { 47240 return grammarErrorOnNode( 47241 (node.parent as ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode).members[0], 47242 Diagnostics.A_mapped_type_may_not_declare_properties_or_methods); 47243 } 47244 if (isClassLike(node.parent)) { 47245 if (isStringLiteral(node.name) && node.name.text === "constructor") { 47246 return grammarErrorOnNode(node.name, Diagnostics.Classes_may_not_have_a_field_named_constructor); 47247 } 47248 if (checkGrammarForInvalidDynamicName(node.name, Diagnostics.A_computed_property_name_in_a_class_property_declaration_must_have_a_simple_literal_type_or_a_unique_symbol_type)) { 47249 return true; 47250 } 47251 if (languageVersion < ScriptTarget.ES2015 && isPrivateIdentifier(node.name)) { 47252 return grammarErrorOnNode(node.name, Diagnostics.Private_identifiers_are_only_available_when_targeting_ECMAScript_2015_and_higher); 47253 } 47254 if (languageVersion < ScriptTarget.ES2015 && isAutoAccessorPropertyDeclaration(node)) { 47255 return grammarErrorOnNode(node.name, Diagnostics.Properties_with_the_accessor_modifier_are_only_available_when_targeting_ECMAScript_2015_and_higher); 47256 } 47257 if (isAutoAccessorPropertyDeclaration(node) && checkGrammarForInvalidQuestionMark(node.questionToken, Diagnostics.An_accessor_property_cannot_be_declared_optional)) { 47258 return true; 47259 } 47260 } 47261 else if (node.parent.kind === SyntaxKind.InterfaceDeclaration) { 47262 if (checkGrammarForInvalidDynamicName(node.name, Diagnostics.A_computed_property_name_in_an_interface_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type)) { 47263 return true; 47264 } 47265 47266 // Interfaces cannot contain property declarations 47267 Debug.assertNode(node, isPropertySignature); 47268 if (node.initializer) { 47269 return grammarErrorOnNode(node.initializer, Diagnostics.An_interface_property_cannot_have_an_initializer); 47270 } 47271 } 47272 else if (isTypeLiteralNode(node.parent)) { 47273 if (checkGrammarForInvalidDynamicName(node.name, Diagnostics.A_computed_property_name_in_a_type_literal_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type)) { 47274 return true; 47275 } 47276 // Type literals cannot contain property declarations 47277 Debug.assertNode(node, isPropertySignature); 47278 if (node.initializer) { 47279 return grammarErrorOnNode(node.initializer, Diagnostics.A_type_literal_property_cannot_have_an_initializer); 47280 } 47281 } 47282 47283 if (node.flags & NodeFlags.Ambient) { 47284 checkAmbientInitializer(node); 47285 } 47286 47287 if (isPropertyDeclaration(node) && node.exclamationToken && (!isClassLike(node.parent) || !node.type || node.initializer || 47288 node.flags & NodeFlags.Ambient || isStatic(node) || hasAbstractModifier(node))) { 47289 const message = node.initializer 47290 ? Diagnostics.Declarations_with_initializers_cannot_also_have_definite_assignment_assertions 47291 : !node.type 47292 ? Diagnostics.Declarations_with_definite_assignment_assertions_must_also_have_type_annotations 47293 : Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context; 47294 return grammarErrorOnNode(node.exclamationToken, message); 47295 } 47296 } 47297 47298 function checkGrammarTopLevelElementForRequiredDeclareModifier(node: Node): boolean { 47299 // A declare modifier is required for any top level .d.ts declaration except export=, export default, export as namespace 47300 // interfaces and imports categories: 47301 // 47302 // DeclarationElement: 47303 // ExportAssignment 47304 // export_opt InterfaceDeclaration 47305 // export_opt TypeAliasDeclaration 47306 // export_opt ImportDeclaration 47307 // export_opt ExternalImportDeclaration 47308 // export_opt AmbientDeclaration 47309 // 47310 // TODO: The spec needs to be amended to reflect this grammar. 47311 if (node.kind === SyntaxKind.InterfaceDeclaration || 47312 node.kind === SyntaxKind.TypeAliasDeclaration || 47313 node.kind === SyntaxKind.ImportDeclaration || 47314 node.kind === SyntaxKind.ImportEqualsDeclaration || 47315 node.kind === SyntaxKind.ExportDeclaration || 47316 node.kind === SyntaxKind.ExportAssignment || 47317 node.kind === SyntaxKind.NamespaceExportDeclaration || 47318 hasSyntacticModifier(node, ModifierFlags.Ambient | ModifierFlags.Export | ModifierFlags.Default)) { 47319 return false; 47320 } 47321 47322 return grammarErrorOnFirstToken(node, Diagnostics.Top_level_declarations_in_d_ts_files_must_start_with_either_a_declare_or_export_modifier); 47323 } 47324 47325 function checkGrammarTopLevelElementsForRequiredDeclareModifier(file: SourceFile): boolean { 47326 for (const decl of file.statements) { 47327 if (isDeclaration(decl) || decl.kind === SyntaxKind.VariableStatement) { 47328 if (checkGrammarTopLevelElementForRequiredDeclareModifier(decl)) { 47329 return true; 47330 } 47331 } 47332 } 47333 return false; 47334 } 47335 47336 function checkGrammarSourceFile(node: SourceFile): boolean { 47337 return !!(node.flags & NodeFlags.Ambient) && checkGrammarTopLevelElementsForRequiredDeclareModifier(node); 47338 } 47339 47340 function checkGrammarStatementInAmbientContext(node: Node): boolean { 47341 if (node.flags & NodeFlags.Ambient) { 47342 // Find containing block which is either Block, ModuleBlock, SourceFile 47343 const links = getNodeLinks(node); 47344 if (!links.hasReportedStatementInAmbientContext && (isFunctionLike(node.parent) || isAccessor(node.parent))) { 47345 return getNodeLinks(node).hasReportedStatementInAmbientContext = grammarErrorOnFirstToken(node, Diagnostics.An_implementation_cannot_be_declared_in_ambient_contexts); 47346 } 47347 47348 // We are either parented by another statement, or some sort of block. 47349 // If we're in a block, we only want to really report an error once 47350 // to prevent noisiness. So use a bit on the block to indicate if 47351 // this has already been reported, and don't report if it has. 47352 // 47353 if (node.parent.kind === SyntaxKind.Block || node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) { 47354 const links = getNodeLinks(node.parent); 47355 // Check if the containing block ever report this error 47356 if (!links.hasReportedStatementInAmbientContext) { 47357 return links.hasReportedStatementInAmbientContext = grammarErrorOnFirstToken(node, Diagnostics.Statements_are_not_allowed_in_ambient_contexts); 47358 } 47359 } 47360 else { 47361 // We must be parented by a statement. If so, there's no need 47362 // to report the error as our parent will have already done it. 47363 // Debug.assert(isStatement(node.parent)); 47364 } 47365 } 47366 return false; 47367 } 47368 47369 function checkGrammarNumericLiteral(node: NumericLiteral): boolean { 47370 // Grammar checking 47371 if (node.numericLiteralFlags & TokenFlags.Octal) { 47372 let diagnosticMessage: DiagnosticMessage | undefined; 47373 if (languageVersion >= ScriptTarget.ES5) { 47374 diagnosticMessage = Diagnostics.Octal_literals_are_not_available_when_targeting_ECMAScript_5_and_higher_Use_the_syntax_0; 47375 } 47376 else if (isChildOfNodeWithKind(node, SyntaxKind.LiteralType)) { 47377 diagnosticMessage = Diagnostics.Octal_literal_types_must_use_ES2015_syntax_Use_the_syntax_0; 47378 } 47379 else if (isChildOfNodeWithKind(node, SyntaxKind.EnumMember)) { 47380 diagnosticMessage = Diagnostics.Octal_literals_are_not_allowed_in_enums_members_initializer_Use_the_syntax_0; 47381 } 47382 if (diagnosticMessage) { 47383 const withMinus = isPrefixUnaryExpression(node.parent) && node.parent.operator === SyntaxKind.MinusToken; 47384 const literal = (withMinus ? "-" : "") + "0o" + node.text; 47385 return grammarErrorOnNode(withMinus ? node.parent : node, diagnosticMessage, literal); 47386 } 47387 } 47388 47389 // Realism (size) checking 47390 checkNumericLiteralValueSize(node); 47391 47392 return false; 47393 } 47394 47395 function checkNumericLiteralValueSize(node: NumericLiteral) { 47396 // We should test against `getTextOfNode(node)` rather than `node.text`, because `node.text` for large numeric literals can contain "." 47397 // e.g. `node.text` for numeric literal `1100000000000000000000` is `1.1e21`. 47398 const isFractional = getTextOfNode(node).indexOf(".") !== -1; 47399 const isScientific = node.numericLiteralFlags & TokenFlags.Scientific; 47400 47401 // Scientific notation (e.g. 2e54 and 1e00000000010) can't be converted to bigint 47402 // Fractional numbers (e.g. 9000000000000000.001) are inherently imprecise anyway 47403 if (isFractional || isScientific) { 47404 return; 47405 } 47406 47407 // Here `node` is guaranteed to be a numeric literal representing an integer. 47408 // We need to judge whether the integer `node` represents is <= 2 ** 53 - 1, which can be accomplished by comparing to `value` defined below because: 47409 // 1) when `node` represents an integer <= 2 ** 53 - 1, `node.text` is its exact string representation and thus `value` precisely represents the integer. 47410 // 2) otherwise, although `node.text` may be imprecise string representation, its mathematical value and consequently `value` cannot be less than 2 ** 53, 47411 // thus the result of the predicate won't be affected. 47412 const value = +node.text; 47413 if (value <= 2 ** 53 - 1) { 47414 return; 47415 } 47416 47417 addErrorOrSuggestion(/*isError*/ false, createDiagnosticForNode(node, Diagnostics.Numeric_literals_with_absolute_values_equal_to_2_53_or_greater_are_too_large_to_be_represented_accurately_as_integers)); 47418 } 47419 47420 function checkGrammarBigIntLiteral(node: BigIntLiteral): boolean { 47421 const literalType = isLiteralTypeNode(node.parent) || 47422 isPrefixUnaryExpression(node.parent) && isLiteralTypeNode(node.parent.parent); 47423 if (!literalType) { 47424 if (languageVersion < ScriptTarget.ES2020) { 47425 if (grammarErrorOnNode(node, Diagnostics.BigInt_literals_are_not_available_when_targeting_lower_than_ES2020)) { 47426 return true; 47427 } 47428 } 47429 } 47430 return false; 47431 } 47432 47433 function grammarErrorAfterFirstToken(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean { 47434 const sourceFile = getSourceFileOfNode(node); 47435 if (!hasParseDiagnostics(sourceFile)) { 47436 const span = getSpanOfTokenAtPosition(sourceFile, node.pos); 47437 diagnostics.add(createFileDiagnostic(sourceFile, textSpanEnd(span), /*length*/ 0, message, arg0, arg1, arg2)); 47438 return true; 47439 } 47440 return false; 47441 } 47442 47443 function getAmbientModules(): Symbol[] { 47444 if (!ambientModulesCache) { 47445 ambientModulesCache = []; 47446 globals.forEach((global, sym) => { 47447 // No need to `unescapeLeadingUnderscores`, an escaped symbol is never an ambient module. 47448 if (ambientModuleSymbolRegex.test(sym as string)) { 47449 ambientModulesCache!.push(global); 47450 } 47451 }); 47452 } 47453 return ambientModulesCache; 47454 } 47455 47456 function checkGrammarImportClause(node: ImportClause): boolean { 47457 if (node.isTypeOnly && node.name && node.namedBindings) { 47458 return grammarErrorOnNode(node, Diagnostics.A_type_only_import_can_specify_a_default_import_or_named_bindings_but_not_both); 47459 } 47460 if (node.isTypeOnly && node.namedBindings?.kind === SyntaxKind.NamedImports) { 47461 return checkGrammarNamedImportsOrExports(node.namedBindings); 47462 } 47463 return false; 47464 } 47465 47466 function checkGrammarNamedImportsOrExports(namedBindings: NamedImportsOrExports): boolean { 47467 return !!forEach<ImportSpecifier | ExportSpecifier, boolean>(namedBindings.elements, specifier => { 47468 if (specifier.isTypeOnly) { 47469 return grammarErrorOnFirstToken( 47470 specifier, 47471 specifier.kind === SyntaxKind.ImportSpecifier 47472 ? Diagnostics.The_type_modifier_cannot_be_used_on_a_named_import_when_import_type_is_used_on_its_import_statement 47473 : Diagnostics.The_type_modifier_cannot_be_used_on_a_named_export_when_export_type_is_used_on_its_export_statement); 47474 } 47475 }); 47476 } 47477 47478 function checkGrammarImportCallExpression(node: ImportCall): boolean { 47479 if (moduleKind === ModuleKind.ES2015) { 47480 return grammarErrorOnNode(node, Diagnostics.Dynamic_imports_are_only_supported_when_the_module_flag_is_set_to_es2020_es2022_esnext_commonjs_amd_system_umd_node16_or_nodenext); 47481 } 47482 47483 if (node.typeArguments) { 47484 return grammarErrorOnNode(node, Diagnostics.This_use_of_import_is_invalid_import_calls_can_be_written_but_they_must_have_parentheses_and_cannot_have_type_arguments); 47485 } 47486 47487 const nodeArguments = node.arguments; 47488 if (moduleKind !== ModuleKind.ESNext && moduleKind !== ModuleKind.NodeNext && moduleKind !== ModuleKind.Node16) { 47489 // We are allowed trailing comma after proposal-import-assertions. 47490 checkGrammarForDisallowedTrailingComma(nodeArguments); 47491 47492 if (nodeArguments.length > 1) { 47493 const assertionArgument = nodeArguments[1]; 47494 return grammarErrorOnNode(assertionArgument, Diagnostics.Dynamic_imports_only_support_a_second_argument_when_the_module_option_is_set_to_esnext_node16_or_nodenext); 47495 } 47496 } 47497 47498 if (nodeArguments.length === 0 || nodeArguments.length > 2) { 47499 return grammarErrorOnNode(node, Diagnostics.Dynamic_imports_can_only_accept_a_module_specifier_and_an_optional_assertion_as_arguments); 47500 } 47501 47502 // see: parseArgumentOrArrayLiteralElement...we use this function which parse arguments of callExpression to parse specifier for dynamic import. 47503 // parseArgumentOrArrayLiteralElement allows spread element to be in an argument list which is not allowed as specifier in dynamic import. 47504 const spreadElement = find(nodeArguments, isSpreadElement); 47505 if (spreadElement) { 47506 return grammarErrorOnNode(spreadElement, Diagnostics.Argument_of_dynamic_import_cannot_be_spread_element); 47507 } 47508 return false; 47509 } 47510 47511 function findMatchingTypeReferenceOrTypeAliasReference(source: Type, unionTarget: UnionOrIntersectionType) { 47512 const sourceObjectFlags = getObjectFlags(source); 47513 if (sourceObjectFlags & (ObjectFlags.Reference | ObjectFlags.Anonymous) && unionTarget.flags & TypeFlags.Union) { 47514 return find(unionTarget.types, target => { 47515 if (target.flags & TypeFlags.Object) { 47516 const overlapObjFlags = sourceObjectFlags & getObjectFlags(target); 47517 if (overlapObjFlags & ObjectFlags.Reference) { 47518 return (source as TypeReference).target === (target as TypeReference).target; 47519 } 47520 if (overlapObjFlags & ObjectFlags.Anonymous) { 47521 return !!(source as AnonymousType).aliasSymbol && (source as AnonymousType).aliasSymbol === (target as AnonymousType).aliasSymbol; 47522 } 47523 } 47524 return false; 47525 }); 47526 } 47527 } 47528 47529 function findBestTypeForObjectLiteral(source: Type, unionTarget: UnionOrIntersectionType) { 47530 if (getObjectFlags(source) & ObjectFlags.ObjectLiteral && someType(unionTarget, isArrayLikeType)) { 47531 return find(unionTarget.types, t => !isArrayLikeType(t)); 47532 } 47533 } 47534 47535 function findBestTypeForInvokable(source: Type, unionTarget: UnionOrIntersectionType) { 47536 let signatureKind = SignatureKind.Call; 47537 const hasSignatures = getSignaturesOfType(source, signatureKind).length > 0 || 47538 (signatureKind = SignatureKind.Construct, getSignaturesOfType(source, signatureKind).length > 0); 47539 if (hasSignatures) { 47540 return find(unionTarget.types, t => getSignaturesOfType(t, signatureKind).length > 0); 47541 } 47542 } 47543 47544 function findMostOverlappyType(source: Type, unionTarget: UnionOrIntersectionType) { 47545 let bestMatch: Type | undefined; 47546 if (!(source.flags & (TypeFlags.Primitive | TypeFlags.InstantiablePrimitive))) { 47547 let matchingCount = 0; 47548 for (const target of unionTarget.types) { 47549 if (!(target.flags & (TypeFlags.Primitive | TypeFlags.InstantiablePrimitive))) { 47550 const overlap = getIntersectionType([getIndexType(source), getIndexType(target)]); 47551 if (overlap.flags & TypeFlags.Index) { 47552 // perfect overlap of keys 47553 return target; 47554 } 47555 else if (isUnitType(overlap) || overlap.flags & TypeFlags.Union) { 47556 // We only want to account for literal types otherwise. 47557 // If we have a union of index types, it seems likely that we 47558 // needed to elaborate between two generic mapped types anyway. 47559 const len = overlap.flags & TypeFlags.Union ? countWhere((overlap as UnionType).types, isUnitType) : 1; 47560 if (len >= matchingCount) { 47561 bestMatch = target; 47562 matchingCount = len; 47563 } 47564 } 47565 } 47566 } 47567 } 47568 return bestMatch; 47569 } 47570 47571 function filterPrimitivesIfContainsNonPrimitive(type: UnionType) { 47572 if (maybeTypeOfKind(type, TypeFlags.NonPrimitive)) { 47573 const result = filterType(type, t => !(t.flags & TypeFlags.Primitive)); 47574 if (!(result.flags & TypeFlags.Never)) { 47575 return result; 47576 } 47577 } 47578 return type; 47579 } 47580 47581 // Keep this up-to-date with the same logic within `getApparentTypeOfContextualType`, since they should behave similarly 47582 function findMatchingDiscriminantType(source: Type, target: Type, isRelatedTo: (source: Type, target: Type) => Ternary, skipPartial?: boolean) { 47583 if (target.flags & TypeFlags.Union && source.flags & (TypeFlags.Intersection | TypeFlags.Object)) { 47584 const match = getMatchingUnionConstituentForType(target as UnionType, source); 47585 if (match) { 47586 return match; 47587 } 47588 const sourceProperties = getPropertiesOfType(source); 47589 if (sourceProperties) { 47590 const sourcePropertiesFiltered = findDiscriminantProperties(sourceProperties, target); 47591 if (sourcePropertiesFiltered) { 47592 return discriminateTypeByDiscriminableItems(target as UnionType, map(sourcePropertiesFiltered, p => ([() => getTypeOfSymbol(p), p.escapedName] as [() => Type, __String])), isRelatedTo, /*defaultValue*/ undefined, skipPartial); 47593 } 47594 } 47595 } 47596 return undefined; 47597 } 47598 } 47599 47600 function isNotAccessor(declaration: Declaration): boolean { 47601 // Accessors check for their own matching duplicates, and in contexts where they are valid, there are already duplicate identifier checks 47602 return !isAccessor(declaration); 47603 } 47604 47605 function isNotOverload(declaration: Declaration): boolean { 47606 return (declaration.kind !== SyntaxKind.FunctionDeclaration && declaration.kind !== SyntaxKind.MethodDeclaration) || 47607 !!(declaration as FunctionDeclaration).body; 47608 } 47609 47610 /** Like 'isDeclarationName', but returns true for LHS of `import { x as y }` or `export { x as y }`. */ 47611 function isDeclarationNameOrImportPropertyName(name: Node): boolean { 47612 switch (name.parent.kind) { 47613 case SyntaxKind.ImportSpecifier: 47614 case SyntaxKind.ExportSpecifier: 47615 return isIdentifier(name); 47616 default: 47617 return isDeclarationName(name); 47618 } 47619 } 47620 47621 namespace JsxNames { 47622 export const JSX = "JSX" as __String; 47623 export const IntrinsicElements = "IntrinsicElements" as __String; 47624 export const ElementClass = "ElementClass" as __String; 47625 export const ElementAttributesPropertyNameContainer = "ElementAttributesProperty" as __String; // TODO: Deprecate and remove support 47626 export const ElementChildrenAttributeNameContainer = "ElementChildrenAttribute" as __String; 47627 export const Element = "Element" as __String; 47628 export const IntrinsicAttributes = "IntrinsicAttributes" as __String; 47629 export const IntrinsicClassAttributes = "IntrinsicClassAttributes" as __String; 47630 export const LibraryManagedAttributes = "LibraryManagedAttributes" as __String; 47631 } 47632 47633 function getIterationTypesKeyFromIterationTypeKind(typeKind: IterationTypeKind) { 47634 switch (typeKind) { 47635 case IterationTypeKind.Yield: return "yieldType"; 47636 case IterationTypeKind.Return: return "returnType"; 47637 case IterationTypeKind.Next: return "nextType"; 47638 } 47639 } 47640 47641 export function signatureHasRestParameter(s: Signature) { 47642 return !!(s.flags & SignatureFlags.HasRestParameter); 47643 } 47644 47645 export function signatureHasLiteralTypes(s: Signature) { 47646 return !!(s.flags & SignatureFlags.HasLiteralTypes); 47647 } 47648} 47649