diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 76e81a959790b..570e185f60657 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1176,10 +1176,15 @@ const enum IterationUse { Destructuring = AllowsSyncIterablesFlag | DestructuringFlag, ForOf = AllowsSyncIterablesFlag | AllowsStringInputFlag | ForOfFlag, - ForAwaitOf = AllowsSyncIterablesFlag | AllowsAsyncIterablesFlag | AllowsStringInputFlag | ForOfFlag, + ForAwaitOf = AllowsSyncIterablesFlag | + AllowsAsyncIterablesFlag | + AllowsStringInputFlag | + ForOfFlag, YieldStar = AllowsSyncIterablesFlag | YieldStarFlag, - AsyncYieldStar = AllowsSyncIterablesFlag | AllowsAsyncIterablesFlag | YieldStarFlag, + AsyncYieldStar = AllowsSyncIterablesFlag | + AllowsAsyncIterablesFlag | + YieldStarFlag, GeneratorReturnType = AllowsSyncIterablesFlag, AsyncGeneratorReturnType = AllowsAsyncIterablesFlag, @@ -1192,8 +1197,12 @@ const enum IterationTypeKind { } interface IterationTypesResolver { - iterableCacheKey: "iterationTypesOfAsyncIterable" | "iterationTypesOfIterable"; - iteratorCacheKey: "iterationTypesOfAsyncIterator" | "iterationTypesOfIterator"; + iterableCacheKey: + | "iterationTypesOfAsyncIterable" + | "iterationTypesOfIterable"; + iteratorCacheKey: + | "iterationTypesOfAsyncIterator" + | "iterationTypesOfIterator"; iteratorSymbolName: "asyncIterator" | "iterator"; getGlobalIteratorType: (reportErrors: boolean) => GenericType; getGlobalIterableType: (reportErrors: boolean) => GenericType; @@ -1201,7 +1210,10 @@ interface IterationTypesResolver { getGlobalIteratorObjectType: (reportErrors: boolean) => GenericType; getGlobalGeneratorType: (reportErrors: boolean) => GenericType; getGlobalBuiltinIteratorTypes: () => readonly GenericType[]; - resolveIterationType: (type: Type, errorNode: Node | undefined) => Type | undefined; + resolveIterationType: ( + type: Type, + errorNode: Node | undefined + ) => Type | undefined; mustHaveANextMethodDiagnostic: DiagnosticMessage; mustBeAMethodDiagnostic: DiagnosticMessage; mustHaveAValueDiagnostic: DiagnosticMessage; @@ -1218,97 +1230,243 @@ const enum WideningKind { /** @internal */ export const enum TypeFacts { None = 0, - TypeofEQString = 1 << 0, // typeof x === "string" - TypeofEQNumber = 1 << 1, // typeof x === "number" - TypeofEQBigInt = 1 << 2, // typeof x === "bigint" - TypeofEQBoolean = 1 << 3, // typeof x === "boolean" - TypeofEQSymbol = 1 << 4, // typeof x === "symbol" - TypeofEQObject = 1 << 5, // typeof x === "object" - TypeofEQFunction = 1 << 6, // typeof x === "function" - TypeofEQHostObject = 1 << 7, // typeof x === "xxx" - TypeofNEString = 1 << 8, // typeof x !== "string" - TypeofNENumber = 1 << 9, // typeof x !== "number" - TypeofNEBigInt = 1 << 10, // typeof x !== "bigint" - TypeofNEBoolean = 1 << 11, // typeof x !== "boolean" - TypeofNESymbol = 1 << 12, // typeof x !== "symbol" - TypeofNEObject = 1 << 13, // typeof x !== "object" - TypeofNEFunction = 1 << 14, // typeof x !== "function" + TypeofEQString = 1 << 0, // typeof x === "string" + TypeofEQNumber = 1 << 1, // typeof x === "number" + TypeofEQBigInt = 1 << 2, // typeof x === "bigint" + TypeofEQBoolean = 1 << 3, // typeof x === "boolean" + TypeofEQSymbol = 1 << 4, // typeof x === "symbol" + TypeofEQObject = 1 << 5, // typeof x === "object" + TypeofEQFunction = 1 << 6, // typeof x === "function" + TypeofEQHostObject = 1 << 7, // typeof x === "xxx" + TypeofNEString = 1 << 8, // typeof x !== "string" + TypeofNENumber = 1 << 9, // typeof x !== "number" + TypeofNEBigInt = 1 << 10, // typeof x !== "bigint" + TypeofNEBoolean = 1 << 11, // typeof x !== "boolean" + TypeofNESymbol = 1 << 12, // typeof x !== "symbol" + TypeofNEObject = 1 << 13, // typeof x !== "object" + TypeofNEFunction = 1 << 14, // typeof x !== "function" TypeofNEHostObject = 1 << 15, // typeof x !== "xxx" - EQUndefined = 1 << 16, // x === undefined - EQNull = 1 << 17, // x === null - EQUndefinedOrNull = 1 << 18, // x === undefined / x === null - NEUndefined = 1 << 19, // x !== undefined - NENull = 1 << 20, // x !== null - NEUndefinedOrNull = 1 << 21, // x != undefined / x != null - Truthy = 1 << 22, // x - Falsy = 1 << 23, // !x - IsUndefined = 1 << 24, // Contains undefined or intersection with undefined - IsNull = 1 << 25, // Contains null or intersection with null + EQUndefined = 1 << 16, // x === undefined + EQNull = 1 << 17, // x === null + EQUndefinedOrNull = 1 << 18, // x === undefined / x === null + NEUndefined = 1 << 19, // x !== undefined + NENull = 1 << 20, // x !== null + NEUndefinedOrNull = 1 << 21, // x != undefined / x != null + Truthy = 1 << 22, // x + Falsy = 1 << 23, // !x + IsUndefined = 1 << 24, // Contains undefined or intersection with undefined + IsNull = 1 << 25, // Contains null or intersection with null IsUndefinedOrNull = IsUndefined | IsNull, All = (1 << 27) - 1, // The following members encode facts about particular kinds of types for use in the getTypeFacts function. // The presence of a particular fact means that the given test is true for some (and possibly all) values // of that kind of type. - BaseStringStrictFacts = TypeofEQString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull, - BaseStringFacts = BaseStringStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, + BaseStringStrictFacts = TypeofEQString | + TypeofNENumber | + TypeofNEBigInt | + TypeofNEBoolean | + TypeofNESymbol | + TypeofNEObject | + TypeofNEFunction | + TypeofNEHostObject | + NEUndefined | + NENull | + NEUndefinedOrNull, + BaseStringFacts = BaseStringStrictFacts | + EQUndefined | + EQNull | + EQUndefinedOrNull | + Falsy, StringStrictFacts = BaseStringStrictFacts | Truthy | Falsy, StringFacts = BaseStringFacts | Truthy, EmptyStringStrictFacts = BaseStringStrictFacts | Falsy, EmptyStringFacts = BaseStringFacts, NonEmptyStringStrictFacts = BaseStringStrictFacts | Truthy, NonEmptyStringFacts = BaseStringFacts | Truthy, - BaseNumberStrictFacts = TypeofEQNumber | TypeofNEString | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull, - BaseNumberFacts = BaseNumberStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, + BaseNumberStrictFacts = TypeofEQNumber | + TypeofNEString | + TypeofNEBigInt | + TypeofNEBoolean | + TypeofNESymbol | + TypeofNEObject | + TypeofNEFunction | + TypeofNEHostObject | + NEUndefined | + NENull | + NEUndefinedOrNull, + BaseNumberFacts = BaseNumberStrictFacts | + EQUndefined | + EQNull | + EQUndefinedOrNull | + Falsy, NumberStrictFacts = BaseNumberStrictFacts | Truthy | Falsy, NumberFacts = BaseNumberFacts | Truthy, ZeroNumberStrictFacts = BaseNumberStrictFacts | Falsy, ZeroNumberFacts = BaseNumberFacts, NonZeroNumberStrictFacts = BaseNumberStrictFacts | Truthy, NonZeroNumberFacts = BaseNumberFacts | Truthy, - BaseBigIntStrictFacts = TypeofEQBigInt | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull, - BaseBigIntFacts = BaseBigIntStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, + BaseBigIntStrictFacts = TypeofEQBigInt | + TypeofNEString | + TypeofNENumber | + TypeofNEBoolean | + TypeofNESymbol | + TypeofNEObject | + TypeofNEFunction | + TypeofNEHostObject | + NEUndefined | + NENull | + NEUndefinedOrNull, + BaseBigIntFacts = BaseBigIntStrictFacts | + EQUndefined | + EQNull | + EQUndefinedOrNull | + Falsy, BigIntStrictFacts = BaseBigIntStrictFacts | Truthy | Falsy, BigIntFacts = BaseBigIntFacts | Truthy, ZeroBigIntStrictFacts = BaseBigIntStrictFacts | Falsy, ZeroBigIntFacts = BaseBigIntFacts, NonZeroBigIntStrictFacts = BaseBigIntStrictFacts | Truthy, NonZeroBigIntFacts = BaseBigIntFacts | Truthy, - BaseBooleanStrictFacts = TypeofEQBoolean | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull, - BaseBooleanFacts = BaseBooleanStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, + BaseBooleanStrictFacts = TypeofEQBoolean | + TypeofNEString | + TypeofNENumber | + TypeofNEBigInt | + TypeofNESymbol | + TypeofNEObject | + TypeofNEFunction | + TypeofNEHostObject | + NEUndefined | + NENull | + NEUndefinedOrNull, + BaseBooleanFacts = BaseBooleanStrictFacts | + EQUndefined | + EQNull | + EQUndefinedOrNull | + Falsy, BooleanStrictFacts = BaseBooleanStrictFacts | Truthy | Falsy, BooleanFacts = BaseBooleanFacts | Truthy, FalseStrictFacts = BaseBooleanStrictFacts | Falsy, FalseFacts = BaseBooleanFacts, TrueStrictFacts = BaseBooleanStrictFacts | Truthy, TrueFacts = BaseBooleanFacts | Truthy, - SymbolStrictFacts = TypeofEQSymbol | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy, - SymbolFacts = SymbolStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, - ObjectStrictFacts = TypeofEQObject | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | NEUndefined | NENull | NEUndefinedOrNull | Truthy, - ObjectFacts = ObjectStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, - FunctionStrictFacts = TypeofEQFunction | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy, - FunctionFacts = FunctionStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, - VoidFacts = TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | EQUndefined | EQUndefinedOrNull | NENull | Falsy, - UndefinedFacts = TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | EQUndefined | EQUndefinedOrNull | NENull | Falsy | IsUndefined, - NullFacts = TypeofEQObject | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | TypeofNEHostObject | EQNull | EQUndefinedOrNull | NEUndefined | Falsy | IsNull, - EmptyObjectStrictFacts = All & ~(EQUndefined | EQNull | EQUndefinedOrNull | IsUndefinedOrNull), + SymbolStrictFacts = TypeofEQSymbol | + TypeofNEString | + TypeofNENumber | + TypeofNEBigInt | + TypeofNEBoolean | + TypeofNEObject | + TypeofNEFunction | + TypeofNEHostObject | + NEUndefined | + NENull | + NEUndefinedOrNull | + Truthy, + SymbolFacts = SymbolStrictFacts | + EQUndefined | + EQNull | + EQUndefinedOrNull | + Falsy, + ObjectStrictFacts = TypeofEQObject | + TypeofEQHostObject | + TypeofNEString | + TypeofNENumber | + TypeofNEBigInt | + TypeofNEBoolean | + TypeofNESymbol | + TypeofNEFunction | + NEUndefined | + NENull | + NEUndefinedOrNull | + Truthy, + ObjectFacts = ObjectStrictFacts | + EQUndefined | + EQNull | + EQUndefinedOrNull | + Falsy, + FunctionStrictFacts = TypeofEQFunction | + TypeofEQHostObject | + TypeofNEString | + TypeofNENumber | + TypeofNEBigInt | + TypeofNEBoolean | + TypeofNESymbol | + TypeofNEObject | + NEUndefined | + NENull | + NEUndefinedOrNull | + Truthy, + FunctionFacts = FunctionStrictFacts | + EQUndefined | + EQNull | + EQUndefinedOrNull | + Falsy, + VoidFacts = TypeofNEString | + TypeofNENumber | + TypeofNEBigInt | + TypeofNEBoolean | + TypeofNESymbol | + TypeofNEObject | + TypeofNEFunction | + TypeofNEHostObject | + EQUndefined | + EQUndefinedOrNull | + NENull | + Falsy, + UndefinedFacts = TypeofNEString | + TypeofNENumber | + TypeofNEBigInt | + TypeofNEBoolean | + TypeofNESymbol | + TypeofNEObject | + TypeofNEFunction | + TypeofNEHostObject | + EQUndefined | + EQUndefinedOrNull | + NENull | + Falsy | + IsUndefined, + NullFacts = TypeofEQObject | + TypeofNEString | + TypeofNENumber | + TypeofNEBigInt | + TypeofNEBoolean | + TypeofNESymbol | + TypeofNEFunction | + TypeofNEHostObject | + EQNull | + EQUndefinedOrNull | + NEUndefined | + Falsy | + IsNull, + EmptyObjectStrictFacts = All & + ~(EQUndefined | EQNull | EQUndefinedOrNull | IsUndefinedOrNull), EmptyObjectFacts = All & ~IsUndefinedOrNull, UnknownFacts = All & ~IsUndefinedOrNull, - AllTypeofNE = TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | NEUndefined, + AllTypeofNE = TypeofNEString | + TypeofNENumber | + TypeofNEBigInt | + TypeofNEBoolean | + TypeofNESymbol | + TypeofNEObject | + TypeofNEFunction | + NEUndefined, // Masks OrFactsMask = TypeofEQFunction | TypeofNEObject, AndFactsMask = All & ~OrFactsMask, } -const typeofNEFacts: ReadonlyMap = new Map(Object.entries({ - string: TypeFacts.TypeofNEString, - number: TypeFacts.TypeofNENumber, - bigint: TypeFacts.TypeofNEBigInt, - boolean: TypeFacts.TypeofNEBoolean, - symbol: TypeFacts.TypeofNESymbol, - undefined: TypeFacts.NEUndefined, - object: TypeFacts.TypeofNEObject, - function: TypeFacts.TypeofNEFunction, -})); +const typeofNEFacts: ReadonlyMap = new Map( + Object.entries({ + string: TypeFacts.TypeofNEString, + number: TypeFacts.TypeofNENumber, + bigint: TypeFacts.TypeofNEBigInt, + boolean: TypeFacts.TypeofNEBoolean, + symbol: TypeFacts.TypeofNESymbol, + undefined: TypeFacts.NEUndefined, + object: TypeFacts.TypeofNEObject, + function: TypeFacts.TypeofNEFunction, + }) +); type TypeSystemEntity = Node | Symbol | Type | Signature; @@ -1327,16 +1485,16 @@ const enum TypeSystemPropertyName { // dprint-ignore /** @internal */ export const enum CheckMode { - Normal = 0, // Normal type checking - Contextual = 1 << 0, // Explicitly assigned contextual type, therefore not cacheable - Inferential = 1 << 1, // Inferential typing - SkipContextSensitive = 1 << 2, // Skip context sensitive function expressions - SkipGenericFunctions = 1 << 3, // Skip single signature generic functions - IsForSignatureHelp = 1 << 4, // Call resolution for purposes of signature help - RestBindingElement = 1 << 5, // Checking a type that is going to be used to determine the type of a rest binding element - // e.g. in `const { a, ...rest } = foo`, when checking the type of `foo` to determine the type of `rest`, - // we need to preserve generic types instead of substituting them for constraints - TypeOnly = 1 << 6, // Called from getTypeOfExpression, diagnostics may be omitted + Normal = 0, // Normal type checking + Contextual = 1 << 0, // Explicitly assigned contextual type, therefore not cacheable + Inferential = 1 << 1, // Inferential typing + SkipContextSensitive = 1 << 2, // Skip context sensitive function expressions + SkipGenericFunctions = 1 << 3, // Skip single signature generic functions + IsForSignatureHelp = 1 << 4, // Call resolution for purposes of signature help + RestBindingElement = 1 << 5, // Checking a type that is going to be used to determine the type of a rest binding element + // e.g. in `const { a, ...rest } = foo`, when checking the type of `foo` to determine the type of `rest`, + // we need to preserve generic types instead of substituting them for constraints + TypeOnly = 1 << 6, // Called from getTypeOfExpression, diagnostics may be omitted } /** @internal */ @@ -1394,7 +1552,11 @@ const enum UnusedKind { } /** @param containingNode Node to check for parse error */ -type AddUnusedDiagnostic = (containingNode: Node, type: UnusedKind, diagnostic: DiagnosticWithLocation) => void; +type AddUnusedDiagnostic = ( + containingNode: Node, + type: UnusedKind, + diagnostic: DiagnosticWithLocation +) => void; const isNotOverloadAndNotAccessor = and(isNotOverload, isNotAccessor); @@ -1429,13 +1591,15 @@ const enum IntrinsicTypeKind { NoInfer, } -const intrinsicTypeKinds: ReadonlyMap = new Map(Object.entries({ - Uppercase: IntrinsicTypeKind.Uppercase, - Lowercase: IntrinsicTypeKind.Lowercase, - Capitalize: IntrinsicTypeKind.Capitalize, - Uncapitalize: IntrinsicTypeKind.Uncapitalize, - NoInfer: IntrinsicTypeKind.NoInfer, -})); +const intrinsicTypeKinds: ReadonlyMap = new Map( + Object.entries({ + Uppercase: IntrinsicTypeKind.Uppercase, + Lowercase: IntrinsicTypeKind.Lowercase, + Capitalize: IntrinsicTypeKind.Capitalize, + Uncapitalize: IntrinsicTypeKind.Uncapitalize, + NoInfer: IntrinsicTypeKind.NoInfer, + }) +); const SymbolLinks = class implements SymbolLinks { declare _symbolLinksBrand: any; @@ -1465,10 +1629,16 @@ export function getSymbolId(symbol: Symbol): SymbolId { } /** @internal */ -export function isInstantiatedModule(node: ModuleDeclaration, preserveConstEnums: boolean): boolean { +export function isInstantiatedModule( + node: ModuleDeclaration, + preserveConstEnums: boolean +): boolean { const moduleState = getModuleInstanceState(node); - return moduleState === ModuleInstanceState.Instantiated || - (preserveConstEnums && moduleState === ModuleInstanceState.ConstEnumOnly); + return ( + moduleState === ModuleInstanceState.Instantiated || + (preserveConstEnums && + moduleState === ModuleInstanceState.ConstEnumOnly) + ); } /** @internal */ @@ -1518,40 +1688,82 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { var legacyDecorators = !!compilerOptions.experimentalDecorators; var useDefineForClassFields = getUseDefineForClassFields(compilerOptions); var emitStandardClassFields = getEmitStandardClassFields(compilerOptions); - var allowSyntheticDefaultImports = getAllowSyntheticDefaultImports(compilerOptions); - var strictNullChecks = getStrictOptionValue(compilerOptions, "strictNullChecks"); - var strictFunctionTypes = getStrictOptionValue(compilerOptions, "strictFunctionTypes"); - var strictBindCallApply = getStrictOptionValue(compilerOptions, "strictBindCallApply"); - var strictPropertyInitialization = getStrictOptionValue(compilerOptions, "strictPropertyInitialization"); - var strictBuiltinIteratorReturn = getStrictOptionValue(compilerOptions, "strictBuiltinIteratorReturn"); + var allowSyntheticDefaultImports = + getAllowSyntheticDefaultImports(compilerOptions); + var strictNullChecks = getStrictOptionValue( + compilerOptions, + "strictNullChecks" + ); + var strictFunctionTypes = getStrictOptionValue( + compilerOptions, + "strictFunctionTypes" + ); + var strictBindCallApply = getStrictOptionValue( + compilerOptions, + "strictBindCallApply" + ); + var strictPropertyInitialization = getStrictOptionValue( + compilerOptions, + "strictPropertyInitialization" + ); + var strictBuiltinIteratorReturn = getStrictOptionValue( + compilerOptions, + "strictBuiltinIteratorReturn" + ); var noImplicitAny = getStrictOptionValue(compilerOptions, "noImplicitAny"); - var noImplicitThis = getStrictOptionValue(compilerOptions, "noImplicitThis"); - var useUnknownInCatchVariables = getStrictOptionValue(compilerOptions, "useUnknownInCatchVariables"); + var noImplicitThis = getStrictOptionValue( + compilerOptions, + "noImplicitThis" + ); + var useUnknownInCatchVariables = getStrictOptionValue( + compilerOptions, + "useUnknownInCatchVariables" + ); var exactOptionalPropertyTypes = compilerOptions.exactOptionalPropertyTypes; - var noUncheckedSideEffectImports = !!compilerOptions.noUncheckedSideEffectImports; + var noUncheckedSideEffectImports = + !!compilerOptions.noUncheckedSideEffectImports; var checkBinaryExpression = createCheckBinaryExpression(); var emitResolver = createResolver(); var nodeBuilder = createNodeBuilder(); - var syntacticNodeBuilder = createSyntacticTypeNodeBuilder(compilerOptions, nodeBuilder.syntacticBuilderResolver); + var syntacticNodeBuilder = createSyntacticTypeNodeBuilder( + compilerOptions, + nodeBuilder.syntacticBuilderResolver + ); var evaluate = createEvaluator({ evaluateElementAccessExpression, evaluateEntityNameExpression, }); var globals = createSymbolTable(); - var undefinedSymbol = createSymbol(SymbolFlags.Property, "undefined" as __String); + var undefinedSymbol = createSymbol( + SymbolFlags.Property, + "undefined" as __String + ); undefinedSymbol.declarations = []; - var globalThisSymbol = createSymbol(SymbolFlags.Module, "globalThis" as __String, CheckFlags.Readonly); + var globalThisSymbol = createSymbol( + SymbolFlags.Module, + "globalThis" as __String, + CheckFlags.Readonly + ); globalThisSymbol.exports = globals; globalThisSymbol.declarations = []; globals.set(globalThisSymbol.escapedName, globalThisSymbol); - var argumentsSymbol = createSymbol(SymbolFlags.Property, "arguments" as __String); - var requireSymbol = createSymbol(SymbolFlags.Property, "require" as __String); - var isolatedModulesLikeFlagName = compilerOptions.verbatimModuleSyntax ? "verbatimModuleSyntax" : "isolatedModules"; - var canCollectSymbolAliasAccessabilityData = !compilerOptions.verbatimModuleSyntax; + var argumentsSymbol = createSymbol( + SymbolFlags.Property, + "arguments" as __String + ); + var requireSymbol = createSymbol( + SymbolFlags.Property, + "require" as __String + ); + var isolatedModulesLikeFlagName = compilerOptions.verbatimModuleSyntax + ? "verbatimModuleSyntax" + : "isolatedModules"; + var canCollectSymbolAliasAccessabilityData = + !compilerOptions.verbatimModuleSyntax; /** This will be set during calls to `getResolvedSignature` where services determines an apparent number of arguments greater than what is actually provided. */ var apparentArgumentCount: number | undefined; @@ -1570,7 +1782,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { getRequiresScopeChangeCache, setRequiresScopeChangeCache, lookup: getSymbol, - onPropertyWithInvalidInitializer: checkAndReportErrorForInvalidInitializer, + onPropertyWithInvalidInitializer: + checkAndReportErrorForInvalidInitializer, onFailedToResolveSymbol, onSuccessfullyResolvedSymbol, }); @@ -1592,9 +1805,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // extra cost of calling `getParseTreeNode` when calling these functions from inside the // checker. const checker: TypeChecker = { - getNodeCount: () => reduceLeft(host.getSourceFiles(), (n, s) => n + s.nodeCount, 0), - getIdentifierCount: () => reduceLeft(host.getSourceFiles(), (n, s) => n + s.identifierCount, 0), - getSymbolCount: () => reduceLeft(host.getSourceFiles(), (n, s) => n + s.symbolCount, symbolCount), + getNodeCount: () => + reduceLeft(host.getSourceFiles(), (n, s) => n + s.nodeCount, 0), + getIdentifierCount: () => + reduceLeft( + host.getSourceFiles(), + (n, s) => n + s.identifierCount, + 0 + ), + getSymbolCount: () => + reduceLeft( + host.getSourceFiles(), + (n, s) => n + s.symbolCount, + symbolCount + ), getTypeCount: () => typeCount, getInstantiationCount: () => totalInstantiationCount, getRelationCacheSizes: () => ({ @@ -1603,9 +1827,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { subtype: subtypeRelation.size, strictSubtype: strictSubtypeRelation.size, }), - isUndefinedSymbol: symbol => symbol === undefinedSymbol, - isArgumentsSymbol: symbol => symbol === argumentsSymbol, - isUnknownSymbol: symbol => symbol === unknownSymbol, + isUndefinedSymbol: (symbol) => symbol === undefinedSymbol, + isArgumentsSymbol: (symbol) => symbol === argumentsSymbol, + isUnknownSymbol: (symbol) => symbol === unknownSymbol, getMergedSymbol, symbolIsValue, getDiagnostics, @@ -1614,47 +1838,80 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { getUnmatchedProperties, getTypeOfSymbolAtLocation: (symbol, locationIn) => { const location = getParseTreeNode(locationIn); - return location ? getTypeOfSymbolAtLocation(symbol, location) : errorType; + return location + ? getTypeOfSymbolAtLocation(symbol, location) + : errorType; }, getTypeOfSymbol, - getSymbolsOfParameterPropertyDeclaration: (parameterIn, parameterName) => { + getSymbolsOfParameterPropertyDeclaration: ( + parameterIn, + parameterName + ) => { const parameter = getParseTreeNode(parameterIn, isParameter); - if (parameter === undefined) return Debug.fail("Cannot get symbols of a synthetic parameter that cannot be resolved to a parse-tree node."); - Debug.assert(isParameterPropertyDeclaration(parameter, parameter.parent)); - return getSymbolsOfParameterPropertyDeclaration(parameter, escapeLeadingUnderscores(parameterName)); + if (parameter === undefined) + return Debug.fail( + "Cannot get symbols of a synthetic parameter that cannot be resolved to a parse-tree node." + ); + Debug.assert( + isParameterPropertyDeclaration(parameter, parameter.parent) + ); + return getSymbolsOfParameterPropertyDeclaration( + parameter, + escapeLeadingUnderscores(parameterName) + ); }, getDeclaredTypeOfSymbol, getPropertiesOfType, - getPropertyOfType: (type, name) => getPropertyOfType(type, escapeLeadingUnderscores(name)), - getPrivateIdentifierPropertyOfType: (leftType: Type, name: string, location: Node) => { + getPropertyOfType: (type, name) => + getPropertyOfType(type, escapeLeadingUnderscores(name)), + getPrivateIdentifierPropertyOfType: ( + leftType: Type, + name: string, + location: Node + ) => { const node = getParseTreeNode(location); if (!node) { return undefined; } const propName = escapeLeadingUnderscores(name); - const lexicallyScopedIdentifier = lookupSymbolForPrivateIdentifierDeclaration(propName, node); - return lexicallyScopedIdentifier ? getPrivateIdentifierPropertyOfType(leftType, lexicallyScopedIdentifier) : undefined; + const lexicallyScopedIdentifier = + lookupSymbolForPrivateIdentifierDeclaration(propName, node); + return lexicallyScopedIdentifier + ? getPrivateIdentifierPropertyOfType( + leftType, + lexicallyScopedIdentifier + ) + : undefined; }, - getTypeOfPropertyOfType: (type, name) => getTypeOfPropertyOfType(type, escapeLeadingUnderscores(name)), - getIndexInfoOfType: (type, kind) => getIndexInfoOfType(type, kind === IndexKind.String ? stringType : numberType), + getTypeOfPropertyOfType: (type, name) => + getTypeOfPropertyOfType(type, escapeLeadingUnderscores(name)), + getIndexInfoOfType: (type, kind) => + getIndexInfoOfType( + type, + kind === IndexKind.String ? stringType : numberType + ), getIndexInfosOfType, getIndexInfosOfIndexSymbol, getSignaturesOfType, - getIndexTypeOfType: (type, kind) => getIndexTypeOfType(type, kind === IndexKind.String ? stringType : numberType), - getIndexType: type => getIndexType(type), + getIndexTypeOfType: (type, kind) => + getIndexTypeOfType( + type, + kind === IndexKind.String ? stringType : numberType + ), + getIndexType: (type) => getIndexType(type), getBaseTypes, getBaseTypeOfLiteralType, getWidenedType, getWidenedLiteralType, fillMissingTypeArguments, - getTypeFromTypeNode: nodeIn => { + getTypeFromTypeNode: (nodeIn) => { const node = getParseTreeNode(nodeIn, isTypeNode); return node ? getTypeFromTypeNode(node) : errorType; }, getParameterType: getTypeAtPosition, getParameterIdentifierInfoAtPosition, getPromisedTypeOfPromise, - getAwaitedType: type => getAwaitedType(type), + getAwaitedType: (type) => getAwaitedType(type), getReturnTypeOfSignature, isNullableType, getNullableType, @@ -1662,126 +1919,250 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { getNonOptionalType: removeOptionalTypeMarker, getTypeArguments, typeToTypeNode: nodeBuilder.typeToTypeNode, - typePredicateToTypePredicateNode: nodeBuilder.typePredicateToTypePredicateNode, - indexInfoToIndexSignatureDeclaration: nodeBuilder.indexInfoToIndexSignatureDeclaration, - signatureToSignatureDeclaration: nodeBuilder.signatureToSignatureDeclaration, + typePredicateToTypePredicateNode: + nodeBuilder.typePredicateToTypePredicateNode, + indexInfoToIndexSignatureDeclaration: + nodeBuilder.indexInfoToIndexSignatureDeclaration, + signatureToSignatureDeclaration: + nodeBuilder.signatureToSignatureDeclaration, symbolToEntityName: nodeBuilder.symbolToEntityName, symbolToExpression: nodeBuilder.symbolToExpression, symbolToNode: nodeBuilder.symbolToNode, - symbolToTypeParameterDeclarations: nodeBuilder.symbolToTypeParameterDeclarations, + symbolToTypeParameterDeclarations: + nodeBuilder.symbolToTypeParameterDeclarations, symbolToParameterDeclaration: nodeBuilder.symbolToParameterDeclaration, typeParameterToDeclaration: nodeBuilder.typeParameterToDeclaration, getSymbolsInScope: (locationIn, meaning) => { const location = getParseTreeNode(locationIn); return location ? getSymbolsInScope(location, meaning) : []; }, - getSymbolAtLocation: nodeIn => { + getSymbolAtLocation: (nodeIn) => { const node = getParseTreeNode(nodeIn); // set ignoreErrors: true because any lookups invoked by the API shouldn't cause any new errors - return node ? getSymbolAtLocation(node, /*ignoreErrors*/ true) : undefined; + return node + ? getSymbolAtLocation(node, /*ignoreErrors*/ true) + : undefined; }, - getIndexInfosAtLocation: nodeIn => { + getIndexInfosAtLocation: (nodeIn) => { const node = getParseTreeNode(nodeIn); return node ? getIndexInfosAtLocation(node) : undefined; }, - getShorthandAssignmentValueSymbol: nodeIn => { + getShorthandAssignmentValueSymbol: (nodeIn) => { const node = getParseTreeNode(nodeIn); return node ? getShorthandAssignmentValueSymbol(node) : undefined; }, - getExportSpecifierLocalTargetSymbol: nodeIn => { + getExportSpecifierLocalTargetSymbol: (nodeIn) => { const node = getParseTreeNode(nodeIn, isExportSpecifier); return node ? getExportSpecifierLocalTargetSymbol(node) : undefined; }, getExportSymbolOfSymbol(symbol) { return getMergedSymbol(symbol.exportSymbol || symbol); }, - getTypeAtLocation: nodeIn => { + getTypeAtLocation: (nodeIn) => { const node = getParseTreeNode(nodeIn); return node ? getTypeOfNode(node) : errorType; }, - getTypeOfAssignmentPattern: nodeIn => { + getTypeOfAssignmentPattern: (nodeIn) => { const node = getParseTreeNode(nodeIn, isAssignmentPattern); - return node && getTypeOfAssignmentPattern(node) || errorType; + return (node && getTypeOfAssignmentPattern(node)) || errorType; }, - getPropertySymbolOfDestructuringAssignment: locationIn => { + getPropertySymbolOfDestructuringAssignment: (locationIn) => { const location = getParseTreeNode(locationIn, isIdentifier); - return location ? getPropertySymbolOfDestructuringAssignment(location) : undefined; + return location + ? getPropertySymbolOfDestructuringAssignment(location) + : undefined; }, signatureToString: (signature, enclosingDeclaration, flags, kind) => { - return signatureToString(signature, getParseTreeNode(enclosingDeclaration), flags, kind); + return signatureToString( + signature, + getParseTreeNode(enclosingDeclaration), + flags, + kind + ); }, typeToString: (type, enclosingDeclaration, flags) => { - return typeToString(type, getParseTreeNode(enclosingDeclaration), flags); + return typeToString( + type, + getParseTreeNode(enclosingDeclaration), + flags + ); }, symbolToString: (symbol, enclosingDeclaration, meaning, flags) => { - return symbolToString(symbol, getParseTreeNode(enclosingDeclaration), meaning, flags); + return symbolToString( + symbol, + getParseTreeNode(enclosingDeclaration), + meaning, + flags + ); }, typePredicateToString: (predicate, enclosingDeclaration, flags) => { - return typePredicateToString(predicate, getParseTreeNode(enclosingDeclaration), flags); + return typePredicateToString( + predicate, + getParseTreeNode(enclosingDeclaration), + flags + ); }, - writeSignature: (signature, enclosingDeclaration, flags, kind, writer, maximumLength, verbosityLevel, out) => { - return signatureToString(signature, getParseTreeNode(enclosingDeclaration), flags, kind, writer, maximumLength, verbosityLevel, out); + writeSignature: ( + signature, + enclosingDeclaration, + flags, + kind, + writer, + maximumLength, + verbosityLevel, + out + ) => { + return signatureToString( + signature, + getParseTreeNode(enclosingDeclaration), + flags, + kind, + writer, + maximumLength, + verbosityLevel, + out + ); }, - writeType: (type, enclosingDeclaration, flags, writer, maximumLength, verbosityLevel, out) => { - return typeToString(type, getParseTreeNode(enclosingDeclaration), flags, writer, maximumLength, verbosityLevel, out); + writeType: ( + type, + enclosingDeclaration, + flags, + writer, + maximumLength, + verbosityLevel, + out + ) => { + return typeToString( + type, + getParseTreeNode(enclosingDeclaration), + flags, + writer, + maximumLength, + verbosityLevel, + out + ); }, writeSymbol: (symbol, enclosingDeclaration, meaning, flags, writer) => { - return symbolToString(symbol, getParseTreeNode(enclosingDeclaration), meaning, flags, writer); + return symbolToString( + symbol, + getParseTreeNode(enclosingDeclaration), + meaning, + flags, + writer + ); }, - writeTypePredicate: (predicate, enclosingDeclaration, flags, writer) => { - return typePredicateToString(predicate, getParseTreeNode(enclosingDeclaration), flags, writer); + writeTypePredicate: ( + predicate, + enclosingDeclaration, + flags, + writer + ) => { + return typePredicateToString( + predicate, + getParseTreeNode(enclosingDeclaration), + flags, + writer + ); }, getAugmentedPropertiesOfType, getRootSymbols, getSymbolOfExpando, - getContextualType: (nodeIn: Expression, contextFlags?: ContextFlags) => { + getContextualType: ( + nodeIn: Expression, + contextFlags?: ContextFlags + ) => { const node = getParseTreeNode(nodeIn, isExpression); if (!node) { return undefined; } if (contextFlags! & ContextFlags.Completions) { - return runWithInferenceBlockedFromSourceNode(node, () => getContextualType(node, contextFlags)); + return runWithInferenceBlockedFromSourceNode(node, () => + getContextualType(node, contextFlags) + ); } return getContextualType(node, contextFlags); }, - getContextualTypeForObjectLiteralElement: nodeIn => { + getContextualTypeForObjectLiteralElement: (nodeIn) => { const node = getParseTreeNode(nodeIn, isObjectLiteralElementLike); - return node ? getContextualTypeForObjectLiteralElement(node, /*contextFlags*/ undefined) : undefined; + return node + ? getContextualTypeForObjectLiteralElement( + node, + /*contextFlags*/ undefined + ) + : undefined; }, getContextualTypeForArgumentAtIndex: (nodeIn, argIndex) => { const node = getParseTreeNode(nodeIn, isCallLikeExpression); return node && getContextualTypeForArgumentAtIndex(node, argIndex); }, - getContextualTypeForJsxAttribute: nodeIn => { + getContextualTypeForJsxAttribute: (nodeIn) => { const node = getParseTreeNode(nodeIn, isJsxAttributeLike); - return node && getContextualTypeForJsxAttribute(node, /*contextFlags*/ undefined); + return ( + node && + getContextualTypeForJsxAttribute( + node, + /*contextFlags*/ undefined + ) + ); }, isContextSensitive, getTypeOfPropertyOfContextualType, getFullyQualifiedName, - getResolvedSignature: (node, candidatesOutArray, argumentCount) => getResolvedSignatureWorker(node, candidatesOutArray, argumentCount, CheckMode.Normal), + getResolvedSignature: (node, candidatesOutArray, argumentCount) => + getResolvedSignatureWorker( + node, + candidatesOutArray, + argumentCount, + CheckMode.Normal + ), getCandidateSignaturesForStringLiteralCompletions, - getResolvedSignatureForSignatureHelp: (node, candidatesOutArray, argumentCount) => runWithoutResolvedSignatureCaching(node, () => getResolvedSignatureWorker(node, candidatesOutArray, argumentCount, CheckMode.IsForSignatureHelp)), + getResolvedSignatureForSignatureHelp: ( + node, + candidatesOutArray, + argumentCount + ) => + runWithoutResolvedSignatureCaching(node, () => + getResolvedSignatureWorker( + node, + candidatesOutArray, + argumentCount, + CheckMode.IsForSignatureHelp + ) + ), getExpandedParameters, hasEffectiveRestParameter, containsArgumentsReference, - getConstantValue: nodeIn => { + getConstantValue: (nodeIn) => { const node = getParseTreeNode(nodeIn, canHaveConstantValue); return node ? getConstantValue(node) : undefined; }, isValidPropertyAccess: (nodeIn, propertyName) => { - const node = getParseTreeNode(nodeIn, isPropertyAccessOrQualifiedNameOrImportTypeNode); - return !!node && isValidPropertyAccess(node, escapeLeadingUnderscores(propertyName)); + const node = getParseTreeNode( + nodeIn, + isPropertyAccessOrQualifiedNameOrImportTypeNode + ); + return ( + !!node && + isValidPropertyAccess( + node, + escapeLeadingUnderscores(propertyName) + ) + ); }, isValidPropertyAccessForCompletions: (nodeIn, type, property) => { const node = getParseTreeNode(nodeIn, isPropertyAccessExpression); - return !!node && isValidPropertyAccessForCompletions(node, type, property); + return ( + !!node && + isValidPropertyAccessForCompletions(node, type, property) + ); }, - getSignatureFromDeclaration: declarationIn => { + getSignatureFromDeclaration: (declarationIn) => { const declaration = getParseTreeNode(declarationIn, isFunctionLike); - return declaration ? getSignatureFromDeclaration(declaration) : undefined; + return declaration + ? getSignatureFromDeclaration(declaration) + : undefined; }, - isImplementationOfOverload: nodeIn => { + isImplementationOfOverload: (nodeIn) => { const node = getParseTreeNode(nodeIn, isFunctionLike); return node ? isImplementationOfOverload(node) : undefined; }, @@ -1802,17 +2183,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { getResolvedSymbol, getConstraintOfTypeParameter, getFirstIdentifier, - getTypeArguments, + getTypeArguments ), getAmbientModules, getJsxIntrinsicTagNamesAt, - isOptionalParameter: nodeIn => { + isOptionalParameter: (nodeIn) => { const node = getParseTreeNode(nodeIn, isParameter); return node ? isOptionalParameter(node) : false; }, - tryGetMemberInModuleExports: (name, symbol) => tryGetMemberInModuleExports(escapeLeadingUnderscores(name), symbol), - tryGetMemberInModuleExportsAndProperties: (name, symbol) => tryGetMemberInModuleExportsAndProperties(escapeLeadingUnderscores(name), symbol), - tryFindAmbientModule: moduleName => tryFindAmbientModule(moduleName, /*withAugmentations*/ true), + tryGetMemberInModuleExports: (name, symbol) => + tryGetMemberInModuleExports(escapeLeadingUnderscores(name), symbol), + tryGetMemberInModuleExportsAndProperties: (name, symbol) => + tryGetMemberInModuleExportsAndProperties( + escapeLeadingUnderscores(name), + symbol + ), + tryFindAmbientModule: (moduleName) => + tryFindAmbientModule(moduleName, /*withAugmentations*/ true), getApparentType, getUnionType, isTypeAssignableTo, @@ -1832,8 +2219,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { createArrayType, getElementTypeOfArrayType, getBooleanType: () => booleanType, - getFalseType: (fresh?) => fresh ? falseType : regularFalseType, - getTrueType: (fresh?) => fresh ? trueType : regularTrueType, + getFalseType: (fresh?) => (fresh ? falseType : regularFalseType), + getTrueType: (fresh?) => (fresh ? trueType : regularTrueType), getVoidType: () => voidType, getUndefinedType: () => undefinedType, getNullType: () => nullType, @@ -1842,7 +2229,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { getNonPrimitiveType: () => nonPrimitiveType, getOptionalType: () => optionalType, getPromiseType: () => getGlobalPromiseType(/*reportErrors*/ false), - getPromiseLikeType: () => getGlobalPromiseLikeType(/*reportErrors*/ false), + getPromiseLikeType: () => + getGlobalPromiseLikeType(/*reportErrors*/ false), getAnyAsyncIterableType: () => { const type = getGlobalAsyncIterableType(/*reportErrors*/ false); if (type === emptyGenericType) return undefined; @@ -1858,36 +2246,68 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { getAllPossiblePropertiesOfTypes, getSuggestedSymbolForNonexistentProperty, getSuggestedSymbolForNonexistentJSXAttribute, - getSuggestedSymbolForNonexistentSymbol: (location, name, meaning) => getSuggestedSymbolForNonexistentSymbol(location, escapeLeadingUnderscores(name), meaning), + getSuggestedSymbolForNonexistentSymbol: (location, name, meaning) => + getSuggestedSymbolForNonexistentSymbol( + location, + escapeLeadingUnderscores(name), + meaning + ), getSuggestedSymbolForNonexistentModule, getSuggestedSymbolForNonexistentClassMember, getBaseConstraintOfType, - getDefaultFromTypeParameter: type => type && type.flags & TypeFlags.TypeParameter ? getDefaultFromTypeParameter(type as TypeParameter) : undefined, + getDefaultFromTypeParameter: (type) => + type && type.flags & TypeFlags.TypeParameter + ? getDefaultFromTypeParameter(type as TypeParameter) + : undefined, resolveName(name, location, meaning, excludeGlobals) { - return resolveName(location, escapeLeadingUnderscores(name), meaning, /*nameNotFoundMessage*/ undefined, /*isUse*/ false, excludeGlobals); + return resolveName( + location, + escapeLeadingUnderscores(name), + meaning, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ false, + excludeGlobals + ); }, - getJsxNamespace: n => unescapeLeadingUnderscores(getJsxNamespace(n)), - getJsxFragmentFactory: n => { + getJsxNamespace: (n) => unescapeLeadingUnderscores(getJsxNamespace(n)), + getJsxFragmentFactory: (n) => { const jsxFragmentFactory = getJsxFragmentFactoryEntity(n); - return jsxFragmentFactory && unescapeLeadingUnderscores(getFirstIdentifier(jsxFragmentFactory).escapedText); + return ( + jsxFragmentFactory && + unescapeLeadingUnderscores( + getFirstIdentifier(jsxFragmentFactory).escapedText + ) + ); }, getAccessibleSymbolChain, getTypePredicateOfSignature, - resolveExternalModuleName: moduleSpecifierIn => { - const moduleSpecifier = getParseTreeNode(moduleSpecifierIn, isExpression); - return moduleSpecifier && resolveExternalModuleName(moduleSpecifier, moduleSpecifier, /*ignoreErrors*/ true); + resolveExternalModuleName: (moduleSpecifierIn) => { + const moduleSpecifier = getParseTreeNode( + moduleSpecifierIn, + isExpression + ); + return ( + moduleSpecifier && + resolveExternalModuleName( + moduleSpecifier, + moduleSpecifier, + /*ignoreErrors*/ true + ) + ); }, resolveExternalModuleSymbol, tryGetThisTypeAt: (nodeIn, includeGlobalThis, container) => { const node = getParseTreeNode(nodeIn); return node && tryGetThisTypeAt(node, includeGlobalThis, container); }, - getTypeArgumentConstraint: nodeIn => { + getTypeArgumentConstraint: (nodeIn) => { const node = getParseTreeNode(nodeIn, isTypeNode); return node && getTypeArgumentConstraint(node); }, getSuggestionDiagnostics: (fileIn, ct) => { - const file = getParseTreeNode(fileIn, isSourceFile) || Debug.fail("Could not determine parsed source file."); + const file = + getParseTreeNode(fileIn, isSourceFile) || + Debug.fail("Could not determine parsed source file."); if (skipTypeChecking(file, compilerOptions, host)) { return emptyArray; } @@ -1901,18 +2321,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Ensure file is type checked, with _eager_ diagnostic production, so identifiers are registered as potentially unused checkSourceFileWithEagerDiagnostics(file); - Debug.assert(!!(getNodeLinks(file).flags & NodeCheckFlags.TypeChecked)); + Debug.assert( + !!(getNodeLinks(file).flags & NodeCheckFlags.TypeChecked) + ); - diagnostics = addRange(diagnostics, suggestionDiagnostics.getDiagnostics(file.fileName)); - checkUnusedIdentifiers(getPotentiallyUnusedIdentifiers(file), (containingNode, kind, diag) => { - if (!containsParseError(containingNode) && !unusedIsError(kind, !!(containingNode.flags & NodeFlags.Ambient))) { - (diagnostics || (diagnostics = [])).push({ ...diag, category: DiagnosticCategory.Suggestion }); + diagnostics = addRange( + diagnostics, + suggestionDiagnostics.getDiagnostics(file.fileName) + ); + checkUnusedIdentifiers( + getPotentiallyUnusedIdentifiers(file), + (containingNode, kind, diag) => { + if ( + !containsParseError(containingNode) && + !unusedIsError( + kind, + !!(containingNode.flags & NodeFlags.Ambient) + ) + ) { + (diagnostics || (diagnostics = [])).push({ + ...diag, + category: DiagnosticCategory.Suggestion, + }); + } } - }); + ); return diagnostics || emptyArray; - } - finally { + } finally { cancellationToken = undefined; } }, @@ -1921,8 +2357,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { try { cancellationToken = token; return callback(checker); - } - finally { + } finally { cancellationToken = undefined; } }, @@ -1941,15 +2376,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getTypeArgumentsForResolvedSignature(signature: Signature) { if (signature.mapper === undefined) return undefined; - return instantiateTypes((signature.target || signature).typeParameters, signature.mapper); + return instantiateTypes( + (signature.target || signature).typeParameters, + signature.mapper + ); } - function getCandidateSignaturesForStringLiteralCompletions(call: CallLikeExpression, editingArgument: Node) { + function getCandidateSignaturesForStringLiteralCompletions( + call: CallLikeExpression, + editingArgument: Node + ) { const candidatesSet = new Set(); const candidates: Signature[] = []; // first, get candidates when inference is blocked from the source node. - runWithInferenceBlockedFromSourceNode(editingArgument, () => getResolvedSignatureWorker(call, candidates, /*argumentCount*/ undefined, CheckMode.Normal)); + runWithInferenceBlockedFromSourceNode(editingArgument, () => + getResolvedSignatureWorker( + call, + candidates, + /*argumentCount*/ undefined, + CheckMode.Normal + ) + ); for (const candidate of candidates) { candidatesSet.add(candidate); } @@ -1958,7 +2406,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { candidates.length = 0; // next, get candidates where the source node is considered for inference. - runWithoutResolvedSignatureCaching(editingArgument, () => getResolvedSignatureWorker(call, candidates, /*argumentCount*/ undefined, CheckMode.Normal)); + runWithoutResolvedSignatureCaching(editingArgument, () => + getResolvedSignatureWorker( + call, + candidates, + /*argumentCount*/ undefined, + CheckMode.Normal + ) + ); for (const candidate of candidates) { candidatesSet.add(candidate); } @@ -1966,25 +2421,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return arrayFrom(candidatesSet); } - function runWithoutResolvedSignatureCaching(node: Node | undefined, fn: () => T): T { + function runWithoutResolvedSignatureCaching( + node: Node | undefined, + fn: () => T + ): T { node = findAncestor(node, isCallLikeOrFunctionLikeExpression); if (node) { const cachedResolvedSignatures = []; const cachedTypes = []; while (node) { const nodeLinks = getNodeLinks(node); - cachedResolvedSignatures.push([nodeLinks, nodeLinks.resolvedSignature] as const); + cachedResolvedSignatures.push([ + nodeLinks, + nodeLinks.resolvedSignature, + ] as const); nodeLinks.resolvedSignature = undefined; if (isFunctionExpressionOrArrowFunction(node)) { - const symbolLinks = getSymbolLinks(getSymbolOfDeclaration(node)); + const symbolLinks = getSymbolLinks( + getSymbolOfDeclaration(node) + ); const type = symbolLinks.type; cachedTypes.push([symbolLinks, type] as const); symbolLinks.type = undefined; } - node = findAncestor(node.parent, isCallLikeOrFunctionLikeExpression); + node = findAncestor( + node.parent, + isCallLikeOrFunctionLikeExpression + ); } const result = fn(); - for (const [nodeLinks, resolvedSignature] of cachedResolvedSignatures) { + for (const [ + nodeLinks, + resolvedSignature, + ] of cachedResolvedSignatures) { nodeLinks.resolvedSignature = resolvedSignature; } for (const [symbolLinks, type] of cachedTypes) { @@ -1995,15 +2464,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return fn(); } - function runWithInferenceBlockedFromSourceNode(node: Node | undefined, fn: () => T): T { + function runWithInferenceBlockedFromSourceNode( + node: Node | undefined, + fn: () => T + ): T { const containingCall = findAncestor(node, isCallLikeExpression); if (containingCall) { let toMarkSkip = node!; do { getNodeLinks(toMarkSkip).skipDirectInference = true; toMarkSkip = toMarkSkip.parent; - } - while (toMarkSkip && toMarkSkip !== containingCall); + } while (toMarkSkip && toMarkSkip !== containingCall); } isInferencePartiallyBlocked = true; @@ -2015,16 +2486,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { do { getNodeLinks(toMarkSkip).skipDirectInference = undefined; toMarkSkip = toMarkSkip.parent; - } - while (toMarkSkip && toMarkSkip !== containingCall); + } while (toMarkSkip && toMarkSkip !== containingCall); } return result; } - function getResolvedSignatureWorker(nodeIn: CallLikeExpression, candidatesOutArray: Signature[] | undefined, argumentCount: number | undefined, checkMode: CheckMode): Signature | undefined { + function getResolvedSignatureWorker( + nodeIn: CallLikeExpression, + candidatesOutArray: Signature[] | undefined, + argumentCount: number | undefined, + checkMode: CheckMode + ): Signature | undefined { const node = getParseTreeNode(nodeIn, isCallLikeExpression); apparentArgumentCount = argumentCount; - const res = !node ? undefined : getResolvedSignature(node, candidatesOutArray, checkMode); + const res = !node + ? undefined + : getResolvedSignature(node, candidatesOutArray, checkMode); apparentArgumentCount = undefined; return res; } @@ -2048,7 +2525,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { var undefinedProperties: SymbolTable = new Map(); var markerTypes = new Set(); - var unknownSymbol = createSymbol(SymbolFlags.Property, "unknown" as __String); + var unknownSymbol = createSymbol( + SymbolFlags.Property, + "unknown" as __String + ); var resolvingSymbol = createSymbol(0, InternalSymbolName.Resolving); var unresolvedSymbols = new Map(); var errorTypes = new Map(); @@ -2060,28 +2540,90 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { var seenIntrinsicNames = new Set(); var anyType = createIntrinsicType(TypeFlags.Any, "any"); - var autoType = createIntrinsicType(TypeFlags.Any, "any", ObjectFlags.NonInferrableType, "auto"); - var wildcardType = createIntrinsicType(TypeFlags.Any, "any", /*objectFlags*/ undefined, "wildcard"); - var blockedStringType = createIntrinsicType(TypeFlags.Any, "any", /*objectFlags*/ undefined, "blocked string"); + var autoType = createIntrinsicType( + TypeFlags.Any, + "any", + ObjectFlags.NonInferrableType, + "auto" + ); + var wildcardType = createIntrinsicType( + TypeFlags.Any, + "any", + /*objectFlags*/ undefined, + "wildcard" + ); + var blockedStringType = createIntrinsicType( + TypeFlags.Any, + "any", + /*objectFlags*/ undefined, + "blocked string" + ); var errorType = createIntrinsicType(TypeFlags.Any, "error"); var unresolvedType = createIntrinsicType(TypeFlags.Any, "unresolved"); - var nonInferrableAnyType = createIntrinsicType(TypeFlags.Any, "any", ObjectFlags.ContainsWideningType, "non-inferrable"); + var nonInferrableAnyType = createIntrinsicType( + TypeFlags.Any, + "any", + ObjectFlags.ContainsWideningType, + "non-inferrable" + ); var intrinsicMarkerType = createIntrinsicType(TypeFlags.Any, "intrinsic"); var unknownType = createIntrinsicType(TypeFlags.Unknown, "unknown"); var undefinedType = createIntrinsicType(TypeFlags.Undefined, "undefined"); - var undefinedWideningType = strictNullChecks ? undefinedType : createIntrinsicType(TypeFlags.Undefined, "undefined", ObjectFlags.ContainsWideningType, "widening"); - var missingType = createIntrinsicType(TypeFlags.Undefined, "undefined", /*objectFlags*/ undefined, "missing"); - var undefinedOrMissingType = exactOptionalPropertyTypes ? missingType : undefinedType; - var optionalType = createIntrinsicType(TypeFlags.Undefined, "undefined", /*objectFlags*/ undefined, "optional"); + var undefinedWideningType = strictNullChecks + ? undefinedType + : createIntrinsicType( + TypeFlags.Undefined, + "undefined", + ObjectFlags.ContainsWideningType, + "widening" + ); + var missingType = createIntrinsicType( + TypeFlags.Undefined, + "undefined", + /*objectFlags*/ undefined, + "missing" + ); + var undefinedOrMissingType = exactOptionalPropertyTypes + ? missingType + : undefinedType; + var optionalType = createIntrinsicType( + TypeFlags.Undefined, + "undefined", + /*objectFlags*/ undefined, + "optional" + ); var nullType = createIntrinsicType(TypeFlags.Null, "null"); - var nullWideningType = strictNullChecks ? nullType : createIntrinsicType(TypeFlags.Null, "null", ObjectFlags.ContainsWideningType, "widening"); + var nullWideningType = strictNullChecks + ? nullType + : createIntrinsicType( + TypeFlags.Null, + "null", + ObjectFlags.ContainsWideningType, + "widening" + ); var stringType = createIntrinsicType(TypeFlags.String, "string"); var numberType = createIntrinsicType(TypeFlags.Number, "number"); var bigintType = createIntrinsicType(TypeFlags.BigInt, "bigint"); - var falseType = createIntrinsicType(TypeFlags.BooleanLiteral, "false", /*objectFlags*/ undefined, "fresh") as FreshableIntrinsicType; - var regularFalseType = createIntrinsicType(TypeFlags.BooleanLiteral, "false") as FreshableIntrinsicType; - var trueType = createIntrinsicType(TypeFlags.BooleanLiteral, "true", /*objectFlags*/ undefined, "fresh") as FreshableIntrinsicType; - var regularTrueType = createIntrinsicType(TypeFlags.BooleanLiteral, "true") as FreshableIntrinsicType; + var falseType = createIntrinsicType( + TypeFlags.BooleanLiteral, + "false", + /*objectFlags*/ undefined, + "fresh" + ) as FreshableIntrinsicType; + var regularFalseType = createIntrinsicType( + TypeFlags.BooleanLiteral, + "false" + ) as FreshableIntrinsicType; + var trueType = createIntrinsicType( + TypeFlags.BooleanLiteral, + "true", + /*objectFlags*/ undefined, + "fresh" + ) as FreshableIntrinsicType; + var regularTrueType = createIntrinsicType( + TypeFlags.BooleanLiteral, + "true" + ) as FreshableIntrinsicType; trueType.regularType = regularTrueType; trueType.freshType = trueType; regularTrueType.regularType = regularTrueType; @@ -2094,58 +2636,191 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { var esSymbolType = createIntrinsicType(TypeFlags.ESSymbol, "symbol"); var voidType = createIntrinsicType(TypeFlags.Void, "void"); var neverType = createIntrinsicType(TypeFlags.Never, "never"); - var silentNeverType = createIntrinsicType(TypeFlags.Never, "never", ObjectFlags.NonInferrableType, "silent"); - var implicitNeverType = createIntrinsicType(TypeFlags.Never, "never", /*objectFlags*/ undefined, "implicit"); - var unreachableNeverType = createIntrinsicType(TypeFlags.Never, "never", /*objectFlags*/ undefined, "unreachable"); - var nonPrimitiveType = createIntrinsicType(TypeFlags.NonPrimitive, "object"); + var silentNeverType = createIntrinsicType( + TypeFlags.Never, + "never", + ObjectFlags.NonInferrableType, + "silent" + ); + var implicitNeverType = createIntrinsicType( + TypeFlags.Never, + "never", + /*objectFlags*/ undefined, + "implicit" + ); + var unreachableNeverType = createIntrinsicType( + TypeFlags.Never, + "never", + /*objectFlags*/ undefined, + "unreachable" + ); + var nonPrimitiveType = createIntrinsicType( + TypeFlags.NonPrimitive, + "object" + ); var stringOrNumberType = getUnionType([stringType, numberType]); - var stringNumberSymbolType = getUnionType([stringType, numberType, esSymbolType]); + var stringNumberSymbolType = getUnionType([ + stringType, + numberType, + esSymbolType, + ]); var numberOrBigIntType = getUnionType([numberType, bigintType]); - var templateConstraintType = getUnionType([stringType, numberType, booleanType, bigintType, nullType, undefinedType]) as UnionType; + var templateConstraintType = getUnionType([ + stringType, + numberType, + booleanType, + bigintType, + nullType, + undefinedType, + ]) as UnionType; var numericStringType = getTemplateLiteralType(["", ""], [numberType]); // The `${number}` type - var restrictiveMapper: TypeMapper = makeFunctionTypeMapper(t => t.flags & TypeFlags.TypeParameter ? getRestrictiveTypeParameter(t as TypeParameter) : t, () => "(restrictive mapper)"); - var permissiveMapper: TypeMapper = makeFunctionTypeMapper(t => t.flags & TypeFlags.TypeParameter ? wildcardType : t, () => "(permissive mapper)"); - var uniqueLiteralType = createIntrinsicType(TypeFlags.Never, "never", /*objectFlags*/ undefined, "unique literal"); // `uniqueLiteralType` is a special `never` flagged by union reduction to behave as a literal - var uniqueLiteralMapper: TypeMapper = makeFunctionTypeMapper(t => t.flags & TypeFlags.TypeParameter ? uniqueLiteralType : t, () => "(unique literal mapper)"); // replace all type parameters with the unique literal type (disregarding constraints) - var outofbandVarianceMarkerHandler: ((onlyUnreliable: boolean) => void) | undefined; - var reportUnreliableMapper = makeFunctionTypeMapper(t => { - if (outofbandVarianceMarkerHandler && (t === markerSuperType || t === markerSubType || t === markerOtherType)) { - outofbandVarianceMarkerHandler(/*onlyUnreliable*/ true); - } - return t; - }, () => "(unmeasurable reporter)"); - var reportUnmeasurableMapper = makeFunctionTypeMapper(t => { - if (outofbandVarianceMarkerHandler && (t === markerSuperType || t === markerSubType || t === markerOtherType)) { - outofbandVarianceMarkerHandler(/*onlyUnreliable*/ false); - } - return t; - }, () => "(unreliable reporter)"); - - var emptyObjectType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray); - var emptyJsxObjectType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray); + var restrictiveMapper: TypeMapper = makeFunctionTypeMapper( + (t) => + t.flags & TypeFlags.TypeParameter + ? getRestrictiveTypeParameter(t as TypeParameter) + : t, + () => "(restrictive mapper)" + ); + var permissiveMapper: TypeMapper = makeFunctionTypeMapper( + (t) => (t.flags & TypeFlags.TypeParameter ? wildcardType : t), + () => "(permissive mapper)" + ); + var uniqueLiteralType = createIntrinsicType( + TypeFlags.Never, + "never", + /*objectFlags*/ undefined, + "unique literal" + ); // `uniqueLiteralType` is a special `never` flagged by union reduction to behave as a literal + var uniqueLiteralMapper: TypeMapper = makeFunctionTypeMapper( + (t) => (t.flags & TypeFlags.TypeParameter ? uniqueLiteralType : t), + () => "(unique literal mapper)" + ); // replace all type parameters with the unique literal type (disregarding constraints) + var outofbandVarianceMarkerHandler: + | ((onlyUnreliable: boolean) => void) + | undefined; + var reportUnreliableMapper = makeFunctionTypeMapper( + (t) => { + if ( + outofbandVarianceMarkerHandler && + (t === markerSuperType || + t === markerSubType || + t === markerOtherType) + ) { + outofbandVarianceMarkerHandler(/*onlyUnreliable*/ true); + } + return t; + }, + () => "(unmeasurable reporter)" + ); + var reportUnmeasurableMapper = makeFunctionTypeMapper( + (t) => { + if ( + outofbandVarianceMarkerHandler && + (t === markerSuperType || + t === markerSubType || + t === markerOtherType) + ) { + outofbandVarianceMarkerHandler(/*onlyUnreliable*/ false); + } + return t; + }, + () => "(unreliable reporter)" + ); + + var emptyObjectType = createAnonymousType( + /*symbol*/ undefined, + emptySymbols, + emptyArray, + emptyArray, + emptyArray + ); + var emptyJsxObjectType = createAnonymousType( + /*symbol*/ undefined, + emptySymbols, + emptyArray, + emptyArray, + emptyArray + ); emptyJsxObjectType.objectFlags |= ObjectFlags.JsxAttributes; - var emptyFreshJsxObjectType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray); - emptyFreshJsxObjectType.objectFlags |= ObjectFlags.JsxAttributes | ObjectFlags.FreshLiteral | ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral; - - var emptyTypeLiteralSymbol = createSymbol(SymbolFlags.TypeLiteral, InternalSymbolName.Type); + var emptyFreshJsxObjectType = createAnonymousType( + /*symbol*/ undefined, + emptySymbols, + emptyArray, + emptyArray, + emptyArray + ); + emptyFreshJsxObjectType.objectFlags |= + ObjectFlags.JsxAttributes | + ObjectFlags.FreshLiteral | + ObjectFlags.ObjectLiteral | + ObjectFlags.ContainsObjectOrArrayLiteral; + + var emptyTypeLiteralSymbol = createSymbol( + SymbolFlags.TypeLiteral, + InternalSymbolName.Type + ); emptyTypeLiteralSymbol.members = createSymbolTable(); - var emptyTypeLiteralType = createAnonymousType(emptyTypeLiteralSymbol, emptySymbols, emptyArray, emptyArray, emptyArray); - - var unknownEmptyObjectType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray); - var unknownUnionType = strictNullChecks ? getUnionType([undefinedType, nullType, unknownEmptyObjectType]) : unknownType; - - var emptyGenericType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray) as ObjectType as GenericType; + var emptyTypeLiteralType = createAnonymousType( + emptyTypeLiteralSymbol, + emptySymbols, + emptyArray, + emptyArray, + emptyArray + ); + + var unknownEmptyObjectType = createAnonymousType( + /*symbol*/ undefined, + emptySymbols, + emptyArray, + emptyArray, + emptyArray + ); + var unknownUnionType = strictNullChecks + ? getUnionType([undefinedType, nullType, unknownEmptyObjectType]) + : unknownType; + + var emptyGenericType = createAnonymousType( + /*symbol*/ undefined, + emptySymbols, + emptyArray, + emptyArray, + emptyArray + ) as ObjectType as GenericType; emptyGenericType.instantiations = new Map(); - var anyFunctionType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray); + var anyFunctionType = createAnonymousType( + /*symbol*/ undefined, + emptySymbols, + emptyArray, + emptyArray, + emptyArray + ); // The anyFunctionType contains the anyFunctionType by definition. The flag is further propagated // in getPropagatingFlagsOfTypes, and it is checked in inferFromTypes. anyFunctionType.objectFlags |= ObjectFlags.NonInferrableType; - var noConstraintType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray); - var circularConstraintType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray); - var resolvingDefaultType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray); + var noConstraintType = createAnonymousType( + /*symbol*/ undefined, + emptySymbols, + emptyArray, + emptyArray, + emptyArray + ); + var circularConstraintType = createAnonymousType( + /*symbol*/ undefined, + emptySymbols, + emptyArray, + emptyArray, + emptyArray + ); + var resolvingDefaultType = createAnonymousType( + /*symbol*/ undefined, + emptySymbols, + emptyArray, + emptyArray, + emptyArray + ); var markerSuperType = createTypeParameter(); var markerSubType = createTypeParameter(); @@ -2156,15 +2831,64 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { var markerSubTypeForCheck = createTypeParameter(); markerSubTypeForCheck.constraint = markerSuperTypeForCheck; - var noTypePredicate = createTypePredicate(TypePredicateKind.Identifier, "<>", 0, anyType); - - var anySignature = createSignature(/*declaration*/ undefined, /*typeParameters*/ undefined, /*thisParameter*/ undefined, emptyArray, anyType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.None); - var unknownSignature = createSignature(/*declaration*/ undefined, /*typeParameters*/ undefined, /*thisParameter*/ undefined, emptyArray, errorType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.None); - var resolvingSignature = createSignature(/*declaration*/ undefined, /*typeParameters*/ undefined, /*thisParameter*/ undefined, emptyArray, anyType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.None); - var silentNeverSignature = createSignature(/*declaration*/ undefined, /*typeParameters*/ undefined, /*thisParameter*/ undefined, emptyArray, silentNeverType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.None); - - var enumNumberIndexInfo = createIndexInfo(numberType, stringType, /*isReadonly*/ true); - var anyBaseTypeIndexInfo = createIndexInfo(stringType, anyType, /*isReadonly*/ false); + var noTypePredicate = createTypePredicate( + TypePredicateKind.Identifier, + "<>", + 0, + anyType + ); + + var anySignature = createSignature( + /*declaration*/ undefined, + /*typeParameters*/ undefined, + /*thisParameter*/ undefined, + emptyArray, + anyType, + /*resolvedTypePredicate*/ undefined, + 0, + SignatureFlags.None + ); + var unknownSignature = createSignature( + /*declaration*/ undefined, + /*typeParameters*/ undefined, + /*thisParameter*/ undefined, + emptyArray, + errorType, + /*resolvedTypePredicate*/ undefined, + 0, + SignatureFlags.None + ); + var resolvingSignature = createSignature( + /*declaration*/ undefined, + /*typeParameters*/ undefined, + /*thisParameter*/ undefined, + emptyArray, + anyType, + /*resolvedTypePredicate*/ undefined, + 0, + SignatureFlags.None + ); + var silentNeverSignature = createSignature( + /*declaration*/ undefined, + /*typeParameters*/ undefined, + /*thisParameter*/ undefined, + emptyArray, + silentNeverType, + /*resolvedTypePredicate*/ undefined, + 0, + SignatureFlags.None + ); + + var enumNumberIndexInfo = createIndexInfo( + numberType, + stringType, + /*isReadonly*/ true + ); + var anyBaseTypeIndexInfo = createIndexInfo( + stringType, + anyType, + /*isReadonly*/ false + ); var iterationTypesCache = new Map(); // cache for common IterationTypes instances var noIterationTypes: IterationTypes = { @@ -2191,10 +2915,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { getGlobalIteratorObjectType: getGlobalAsyncIteratorObjectType, getGlobalGeneratorType: getGlobalAsyncGeneratorType, getGlobalBuiltinIteratorTypes: getGlobalBuiltinAsyncIteratorTypes, - resolveIterationType: (type, errorNode) => getAwaitedType(type, errorNode, Diagnostics.Type_of_await_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member), - mustHaveANextMethodDiagnostic: Diagnostics.An_async_iterator_must_have_a_next_method, - mustBeAMethodDiagnostic: Diagnostics.The_0_property_of_an_async_iterator_must_be_a_method, - mustHaveAValueDiagnostic: Diagnostics.The_type_returned_by_the_0_method_of_an_async_iterator_must_be_a_promise_for_a_type_with_a_value_property, + resolveIterationType: (type, errorNode) => + getAwaitedType( + type, + errorNode, + Diagnostics.Type_of_await_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member + ), + mustHaveANextMethodDiagnostic: + Diagnostics.An_async_iterator_must_have_a_next_method, + mustBeAMethodDiagnostic: + Diagnostics.The_0_property_of_an_async_iterator_must_be_a_method, + mustHaveAValueDiagnostic: + Diagnostics.The_type_returned_by_the_0_method_of_an_async_iterator_must_be_a_promise_for_a_type_with_a_value_property, }; var syncIterationTypesResolver: IterationTypesResolver = { @@ -2208,9 +2940,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { getGlobalGeneratorType, getGlobalBuiltinIteratorTypes, resolveIterationType: (type, _errorNode) => type, - mustHaveANextMethodDiagnostic: Diagnostics.An_iterator_must_have_a_next_method, - mustBeAMethodDiagnostic: Diagnostics.The_0_property_of_an_iterator_must_be_a_method, - mustHaveAValueDiagnostic: Diagnostics.The_type_returned_by_the_0_method_of_an_iterator_must_have_a_value_property, + mustHaveANextMethodDiagnostic: + Diagnostics.An_iterator_must_have_a_next_method, + mustBeAMethodDiagnostic: + Diagnostics.The_0_property_of_an_iterator_must_be_a_method, + mustHaveAValueDiagnostic: + Diagnostics.The_type_returned_by_the_0_method_of_an_iterator_must_have_a_value_property, }; interface DuplicateInfoForSymbol { @@ -2275,7 +3010,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { var deferredGlobalAsyncIteratorType: GenericType | undefined; var deferredGlobalAsyncIterableIteratorType: GenericType | undefined; var deferredGlobalBuiltinIteratorTypes: readonly GenericType[] | undefined; - var deferredGlobalBuiltinAsyncIteratorTypes: readonly GenericType[] | undefined; + var deferredGlobalBuiltinAsyncIteratorTypes: + | readonly GenericType[] + | undefined; var deferredGlobalAsyncIteratorObjectType: GenericType | undefined; var deferredGlobalAsyncGeneratorType: GenericType | undefined; var deferredGlobalTemplateStringsArrayType: ObjectType | undefined; @@ -2295,12 +3032,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { var deferredGlobalClassMethodDecoratorContextType: GenericType | undefined; var deferredGlobalClassGetterDecoratorContextType: GenericType | undefined; var deferredGlobalClassSetterDecoratorContextType: GenericType | undefined; - var deferredGlobalClassAccessorDecoratorContextType: GenericType | undefined; + var deferredGlobalClassAccessorDecoratorContextType: + | GenericType + | undefined; var deferredGlobalClassAccessorDecoratorTargetType: GenericType | undefined; var deferredGlobalClassAccessorDecoratorResultType: GenericType | undefined; var deferredGlobalClassFieldDecoratorContextType: GenericType | undefined; - var allPotentiallyUnusedIdentifiers = new Map(); // key is file name + var allPotentiallyUnusedIdentifiers = new Map< + Path, + PotentiallyUnusedIdentifier[] + >(); // key is file name var flowLoopStart = 0; var flowLoopCount = 0; @@ -2327,7 +3069,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { var emptyStringType = getStringLiteralType(""); var zeroType = getNumberLiteralType(0); - var zeroBigIntType = getBigIntLiteralType({ negative: false, base10Value: "0" }); + var zeroBigIntType = getBigIntLiteralType({ + negative: false, + base10Value: "0", + }); var resolutionTargets: TypeSystemEntity[] = []; var resolutionResults: boolean[] = []; @@ -2398,14 +3143,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isDefinitelyReferenceToGlobalSymbolObject(node: Node): boolean { if (!isPropertyAccessExpression(node)) return false; if (!isIdentifier(node.name)) return false; - if (!isPropertyAccessExpression(node.expression) && !isIdentifier(node.expression)) return false; + if ( + !isPropertyAccessExpression(node.expression) && + !isIdentifier(node.expression) + ) + return false; if (isIdentifier(node.expression)) { // Exactly `Symbol.something` and `Symbol` either does not resolve or definitely resolves to the global Symbol - return idText(node.expression) === "Symbol" && getResolvedSymbol(node.expression) === (getGlobalSymbol("Symbol" as __String, SymbolFlags.Value | SymbolFlags.ExportValue, /*diagnostic*/ undefined) || unknownSymbol); + return ( + idText(node.expression) === "Symbol" && + getResolvedSymbol(node.expression) === + (getGlobalSymbol( + "Symbol" as __String, + SymbolFlags.Value | SymbolFlags.ExportValue, + /*diagnostic*/ undefined + ) || unknownSymbol) + ); } if (!isIdentifier(node.expression.expression)) return false; // Exactly `globalThis.Symbol.something` and `globalThis` resolves to the global `globalThis` - return idText(node.expression.name) === "Symbol" && idText(node.expression.expression) === "globalThis" && getResolvedSymbol(node.expression.expression) === globalThisSymbol; + return ( + idText(node.expression.name) === "Symbol" && + idText(node.expression.expression) === "globalThis" && + getResolvedSymbol(node.expression.expression) === globalThisSymbol + ); } function getCachedType(key: string | undefined) { @@ -2427,23 +3188,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const jsxFragmentPragma = file.pragmas.get("jsxfrag"); if (jsxFragmentPragma) { - const chosenPragma = isArray(jsxFragmentPragma) ? jsxFragmentPragma[0] : jsxFragmentPragma; - file.localJsxFragmentFactory = parseIsolatedEntityName(chosenPragma.arguments.factory, languageVersion); - visitNode(file.localJsxFragmentFactory, markAsSynthetic, isEntityName); + const chosenPragma = isArray(jsxFragmentPragma) + ? jsxFragmentPragma[0] + : jsxFragmentPragma; + file.localJsxFragmentFactory = parseIsolatedEntityName( + chosenPragma.arguments.factory, + languageVersion + ); + visitNode( + file.localJsxFragmentFactory, + markAsSynthetic, + isEntityName + ); if (file.localJsxFragmentFactory) { - return file.localJsxFragmentNamespace = getFirstIdentifier(file.localJsxFragmentFactory).escapedText; + return (file.localJsxFragmentNamespace = + getFirstIdentifier( + file.localJsxFragmentFactory + ).escapedText); } } const entity = getJsxFragmentFactoryEntity(location); if (entity) { file.localJsxFragmentFactory = entity; - return file.localJsxFragmentNamespace = getFirstIdentifier(entity).escapedText; + return (file.localJsxFragmentNamespace = + getFirstIdentifier(entity).escapedText); } - } - else { + } else { const localJsxNamespace = getLocalJsxNamespace(file); if (localJsxNamespace) { - return file.localJsxNamespace = localJsxNamespace; + return (file.localJsxNamespace = localJsxNamespace); } } } @@ -2451,18 +3224,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!_jsxNamespace) { _jsxNamespace = "React" as __String; if (compilerOptions.jsxFactory) { - _jsxFactoryEntity = parseIsolatedEntityName(compilerOptions.jsxFactory, languageVersion); + _jsxFactoryEntity = parseIsolatedEntityName( + compilerOptions.jsxFactory, + languageVersion + ); visitNode(_jsxFactoryEntity, markAsSynthetic); if (_jsxFactoryEntity) { - _jsxNamespace = getFirstIdentifier(_jsxFactoryEntity).escapedText; + _jsxNamespace = + getFirstIdentifier(_jsxFactoryEntity).escapedText; } - } - else if (compilerOptions.reactNamespace) { - _jsxNamespace = escapeLeadingUnderscores(compilerOptions.reactNamespace); + } else if (compilerOptions.reactNamespace) { + _jsxNamespace = escapeLeadingUnderscores( + compilerOptions.reactNamespace + ); } } if (!_jsxFactoryEntity) { - _jsxFactoryEntity = factory.createQualifiedName(factory.createIdentifier(unescapeLeadingUnderscores(_jsxNamespace)), "createElement"); + _jsxFactoryEntity = factory.createQualifiedName( + factory.createIdentifier( + unescapeLeadingUnderscores(_jsxNamespace) + ), + "createElement" + ); } return _jsxNamespace; } @@ -2474,53 +3257,82 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const jsxPragma = file.pragmas.get("jsx"); if (jsxPragma) { const chosenPragma = isArray(jsxPragma) ? jsxPragma[0] : jsxPragma; - file.localJsxFactory = parseIsolatedEntityName(chosenPragma.arguments.factory, languageVersion); + file.localJsxFactory = parseIsolatedEntityName( + chosenPragma.arguments.factory, + languageVersion + ); visitNode(file.localJsxFactory, markAsSynthetic, isEntityName); if (file.localJsxFactory) { - return file.localJsxNamespace = getFirstIdentifier(file.localJsxFactory).escapedText; + return (file.localJsxNamespace = getFirstIdentifier( + file.localJsxFactory + ).escapedText); } } } function markAsSynthetic(node: T): VisitResult { setTextRangePosEnd(node, -1, -1); - return visitEachChildWorker(node, markAsSynthetic, /*context*/ undefined); + return visitEachChildWorker( + node, + markAsSynthetic, + /*context*/ undefined + ); } - function getEmitResolver(sourceFile: SourceFile, cancellationToken: CancellationToken, skipDiagnostics?: boolean) { + function getEmitResolver( + sourceFile: SourceFile, + cancellationToken: CancellationToken, + skipDiagnostics?: boolean + ) { // Ensure we have all the type information in place for this file so that all the // emitter questions of this resolver will return the right information. if (!skipDiagnostics) getDiagnostics(sourceFile, cancellationToken); return emitResolver; } - function lookupOrIssueError(location: Node | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments): Diagnostic { + function lookupOrIssueError( + location: Node | undefined, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ): Diagnostic { const diagnostic = location ? createDiagnosticForNode(location, message, ...args) : createCompilerDiagnostic(message, ...args); const existing = diagnostics.lookup(diagnostic); if (existing) { return existing; - } - else { + } else { diagnostics.add(diagnostic); return diagnostic; } } - function errorSkippedOn(key: keyof CompilerOptions, location: Node | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments): Diagnostic { + function errorSkippedOn( + key: keyof CompilerOptions, + location: Node | undefined, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ): Diagnostic { const diagnostic = error(location, message, ...args); diagnostic.skippedOn = key; return diagnostic; } - function createError(location: Node | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments): Diagnostic { + function createError( + location: Node | undefined, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ): Diagnostic { return location ? createDiagnosticForNode(location, message, ...args) : createCompilerDiagnostic(message, ...args); } - function error(location: Node | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments): Diagnostic { + function error( + location: Node | undefined, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ): Diagnostic { const diagnostic = createError(location, message, ...args); diagnostics.add(diagnostic); return diagnostic; @@ -2529,12 +3341,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function addErrorOrSuggestion(isError: boolean, diagnostic: Diagnostic) { if (isError) { diagnostics.add(diagnostic); - } - else { - suggestionDiagnostics.add({ ...diagnostic, category: DiagnosticCategory.Suggestion }); + } else { + suggestionDiagnostics.add({ + ...diagnostic, + category: DiagnosticCategory.Suggestion, + }); } } - function errorOrSuggestion(isError: boolean, location: Node, message: DiagnosticMessage | DiagnosticMessageChain, ...args: DiagnosticArguments): void { + function errorOrSuggestion( + isError: boolean, + location: Node, + message: DiagnosticMessage | DiagnosticMessageChain, + ...args: DiagnosticArguments + ): void { // Pseudo-synthesized input node if (location.pos < 0 || location.end < 0) { if (!isError) { @@ -2542,10 +3361,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Issue errors globally const file = getSourceFileOfNode(location); - addErrorOrSuggestion(isError, "message" in message ? createFileDiagnostic(file, 0, 0, message, ...args) : createDiagnosticForFileFromMessageChain(file, message)); // eslint-disable-line local/no-in-operator + addErrorOrSuggestion( + isError, + "message" in message + ? createFileDiagnostic(file, 0, 0, message, ...args) + : createDiagnosticForFileFromMessageChain(file, message) + ); return; } - addErrorOrSuggestion(isError, "message" in message ? createDiagnosticForNode(location, message, ...args) : createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(location), location, message)); // eslint-disable-line local/no-in-operator + addErrorOrSuggestion( + isError, + "message" in message + ? createDiagnosticForNode(location, message, ...args) + : createDiagnosticForNodeFromMessageChain( + getSourceFileOfNode(location), + location, + message + ) + ); } function errorAndMaybeSuggestAwait( @@ -2556,18 +3389,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { ): Diagnostic { const diagnostic = error(location, message, ...args); if (maybeMissingAwait) { - const related = createDiagnosticForNode(location, Diagnostics.Did_you_forget_to_use_await); + const related = createDiagnosticForNode( + location, + Diagnostics.Did_you_forget_to_use_await + ); addRelatedInfo(diagnostic, related); } return diagnostic; } - function addDeprecatedSuggestionWorker(declarations: Node | Node[], diagnostic: DiagnosticWithLocation) { - const deprecatedTag = Array.isArray(declarations) ? forEach(declarations, getJSDocDeprecatedTag) : getJSDocDeprecatedTag(declarations); + function addDeprecatedSuggestionWorker( + declarations: Node | Node[], + diagnostic: DiagnosticWithLocation + ) { + const deprecatedTag = Array.isArray(declarations) + ? forEach(declarations, getJSDocDeprecatedTag) + : getJSDocDeprecatedTag(declarations); if (deprecatedTag) { addRelatedInfo( diagnostic, - createDiagnosticForNode(deprecatedTag, Diagnostics.The_declaration_was_marked_as_deprecated_here), + createDiagnosticForNode( + deprecatedTag, + Diagnostics.The_declaration_was_marked_as_deprecated_here + ) ); } // We call `addRelatedInfo()` before adding the diagnostic to prevent duplicates. @@ -2578,31 +3422,68 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isDeprecatedSymbol(symbol: Symbol) { const parentSymbol = getParentOfSymbol(symbol); if (parentSymbol && length(symbol.declarations) > 1) { - return parentSymbol.flags & SymbolFlags.Interface ? some(symbol.declarations, isDeprecatedDeclaration) : every(symbol.declarations, isDeprecatedDeclaration); - } - return !!symbol.valueDeclaration && isDeprecatedDeclaration(symbol.valueDeclaration) - || length(symbol.declarations) && every(symbol.declarations, isDeprecatedDeclaration); + return parentSymbol.flags & SymbolFlags.Interface + ? some(symbol.declarations, isDeprecatedDeclaration) + : every(symbol.declarations, isDeprecatedDeclaration); + } + return ( + (!!symbol.valueDeclaration && + isDeprecatedDeclaration(symbol.valueDeclaration)) || + (length(symbol.declarations) && + every(symbol.declarations, isDeprecatedDeclaration)) + ); } function isDeprecatedDeclaration(declaration: Declaration) { - return !!(getCombinedNodeFlagsCached(declaration) & NodeFlags.Deprecated); + return !!( + getCombinedNodeFlagsCached(declaration) & NodeFlags.Deprecated + ); } - function addDeprecatedSuggestion(location: Node, declarations: Node[], deprecatedEntity: string) { - const diagnostic = createDiagnosticForNode(location, Diagnostics._0_is_deprecated, deprecatedEntity); + function addDeprecatedSuggestion( + location: Node, + declarations: Node[], + deprecatedEntity: string + ) { + const diagnostic = createDiagnosticForNode( + location, + Diagnostics._0_is_deprecated, + deprecatedEntity + ); return addDeprecatedSuggestionWorker(declarations, diagnostic); } - function addDeprecatedSuggestionWithSignature(location: Node, declaration: Node, deprecatedEntity: string | undefined, signatureString: string) { + function addDeprecatedSuggestionWithSignature( + location: Node, + declaration: Node, + deprecatedEntity: string | undefined, + signatureString: string + ) { const diagnostic = deprecatedEntity - ? createDiagnosticForNode(location, Diagnostics.The_signature_0_of_1_is_deprecated, signatureString, deprecatedEntity) - : createDiagnosticForNode(location, Diagnostics._0_is_deprecated, signatureString); + ? createDiagnosticForNode( + location, + Diagnostics.The_signature_0_of_1_is_deprecated, + signatureString, + deprecatedEntity + ) + : createDiagnosticForNode( + location, + Diagnostics._0_is_deprecated, + signatureString + ); return addDeprecatedSuggestionWorker(declaration, diagnostic); } - function createSymbol(flags: SymbolFlags, name: __String, checkFlags?: CheckFlags) { + function createSymbol( + flags: SymbolFlags, + name: __String, + checkFlags?: CheckFlags + ) { symbolCount++; - const symbol = new Symbol(flags | SymbolFlags.Transient, name) as TransientSymbol; + const symbol = new Symbol( + flags | SymbolFlags.Transient, + name + ) as TransientSymbol; symbol.links = new SymbolLinks() as TransientSymbolLinks; symbol.links.checkFlags = checkFlags || CheckFlags.None; return symbol; @@ -2622,21 +3503,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getExcludedSymbolFlags(flags: SymbolFlags): SymbolFlags { let result: SymbolFlags = 0; - if (flags & SymbolFlags.BlockScopedVariable) result |= SymbolFlags.BlockScopedVariableExcludes; - if (flags & SymbolFlags.FunctionScopedVariable) result |= SymbolFlags.FunctionScopedVariableExcludes; - if (flags & SymbolFlags.Property) result |= SymbolFlags.PropertyExcludes; - if (flags & SymbolFlags.EnumMember) result |= SymbolFlags.EnumMemberExcludes; - if (flags & SymbolFlags.Function) result |= SymbolFlags.FunctionExcludes; + if (flags & SymbolFlags.BlockScopedVariable) + result |= SymbolFlags.BlockScopedVariableExcludes; + if (flags & SymbolFlags.FunctionScopedVariable) + result |= SymbolFlags.FunctionScopedVariableExcludes; + if (flags & SymbolFlags.Property) + result |= SymbolFlags.PropertyExcludes; + if (flags & SymbolFlags.EnumMember) + result |= SymbolFlags.EnumMemberExcludes; + if (flags & SymbolFlags.Function) + result |= SymbolFlags.FunctionExcludes; if (flags & SymbolFlags.Class) result |= SymbolFlags.ClassExcludes; - if (flags & SymbolFlags.Interface) result |= SymbolFlags.InterfaceExcludes; - if (flags & SymbolFlags.RegularEnum) result |= SymbolFlags.RegularEnumExcludes; - if (flags & SymbolFlags.ConstEnum) result |= SymbolFlags.ConstEnumExcludes; - if (flags & SymbolFlags.ValueModule) result |= SymbolFlags.ValueModuleExcludes; + if (flags & SymbolFlags.Interface) + result |= SymbolFlags.InterfaceExcludes; + if (flags & SymbolFlags.RegularEnum) + result |= SymbolFlags.RegularEnumExcludes; + if (flags & SymbolFlags.ConstEnum) + result |= SymbolFlags.ConstEnumExcludes; + if (flags & SymbolFlags.ValueModule) + result |= SymbolFlags.ValueModuleExcludes; if (flags & SymbolFlags.Method) result |= SymbolFlags.MethodExcludes; - if (flags & SymbolFlags.GetAccessor) result |= SymbolFlags.GetAccessorExcludes; - if (flags & SymbolFlags.SetAccessor) result |= SymbolFlags.SetAccessorExcludes; - if (flags & SymbolFlags.TypeParameter) result |= SymbolFlags.TypeParameterExcludes; - if (flags & SymbolFlags.TypeAlias) result |= SymbolFlags.TypeAliasExcludes; + if (flags & SymbolFlags.GetAccessor) + result |= SymbolFlags.GetAccessorExcludes; + if (flags & SymbolFlags.SetAccessor) + result |= SymbolFlags.SetAccessorExcludes; + if (flags & SymbolFlags.TypeParameter) + result |= SymbolFlags.TypeParameterExcludes; + if (flags & SymbolFlags.TypeAlias) + result |= SymbolFlags.TypeAliasExcludes; if (flags & SymbolFlags.Alias) result |= SymbolFlags.AliasExcludes; return result; } @@ -2651,9 +3545,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function cloneSymbol(symbol: Symbol): TransientSymbol { const result = createSymbol(symbol.flags, symbol.escapedName); - result.declarations = symbol.declarations ? symbol.declarations.slice() : []; + result.declarations = symbol.declarations + ? symbol.declarations.slice() + : []; result.parent = symbol.parent; - if (symbol.valueDeclaration) result.valueDeclaration = symbol.valueDeclaration; + if (symbol.valueDeclaration) + result.valueDeclaration = symbol.valueDeclaration; if (symbol.constEnumOnlyModule) result.constEnumOnlyModule = true; if (symbol.members) result.members = new Map(symbol.members); if (symbol.exports) result.exports = new Map(symbol.exports); @@ -2665,7 +3562,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Note: if target is transient, then it is mutable, and mergeSymbol with both mutate and return it. * If target is not transient, mergeSymbol will produce a transient clone, mutate that and return it. */ - function mergeSymbol(target: Symbol, source: Symbol, unidirectional = false): Symbol { + function mergeSymbol( + target: Symbol, + source: Symbol, + unidirectional = false + ): Symbol { if ( !(target.flags & getExcludedSymbolFlags(source.flags)) || (source.flags | target.flags) & SymbolFlags.Assignment @@ -2681,18 +3582,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return source; } if ( - !(resolvedTarget.flags & getExcludedSymbolFlags(source.flags)) || - (source.flags | resolvedTarget.flags) & SymbolFlags.Assignment + !( + resolvedTarget.flags & + getExcludedSymbolFlags(source.flags) + ) || + (source.flags | resolvedTarget.flags) & + SymbolFlags.Assignment ) { target = cloneSymbol(resolvedTarget); - } - else { + } else { reportMergeSymbolError(target, source); return source; } } // Javascript static-property-assignment declarations always merge, even though they are also values - if (source.flags & SymbolFlags.ValueModule && target.flags & SymbolFlags.ValueModule && target.constEnumOnlyModule && !source.constEnumOnlyModule) { + if ( + source.flags & SymbolFlags.ValueModule && + target.flags & SymbolFlags.ValueModule && + target.constEnumOnlyModule && + !source.constEnumOnlyModule + ) { // reset flag when merging instantiated module into value module that has only const enums target.constEnumOnlyModule = false; } @@ -2703,62 +3612,141 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { addRange(target.declarations, source.declarations); if (source.members) { if (!target.members) target.members = createSymbolTable(); - mergeSymbolTable(target.members, source.members, unidirectional); + mergeSymbolTable( + target.members, + source.members, + unidirectional + ); } if (source.exports) { if (!target.exports) target.exports = createSymbolTable(); - mergeSymbolTable(target.exports, source.exports, unidirectional, target); + mergeSymbolTable( + target.exports, + source.exports, + unidirectional, + target + ); } if (!unidirectional) { recordMergedSymbol(target, source); } - } - else if (target.flags & SymbolFlags.NamespaceModule) { + } else if (target.flags & SymbolFlags.NamespaceModule) { // Do not report an error when merging `var globalThis` with the built-in `globalThis`, // as we will already report a "Declaration name conflicts..." error, and this error // won't make much sense. if (target !== globalThisSymbol) { error( - source.declarations && getNameOfDeclaration(source.declarations[0]), + source.declarations && + getNameOfDeclaration(source.declarations[0]), Diagnostics.Cannot_augment_module_0_with_value_exports_because_it_resolves_to_a_non_module_entity, - symbolToString(target), + symbolToString(target) ); } - } - else { + } else { reportMergeSymbolError(target, source); } return target; function reportMergeSymbolError(target: Symbol, source: Symbol) { - const isEitherEnum = !!(target.flags & SymbolFlags.Enum || source.flags & SymbolFlags.Enum); - const isEitherBlockScoped = !!(target.flags & SymbolFlags.BlockScopedVariable || source.flags & SymbolFlags.BlockScopedVariable); - const message = isEitherEnum ? Diagnostics.Enum_declarations_can_only_merge_with_namespace_or_other_enum_declarations - : isEitherBlockScoped ? Diagnostics.Cannot_redeclare_block_scoped_variable_0 + const isEitherEnum = !!( + target.flags & SymbolFlags.Enum || + source.flags & SymbolFlags.Enum + ); + const isEitherBlockScoped = !!( + target.flags & SymbolFlags.BlockScopedVariable || + source.flags & SymbolFlags.BlockScopedVariable + ); + const message = isEitherEnum + ? Diagnostics.Enum_declarations_can_only_merge_with_namespace_or_other_enum_declarations + : isEitherBlockScoped + ? Diagnostics.Cannot_redeclare_block_scoped_variable_0 : Diagnostics.Duplicate_identifier_0; - const sourceSymbolFile = source.declarations && getSourceFileOfNode(source.declarations[0]); - const targetSymbolFile = target.declarations && getSourceFileOfNode(target.declarations[0]); - - const isSourcePlainJs = isPlainJsFile(sourceSymbolFile, compilerOptions.checkJs); - const isTargetPlainJs = isPlainJsFile(targetSymbolFile, compilerOptions.checkJs); + const sourceSymbolFile = + source.declarations && + getSourceFileOfNode(source.declarations[0]); + const targetSymbolFile = + target.declarations && + getSourceFileOfNode(target.declarations[0]); + + const isSourcePlainJs = isPlainJsFile( + sourceSymbolFile, + compilerOptions.checkJs + ); + const isTargetPlainJs = isPlainJsFile( + targetSymbolFile, + compilerOptions.checkJs + ); const symbolName = symbolToString(source); // Collect top-level duplicate identifier errors into one mapping, so we can then merge their diagnostics if there are a bunch - if (sourceSymbolFile && targetSymbolFile && amalgamatedDuplicates && !isEitherEnum && sourceSymbolFile !== targetSymbolFile) { - const firstFile = comparePaths(sourceSymbolFile.path, targetSymbolFile.path) === Comparison.LessThan ? sourceSymbolFile : targetSymbolFile; - const secondFile = firstFile === sourceSymbolFile ? targetSymbolFile : sourceSymbolFile; - const filesDuplicates = getOrUpdate(amalgamatedDuplicates, `${firstFile.path}|${secondFile.path}`, (): DuplicateInfoForFiles => ({ firstFile, secondFile, conflictingSymbols: new Map() })); - const conflictingSymbolInfo = getOrUpdate(filesDuplicates.conflictingSymbols, symbolName, (): DuplicateInfoForSymbol => ({ isBlockScoped: isEitherBlockScoped, firstFileLocations: [], secondFileLocations: [] })); - if (!isSourcePlainJs) addDuplicateLocations(conflictingSymbolInfo.firstFileLocations, source); - if (!isTargetPlainJs) addDuplicateLocations(conflictingSymbolInfo.secondFileLocations, target); - } - else { - if (!isSourcePlainJs) addDuplicateDeclarationErrorsForSymbols(source, message, symbolName, target); - if (!isTargetPlainJs) addDuplicateDeclarationErrorsForSymbols(target, message, symbolName, source); + if ( + sourceSymbolFile && + targetSymbolFile && + amalgamatedDuplicates && + !isEitherEnum && + sourceSymbolFile !== targetSymbolFile + ) { + const firstFile = + comparePaths( + sourceSymbolFile.path, + targetSymbolFile.path + ) === Comparison.LessThan + ? sourceSymbolFile + : targetSymbolFile; + const secondFile = + firstFile === sourceSymbolFile + ? targetSymbolFile + : sourceSymbolFile; + const filesDuplicates = getOrUpdate( + amalgamatedDuplicates, + `${firstFile.path}|${secondFile.path}`, + (): DuplicateInfoForFiles => ({ + firstFile, + secondFile, + conflictingSymbols: new Map(), + }) + ); + const conflictingSymbolInfo = getOrUpdate( + filesDuplicates.conflictingSymbols, + symbolName, + (): DuplicateInfoForSymbol => ({ + isBlockScoped: isEitherBlockScoped, + firstFileLocations: [], + secondFileLocations: [], + }) + ); + if (!isSourcePlainJs) + addDuplicateLocations( + conflictingSymbolInfo.firstFileLocations, + source + ); + if (!isTargetPlainJs) + addDuplicateLocations( + conflictingSymbolInfo.secondFileLocations, + target + ); + } else { + if (!isSourcePlainJs) + addDuplicateDeclarationErrorsForSymbols( + source, + message, + symbolName, + target + ); + if (!isTargetPlainJs) + addDuplicateDeclarationErrorsForSymbols( + target, + message, + symbolName, + source + ); } } - function addDuplicateLocations(locs: Declaration[], symbol: Symbol): void { + function addDuplicateLocations( + locs: Declaration[], + symbol: Symbol + ): void { if (symbol.declarations) { for (const decl of symbol.declarations) { pushIfUnique(locs, decl); @@ -2767,27 +3755,77 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function addDuplicateDeclarationErrorsForSymbols(target: Symbol, message: DiagnosticMessage, symbolName: string, source: Symbol) { - forEach(target.declarations, node => { - addDuplicateDeclarationError(node, message, symbolName, source.declarations); + function addDuplicateDeclarationErrorsForSymbols( + target: Symbol, + message: DiagnosticMessage, + symbolName: string, + source: Symbol + ) { + forEach(target.declarations, (node) => { + addDuplicateDeclarationError( + node, + message, + symbolName, + source.declarations + ); }); } - function addDuplicateDeclarationError(node: Declaration, message: DiagnosticMessage, symbolName: string, relatedNodes: readonly Declaration[] | undefined) { - const errorNode = (getExpandoInitializer(node, /*isPrototypeAssignment*/ false) ? getNameOfExpando(node) : getNameOfDeclaration(node)) || node; + function addDuplicateDeclarationError( + node: Declaration, + message: DiagnosticMessage, + symbolName: string, + relatedNodes: readonly Declaration[] | undefined + ) { + const errorNode = + (getExpandoInitializer(node, /*isPrototypeAssignment*/ false) + ? getNameOfExpando(node) + : getNameOfDeclaration(node)) || node; const err = lookupOrIssueError(errorNode, message, symbolName); for (const relatedNode of relatedNodes || emptyArray) { - const adjustedNode = (getExpandoInitializer(relatedNode, /*isPrototypeAssignment*/ false) ? getNameOfExpando(relatedNode) : getNameOfDeclaration(relatedNode)) || relatedNode; + const adjustedNode = + (getExpandoInitializer( + relatedNode, + /*isPrototypeAssignment*/ false + ) + ? getNameOfExpando(relatedNode) + : getNameOfDeclaration(relatedNode)) || relatedNode; if (adjustedNode === errorNode) continue; err.relatedInformation = err.relatedInformation || []; - const leadingMessage = createDiagnosticForNode(adjustedNode, Diagnostics._0_was_also_declared_here, symbolName); - const followOnMessage = createDiagnosticForNode(adjustedNode, Diagnostics.and_here); - if (length(err.relatedInformation) >= 5 || some(err.relatedInformation, r => compareDiagnostics(r, followOnMessage) === Comparison.EqualTo || compareDiagnostics(r, leadingMessage) === Comparison.EqualTo)) continue; - addRelatedInfo(err, !length(err.relatedInformation) ? leadingMessage : followOnMessage); + const leadingMessage = createDiagnosticForNode( + adjustedNode, + Diagnostics._0_was_also_declared_here, + symbolName + ); + const followOnMessage = createDiagnosticForNode( + adjustedNode, + Diagnostics.and_here + ); + if ( + length(err.relatedInformation) >= 5 || + some( + err.relatedInformation, + (r) => + compareDiagnostics(r, followOnMessage) === + Comparison.EqualTo || + compareDiagnostics(r, leadingMessage) === + Comparison.EqualTo + ) + ) + continue; + addRelatedInfo( + err, + !length(err.relatedInformation) + ? leadingMessage + : followOnMessage + ); } } - function combineSymbolTables(first: SymbolTable | undefined, second: SymbolTable | undefined): SymbolTable | undefined { + function combineSymbolTables( + first: SymbolTable | undefined, + second: SymbolTable | undefined + ): SymbolTable | undefined { if (!first?.size) return second; if (!second?.size) return first; const combined = createSymbolTable(); @@ -2796,10 +3834,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return combined; } - function mergeSymbolTable(target: SymbolTable, source: SymbolTable, unidirectional = false, mergedParent?: Symbol) { + function mergeSymbolTable( + target: SymbolTable, + source: SymbolTable, + unidirectional = false, + mergedParent?: Symbol + ) { source.forEach((sourceSymbol, id) => { const targetSymbol = target.get(id); - const merged = targetSymbol ? mergeSymbol(targetSymbol, sourceSymbol, unidirectional) : getMergedSymbol(sourceSymbol); + const merged = targetSymbol + ? mergeSymbol(targetSymbol, sourceSymbol, unidirectional) + : getMergedSymbol(sourceSymbol); if (mergedParent && targetSymbol) { // If a merge was performed on the target symbol, set its parent to the merged parent that initiated the merge // of its exports. Otherwise, `merged` came only from `sourceSymbol` and can keep its parent: @@ -2822,9 +3867,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { }); } - function mergeModuleAugmentation(moduleName: StringLiteral | Identifier): void { + function mergeModuleAugmentation( + moduleName: StringLiteral | Identifier + ): void { const moduleAugmentation = moduleName.parent as ModuleDeclaration; - if (moduleAugmentation.symbol.declarations?.[0] !== moduleAugmentation) { + if ( + moduleAugmentation.symbol.declarations?.[0] !== moduleAugmentation + ) { // this is a combined symbol for multiple augmentations within the same file. // its symbol already has accumulated information for all declarations // so we need to add it just once - do the work only for first declaration @@ -2834,14 +3883,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isGlobalScopeAugmentation(moduleAugmentation)) { mergeSymbolTable(globals, moduleAugmentation.symbol.exports!); - } - else { + } else { // find a module that about to be augmented // do not validate names of augmentations that are defined in ambient context - const moduleNotFoundError = !(moduleName.parent.parent.flags & NodeFlags.Ambient) + const moduleNotFoundError = !( + moduleName.parent.parent.flags & NodeFlags.Ambient + ) ? Diagnostics.Invalid_module_name_in_augmentation_module_0_cannot_be_found : undefined; - let mainModule = resolveExternalModuleNameWorker(moduleName, moduleName, moduleNotFoundError, /*ignoreErrors*/ false, /*isForAugmentation*/ true); + let mainModule = resolveExternalModuleNameWorker( + moduleName, + moduleName, + moduleNotFoundError, + /*ignoreErrors*/ false, + /*isForAugmentation*/ true + ); if (!mainModule) { return; } @@ -2853,30 +3909,58 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // the pattern ('*.foo'), so that 'getMergedSymbol()' on a.foo gives you // all the exports both from the pattern and from the augmentation, but // 'getMergedSymbol()' on *.foo only gives you exports from *.foo. - if (some(patternAmbientModules, module => mainModule === module.symbol)) { - const merged = mergeSymbol(moduleAugmentation.symbol, mainModule, /*unidirectional*/ true); + if ( + some( + patternAmbientModules, + (module) => mainModule === module.symbol + ) + ) { + const merged = mergeSymbol( + moduleAugmentation.symbol, + mainModule, + /*unidirectional*/ true + ); if (!patternAmbientModuleAugmentations) { patternAmbientModuleAugmentations = new Map(); } // moduleName will be a StringLiteral since this is not `declare global`. - patternAmbientModuleAugmentations.set((moduleName as StringLiteral).text, merged); - } - else { - if (mainModule.exports?.get(InternalSymbolName.ExportStar) && moduleAugmentation.symbol.exports?.size) { + patternAmbientModuleAugmentations.set( + (moduleName as StringLiteral).text, + merged + ); + } else { + if ( + mainModule.exports?.get( + InternalSymbolName.ExportStar + ) && + moduleAugmentation.symbol.exports?.size + ) { // We may need to merge the module augmentation's exports into the target symbols of the resolved exports - const resolvedExports = getResolvedMembersOrExportsOfSymbol(mainModule, MembersOrExportsResolutionKind.resolvedExports); - for (const [key, value] of arrayFrom(moduleAugmentation.symbol.exports.entries())) { - if (resolvedExports.has(key) && !mainModule.exports.has(key)) { + const resolvedExports = + getResolvedMembersOrExportsOfSymbol( + mainModule, + MembersOrExportsResolutionKind.resolvedExports + ); + for (const [key, value] of arrayFrom( + moduleAugmentation.symbol.exports.entries() + )) { + if ( + resolvedExports.has(key) && + !mainModule.exports.has(key) + ) { mergeSymbol(resolvedExports.get(key)!, value); } } } mergeSymbol(mainModule, moduleAugmentation.symbol); } - } - else { + } else { // moduleName will be a StringLiteral since this is not `declare global`. - error(moduleName, Diagnostics.Cannot_augment_module_0_because_it_resolves_to_a_non_module_entity, (moduleName as StringLiteral).text); + error( + moduleName, + Diagnostics.Cannot_augment_module_0_because_it_resolves_to_a_non_module_entity, + (moduleName as StringLiteral).text + ); } } } @@ -2885,30 +3969,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const name = undefinedSymbol.escapedName; const targetSymbol = globals.get(name); if (targetSymbol) { - forEach(targetSymbol.declarations, declaration => { + forEach(targetSymbol.declarations, (declaration) => { // checkTypeNameIsReserved will have added better diagnostics for type declarations. if (!isTypeDeclaration(declaration)) { - diagnostics.add(createDiagnosticForNode(declaration, Diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0, unescapeLeadingUnderscores(name))); + diagnostics.add( + createDiagnosticForNode( + declaration, + Diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0, + unescapeLeadingUnderscores(name) + ) + ); } }); - } - else { + } else { globals.set(name, undefinedSymbol); } } function getSymbolLinks(symbol: Symbol): SymbolLinks { - if (symbol.flags & SymbolFlags.Transient) return (symbol as TransientSymbol).links; + if (symbol.flags & SymbolFlags.Transient) + return (symbol as TransientSymbol).links; const id = getSymbolId(symbol); - return symbolLinks[id] ??= new SymbolLinks(); + return (symbolLinks[id] ??= new SymbolLinks()); } function getNodeLinks(node: Node): NodeLinks { const nodeId = getNodeId(node); - return nodeLinks[nodeId] || (nodeLinks[nodeId] = new (NodeLinks as any)()); + return ( + nodeLinks[nodeId] || (nodeLinks[nodeId] = new (NodeLinks as any)()) + ); } - function getSymbol(symbols: SymbolTable, name: __String, meaning: SymbolFlags): Symbol | undefined { + function getSymbol( + symbols: SymbolTable, + name: __String, + meaning: SymbolFlags + ): Symbol | undefined { if (meaning) { const symbol = getMergedSymbol(symbols.get(name)); if (symbol) { @@ -2933,28 +4029,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param parameterName a name of the parameter to get the symbols for. * @return a tuple of two symbols */ - function getSymbolsOfParameterPropertyDeclaration(parameter: ParameterPropertyDeclaration, parameterName: __String): [Symbol, Symbol] { + function getSymbolsOfParameterPropertyDeclaration( + parameter: ParameterPropertyDeclaration, + parameterName: __String + ): [Symbol, Symbol] { const constructorDeclaration = parameter.parent; const classDeclaration = parameter.parent.parent; - const parameterSymbol = getSymbol(constructorDeclaration.locals!, parameterName, SymbolFlags.Value); - const propertySymbol = getSymbol(getMembersOfSymbol(classDeclaration.symbol), parameterName, SymbolFlags.Value); + const parameterSymbol = getSymbol( + constructorDeclaration.locals!, + parameterName, + SymbolFlags.Value + ); + const propertySymbol = getSymbol( + getMembersOfSymbol(classDeclaration.symbol), + parameterName, + SymbolFlags.Value + ); if (parameterSymbol && propertySymbol) { return [parameterSymbol, propertySymbol]; } - return Debug.fail("There should exist two symbols, one as property declaration and one as parameter declaration"); + return Debug.fail( + "There should exist two symbols, one as property declaration and one as parameter declaration" + ); } - function isBlockScopedNameDeclaredBeforeUse(declaration: Declaration, usage: Node): boolean { + function isBlockScopedNameDeclaredBeforeUse( + declaration: Declaration, + usage: Node + ): boolean { const declarationFile = getSourceFileOfNode(declaration); const useFile = getSourceFileOfNode(usage); const declContainer = getEnclosingBlockScopeContainer(declaration); if (declarationFile !== useFile) { if ( - (moduleKind && (declarationFile.externalModuleIndicator || useFile.externalModuleIndicator)) || - (!compilerOptions.outFile) || + (moduleKind && + (declarationFile.externalModuleIndicator || + useFile.externalModuleIndicator)) || + !compilerOptions.outFile || isInTypeQuery(usage) || declaration.flags & NodeFlags.Ambient ) { @@ -2967,59 +4081,108 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; } const sourceFiles = host.getSourceFiles(); - return sourceFiles.indexOf(declarationFile) <= sourceFiles.indexOf(useFile); + return ( + sourceFiles.indexOf(declarationFile) <= + sourceFiles.indexOf(useFile) + ); } // deferred usage in a type context is always OK regardless of the usage position: - if (!!(usage.flags & NodeFlags.JSDoc) || isInTypeQuery(usage) || isInAmbientOrTypeNode(usage)) { + if ( + !!(usage.flags & NodeFlags.JSDoc) || + isInTypeQuery(usage) || + isInAmbientOrTypeNode(usage) + ) { return true; } - if (declaration.pos <= usage.pos && !(isPropertyDeclaration(declaration) && isThisProperty(usage.parent) && !declaration.initializer && !declaration.exclamationToken)) { + if ( + declaration.pos <= usage.pos && + !( + isPropertyDeclaration(declaration) && + isThisProperty(usage.parent) && + !declaration.initializer && + !declaration.exclamationToken + ) + ) { // declaration is before usage if (declaration.kind === SyntaxKind.BindingElement) { // still might be illegal if declaration and usage are both binding elements (eg var [a = b, b = b] = [1, 2]) - const errorBindingElement = getAncestor(usage, SyntaxKind.BindingElement) as BindingElement; + const errorBindingElement = getAncestor( + usage, + SyntaxKind.BindingElement + ) as BindingElement; if (errorBindingElement) { - return findAncestor(errorBindingElement, isBindingElement) !== findAncestor(declaration, isBindingElement) || - declaration.pos < errorBindingElement.pos; + return ( + findAncestor(errorBindingElement, isBindingElement) !== + findAncestor(declaration, isBindingElement) || + declaration.pos < errorBindingElement.pos + ); } // or it might be illegal if usage happens before parent variable is declared (eg var [a] = a) - return isBlockScopedNameDeclaredBeforeUse(getAncestor(declaration, SyntaxKind.VariableDeclaration) as Declaration, usage); - } - else if (declaration.kind === SyntaxKind.VariableDeclaration) { + return isBlockScopedNameDeclaredBeforeUse( + getAncestor( + declaration, + SyntaxKind.VariableDeclaration + ) as Declaration, + usage + ); + } else if (declaration.kind === SyntaxKind.VariableDeclaration) { // still might be illegal if usage is in the initializer of the variable declaration (eg var a = a) - return !isImmediatelyUsedInInitializerOfBlockScopedVariable(declaration as VariableDeclaration, usage); - } - else if (isClassLike(declaration)) { + return !isImmediatelyUsedInInitializerOfBlockScopedVariable( + declaration as VariableDeclaration, + usage + ); + } else if (isClassLike(declaration)) { // still might be illegal if the usage is within a computed property name in the class (eg class A { static p = "a"; [A.p]() {} }) // or when used within a decorator in the class (e.g. `@dec(A.x) class A { static x = "x" }`), // except when used in a function that is not an IIFE (e.g., `@dec(() => A.x) class A { ... }`) - const container = findAncestor(usage, n => - n === declaration ? "quit" : - isComputedPropertyName(n) ? n.parent.parent === declaration : - !legacyDecorators && isDecorator(n) && (n.parent === declaration || - isMethodDeclaration(n.parent) && n.parent.parent === declaration || - isGetOrSetAccessorDeclaration(n.parent) && n.parent.parent === declaration || - isPropertyDeclaration(n.parent) && n.parent.parent === declaration || - isParameter(n.parent) && n.parent.parent.parent === declaration)); + const container = findAncestor(usage, (n) => + n === declaration + ? "quit" + : isComputedPropertyName(n) + ? n.parent.parent === declaration + : !legacyDecorators && + isDecorator(n) && + (n.parent === declaration || + (isMethodDeclaration(n.parent) && + n.parent.parent === declaration) || + (isGetOrSetAccessorDeclaration(n.parent) && + n.parent.parent === declaration) || + (isPropertyDeclaration(n.parent) && + n.parent.parent === declaration) || + (isParameter(n.parent) && + n.parent.parent.parent === declaration)) + ); if (!container) { return true; } if (!legacyDecorators && isDecorator(container)) { - return !!findAncestor(usage, n => n === container ? "quit" : isFunctionLike(n) && !getImmediatelyInvokedFunctionExpression(n)); + return !!findAncestor(usage, (n) => + n === container + ? "quit" + : isFunctionLike(n) && + !getImmediatelyInvokedFunctionExpression(n) + ); } return false; - } - else if (isPropertyDeclaration(declaration)) { + } else if (isPropertyDeclaration(declaration)) { // still might be illegal if a self-referencing property initializer (eg private x = this.x) - return !isPropertyImmediatelyReferencedWithinDeclaration(declaration, usage, /*stopAtAnyPropertyDeclaration*/ false); - } - else if (isParameterPropertyDeclaration(declaration, declaration.parent)) { + return !isPropertyImmediatelyReferencedWithinDeclaration( + declaration, + usage, + /*stopAtAnyPropertyDeclaration*/ false + ); + } else if ( + isParameterPropertyDeclaration(declaration, declaration.parent) + ) { // foo = this.bar is illegal in emitStandardClassFields when bar is a parameter property - return !(emitStandardClassFields - && getContainingClass(declaration) === getContainingClass(usage) - && isUsedInFunctionOrInstanceProperty(usage, declaration)); + return !( + emitStandardClassFields && + getContainingClass(declaration) === + getContainingClass(usage) && + isUsedInFunctionOrInstanceProperty(usage, declaration) + ); } return true; } @@ -3031,37 +4194,60 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // (except when emitStandardClassFields: true and the reference is to a parameter property) // 4. inside a static property initializer, a reference to a static method in the same class // 5. inside a TS export= declaration (since we will move the export statement during emit to avoid TDZ) - if (usage.parent.kind === SyntaxKind.ExportSpecifier || (usage.parent.kind === SyntaxKind.ExportAssignment && (usage.parent as ExportAssignment).isExportEquals)) { + if ( + usage.parent.kind === SyntaxKind.ExportSpecifier || + (usage.parent.kind === SyntaxKind.ExportAssignment && + (usage.parent as ExportAssignment).isExportEquals) + ) { // export specifiers do not use the variable, they only make it available for use return true; } // When resolving symbols for exports, the `usage` location passed in can be the export site directly - if (usage.kind === SyntaxKind.ExportAssignment && (usage as ExportAssignment).isExportEquals) { + if ( + usage.kind === SyntaxKind.ExportAssignment && + (usage as ExportAssignment).isExportEquals + ) { return true; } if (isUsedInFunctionOrInstanceProperty(usage, declaration)) { if ( - emitStandardClassFields - && getContainingClass(declaration) - && (isPropertyDeclaration(declaration) || isParameterPropertyDeclaration(declaration, declaration.parent)) + emitStandardClassFields && + getContainingClass(declaration) && + (isPropertyDeclaration(declaration) || + isParameterPropertyDeclaration( + declaration, + declaration.parent + )) ) { - return !isPropertyImmediatelyReferencedWithinDeclaration(declaration, usage, /*stopAtAnyPropertyDeclaration*/ true); - } - else { + return !isPropertyImmediatelyReferencedWithinDeclaration( + declaration, + usage, + /*stopAtAnyPropertyDeclaration*/ true + ); + } else { return true; } } return false; - function isImmediatelyUsedInInitializerOfBlockScopedVariable(declaration: VariableDeclaration, usage: Node): boolean { + function isImmediatelyUsedInInitializerOfBlockScopedVariable( + declaration: VariableDeclaration, + usage: Node + ): boolean { switch (declaration.parent.parent.kind) { case SyntaxKind.VariableStatement: case SyntaxKind.ForStatement: case SyntaxKind.ForOfStatement: // variable statement/for/for-of statement case, // use site should not be inside variable declaration (initializer of declaration or binding element) - if (isSameScopeDescendentOf(usage, declaration, declContainer)) { + if ( + isSameScopeDescendentOf( + usage, + declaration, + declContainer + ) + ) { return true; } break; @@ -3069,15 +4255,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // ForIn/ForOf case - use site should not be used in expression part const grandparent = declaration.parent.parent; - return isForInOrOfStatement(grandparent) && isSameScopeDescendentOf(usage, grandparent.expression, declContainer); + return ( + isForInOrOfStatement(grandparent) && + isSameScopeDescendentOf( + usage, + grandparent.expression, + declContainer + ) + ); } - function isUsedInFunctionOrInstanceProperty(usage: Node, declaration: Node) { + function isUsedInFunctionOrInstanceProperty( + usage: Node, + declaration: Node + ) { return isUsedInFunctionOrInstancePropertyWorker(usage, declaration); } - function isUsedInFunctionOrInstancePropertyWorker(usage: Node, declaration: Node): boolean { - return !!findAncestor(usage, current => { + function isUsedInFunctionOrInstancePropertyWorker( + usage: Node, + declaration: Node + ): boolean { + return !!findAncestor(usage, (current) => { if (current === declContainer) { return "quit"; } @@ -3088,28 +4287,61 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return declaration.pos < usage.pos; } - const propertyDeclaration = tryCast(current.parent, isPropertyDeclaration); + const propertyDeclaration = tryCast( + current.parent, + isPropertyDeclaration + ); if (propertyDeclaration) { - const initializerOfProperty = propertyDeclaration.initializer === current; + const initializerOfProperty = + propertyDeclaration.initializer === current; if (initializerOfProperty) { if (isStatic(current.parent)) { - if (declaration.kind === SyntaxKind.MethodDeclaration) { + if ( + declaration.kind === + SyntaxKind.MethodDeclaration + ) { return true; } - if (isPropertyDeclaration(declaration) && getContainingClass(usage) === getContainingClass(declaration)) { + if ( + isPropertyDeclaration(declaration) && + getContainingClass(usage) === + getContainingClass(declaration) + ) { const propName = declaration.name; - if (isIdentifier(propName) || isPrivateIdentifier(propName)) { - const type = getTypeOfSymbol(getSymbolOfDeclaration(declaration)); - const staticBlocks = filter(declaration.parent.members, isClassStaticBlockDeclaration); - if (isPropertyInitializedInStaticBlocks(propName, type, staticBlocks, declaration.parent.pos, current.pos)) { + if ( + isIdentifier(propName) || + isPrivateIdentifier(propName) + ) { + const type = getTypeOfSymbol( + getSymbolOfDeclaration(declaration) + ); + const staticBlocks = filter( + declaration.parent.members, + isClassStaticBlockDeclaration + ); + if ( + isPropertyInitializedInStaticBlocks( + propName, + type, + staticBlocks, + declaration.parent.pos, + current.pos + ) + ) { return true; } } } - } - else { - const isDeclarationInstanceProperty = declaration.kind === SyntaxKind.PropertyDeclaration && !isStatic(declaration); - if (!isDeclarationInstanceProperty || getContainingClass(usage) !== getContainingClass(declaration)) { + } else { + const isDeclarationInstanceProperty = + declaration.kind === + SyntaxKind.PropertyDeclaration && + !isStatic(declaration); + if ( + !isDeclarationInstanceProperty || + getContainingClass(usage) !== + getContainingClass(declaration) + ) { return true; } } @@ -3119,10 +4351,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const decorator = tryCast(current.parent, isDecorator); if (decorator && decorator.expression === current) { if (isParameter(decorator.parent)) { - return isUsedInFunctionOrInstancePropertyWorker(decorator.parent.parent.parent, declaration) ? true : "quit"; + return isUsedInFunctionOrInstancePropertyWorker( + decorator.parent.parent.parent, + declaration + ) + ? true + : "quit"; } if (isMethodDeclaration(decorator.parent)) { - return isUsedInFunctionOrInstancePropertyWorker(decorator.parent.parent, declaration) ? true : "quit"; + return isUsedInFunctionOrInstancePropertyWorker( + decorator.parent.parent, + declaration + ) + ? true + : "quit"; } } @@ -3131,7 +4373,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } /** stopAtAnyPropertyDeclaration is used for detecting ES-standard class field use-before-def errors */ - function isPropertyImmediatelyReferencedWithinDeclaration(declaration: PropertyDeclaration | ParameterPropertyDeclaration, usage: Node, stopAtAnyPropertyDeclaration: boolean) { + function isPropertyImmediatelyReferencedWithinDeclaration( + declaration: PropertyDeclaration | ParameterPropertyDeclaration, + usage: Node, + stopAtAnyPropertyDeclaration: boolean + ) { // always legal if usage is after declaration if (usage.end > declaration.end) { return false; @@ -3139,33 +4385,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // still might be legal if usage is deferred (e.g. x: any = () => this.x) // otherwise illegal if immediately referenced within the declaration (e.g. x: any = this.x) - const ancestorChangingReferenceScope = findAncestor(usage, (node: Node) => { - if (node === declaration) { - return "quit"; - } + const ancestorChangingReferenceScope = findAncestor( + usage, + (node: Node) => { + if (node === declaration) { + return "quit"; + } - switch (node.kind) { - case SyntaxKind.ArrowFunction: - return true; - case SyntaxKind.PropertyDeclaration: - // even when stopping at any property declaration, they need to come from the same class - return stopAtAnyPropertyDeclaration && - (isPropertyDeclaration(declaration) && node.parent === declaration.parent - || isParameterPropertyDeclaration(declaration, declaration.parent) && node.parent === declaration.parent.parent) - ? "quit" : true; - case SyntaxKind.Block: - switch (node.parent.kind) { - case SyntaxKind.GetAccessor: - case SyntaxKind.MethodDeclaration: - case SyntaxKind.SetAccessor: - return true; - default: - return false; - } - default: - return false; + switch (node.kind) { + case SyntaxKind.ArrowFunction: + return true; + case SyntaxKind.PropertyDeclaration: + // even when stopping at any property declaration, they need to come from the same class + return stopAtAnyPropertyDeclaration && + ((isPropertyDeclaration(declaration) && + node.parent === declaration.parent) || + (isParameterPropertyDeclaration( + declaration, + declaration.parent + ) && + node.parent === + declaration.parent.parent)) + ? "quit" + : true; + case SyntaxKind.Block: + switch (node.parent.kind) { + case SyntaxKind.GetAccessor: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.SetAccessor: + return true; + default: + return false; + } + default: + return false; + } } - }); + ); return ancestorChangingReferenceScope === undefined; } @@ -3174,15 +4430,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getRequiresScopeChangeCache(node: FunctionLikeDeclaration) { return getNodeLinks(node).declarationRequiresScopeChange; } - function setRequiresScopeChangeCache(node: FunctionLikeDeclaration, value: boolean) { + function setRequiresScopeChangeCache( + node: FunctionLikeDeclaration, + value: boolean + ) { getNodeLinks(node).declarationRequiresScopeChange = value; } // The invalid initializer error is needed in two situation: // 1. When result is undefined, after checking for a missing "this." // 2. When result is defined - function checkAndReportErrorForInvalidInitializer(errorLocation: Node | undefined, name: __String, propertyWithInvalidInitializer: PropertyDeclaration, result: Symbol | undefined) { + function checkAndReportErrorForInvalidInitializer( + errorLocation: Node | undefined, + name: __String, + propertyWithInvalidInitializer: PropertyDeclaration, + result: Symbol | undefined + ) { if (!emitStandardClassFields) { - if (errorLocation && !result && checkAndReportErrorForMissingPrefix(errorLocation, name, name)) { + if ( + errorLocation && + !result && + checkAndReportErrorForMissingPrefix(errorLocation, name, name) + ) { return true; } // We have a match, but the reference occurred within a property initializer and the identifier also binds @@ -3190,11 +4458,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // with emitStandardClassFields because the scope semantics are different. error( errorLocation, - errorLocation && propertyWithInvalidInitializer.type && textRangeContainsPositionInclusive(propertyWithInvalidInitializer.type, errorLocation.pos) + errorLocation && + propertyWithInvalidInitializer.type && + textRangeContainsPositionInclusive( + propertyWithInvalidInitializer.type, + errorLocation.pos + ) ? Diagnostics.Type_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor : Diagnostics.Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor, declarationNameToString(propertyWithInvalidInitializer.name), - diagnosticName(name), + diagnosticName(name) ); return true; } @@ -3204,20 +4477,45 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { errorLocation: Node | undefined, nameArg: __String | Identifier, meaning: SymbolFlags, - nameNotFoundMessage: DiagnosticMessage, + nameNotFoundMessage: DiagnosticMessage ) { - const name = isString(nameArg) ? nameArg : (nameArg as Identifier).escapedText; + const name = isString(nameArg) + ? nameArg + : (nameArg as Identifier).escapedText; addLazyDiagnostic(() => { if ( !errorLocation || - errorLocation.parent.kind !== SyntaxKind.JSDocLink && - !checkAndReportErrorForMissingPrefix(errorLocation, name, nameArg) && + (errorLocation.parent.kind !== SyntaxKind.JSDocLink && + !checkAndReportErrorForMissingPrefix( + errorLocation, + name, + nameArg + ) && !checkAndReportErrorForExtendingInterface(errorLocation) && - !checkAndReportErrorForUsingTypeAsNamespace(errorLocation, name, meaning) && - !checkAndReportErrorForExportingPrimitiveType(errorLocation, name) && - !checkAndReportErrorForUsingNamespaceAsTypeOrValue(errorLocation, name, meaning) && - !checkAndReportErrorForUsingTypeAsValue(errorLocation, name, meaning) && - !checkAndReportErrorForUsingValueAsType(errorLocation, name, meaning) + !checkAndReportErrorForUsingTypeAsNamespace( + errorLocation, + name, + meaning + ) && + !checkAndReportErrorForExportingPrimitiveType( + errorLocation, + name + ) && + !checkAndReportErrorForUsingNamespaceAsTypeOrValue( + errorLocation, + name, + meaning + ) && + !checkAndReportErrorForUsingTypeAsValue( + errorLocation, + name, + meaning + ) && + !checkAndReportErrorForUsingValueAsType( + errorLocation, + name, + meaning + )) ) { let suggestion: Symbol | undefined; let suggestedLib: string | undefined; @@ -3225,38 +4523,74 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (nameArg) { suggestedLib = getSuggestedLibForNonExistentName(nameArg); if (suggestedLib) { - error(errorLocation, nameNotFoundMessage, diagnosticName(nameArg), suggestedLib); + error( + errorLocation, + nameNotFoundMessage, + diagnosticName(nameArg), + suggestedLib + ); } } // then spelling suggestions if (!suggestedLib && suggestionCount < maximumSuggestionCount) { - suggestion = getSuggestedSymbolForNonexistentSymbol(errorLocation, name, meaning); - const isGlobalScopeAugmentationDeclaration = suggestion?.valueDeclaration && isAmbientModule(suggestion.valueDeclaration) && isGlobalScopeAugmentation(suggestion.valueDeclaration); + suggestion = getSuggestedSymbolForNonexistentSymbol( + errorLocation, + name, + meaning + ); + const isGlobalScopeAugmentationDeclaration = + suggestion?.valueDeclaration && + isAmbientModule(suggestion.valueDeclaration) && + isGlobalScopeAugmentation(suggestion.valueDeclaration); if (isGlobalScopeAugmentationDeclaration) { suggestion = undefined; } if (suggestion) { const suggestionName = symbolToString(suggestion); - const isUncheckedJS = isUncheckedJSSuggestion(errorLocation, suggestion, /*excludeClasses*/ false); - const message = meaning === SymbolFlags.Namespace || - nameArg && typeof nameArg !== "string" && nodeIsSynthesized(nameArg) ? - Diagnostics.Cannot_find_namespace_0_Did_you_mean_1 - : isUncheckedJS ? Diagnostics.Could_not_find_name_0_Did_you_mean_1 - : Diagnostics.Cannot_find_name_0_Did_you_mean_1; - const diagnostic = createError(errorLocation, message, diagnosticName(nameArg), suggestionName); - diagnostic.canonicalHead = getCanonicalDiagnostic(nameNotFoundMessage, diagnosticName(nameArg)); + const isUncheckedJS = isUncheckedJSSuggestion( + errorLocation, + suggestion, + /*excludeClasses*/ false + ); + const message = + meaning === SymbolFlags.Namespace || + (nameArg && + typeof nameArg !== "string" && + nodeIsSynthesized(nameArg)) + ? Diagnostics.Cannot_find_namespace_0_Did_you_mean_1 + : isUncheckedJS + ? Diagnostics.Could_not_find_name_0_Did_you_mean_1 + : Diagnostics.Cannot_find_name_0_Did_you_mean_1; + const diagnostic = createError( + errorLocation, + message, + diagnosticName(nameArg), + suggestionName + ); + diagnostic.canonicalHead = getCanonicalDiagnostic( + nameNotFoundMessage, + diagnosticName(nameArg) + ); addErrorOrSuggestion(!isUncheckedJS, diagnostic); if (suggestion.valueDeclaration) { addRelatedInfo( diagnostic, - createDiagnosticForNode(suggestion.valueDeclaration, Diagnostics._0_is_declared_here, suggestionName), + createDiagnosticForNode( + suggestion.valueDeclaration, + Diagnostics._0_is_declared_here, + suggestionName + ) ); } } } // And then fall back to unspecified "not found" if (!suggestion && !suggestedLib && nameArg) { - error(errorLocation, nameNotFoundMessage, diagnosticName(nameArg)); + error( + errorLocation, + nameNotFoundMessage, + diagnosticName(nameArg) + ); } suggestionCount++; } @@ -3268,12 +4602,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { result: Symbol, meaning: SymbolFlags, lastLocation: Node | undefined, - associatedDeclarationForContainingInitializerOrBindingName: ParameterDeclaration | BindingElement | undefined, - withinDeferredContext: boolean, + associatedDeclarationForContainingInitializerOrBindingName: + | ParameterDeclaration + | BindingElement + | undefined, + withinDeferredContext: boolean ) { addLazyDiagnostic(() => { const name = result.escapedName; - const isInExternalModule = lastLocation && isSourceFile(lastLocation) && isExternalOrCommonJsModule(lastLocation); + const isInExternalModule = + lastLocation && + isSourceFile(lastLocation) && + isExternalOrCommonJsModule(lastLocation); // Only check for block-scoped variable if we have an error location and are looking for the // name with variable meaning // For example, @@ -3288,89 +4628,210 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if ( errorLocation && (meaning & SymbolFlags.BlockScopedVariable || - ((meaning & SymbolFlags.Class || meaning & SymbolFlags.Enum) && (meaning & SymbolFlags.Value) === SymbolFlags.Value)) + ((meaning & SymbolFlags.Class || + meaning & SymbolFlags.Enum) && + (meaning & SymbolFlags.Value) === SymbolFlags.Value)) ) { - const exportOrLocalSymbol = getExportSymbolOfValueSymbolIfExported(result); - if (exportOrLocalSymbol.flags & SymbolFlags.BlockScopedVariable || exportOrLocalSymbol.flags & SymbolFlags.Class || exportOrLocalSymbol.flags & SymbolFlags.Enum) { - checkResolvedBlockScopedVariable(exportOrLocalSymbol, errorLocation); + const exportOrLocalSymbol = + getExportSymbolOfValueSymbolIfExported(result); + if ( + exportOrLocalSymbol.flags & + SymbolFlags.BlockScopedVariable || + exportOrLocalSymbol.flags & SymbolFlags.Class || + exportOrLocalSymbol.flags & SymbolFlags.Enum + ) { + checkResolvedBlockScopedVariable( + exportOrLocalSymbol, + errorLocation + ); } } // If we're in an external module, we can't reference value symbols created from UMD export declarations - if (isInExternalModule && (meaning & SymbolFlags.Value) === SymbolFlags.Value && !(errorLocation!.flags & NodeFlags.JSDoc)) { + if ( + isInExternalModule && + (meaning & SymbolFlags.Value) === SymbolFlags.Value && + !(errorLocation!.flags & NodeFlags.JSDoc) + ) { const merged = getMergedSymbol(result); - if (length(merged.declarations) && every(merged.declarations, d => isNamespaceExportDeclaration(d) || isSourceFile(d) && !!d.symbol.globalExports)) { - 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)); + if ( + length(merged.declarations) && + every( + merged.declarations, + (d) => + isNamespaceExportDeclaration(d) || + (isSourceFile(d) && !!d.symbol.globalExports) + ) + ) { + 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) + ); } } // 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 - if (associatedDeclarationForContainingInitializerOrBindingName && !withinDeferredContext && (meaning & SymbolFlags.Value) === SymbolFlags.Value) { + if ( + associatedDeclarationForContainingInitializerOrBindingName && + !withinDeferredContext && + (meaning & SymbolFlags.Value) === SymbolFlags.Value + ) { const candidate = getMergedSymbol(getLateBoundSymbol(result)); - const root = getRootDeclaration(associatedDeclarationForContainingInitializerOrBindingName) as ParameterDeclaration; + const root = getRootDeclaration( + associatedDeclarationForContainingInitializerOrBindingName + ) as ParameterDeclaration; // A parameter initializer or binding pattern initializer within a parameter cannot refer to itself - if (candidate === getSymbolOfDeclaration(associatedDeclarationForContainingInitializerOrBindingName)) { - error(errorLocation, Diagnostics.Parameter_0_cannot_reference_itself, declarationNameToString(associatedDeclarationForContainingInitializerOrBindingName.name)); + if ( + candidate === + getSymbolOfDeclaration( + associatedDeclarationForContainingInitializerOrBindingName + ) + ) { + error( + errorLocation, + Diagnostics.Parameter_0_cannot_reference_itself, + declarationNameToString( + associatedDeclarationForContainingInitializerOrBindingName.name + ) + ); } // And it cannot refer to any declarations which come after it - else if (candidate.valueDeclaration && candidate.valueDeclaration.pos > associatedDeclarationForContainingInitializerOrBindingName.pos && root.parent.locals && getSymbol(root.parent.locals, candidate.escapedName, meaning) === candidate) { - error(errorLocation, Diagnostics.Parameter_0_cannot_reference_identifier_1_declared_after_it, declarationNameToString(associatedDeclarationForContainingInitializerOrBindingName.name), declarationNameToString(errorLocation as Identifier)); + else if ( + candidate.valueDeclaration && + candidate.valueDeclaration.pos > + associatedDeclarationForContainingInitializerOrBindingName.pos && + root.parent.locals && + getSymbol( + root.parent.locals, + candidate.escapedName, + meaning + ) === candidate + ) { + error( + errorLocation, + Diagnostics.Parameter_0_cannot_reference_identifier_1_declared_after_it, + declarationNameToString( + associatedDeclarationForContainingInitializerOrBindingName.name + ), + declarationNameToString(errorLocation as Identifier) + ); } } - if (errorLocation && meaning & SymbolFlags.Value && result.flags & SymbolFlags.Alias && !(result.flags & SymbolFlags.Value) && !isValidTypeOnlyAliasUseSite(errorLocation)) { - const typeOnlyDeclaration = getTypeOnlyAliasDeclaration(result, SymbolFlags.Value); + if ( + errorLocation && + meaning & SymbolFlags.Value && + result.flags & SymbolFlags.Alias && + !(result.flags & SymbolFlags.Value) && + !isValidTypeOnlyAliasUseSite(errorLocation) + ) { + const typeOnlyDeclaration = getTypeOnlyAliasDeclaration( + result, + SymbolFlags.Value + ); if (typeOnlyDeclaration) { - const message = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier || typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration || typeOnlyDeclaration.kind === SyntaxKind.NamespaceExport - ? Diagnostics._0_cannot_be_used_as_a_value_because_it_was_exported_using_export_type - : Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type; + const message = + typeOnlyDeclaration.kind === + SyntaxKind.ExportSpecifier || + typeOnlyDeclaration.kind === + SyntaxKind.ExportDeclaration || + typeOnlyDeclaration.kind === SyntaxKind.NamespaceExport + ? Diagnostics._0_cannot_be_used_as_a_value_because_it_was_exported_using_export_type + : Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type; const unescapedName = unescapeLeadingUnderscores(name); addTypeOnlyDeclarationRelatedInfo( error(errorLocation, message, unescapedName), typeOnlyDeclaration, - unescapedName, + unescapedName ); } } // Look at 'compilerOptions.isolatedModules' and not 'getIsolatedModules(...)' (which considers 'verbatimModuleSyntax') // here because 'verbatimModuleSyntax' will already have an error for importing a type without 'import type'. - if (compilerOptions.isolatedModules && result && isInExternalModule && (meaning & SymbolFlags.Value) === SymbolFlags.Value) { + if ( + compilerOptions.isolatedModules && + result && + isInExternalModule && + (meaning & SymbolFlags.Value) === SymbolFlags.Value + ) { const isGlobal = getSymbol(globals, name, meaning) === result; - const nonValueSymbol = isGlobal && isSourceFile(lastLocation) && lastLocation.locals && getSymbol(lastLocation.locals, name, ~SymbolFlags.Value); + const nonValueSymbol = + isGlobal && + isSourceFile(lastLocation) && + lastLocation.locals && + getSymbol(lastLocation.locals, name, ~SymbolFlags.Value); if (nonValueSymbol) { - const importDecl = nonValueSymbol.declarations?.find(d => d.kind === SyntaxKind.ImportSpecifier || d.kind === SyntaxKind.ImportClause || d.kind === SyntaxKind.NamespaceImport || d.kind === SyntaxKind.ImportEqualsDeclaration); - if (importDecl && !isTypeOnlyImportDeclaration(importDecl)) { - error(importDecl, Diagnostics.Import_0_conflicts_with_global_value_used_in_this_file_so_must_be_declared_with_a_type_only_import_when_isolatedModules_is_enabled, unescapeLeadingUnderscores(name)); + const importDecl = nonValueSymbol.declarations?.find( + (d) => + d.kind === SyntaxKind.ImportSpecifier || + d.kind === SyntaxKind.ImportClause || + d.kind === SyntaxKind.NamespaceImport || + d.kind === SyntaxKind.ImportEqualsDeclaration + ); + if ( + importDecl && + !isTypeOnlyImportDeclaration(importDecl) + ) { + error( + importDecl, + Diagnostics.Import_0_conflicts_with_global_value_used_in_this_file_so_must_be_declared_with_a_type_only_import_when_isolatedModules_is_enabled, + unescapeLeadingUnderscores(name) + ); } } } }); } - function addTypeOnlyDeclarationRelatedInfo(diagnostic: Diagnostic, typeOnlyDeclaration: TypeOnlyCompatibleAliasDeclaration | undefined, unescapedName: string) { + function addTypeOnlyDeclarationRelatedInfo( + diagnostic: Diagnostic, + typeOnlyDeclaration: TypeOnlyCompatibleAliasDeclaration | undefined, + unescapedName: string + ) { if (!typeOnlyDeclaration) return diagnostic; return addRelatedInfo( diagnostic, createDiagnosticForNode( typeOnlyDeclaration, - typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier || typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration || typeOnlyDeclaration.kind === SyntaxKind.NamespaceExport + typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier || + typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration || + typeOnlyDeclaration.kind === SyntaxKind.NamespaceExport ? Diagnostics._0_was_exported_here : Diagnostics._0_was_imported_here, - unescapedName, - ), + unescapedName + ) ); } - function diagnosticName(nameArg: __String | Identifier | PrivateIdentifier) { - return isString(nameArg) ? unescapeLeadingUnderscores(nameArg as __String) : declarationNameToString(nameArg as Identifier); + function diagnosticName( + nameArg: __String | Identifier | PrivateIdentifier + ) { + return isString(nameArg) + ? unescapeLeadingUnderscores(nameArg as __String) + : declarationNameToString(nameArg as Identifier); } - function checkAndReportErrorForMissingPrefix(errorLocation: Node, name: __String, nameArg: __String | Identifier): boolean { - if (!isIdentifier(errorLocation) || errorLocation.escapedText !== name || isTypeReferenceIdentifier(errorLocation) || isInTypeQuery(errorLocation)) { + function checkAndReportErrorForMissingPrefix( + errorLocation: Node, + name: __String, + nameArg: __String | Identifier + ): boolean { + if ( + !isIdentifier(errorLocation) || + errorLocation.escapedText !== name || + isTypeReferenceIdentifier(errorLocation) || + isInTypeQuery(errorLocation) + ) { return false; } - const container = getThisContainer(errorLocation, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); + const container = getThisContainer( + errorLocation, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false + ); let location: Node = container; while (location) { if (isClassLike(location.parent)) { @@ -3382,16 +4843,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Check to see if a static member exists. const constructorType = getTypeOfSymbol(classSymbol); if (getPropertyOfType(constructorType, name)) { - error(errorLocation, Diagnostics.Cannot_find_name_0_Did_you_mean_the_static_member_1_0, diagnosticName(nameArg), symbolToString(classSymbol)); + error( + errorLocation, + Diagnostics.Cannot_find_name_0_Did_you_mean_the_static_member_1_0, + diagnosticName(nameArg), + symbolToString(classSymbol) + ); return true; } // No static member is present. // Check if we're in an instance method and look for a relevant instance member. if (location === container && !isStatic(location)) { - const instanceType = (getDeclaredTypeOfSymbol(classSymbol) as InterfaceType).thisType!; // TODO: GH#18217 + const instanceType = ( + getDeclaredTypeOfSymbol(classSymbol) as InterfaceType + ).thisType!; // TODO: GH#18217 if (getPropertyOfType(instanceType, name)) { - error(errorLocation, Diagnostics.Cannot_find_name_0_Did_you_mean_the_instance_member_this_0, diagnosticName(nameArg)); + error( + errorLocation, + Diagnostics.Cannot_find_name_0_Did_you_mean_the_instance_member_this_0, + diagnosticName(nameArg) + ); return true; } } @@ -3402,10 +4874,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function checkAndReportErrorForExtendingInterface(errorLocation: Node): boolean { + function checkAndReportErrorForExtendingInterface( + errorLocation: Node + ): boolean { const expression = getEntityNameForExtendingInterface(errorLocation); - if (expression && resolveEntityName(expression, SymbolFlags.Interface, /*ignoreErrors*/ true)) { - error(errorLocation, Diagnostics.Cannot_extend_an_interface_0_Did_you_mean_implements, getTextOfNode(expression)); + if ( + expression && + resolveEntityName( + expression, + SymbolFlags.Interface, + /*ignoreErrors*/ true + ) + ) { + error( + errorLocation, + Diagnostics.Cannot_extend_an_interface_0_Did_you_mean_implements, + getTextOfNode(expression) + ); return true; } return false; @@ -3414,42 +4899,75 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Climbs up parents to an ExpressionWithTypeArguments, and returns its expression, * but returns undefined if that expression is not an EntityNameExpression. */ - function getEntityNameForExtendingInterface(node: Node): EntityNameExpression | undefined { + function getEntityNameForExtendingInterface( + node: Node + ): EntityNameExpression | undefined { switch (node.kind) { case SyntaxKind.Identifier: case SyntaxKind.PropertyAccessExpression: - return node.parent ? getEntityNameForExtendingInterface(node.parent) : undefined; + return node.parent + ? getEntityNameForExtendingInterface(node.parent) + : undefined; case SyntaxKind.ExpressionWithTypeArguments: - if (isEntityNameExpression((node as ExpressionWithTypeArguments).expression)) { - return (node as ExpressionWithTypeArguments).expression as EntityNameExpression; + if ( + isEntityNameExpression( + (node as ExpressionWithTypeArguments).expression + ) + ) { + return (node as ExpressionWithTypeArguments) + .expression as EntityNameExpression; } - // falls through + // falls through default: return undefined; } } - function checkAndReportErrorForUsingTypeAsNamespace(errorLocation: Node, name: __String, meaning: SymbolFlags): boolean { - const namespaceMeaning = SymbolFlags.Namespace | (isInJSFile(errorLocation) ? SymbolFlags.Value : 0); + function checkAndReportErrorForUsingTypeAsNamespace( + errorLocation: Node, + name: __String, + meaning: SymbolFlags + ): boolean { + const namespaceMeaning = + SymbolFlags.Namespace | + (isInJSFile(errorLocation) ? SymbolFlags.Value : 0); if (meaning === namespaceMeaning) { - const symbol = resolveSymbol(resolveName(errorLocation, name, SymbolFlags.Type & ~namespaceMeaning, /*nameNotFoundMessage*/ undefined, /*isUse*/ false)); + const symbol = resolveSymbol( + resolveName( + errorLocation, + name, + SymbolFlags.Type & ~namespaceMeaning, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ false + ) + ); const parent = errorLocation.parent; if (symbol) { if (isQualifiedName(parent)) { - Debug.assert(parent.left === errorLocation, "Should only be resolving left side of qualified name as a namespace"); + Debug.assert( + parent.left === errorLocation, + "Should only be resolving left side of qualified name as a namespace" + ); const propName = parent.right.escapedText; - const propType = getPropertyOfType(getDeclaredTypeOfSymbol(symbol), propName); + const propType = getPropertyOfType( + getDeclaredTypeOfSymbol(symbol), + propName + ); if (propType) { error( parent, 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, unescapeLeadingUnderscores(name), - unescapeLeadingUnderscores(propName), + unescapeLeadingUnderscores(propName) ); return true; } } - error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_namespace_here, unescapeLeadingUnderscores(name)); + error( + errorLocation, + Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_namespace_here, + unescapeLeadingUnderscores(name) + ); return true; } } @@ -3457,11 +4975,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function checkAndReportErrorForUsingValueAsType(errorLocation: Node, name: __String, meaning: SymbolFlags): boolean { + function checkAndReportErrorForUsingValueAsType( + errorLocation: Node, + name: __String, + meaning: SymbolFlags + ): boolean { if (meaning & (SymbolFlags.Type & ~SymbolFlags.Namespace)) { - const symbol = resolveSymbol(resolveName(errorLocation, name, ~SymbolFlags.Type & SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*isUse*/ false)); + const symbol = resolveSymbol( + resolveName( + errorLocation, + name, + ~SymbolFlags.Type & SymbolFlags.Value, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ false + ) + ); if (symbol && !(symbol.flags & SymbolFlags.Namespace)) { - error(errorLocation, Diagnostics._0_refers_to_a_value_but_is_being_used_as_a_type_here_Did_you_mean_typeof_0, unescapeLeadingUnderscores(name)); + error( + errorLocation, + Diagnostics._0_refers_to_a_value_but_is_being_used_as_a_type_here_Did_you_mean_typeof_0, + unescapeLeadingUnderscores(name) + ); return true; } } @@ -3469,51 +5003,121 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isPrimitiveTypeName(name: __String) { - return name === "any" || name === "string" || name === "number" || name === "boolean" || name === "never" || name === "unknown"; + return ( + name === "any" || + name === "string" || + name === "number" || + name === "boolean" || + name === "never" || + name === "unknown" + ); } - function checkAndReportErrorForExportingPrimitiveType(errorLocation: Node, name: __String): boolean { - if (isPrimitiveTypeName(name) && errorLocation.parent.kind === SyntaxKind.ExportSpecifier) { - error(errorLocation, Diagnostics.Cannot_export_0_Only_local_declarations_can_be_exported_from_a_module, name as string); + function checkAndReportErrorForExportingPrimitiveType( + errorLocation: Node, + name: __String + ): boolean { + if ( + isPrimitiveTypeName(name) && + errorLocation.parent.kind === SyntaxKind.ExportSpecifier + ) { + error( + errorLocation, + Diagnostics.Cannot_export_0_Only_local_declarations_can_be_exported_from_a_module, + name as string + ); return true; } return false; } - function checkAndReportErrorForUsingTypeAsValue(errorLocation: Node, name: __String, meaning: SymbolFlags): boolean { + function checkAndReportErrorForUsingTypeAsValue( + errorLocation: Node, + name: __String, + meaning: SymbolFlags + ): boolean { if (meaning & SymbolFlags.Value) { if (isPrimitiveTypeName(name)) { const grandparent = errorLocation.parent.parent; - if (grandparent && grandparent.parent && isHeritageClause(grandparent)) { + if ( + grandparent && + grandparent.parent && + isHeritageClause(grandparent) + ) { const heritageKind = grandparent.token; const containerKind = grandparent.parent.kind; - if (containerKind === SyntaxKind.InterfaceDeclaration && heritageKind === SyntaxKind.ExtendsKeyword) { - error(errorLocation, Diagnostics.An_interface_cannot_extend_a_primitive_type_like_0_It_can_only_extend_other_named_object_types, unescapeLeadingUnderscores(name)); - } - else if (isClassLike(grandparent.parent) && heritageKind === SyntaxKind.ExtendsKeyword) { - error(errorLocation, Diagnostics.A_class_cannot_extend_a_primitive_type_like_0_Classes_can_only_extend_constructable_values, unescapeLeadingUnderscores(name)); - } - else if (isClassLike(grandparent.parent) && heritageKind === SyntaxKind.ImplementsKeyword) { - error(errorLocation, Diagnostics.A_class_cannot_implement_a_primitive_type_like_0_It_can_only_implement_other_named_object_types, unescapeLeadingUnderscores(name)); + if ( + containerKind === SyntaxKind.InterfaceDeclaration && + heritageKind === SyntaxKind.ExtendsKeyword + ) { + error( + errorLocation, + Diagnostics.An_interface_cannot_extend_a_primitive_type_like_0_It_can_only_extend_other_named_object_types, + unescapeLeadingUnderscores(name) + ); + } else if ( + isClassLike(grandparent.parent) && + heritageKind === SyntaxKind.ExtendsKeyword + ) { + error( + errorLocation, + Diagnostics.A_class_cannot_extend_a_primitive_type_like_0_Classes_can_only_extend_constructable_values, + unescapeLeadingUnderscores(name) + ); + } else if ( + isClassLike(grandparent.parent) && + heritageKind === SyntaxKind.ImplementsKeyword + ) { + error( + errorLocation, + Diagnostics.A_class_cannot_implement_a_primitive_type_like_0_It_can_only_implement_other_named_object_types, + unescapeLeadingUnderscores(name) + ); } - } - else { - error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here, unescapeLeadingUnderscores(name)); + } else { + error( + errorLocation, + Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here, + unescapeLeadingUnderscores(name) + ); } return true; } - const symbol = resolveSymbol(resolveName(errorLocation, name, SymbolFlags.Type & ~SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*isUse*/ false)); + const symbol = resolveSymbol( + resolveName( + errorLocation, + name, + SymbolFlags.Type & ~SymbolFlags.Value, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ false + ) + ); const allFlags = symbol && getSymbolFlags(symbol); - if (symbol && allFlags !== undefined && !(allFlags & SymbolFlags.Value)) { + if ( + symbol && + allFlags !== undefined && + !(allFlags & SymbolFlags.Value) + ) { const rawName = unescapeLeadingUnderscores(name); if (isES2015OrLaterConstructorName(name)) { - 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); - } - else if (maybeMappedType(errorLocation, symbol)) { - 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"); - } - else { - error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here, rawName); + 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 + ); + } else if (maybeMappedType(errorLocation, symbol)) { + 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" + ); + } else { + error( + errorLocation, + Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here, + rawName + ); } return true; } @@ -3522,10 +5126,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function maybeMappedType(node: Node, symbol: Symbol) { - const container = findAncestor(node.parent, n => isComputedPropertyName(n) || isPropertySignature(n) ? false : isTypeLiteralNode(n) || "quit") as TypeLiteralNode | undefined; + const container = findAncestor(node.parent, (n) => + isComputedPropertyName(n) || isPropertySignature(n) + ? false + : isTypeLiteralNode(n) || "quit" + ) as TypeLiteralNode | undefined; if (container && container.members.length === 1) { const type = getDeclaredTypeOfSymbol(symbol); - return !!(type.flags & TypeFlags.Union) && allTypesAssignableToKind(type, TypeFlags.StringOrNumberLiteral, /*strict*/ true); + return ( + !!(type.flags & TypeFlags.Union) && + allTypesAssignableToKind( + type, + TypeFlags.StringOrNumberLiteral, + /*strict*/ true + ) + ); } return false; } @@ -3543,62 +5158,131 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function checkAndReportErrorForUsingNamespaceAsTypeOrValue(errorLocation: Node, name: __String, meaning: SymbolFlags): boolean { + function checkAndReportErrorForUsingNamespaceAsTypeOrValue( + errorLocation: Node, + name: __String, + meaning: SymbolFlags + ): boolean { if (meaning & (SymbolFlags.Value & ~SymbolFlags.Type)) { - const symbol = resolveSymbol(resolveName(errorLocation, name, SymbolFlags.NamespaceModule, /*nameNotFoundMessage*/ undefined, /*isUse*/ false)); + const symbol = resolveSymbol( + resolveName( + errorLocation, + name, + SymbolFlags.NamespaceModule, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ false + ) + ); if (symbol) { error( errorLocation, Diagnostics.Cannot_use_namespace_0_as_a_value, - unescapeLeadingUnderscores(name), + unescapeLeadingUnderscores(name) ); return true; } - } - else if (meaning & (SymbolFlags.Type & ~SymbolFlags.Value)) { - const symbol = resolveSymbol(resolveName(errorLocation, name, SymbolFlags.Module, /*nameNotFoundMessage*/ undefined, /*isUse*/ false)); + } else if (meaning & (SymbolFlags.Type & ~SymbolFlags.Value)) { + const symbol = resolveSymbol( + resolveName( + errorLocation, + name, + SymbolFlags.Module, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ false + ) + ); if (symbol) { - error(errorLocation, Diagnostics.Cannot_use_namespace_0_as_a_type, unescapeLeadingUnderscores(name)); + error( + errorLocation, + Diagnostics.Cannot_use_namespace_0_as_a_type, + unescapeLeadingUnderscores(name) + ); return true; } } return false; } - function checkResolvedBlockScopedVariable(result: Symbol, errorLocation: Node): void { - Debug.assert(!!(result.flags & SymbolFlags.BlockScopedVariable || result.flags & SymbolFlags.Class || result.flags & SymbolFlags.Enum)); - if (result.flags & (SymbolFlags.Function | SymbolFlags.FunctionScopedVariable | SymbolFlags.Assignment) && result.flags & SymbolFlags.Class) { + function checkResolvedBlockScopedVariable( + result: Symbol, + errorLocation: Node + ): void { + Debug.assert( + !!( + result.flags & SymbolFlags.BlockScopedVariable || + result.flags & SymbolFlags.Class || + result.flags & SymbolFlags.Enum + ) + ); + if ( + result.flags & + (SymbolFlags.Function | + SymbolFlags.FunctionScopedVariable | + SymbolFlags.Assignment) && + result.flags & SymbolFlags.Class + ) { // constructor functions aren't block scoped return; } // Block-scoped variables cannot be used before their definition const declaration = result.declarations?.find( - d => isBlockOrCatchScoped(d) || isClassLike(d) || (d.kind === SyntaxKind.EnumDeclaration), + (d) => + isBlockOrCatchScoped(d) || + isClassLike(d) || + d.kind === SyntaxKind.EnumDeclaration ); - if (declaration === undefined) return Debug.fail("checkResolvedBlockScopedVariable could not find block-scoped declaration"); + if (declaration === undefined) + return Debug.fail( + "checkResolvedBlockScopedVariable could not find block-scoped declaration" + ); - if (!(declaration.flags & NodeFlags.Ambient) && !isBlockScopedNameDeclaredBeforeUse(declaration, errorLocation)) { + if ( + !(declaration.flags & NodeFlags.Ambient) && + !isBlockScopedNameDeclaredBeforeUse(declaration, errorLocation) + ) { let diagnosticMessage; - const declarationName = declarationNameToString(getNameOfDeclaration(declaration)); + const declarationName = declarationNameToString( + getNameOfDeclaration(declaration) + ); if (result.flags & SymbolFlags.BlockScopedVariable) { - diagnosticMessage = error(errorLocation, Diagnostics.Block_scoped_variable_0_used_before_its_declaration, declarationName); - } - else if (result.flags & SymbolFlags.Class) { - diagnosticMessage = error(errorLocation, Diagnostics.Class_0_used_before_its_declaration, declarationName); - } - else if (result.flags & SymbolFlags.RegularEnum) { - diagnosticMessage = error(errorLocation, Diagnostics.Enum_0_used_before_its_declaration, declarationName); - } - else { + diagnosticMessage = error( + errorLocation, + Diagnostics.Block_scoped_variable_0_used_before_its_declaration, + declarationName + ); + } else if (result.flags & SymbolFlags.Class) { + diagnosticMessage = error( + errorLocation, + Diagnostics.Class_0_used_before_its_declaration, + declarationName + ); + } else if (result.flags & SymbolFlags.RegularEnum) { + diagnosticMessage = error( + errorLocation, + Diagnostics.Enum_0_used_before_its_declaration, + declarationName + ); + } else { Debug.assert(!!(result.flags & SymbolFlags.ConstEnum)); if (getIsolatedModules(compilerOptions)) { - diagnosticMessage = error(errorLocation, Diagnostics.Enum_0_used_before_its_declaration, declarationName); + diagnosticMessage = error( + errorLocation, + Diagnostics.Enum_0_used_before_its_declaration, + declarationName + ); } } if (diagnosticMessage) { - addRelatedInfo(diagnosticMessage, createDiagnosticForNode(declaration, Diagnostics._0_is_declared_here, declarationName)); + addRelatedInfo( + diagnosticMessage, + createDiagnosticForNode( + declaration, + Diagnostics._0_is_declared_here, + declarationName + ) + ); } } } @@ -3608,13 +5292,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * If current node is an IIFE, continue walking up. * Return false if 'stopAt' node is reached or isFunctionLike(current) === true. */ - function isSameScopeDescendentOf(initial: Node, parent: Node | undefined, stopAt: Node): boolean { - return !!parent && !!findAncestor(initial, n => - n === parent - || (n === stopAt || isFunctionLike(n) && (!getImmediatelyInvokedFunctionExpression(n) || (getFunctionFlags(n) & FunctionFlags.AsyncGenerator)) ? "quit" : false)); + function isSameScopeDescendentOf( + initial: Node, + parent: Node | undefined, + stopAt: Node + ): boolean { + return ( + !!parent && + !!findAncestor( + initial, + (n) => + n === parent || + (n === stopAt || + (isFunctionLike(n) && + (!getImmediatelyInvokedFunctionExpression(n) || + getFunctionFlags(n) & FunctionFlags.AsyncGenerator)) + ? "quit" + : false) + ) + ); } - function getAnyImportSyntax(node: Node): AnyImportOrJsDocImport | undefined { + function getAnyImportSyntax( + node: Node + ): AnyImportOrJsDocImport | undefined { switch (node.kind) { case SyntaxKind.ImportEqualsDeclaration: return node as ImportEqualsDeclaration; @@ -3629,8 +5330,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getDeclarationOfAliasSymbol(symbol: Symbol): Declaration | undefined { - return symbol.declarations && findLast(symbol.declarations, isAliasSymbolDeclaration); + function getDeclarationOfAliasSymbol( + symbol: Symbol + ): Declaration | undefined { + return ( + symbol.declarations && + findLast(symbol.declarations, isAliasSymbolDeclaration) + ); } /** @@ -3649,62 +5355,132 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * const { x } = require ... */ function isAliasSymbolDeclaration(node: Node): boolean { - return node.kind === SyntaxKind.ImportEqualsDeclaration - || node.kind === SyntaxKind.NamespaceExportDeclaration - || node.kind === SyntaxKind.ImportClause && !!(node as ImportClause).name - || node.kind === SyntaxKind.NamespaceImport - || node.kind === SyntaxKind.NamespaceExport - || node.kind === SyntaxKind.ImportSpecifier - || node.kind === SyntaxKind.ExportSpecifier - || node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(node as ExportAssignment) - || isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ModuleExports && exportAssignmentIsAlias(node) - || isAccessExpression(node) - && isBinaryExpression(node.parent) - && node.parent.left === node - && node.parent.operatorToken.kind === SyntaxKind.EqualsToken - && isAliasableOrJsExpression(node.parent.right) - || node.kind === SyntaxKind.ShorthandPropertyAssignment - || node.kind === SyntaxKind.PropertyAssignment && isAliasableOrJsExpression((node as PropertyAssignment).initializer) - || node.kind === SyntaxKind.VariableDeclaration && isVariableDeclarationInitializedToBareOrAccessedRequire(node) - || node.kind === SyntaxKind.BindingElement && isVariableDeclarationInitializedToBareOrAccessedRequire(node.parent.parent); + return ( + node.kind === SyntaxKind.ImportEqualsDeclaration || + node.kind === SyntaxKind.NamespaceExportDeclaration || + (node.kind === SyntaxKind.ImportClause && + !!(node as ImportClause).name) || + node.kind === SyntaxKind.NamespaceImport || + node.kind === SyntaxKind.NamespaceExport || + node.kind === SyntaxKind.ImportSpecifier || + node.kind === SyntaxKind.ExportSpecifier || + (node.kind === SyntaxKind.ExportAssignment && + exportAssignmentIsAlias(node as ExportAssignment)) || + (isBinaryExpression(node) && + getAssignmentDeclarationKind(node) === + AssignmentDeclarationKind.ModuleExports && + exportAssignmentIsAlias(node)) || + (isAccessExpression(node) && + isBinaryExpression(node.parent) && + node.parent.left === node && + node.parent.operatorToken.kind === SyntaxKind.EqualsToken && + isAliasableOrJsExpression(node.parent.right)) || + node.kind === SyntaxKind.ShorthandPropertyAssignment || + (node.kind === SyntaxKind.PropertyAssignment && + isAliasableOrJsExpression( + (node as PropertyAssignment).initializer + )) || + (node.kind === SyntaxKind.VariableDeclaration && + isVariableDeclarationInitializedToBareOrAccessedRequire( + node + )) || + (node.kind === SyntaxKind.BindingElement && + isVariableDeclarationInitializedToBareOrAccessedRequire( + node.parent.parent + )) + ); } function isAliasableOrJsExpression(e: Expression) { - return isAliasableExpression(e) || isFunctionExpression(e) && isJSConstructor(e); + return ( + isAliasableExpression(e) || + (isFunctionExpression(e) && isJSConstructor(e)) + ); } - function getTargetOfImportEqualsDeclaration(node: ImportEqualsDeclaration | VariableDeclaration, dontResolveAlias: boolean): Symbol | undefined { + function getTargetOfImportEqualsDeclaration( + node: ImportEqualsDeclaration | VariableDeclaration, + dontResolveAlias: boolean + ): Symbol | undefined { const commonJSPropertyAccess = getCommonJSPropertyAccess(node); if (commonJSPropertyAccess) { - const name = (getLeftmostAccessExpression(commonJSPropertyAccess.expression) as CallExpression).arguments[0] as StringLiteral; + const name = ( + getLeftmostAccessExpression( + commonJSPropertyAccess.expression + ) as CallExpression + ).arguments[0] as StringLiteral; return isIdentifier(commonJSPropertyAccess.name) - ? resolveSymbol(getPropertyOfType(resolveExternalModuleTypeByLiteral(name), commonJSPropertyAccess.name.escapedText)) + ? resolveSymbol( + getPropertyOfType( + resolveExternalModuleTypeByLiteral(name), + commonJSPropertyAccess.name.escapedText + ) + ) : undefined; } - if (isVariableDeclaration(node) || node.moduleReference.kind === SyntaxKind.ExternalModuleReference) { + if ( + isVariableDeclaration(node) || + node.moduleReference.kind === SyntaxKind.ExternalModuleReference + ) { const immediate = resolveExternalModuleName( node, - getExternalModuleRequireArgument(node) || getExternalModuleImportEqualsDeclarationExpression(node), + getExternalModuleRequireArgument(node) || + getExternalModuleImportEqualsDeclarationExpression(node) ); const resolved = resolveExternalModuleSymbol(immediate); - if (resolved && ModuleKind.Node20 <= moduleKind && moduleKind <= ModuleKind.NodeNext) { - const moduleExports = getExportOfModule(resolved, "module.exports" as __String, node, dontResolveAlias); + if ( + resolved && + ModuleKind.Node20 <= moduleKind && + moduleKind <= ModuleKind.NodeNext + ) { + const moduleExports = getExportOfModule( + resolved, + "module.exports" as __String, + node, + dontResolveAlias + ); if (moduleExports) { return moduleExports; } } - markSymbolOfAliasDeclarationIfTypeOnly(node, immediate, resolved, /*overwriteEmpty*/ false); + markSymbolOfAliasDeclarationIfTypeOnly( + node, + immediate, + resolved, + /*overwriteEmpty*/ false + ); return resolved; } - const resolved = getSymbolOfPartOfRightHandSideOfImportEquals(node.moduleReference, dontResolveAlias); - checkAndReportErrorForResolvingImportAliasToTypeOnlySymbol(node, resolved); + const resolved = getSymbolOfPartOfRightHandSideOfImportEquals( + node.moduleReference, + dontResolveAlias + ); + checkAndReportErrorForResolvingImportAliasToTypeOnlySymbol( + node, + resolved + ); return resolved; } - function checkAndReportErrorForResolvingImportAliasToTypeOnlySymbol(node: ImportEqualsDeclaration, resolved: Symbol | undefined) { - if (markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false) && !node.isTypeOnly) { - const typeOnlyDeclaration = getTypeOnlyAliasDeclaration(getSymbolOfDeclaration(node))!; - const isExport = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier || typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration; + function checkAndReportErrorForResolvingImportAliasToTypeOnlySymbol( + node: ImportEqualsDeclaration, + resolved: Symbol | undefined + ) { + if ( + markSymbolOfAliasDeclarationIfTypeOnly( + node, + /*immediateTarget*/ undefined, + resolved, + /*overwriteEmpty*/ false + ) && + !node.isTypeOnly + ) { + const typeOnlyDeclaration = getTypeOnlyAliasDeclaration( + getSymbolOfDeclaration(node) + )!; + const isExport = + typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier || + typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration; const message = isExport ? Diagnostics.An_import_alias_cannot_reference_a_declaration_that_was_exported_using_export_type : Diagnostics.An_import_alias_cannot_reference_a_declaration_that_was_imported_using_import_type; @@ -3713,58 +5489,127 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { : Diagnostics._0_was_imported_here; // TODO: how to get name for export *? - const name = typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration ? "*" : moduleExportNameTextUnescaped(typeOnlyDeclaration.name); - addRelatedInfo(error(node.moduleReference, message), createDiagnosticForNode(typeOnlyDeclaration, relatedMessage, name)); + const name = + typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration + ? "*" + : moduleExportNameTextUnescaped(typeOnlyDeclaration.name); + addRelatedInfo( + error(node.moduleReference, message), + createDiagnosticForNode( + typeOnlyDeclaration, + relatedMessage, + name + ) + ); } } - function resolveExportByName(moduleSymbol: Symbol, name: __String, sourceNode: TypeOnlyCompatibleAliasDeclaration | undefined, dontResolveAlias: boolean) { - const exportValue = moduleSymbol.exports!.get(InternalSymbolName.ExportEquals); + function resolveExportByName( + moduleSymbol: Symbol, + name: __String, + sourceNode: TypeOnlyCompatibleAliasDeclaration | undefined, + dontResolveAlias: boolean + ) { + const exportValue = moduleSymbol.exports!.get( + InternalSymbolName.ExportEquals + ); const exportSymbol = exportValue - ? getPropertyOfType(getTypeOfSymbol(exportValue), name, /*skipObjectFunctionPropertyAugment*/ true) + ? getPropertyOfType( + getTypeOfSymbol(exportValue), + name, + /*skipObjectFunctionPropertyAugment*/ true + ) : moduleSymbol.exports!.get(name); const resolved = resolveSymbol(exportSymbol, dontResolveAlias); - markSymbolOfAliasDeclarationIfTypeOnly(sourceNode, exportSymbol, resolved, /*overwriteEmpty*/ false); + markSymbolOfAliasDeclarationIfTypeOnly( + sourceNode, + exportSymbol, + resolved, + /*overwriteEmpty*/ false + ); return resolved; } function isSyntacticDefault(node: Node) { - return ((isExportAssignment(node) && !node.isExportEquals) - || hasSyntacticModifier(node, ModifierFlags.Default) - || isExportSpecifier(node) - || isNamespaceExport(node)); + return ( + (isExportAssignment(node) && !node.isExportEquals) || + hasSyntacticModifier(node, ModifierFlags.Default) || + isExportSpecifier(node) || + isNamespaceExport(node) + ); } function getEmitSyntaxForModuleSpecifierExpression(usage: Expression) { - return isStringLiteralLike(usage) ? host.getEmitSyntaxForUsageLocation(getSourceFileOfNode(usage), usage) : undefined; + return isStringLiteralLike(usage) + ? host.getEmitSyntaxForUsageLocation( + getSourceFileOfNode(usage), + usage + ) + : undefined; } - function isESMFormatImportImportingCommonjsFormatFile(usageMode: ResolutionMode, targetMode: ResolutionMode) { - return usageMode === ModuleKind.ESNext && targetMode === ModuleKind.CommonJS; + function isESMFormatImportImportingCommonjsFormatFile( + usageMode: ResolutionMode, + targetMode: ResolutionMode + ) { + return ( + usageMode === ModuleKind.ESNext && + targetMode === ModuleKind.CommonJS + ); } - function isOnlyImportableAsDefault(usage: Expression, resolvedModule?: Symbol) { + function isOnlyImportableAsDefault( + usage: Expression, + resolvedModule?: Symbol + ) { // In Node.js, JSON modules don't get named exports - if (ModuleKind.Node16 <= moduleKind && moduleKind <= ModuleKind.NodeNext) { + if ( + ModuleKind.Node16 <= moduleKind && + moduleKind <= ModuleKind.NodeNext + ) { const usageMode = getEmitSyntaxForModuleSpecifierExpression(usage); if (usageMode === ModuleKind.ESNext) { - resolvedModule ??= resolveExternalModuleName(usage, usage, /*ignoreErrors*/ true); - const targetFile = resolvedModule && getSourceFileOfModule(resolvedModule); - return targetFile && (isJsonSourceFile(targetFile) || getDeclarationFileExtension(targetFile.fileName) === ".d.json.ts"); + resolvedModule ??= resolveExternalModuleName( + usage, + usage, + /*ignoreErrors*/ true + ); + const targetFile = + resolvedModule && getSourceFileOfModule(resolvedModule); + return ( + targetFile && + (isJsonSourceFile(targetFile) || + getDeclarationFileExtension(targetFile.fileName) === + ".d.json.ts") + ); } } return false; } - function canHaveSyntheticDefault(file: SourceFile | undefined, moduleSymbol: Symbol, dontResolveAlias: boolean, usage: Expression) { - const usageMode = file && getEmitSyntaxForModuleSpecifierExpression(usage); + function canHaveSyntheticDefault( + file: SourceFile | undefined, + moduleSymbol: Symbol, + dontResolveAlias: boolean, + usage: Expression + ) { + const usageMode = + file && getEmitSyntaxForModuleSpecifierExpression(usage); if (file && usageMode !== undefined) { const targetMode = host.getImpliedNodeFormatForEmit(file); - if (usageMode === ModuleKind.ESNext && targetMode === ModuleKind.CommonJS && ModuleKind.Node16 <= moduleKind && moduleKind <= ModuleKind.NodeNext) { + if ( + usageMode === ModuleKind.ESNext && + targetMode === ModuleKind.CommonJS && + ModuleKind.Node16 <= moduleKind && + moduleKind <= ModuleKind.NodeNext + ) { // In Node.js, CommonJS modules always have a synthetic default when imported into ESM return true; } - if (usageMode === ModuleKind.ESNext && targetMode === ModuleKind.ESNext) { + if ( + usageMode === ModuleKind.ESNext && + targetMode === ModuleKind.ESNext + ) { // No matter what the `module` setting is, if we're confident that both files // are ESM, there cannot be a synthetic default. return false; @@ -3776,13 +5621,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Declaration files (and ambient modules) if (!file || file.isDeclarationFile) { // Definitely cannot have a synthetic default if they have a syntactic default member specified - const defaultExportSymbol = resolveExportByName(moduleSymbol, InternalSymbolName.Default, /*sourceNode*/ undefined, /*dontResolveAlias*/ true); // Dont resolve alias because we want the immediately exported symbol's declaration - if (defaultExportSymbol && some(defaultExportSymbol.declarations, isSyntacticDefault)) { + const defaultExportSymbol = resolveExportByName( + moduleSymbol, + InternalSymbolName.Default, + /*sourceNode*/ undefined, + /*dontResolveAlias*/ true + ); // Dont resolve alias because we want the immediately exported symbol's declaration + if ( + defaultExportSymbol && + some(defaultExportSymbol.declarations, isSyntacticDefault) + ) { return false; } // It _might_ still be incorrect to assume there is no __esModule marker on the import at runtime, even if there is no `default` member // So we check a bit more, - if (resolveExportByName(moduleSymbol, escapeLeadingUnderscores("__esModule"), /*sourceNode*/ undefined, dontResolveAlias)) { + if ( + resolveExportByName( + moduleSymbol, + escapeLeadingUnderscores("__esModule"), + /*sourceNode*/ undefined, + dontResolveAlias + ) + ) { // If there is an `__esModule` specified in the declaration (meaning someone explicitly added it or wrote it in their code), // it definitely is a module and does not have a synthetic default return false; @@ -3797,30 +5657,59 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return hasExportAssignmentSymbol(moduleSymbol); } // 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 - return typeof file.externalModuleIndicator !== "object" && !resolveExportByName(moduleSymbol, escapeLeadingUnderscores("__esModule"), /*sourceNode*/ undefined, dontResolveAlias); + return ( + typeof file.externalModuleIndicator !== "object" && + !resolveExportByName( + moduleSymbol, + escapeLeadingUnderscores("__esModule"), + /*sourceNode*/ undefined, + dontResolveAlias + ) + ); } - function getTargetOfImportClause(node: ImportClause, dontResolveAlias: boolean): Symbol | undefined { - const moduleSymbol = resolveExternalModuleName(node, node.parent.moduleSpecifier); + function getTargetOfImportClause( + node: ImportClause, + dontResolveAlias: boolean + ): Symbol | undefined { + const moduleSymbol = resolveExternalModuleName( + node, + node.parent.moduleSpecifier + ); if (moduleSymbol) { - return getTargetofModuleDefault(moduleSymbol, node, dontResolveAlias); + return getTargetofModuleDefault( + moduleSymbol, + node, + dontResolveAlias + ); } } - function getTargetofModuleDefault(moduleSymbol: Symbol, node: ImportClause | ImportOrExportSpecifier, dontResolveAlias: boolean) { + function getTargetofModuleDefault( + moduleSymbol: Symbol, + node: ImportClause | ImportOrExportSpecifier, + dontResolveAlias: boolean + ) { const file = moduleSymbol.declarations?.find(isSourceFile); const specifier = getModuleSpecifierForImportOrExport(node); let exportDefaultSymbol: Symbol | undefined; let exportModuleDotExportsSymbol: Symbol | undefined; if (isShorthandAmbientModuleSymbol(moduleSymbol)) { exportDefaultSymbol = moduleSymbol; - } - else if ( - file && specifier && - ModuleKind.Node20 <= moduleKind && moduleKind <= ModuleKind.NodeNext && - getEmitSyntaxForModuleSpecifierExpression(specifier) === ModuleKind.CommonJS && + } else if ( + file && + specifier && + ModuleKind.Node20 <= moduleKind && + moduleKind <= ModuleKind.NodeNext && + getEmitSyntaxForModuleSpecifierExpression(specifier) === + ModuleKind.CommonJS && host.getImpliedNodeFormatForEmit(file) === ModuleKind.ESNext && - (exportModuleDotExportsSymbol = resolveExportByName(moduleSymbol, "module.exports" as __String, node, dontResolveAlias)) + (exportModuleDotExportsSymbol = resolveExportByName( + moduleSymbol, + "module.exports" as __String, + node, + dontResolveAlias + )) ) { // We have a transpiled default import where the `require` resolves to an ES module with a `module.exports` named // export. If `esModuleInterop` is enabled, this will work: @@ -3836,27 +5725,62 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We could try to resolve the 'default' property in the latter case, but it's a mistake to run in this // environment without `esModuleInterop`, so just error. if (!getESModuleInterop(compilerOptions)) { - error(node.name, Diagnostics.Module_0_can_only_be_default_imported_using_the_1_flag, symbolToString(moduleSymbol), "esModuleInterop"); + error( + node.name, + Diagnostics.Module_0_can_only_be_default_imported_using_the_1_flag, + symbolToString(moduleSymbol), + "esModuleInterop" + ); return undefined; } - markSymbolOfAliasDeclarationIfTypeOnly(node, exportModuleDotExportsSymbol, /*finalTarget*/ undefined, /*overwriteEmpty*/ false); + markSymbolOfAliasDeclarationIfTypeOnly( + node, + exportModuleDotExportsSymbol, + /*finalTarget*/ undefined, + /*overwriteEmpty*/ false + ); return exportModuleDotExportsSymbol; - } - else { - exportDefaultSymbol = resolveExportByName(moduleSymbol, InternalSymbolName.Default, node, dontResolveAlias); + } else { + exportDefaultSymbol = resolveExportByName( + moduleSymbol, + InternalSymbolName.Default, + node, + dontResolveAlias + ); } if (!specifier) { return exportDefaultSymbol; } - const hasDefaultOnly = isOnlyImportableAsDefault(specifier, moduleSymbol); - const hasSyntheticDefault = canHaveSyntheticDefault(file, moduleSymbol, dontResolveAlias, specifier); + const hasDefaultOnly = isOnlyImportableAsDefault( + specifier, + moduleSymbol + ); + const hasSyntheticDefault = canHaveSyntheticDefault( + file, + moduleSymbol, + dontResolveAlias, + specifier + ); if (!exportDefaultSymbol && !hasSyntheticDefault && !hasDefaultOnly) { - if (hasExportAssignmentSymbol(moduleSymbol) && !allowSyntheticDefaultImports) { - const compilerOptionName = moduleKind >= ModuleKind.ES2015 ? "allowSyntheticDefaultImports" : "esModuleInterop"; - const exportEqualsSymbol = moduleSymbol.exports!.get(InternalSymbolName.ExportEquals); + if ( + hasExportAssignmentSymbol(moduleSymbol) && + !allowSyntheticDefaultImports + ) { + const compilerOptionName = + moduleKind >= ModuleKind.ES2015 + ? "allowSyntheticDefaultImports" + : "esModuleInterop"; + const exportEqualsSymbol = moduleSymbol.exports!.get( + InternalSymbolName.ExportEquals + ); const exportAssignment = exportEqualsSymbol!.valueDeclaration; - const err = error(node.name, Diagnostics.Module_0_can_only_be_default_imported_using_the_1_flag, symbolToString(moduleSymbol), compilerOptionName); + const err = error( + node.name, + Diagnostics.Module_0_can_only_be_default_imported_using_the_1_flag, + symbolToString(moduleSymbol), + compilerOptionName + ); if (exportAssignment) { addRelatedInfo( @@ -3864,34 +5788,57 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { createDiagnosticForNode( exportAssignment, Diagnostics.This_module_is_declared_with_export_and_can_only_be_used_with_a_default_import_when_using_the_0_flag, - compilerOptionName, - ), + compilerOptionName + ) ); } - } - else if (isImportClause(node)) { + } else if (isImportClause(node)) { reportNonDefaultExport(moduleSymbol, node); + } else { + errorNoModuleMemberSymbol( + moduleSymbol, + moduleSymbol, + node, + (isImportOrExportSpecifier(node) && node.propertyName) || + node.name + ); } - else { - errorNoModuleMemberSymbol(moduleSymbol, moduleSymbol, node, isImportOrExportSpecifier(node) && node.propertyName || node.name); - } - } - else if (hasSyntheticDefault || hasDefaultOnly) { + } else if (hasSyntheticDefault || hasDefaultOnly) { // per emit behavior, a synthetic default overrides a "real" .default member if `__esModule` is not present - const resolved = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) || resolveSymbol(moduleSymbol, dontResolveAlias); - markSymbolOfAliasDeclarationIfTypeOnly(node, moduleSymbol, resolved, /*overwriteEmpty*/ false); + const resolved = + resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) || + resolveSymbol(moduleSymbol, dontResolveAlias); + markSymbolOfAliasDeclarationIfTypeOnly( + node, + moduleSymbol, + resolved, + /*overwriteEmpty*/ false + ); return resolved; } - markSymbolOfAliasDeclarationIfTypeOnly(node, exportDefaultSymbol, /*finalTarget*/ undefined, /*overwriteEmpty*/ false); + markSymbolOfAliasDeclarationIfTypeOnly( + node, + exportDefaultSymbol, + /*finalTarget*/ undefined, + /*overwriteEmpty*/ false + ); return exportDefaultSymbol; } - function getModuleSpecifierForImportOrExport(node: ImportEqualsDeclaration | ImportClause | NamespaceImport | ImportOrExportSpecifier): Expression | undefined { + function getModuleSpecifierForImportOrExport( + node: + | ImportEqualsDeclaration + | ImportClause + | NamespaceImport + | ImportOrExportSpecifier + ): Expression | undefined { switch (node.kind) { case SyntaxKind.ImportClause: return node.parent.moduleSpecifier; case SyntaxKind.ImportEqualsDeclaration: - return isExternalModuleReference(node.moduleReference) ? node.moduleReference.expression : undefined; + return isExternalModuleReference(node.moduleReference) + ? node.moduleReference.expression + : undefined; case SyntaxKind.NamespaceImport: return node.parent.parent.moduleSpecifier; case SyntaxKind.ImportSpecifier: @@ -3909,39 +5856,84 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { node.name, Diagnostics.Module_0_has_no_default_export_Did_you_mean_to_use_import_1_from_0_instead, symbolToString(moduleSymbol), - symbolToString(node.symbol), + symbolToString(node.symbol) + ); + } else { + const diagnostic = error( + node.name, + Diagnostics.Module_0_has_no_default_export, + symbolToString(moduleSymbol) + ); + const exportStar = moduleSymbol.exports?.get( + InternalSymbolName.ExportStar ); - } - else { - const diagnostic = error(node.name, Diagnostics.Module_0_has_no_default_export, symbolToString(moduleSymbol)); - const exportStar = moduleSymbol.exports?.get(InternalSymbolName.ExportStar); if (exportStar) { - const defaultExport = exportStar.declarations?.find(decl => - !!( - isExportDeclaration(decl) && decl.moduleSpecifier && - resolveExternalModuleName(decl, decl.moduleSpecifier)?.exports?.has(InternalSymbolName.Default) - ) + const defaultExport = exportStar.declarations?.find( + (decl) => + !!( + isExportDeclaration(decl) && + decl.moduleSpecifier && + resolveExternalModuleName( + decl, + decl.moduleSpecifier + )?.exports?.has(InternalSymbolName.Default) + ) ); if (defaultExport) { - addRelatedInfo(diagnostic, createDiagnosticForNode(defaultExport, Diagnostics.export_Asterisk_does_not_re_export_a_default)); + addRelatedInfo( + diagnostic, + createDiagnosticForNode( + defaultExport, + Diagnostics.export_Asterisk_does_not_re_export_a_default + ) + ); } } } } - function getTargetOfNamespaceImport(node: NamespaceImport, dontResolveAlias: boolean): Symbol | undefined { + function getTargetOfNamespaceImport( + node: NamespaceImport, + dontResolveAlias: boolean + ): Symbol | undefined { const moduleSpecifier = node.parent.parent.moduleSpecifier; const immediate = resolveExternalModuleName(node, moduleSpecifier); - const resolved = resolveESModuleSymbol(immediate, moduleSpecifier, dontResolveAlias, /*suppressInteropError*/ false); - markSymbolOfAliasDeclarationIfTypeOnly(node, immediate, resolved, /*overwriteEmpty*/ false); + const resolved = resolveESModuleSymbol( + immediate, + moduleSpecifier, + dontResolveAlias, + /*suppressInteropError*/ false + ); + markSymbolOfAliasDeclarationIfTypeOnly( + node, + immediate, + resolved, + /*overwriteEmpty*/ false + ); return resolved; } - function getTargetOfNamespaceExport(node: NamespaceExport, dontResolveAlias: boolean): Symbol | undefined { + function getTargetOfNamespaceExport( + node: NamespaceExport, + dontResolveAlias: boolean + ): Symbol | undefined { const moduleSpecifier = node.parent.moduleSpecifier; - const immediate = moduleSpecifier && resolveExternalModuleName(node, moduleSpecifier); - const resolved = moduleSpecifier && resolveESModuleSymbol(immediate, moduleSpecifier, dontResolveAlias, /*suppressInteropError*/ false); - markSymbolOfAliasDeclarationIfTypeOnly(node, immediate, resolved, /*overwriteEmpty*/ false); + const immediate = + moduleSpecifier && resolveExternalModuleName(node, moduleSpecifier); + const resolved = + moduleSpecifier && + resolveESModuleSymbol( + immediate, + moduleSpecifier, + dontResolveAlias, + /*suppressInteropError*/ false + ); + markSymbolOfAliasDeclarationIfTypeOnly( + node, + immediate, + resolved, + /*overwriteEmpty*/ false + ); return resolved; } @@ -3963,52 +5955,106 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // // An 'import { Point } from "graphics"' needs to create a symbol that combines the value side 'Point' // property with the type/namespace side interface 'Point'. - function combineValueAndTypeSymbols(valueSymbol: Symbol, typeSymbol: Symbol): Symbol { + function combineValueAndTypeSymbols( + valueSymbol: Symbol, + typeSymbol: Symbol + ): Symbol { if (valueSymbol === unknownSymbol && typeSymbol === unknownSymbol) { return unknownSymbol; } if (valueSymbol.flags & (SymbolFlags.Type | SymbolFlags.Namespace)) { return valueSymbol; } - const result = createSymbol(valueSymbol.flags | typeSymbol.flags, valueSymbol.escapedName); + const result = createSymbol( + valueSymbol.flags | typeSymbol.flags, + valueSymbol.escapedName + ); Debug.assert(valueSymbol.declarations || typeSymbol.declarations); - result.declarations = deduplicate(concatenate(valueSymbol.declarations!, typeSymbol.declarations), equateValues); + result.declarations = deduplicate( + concatenate(valueSymbol.declarations!, typeSymbol.declarations), + equateValues + ); result.parent = valueSymbol.parent || typeSymbol.parent; - if (valueSymbol.valueDeclaration) result.valueDeclaration = valueSymbol.valueDeclaration; + if (valueSymbol.valueDeclaration) + result.valueDeclaration = valueSymbol.valueDeclaration; if (typeSymbol.members) result.members = new Map(typeSymbol.members); if (valueSymbol.exports) result.exports = new Map(valueSymbol.exports); return result; } - function getExportOfModule(symbol: Symbol, nameText: __String, specifier: Declaration, dontResolveAlias: boolean): Symbol | undefined { + function getExportOfModule( + symbol: Symbol, + nameText: __String, + specifier: Declaration, + dontResolveAlias: boolean + ): Symbol | undefined { if (symbol.flags & SymbolFlags.Module) { const exportSymbol = getExportsOfSymbol(symbol).get(nameText); const resolved = resolveSymbol(exportSymbol, dontResolveAlias); - const exportStarDeclaration = getSymbolLinks(symbol).typeOnlyExportStarMap?.get(nameText); - markSymbolOfAliasDeclarationIfTypeOnly(specifier, exportSymbol, resolved, /*overwriteEmpty*/ false, exportStarDeclaration, nameText); + const exportStarDeclaration = + getSymbolLinks(symbol).typeOnlyExportStarMap?.get(nameText); + markSymbolOfAliasDeclarationIfTypeOnly( + specifier, + exportSymbol, + resolved, + /*overwriteEmpty*/ false, + exportStarDeclaration, + nameText + ); return resolved; } } - function getPropertyOfVariable(symbol: Symbol, name: __String): Symbol | undefined { + function getPropertyOfVariable( + symbol: Symbol, + name: __String + ): Symbol | undefined { if (symbol.flags & SymbolFlags.Variable) { - const typeAnnotation = (symbol.valueDeclaration as VariableDeclaration).type; + const typeAnnotation = ( + symbol.valueDeclaration as VariableDeclaration + ).type; if (typeAnnotation) { - return resolveSymbol(getPropertyOfType(getTypeFromTypeNode(typeAnnotation), name)); + return resolveSymbol( + getPropertyOfType(getTypeFromTypeNode(typeAnnotation), name) + ); } } } - function getExternalModuleMember(node: ImportDeclaration | ExportDeclaration | VariableDeclaration | JSDocImportTag, specifier: ImportOrExportSpecifier | BindingElement | PropertyAccessExpression, dontResolveAlias = false): Symbol | undefined { - const moduleSpecifier = getExternalModuleRequireArgument(node) || (node as ImportDeclaration | ExportDeclaration | JSDocImportTag).moduleSpecifier!; + function getExternalModuleMember( + node: + | ImportDeclaration + | ExportDeclaration + | VariableDeclaration + | JSDocImportTag, + specifier: + | ImportOrExportSpecifier + | BindingElement + | PropertyAccessExpression, + dontResolveAlias = false + ): Symbol | undefined { + const moduleSpecifier = + getExternalModuleRequireArgument(node) || + (node as ImportDeclaration | ExportDeclaration | JSDocImportTag) + .moduleSpecifier!; const moduleSymbol = resolveExternalModuleName(node, moduleSpecifier)!; // TODO: GH#18217 - const name = !isPropertyAccessExpression(specifier) && specifier.propertyName || specifier.name; + const name = + (!isPropertyAccessExpression(specifier) && + specifier.propertyName) || + specifier.name; if (!isIdentifier(name) && name.kind !== SyntaxKind.StringLiteral) { return undefined; } const nameText = moduleExportNameTextEscaped(name); - const suppressInteropError = nameText === InternalSymbolName.Default && allowSyntheticDefaultImports; - const targetSymbol = resolveESModuleSymbol(moduleSymbol, moduleSpecifier, /*dontResolveAlias*/ false, suppressInteropError); + const suppressInteropError = + nameText === InternalSymbolName.Default && + allowSyntheticDefaultImports; + const targetSymbol = resolveESModuleSymbol( + moduleSymbol, + moduleSpecifier, + /*dontResolveAlias*/ false, + suppressInteropError + ); if (targetSymbol) { // Note: The empty string is a valid module export name: // @@ -4022,172 +6068,401 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let symbolFromVariable: Symbol | undefined; // First check if module was specified with "export=". If so, get the member from the resolved type - if (moduleSymbol && moduleSymbol.exports && moduleSymbol.exports.get(InternalSymbolName.ExportEquals)) { - symbolFromVariable = getPropertyOfType(getTypeOfSymbol(targetSymbol), nameText, /*skipObjectFunctionPropertyAugment*/ true); - } - else { - symbolFromVariable = getPropertyOfVariable(targetSymbol, nameText); + if ( + moduleSymbol && + moduleSymbol.exports && + moduleSymbol.exports.get(InternalSymbolName.ExportEquals) + ) { + symbolFromVariable = getPropertyOfType( + getTypeOfSymbol(targetSymbol), + nameText, + /*skipObjectFunctionPropertyAugment*/ true + ); + } else { + symbolFromVariable = getPropertyOfVariable( + targetSymbol, + nameText + ); } // if symbolFromVariable is export - get its final target - symbolFromVariable = resolveSymbol(symbolFromVariable, dontResolveAlias); + symbolFromVariable = resolveSymbol( + symbolFromVariable, + dontResolveAlias + ); - let symbolFromModule = getExportOfModule(targetSymbol, nameText, specifier, dontResolveAlias); - if (symbolFromModule === undefined && nameText === InternalSymbolName.Default) { + let symbolFromModule = getExportOfModule( + targetSymbol, + nameText, + specifier, + dontResolveAlias + ); + if ( + symbolFromModule === undefined && + nameText === InternalSymbolName.Default + ) { const file = moduleSymbol.declarations?.find(isSourceFile); - if (isOnlyImportableAsDefault(moduleSpecifier, moduleSymbol) || canHaveSyntheticDefault(file, moduleSymbol, dontResolveAlias, moduleSpecifier)) { - symbolFromModule = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) || resolveSymbol(moduleSymbol, dontResolveAlias); + if ( + isOnlyImportableAsDefault( + moduleSpecifier, + moduleSymbol + ) || + canHaveSyntheticDefault( + file, + moduleSymbol, + dontResolveAlias, + moduleSpecifier + ) + ) { + symbolFromModule = + resolveExternalModuleSymbol( + moduleSymbol, + dontResolveAlias + ) || resolveSymbol(moduleSymbol, dontResolveAlias); } } - const symbol = symbolFromModule && symbolFromVariable && symbolFromModule !== symbolFromVariable ? - combineValueAndTypeSymbols(symbolFromVariable, symbolFromModule) : - symbolFromModule || symbolFromVariable; + const symbol = + symbolFromModule && + symbolFromVariable && + symbolFromModule !== symbolFromVariable + ? combineValueAndTypeSymbols( + symbolFromVariable, + symbolFromModule + ) + : symbolFromModule || symbolFromVariable; - if (isImportOrExportSpecifier(specifier) && isOnlyImportableAsDefault(moduleSpecifier, moduleSymbol) && nameText !== InternalSymbolName.Default) { - error(name, Diagnostics.Named_imports_from_a_JSON_file_into_an_ECMAScript_module_are_not_allowed_when_module_is_set_to_0, ModuleKind[moduleKind]); - } - else if (!symbol) { - errorNoModuleMemberSymbol(moduleSymbol, targetSymbol, node, name); + if ( + isImportOrExportSpecifier(specifier) && + isOnlyImportableAsDefault(moduleSpecifier, moduleSymbol) && + nameText !== InternalSymbolName.Default + ) { + error( + name, + Diagnostics.Named_imports_from_a_JSON_file_into_an_ECMAScript_module_are_not_allowed_when_module_is_set_to_0, + ModuleKind[moduleKind] + ); + } else if (!symbol) { + errorNoModuleMemberSymbol( + moduleSymbol, + targetSymbol, + node, + name + ); } return symbol; } } } - function errorNoModuleMemberSymbol(moduleSymbol: Symbol, targetSymbol: Symbol, node: Node, name: ModuleExportName) { + function errorNoModuleMemberSymbol( + moduleSymbol: Symbol, + targetSymbol: Symbol, + node: Node, + name: ModuleExportName + ) { const moduleName = getFullyQualifiedName(moduleSymbol, node); const declarationName = declarationNameToString(name); - const suggestion = isIdentifier(name) ? getSuggestedSymbolForNonexistentModule(name, targetSymbol) : undefined; + const suggestion = isIdentifier(name) + ? getSuggestedSymbolForNonexistentModule(name, targetSymbol) + : undefined; if (suggestion !== undefined) { const suggestionName = symbolToString(suggestion); - const diagnostic = error(name, Diagnostics._0_has_no_exported_member_named_1_Did_you_mean_2, moduleName, declarationName, suggestionName); + const diagnostic = error( + name, + Diagnostics._0_has_no_exported_member_named_1_Did_you_mean_2, + moduleName, + declarationName, + suggestionName + ); if (suggestion.valueDeclaration) { - addRelatedInfo(diagnostic, createDiagnosticForNode(suggestion.valueDeclaration, Diagnostics._0_is_declared_here, suggestionName)); + addRelatedInfo( + diagnostic, + createDiagnosticForNode( + suggestion.valueDeclaration, + Diagnostics._0_is_declared_here, + suggestionName + ) + ); } - } - else { + } else { if (moduleSymbol.exports?.has(InternalSymbolName.Default)) { error( name, Diagnostics.Module_0_has_no_exported_member_1_Did_you_mean_to_use_import_1_from_0_instead, moduleName, + declarationName + ); + } else { + reportNonExportedMember( + node, + name, declarationName, + moduleSymbol, + moduleName ); } - else { - reportNonExportedMember(node, name, declarationName, moduleSymbol, moduleName); - } } } - function reportNonExportedMember(node: Node, name: ModuleExportName, declarationName: string, moduleSymbol: Symbol, moduleName: string): void { - const localSymbol = tryCast(moduleSymbol.valueDeclaration, canHaveLocals)?.locals?.get(moduleExportNameTextEscaped(name)); + function reportNonExportedMember( + node: Node, + name: ModuleExportName, + declarationName: string, + moduleSymbol: Symbol, + moduleName: string + ): void { + const localSymbol = tryCast( + moduleSymbol.valueDeclaration, + canHaveLocals + )?.locals?.get(moduleExportNameTextEscaped(name)); const exports = moduleSymbol.exports; if (localSymbol) { - const exportedEqualsSymbol = exports?.get(InternalSymbolName.ExportEquals); + const exportedEqualsSymbol = exports?.get( + InternalSymbolName.ExportEquals + ); if (exportedEqualsSymbol) { - getSymbolIfSameReference(exportedEqualsSymbol, localSymbol) ? reportInvalidImportEqualsExportMember(node, name, declarationName, moduleName) : - error(name, Diagnostics.Module_0_has_no_exported_member_1, moduleName, declarationName); - } - else { - const exportedSymbol = exports ? find(symbolsToArray(exports), symbol => !!getSymbolIfSameReference(symbol, localSymbol)) : undefined; - const diagnostic = exportedSymbol ? error(name, Diagnostics.Module_0_declares_1_locally_but_it_is_exported_as_2, moduleName, declarationName, symbolToString(exportedSymbol)) : - error(name, Diagnostics.Module_0_declares_1_locally_but_it_is_not_exported, moduleName, declarationName); + getSymbolIfSameReference(exportedEqualsSymbol, localSymbol) + ? reportInvalidImportEqualsExportMember( + node, + name, + declarationName, + moduleName + ) + : error( + name, + Diagnostics.Module_0_has_no_exported_member_1, + moduleName, + declarationName + ); + } else { + const exportedSymbol = exports + ? find( + symbolsToArray(exports), + (symbol) => + !!getSymbolIfSameReference(symbol, localSymbol) + ) + : undefined; + const diagnostic = exportedSymbol + ? error( + name, + Diagnostics.Module_0_declares_1_locally_but_it_is_exported_as_2, + moduleName, + declarationName, + symbolToString(exportedSymbol) + ) + : error( + name, + Diagnostics.Module_0_declares_1_locally_but_it_is_not_exported, + moduleName, + declarationName + ); if (localSymbol.declarations) { - addRelatedInfo(diagnostic, ...map(localSymbol.declarations, (decl, index) => createDiagnosticForNode(decl, index === 0 ? Diagnostics._0_is_declared_here : Diagnostics.and_here, declarationName))); + addRelatedInfo( + diagnostic, + ...map(localSymbol.declarations, (decl, index) => + createDiagnosticForNode( + decl, + index === 0 + ? Diagnostics._0_is_declared_here + : Diagnostics.and_here, + declarationName + ) + ) + ); } } - } - else { - error(name, Diagnostics.Module_0_has_no_exported_member_1, moduleName, declarationName); + } else { + error( + name, + Diagnostics.Module_0_has_no_exported_member_1, + moduleName, + declarationName + ); } } - function reportInvalidImportEqualsExportMember(node: Node, name: ModuleExportName, declarationName: string, moduleName: string) { + function reportInvalidImportEqualsExportMember( + node: Node, + name: ModuleExportName, + declarationName: string, + moduleName: string + ) { if (moduleKind >= ModuleKind.ES2015) { - const message = getESModuleInterop(compilerOptions) ? Diagnostics._0_can_only_be_imported_by_using_a_default_import : - Diagnostics._0_can_only_be_imported_by_turning_on_the_esModuleInterop_flag_and_using_a_default_import; + const message = getESModuleInterop(compilerOptions) + ? Diagnostics._0_can_only_be_imported_by_using_a_default_import + : Diagnostics._0_can_only_be_imported_by_turning_on_the_esModuleInterop_flag_and_using_a_default_import; error(name, message, declarationName); - } - else { + } else { if (isInJSFile(node)) { - const message = getESModuleInterop(compilerOptions) ? Diagnostics._0_can_only_be_imported_by_using_a_require_call_or_by_using_a_default_import : - Diagnostics._0_can_only_be_imported_by_using_a_require_call_or_by_turning_on_the_esModuleInterop_flag_and_using_a_default_import; + const message = getESModuleInterop(compilerOptions) + ? Diagnostics._0_can_only_be_imported_by_using_a_require_call_or_by_using_a_default_import + : Diagnostics._0_can_only_be_imported_by_using_a_require_call_or_by_turning_on_the_esModuleInterop_flag_and_using_a_default_import; error(name, message, declarationName); - } - else { - const message = getESModuleInterop(compilerOptions) ? Diagnostics._0_can_only_be_imported_by_using_import_1_require_2_or_a_default_import : - Diagnostics._0_can_only_be_imported_by_using_import_1_require_2_or_by_turning_on_the_esModuleInterop_flag_and_using_a_default_import; - error(name, message, declarationName, declarationName, moduleName); + } else { + const message = getESModuleInterop(compilerOptions) + ? Diagnostics._0_can_only_be_imported_by_using_import_1_require_2_or_a_default_import + : Diagnostics._0_can_only_be_imported_by_using_import_1_require_2_or_by_turning_on_the_esModuleInterop_flag_and_using_a_default_import; + error( + name, + message, + declarationName, + declarationName, + moduleName + ); } } } - function getTargetOfImportSpecifier(node: ImportSpecifier | BindingElement, dontResolveAlias: boolean): Symbol | undefined { - if (isImportSpecifier(node) && moduleExportNameIsDefault(node.propertyName || node.name)) { + function getTargetOfImportSpecifier( + node: ImportSpecifier | BindingElement, + dontResolveAlias: boolean + ): Symbol | undefined { + if ( + isImportSpecifier(node) && + moduleExportNameIsDefault(node.propertyName || node.name) + ) { const specifier = getModuleSpecifierForImportOrExport(node); - const moduleSymbol = specifier && resolveExternalModuleName(node, specifier); + const moduleSymbol = + specifier && resolveExternalModuleName(node, specifier); if (moduleSymbol) { - return getTargetofModuleDefault(moduleSymbol, node, dontResolveAlias); + return getTargetofModuleDefault( + moduleSymbol, + node, + dontResolveAlias + ); } } - const root = isBindingElement(node) ? getRootDeclaration(node) as VariableDeclaration : node.parent.parent.parent; + const root = isBindingElement(node) + ? (getRootDeclaration(node) as VariableDeclaration) + : node.parent.parent.parent; const commonJSPropertyAccess = getCommonJSPropertyAccess(root); - const resolved = getExternalModuleMember(root, commonJSPropertyAccess || node, dontResolveAlias); + const resolved = getExternalModuleMember( + root, + commonJSPropertyAccess || node, + dontResolveAlias + ); const name = node.propertyName || node.name; if (commonJSPropertyAccess && resolved && isIdentifier(name)) { - return resolveSymbol(getPropertyOfType(getTypeOfSymbol(resolved), name.escapedText), dontResolveAlias); + return resolveSymbol( + getPropertyOfType(getTypeOfSymbol(resolved), name.escapedText), + dontResolveAlias + ); } - markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false); + markSymbolOfAliasDeclarationIfTypeOnly( + node, + /*immediateTarget*/ undefined, + resolved, + /*overwriteEmpty*/ false + ); return resolved; } function getCommonJSPropertyAccess(node: Node) { - if (isVariableDeclaration(node) && node.initializer && isPropertyAccessExpression(node.initializer)) { + if ( + isVariableDeclaration(node) && + node.initializer && + isPropertyAccessExpression(node.initializer) + ) { return node.initializer; } } - function getTargetOfNamespaceExportDeclaration(node: NamespaceExportDeclaration, dontResolveAlias: boolean): Symbol | undefined { + function getTargetOfNamespaceExportDeclaration( + node: NamespaceExportDeclaration, + dontResolveAlias: boolean + ): Symbol | undefined { if (canHaveSymbol(node.parent)) { - const resolved = resolveExternalModuleSymbol(node.parent.symbol, dontResolveAlias); - markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false); + const resolved = resolveExternalModuleSymbol( + node.parent.symbol, + dontResolveAlias + ); + markSymbolOfAliasDeclarationIfTypeOnly( + node, + /*immediateTarget*/ undefined, + resolved, + /*overwriteEmpty*/ false + ); return resolved; } } - function getTargetOfExportSpecifier(node: ExportSpecifier, meaning: SymbolFlags, dontResolveAlias?: boolean) { + function getTargetOfExportSpecifier( + node: ExportSpecifier, + meaning: SymbolFlags, + dontResolveAlias?: boolean + ) { const name = node.propertyName || node.name; if (moduleExportNameIsDefault(name)) { const specifier = getModuleSpecifierForImportOrExport(node); - const moduleSymbol = specifier && resolveExternalModuleName(node, specifier); + const moduleSymbol = + specifier && resolveExternalModuleName(node, specifier); if (moduleSymbol) { - return getTargetofModuleDefault(moduleSymbol, node, !!dontResolveAlias); + return getTargetofModuleDefault( + moduleSymbol, + node, + !!dontResolveAlias + ); } } - const resolved = node.parent.parent.moduleSpecifier ? - getExternalModuleMember(node.parent.parent, node, dontResolveAlias) : - name.kind === SyntaxKind.StringLiteral ? undefined : // Skip for invalid syntax like this: export { "x" } - resolveEntityName(name, meaning, /*ignoreErrors*/ false, dontResolveAlias); - markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false); + const resolved = node.parent.parent.moduleSpecifier + ? getExternalModuleMember( + node.parent.parent, + node, + dontResolveAlias + ) + : name.kind === SyntaxKind.StringLiteral + ? undefined // Skip for invalid syntax like this: export { "x" } + : resolveEntityName( + name, + meaning, + /*ignoreErrors*/ false, + dontResolveAlias + ); + markSymbolOfAliasDeclarationIfTypeOnly( + node, + /*immediateTarget*/ undefined, + resolved, + /*overwriteEmpty*/ false + ); return resolved; } - function getTargetOfExportAssignment(node: ExportAssignment | BinaryExpression, dontResolveAlias: boolean): Symbol | undefined { - const expression = isExportAssignment(node) ? node.expression : node.right; - const resolved = getTargetOfAliasLikeExpression(expression, dontResolveAlias); - markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false); + function getTargetOfExportAssignment( + node: ExportAssignment | BinaryExpression, + dontResolveAlias: boolean + ): Symbol | undefined { + const expression = isExportAssignment(node) + ? node.expression + : node.right; + const resolved = getTargetOfAliasLikeExpression( + expression, + dontResolveAlias + ); + markSymbolOfAliasDeclarationIfTypeOnly( + node, + /*immediateTarget*/ undefined, + resolved, + /*overwriteEmpty*/ false + ); return resolved; } - function getTargetOfAliasLikeExpression(expression: Expression, dontResolveAlias: boolean) { + function getTargetOfAliasLikeExpression( + expression: Expression, + dontResolveAlias: boolean + ) { if (isClassExpression(expression)) { return checkExpressionCached(expression).symbol; } if (!isEntityName(expression) && !isEntityNameExpression(expression)) { return undefined; } - const aliasLike = resolveEntityName(expression, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, /*ignoreErrors*/ true, dontResolveAlias); + const aliasLike = resolveEntityName( + expression, + SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, + /*ignoreErrors*/ true, + dontResolveAlias + ); if (aliasLike) { return aliasLike; } @@ -4195,42 +6470,97 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getNodeLinks(expression).resolvedSymbol; } - function getTargetOfAccessExpression(node: AccessExpression, dontRecursivelyResolve: boolean): Symbol | undefined { - if (!(isBinaryExpression(node.parent) && node.parent.left === node && node.parent.operatorToken.kind === SyntaxKind.EqualsToken)) { + function getTargetOfAccessExpression( + node: AccessExpression, + dontRecursivelyResolve: boolean + ): Symbol | undefined { + if ( + !( + isBinaryExpression(node.parent) && + node.parent.left === node && + node.parent.operatorToken.kind === SyntaxKind.EqualsToken + ) + ) { return undefined; } - return getTargetOfAliasLikeExpression(node.parent.right, dontRecursivelyResolve); + return getTargetOfAliasLikeExpression( + node.parent.right, + dontRecursivelyResolve + ); } - function getTargetOfAliasDeclaration(node: Declaration, dontRecursivelyResolve = false): Symbol | undefined { + function getTargetOfAliasDeclaration( + node: Declaration, + dontRecursivelyResolve = false + ): Symbol | undefined { switch (node.kind) { case SyntaxKind.ImportEqualsDeclaration: case SyntaxKind.VariableDeclaration: - return getTargetOfImportEqualsDeclaration(node as ImportEqualsDeclaration | VariableDeclaration, dontRecursivelyResolve); + return getTargetOfImportEqualsDeclaration( + node as ImportEqualsDeclaration | VariableDeclaration, + dontRecursivelyResolve + ); case SyntaxKind.ImportClause: - return getTargetOfImportClause(node as ImportClause, dontRecursivelyResolve); + return getTargetOfImportClause( + node as ImportClause, + dontRecursivelyResolve + ); case SyntaxKind.NamespaceImport: - return getTargetOfNamespaceImport(node as NamespaceImport, dontRecursivelyResolve); + return getTargetOfNamespaceImport( + node as NamespaceImport, + dontRecursivelyResolve + ); case SyntaxKind.NamespaceExport: - return getTargetOfNamespaceExport(node as NamespaceExport, dontRecursivelyResolve); + return getTargetOfNamespaceExport( + node as NamespaceExport, + dontRecursivelyResolve + ); case SyntaxKind.ImportSpecifier: case SyntaxKind.BindingElement: - return getTargetOfImportSpecifier(node as ImportSpecifier | BindingElement, dontRecursivelyResolve); + return getTargetOfImportSpecifier( + node as ImportSpecifier | BindingElement, + dontRecursivelyResolve + ); case SyntaxKind.ExportSpecifier: - return getTargetOfExportSpecifier(node as ExportSpecifier, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, dontRecursivelyResolve); + return getTargetOfExportSpecifier( + node as ExportSpecifier, + SymbolFlags.Value | + SymbolFlags.Type | + SymbolFlags.Namespace, + dontRecursivelyResolve + ); case SyntaxKind.ExportAssignment: case SyntaxKind.BinaryExpression: - return getTargetOfExportAssignment(node as ExportAssignment | BinaryExpression, dontRecursivelyResolve); + return getTargetOfExportAssignment( + node as ExportAssignment | BinaryExpression, + dontRecursivelyResolve + ); case SyntaxKind.NamespaceExportDeclaration: - return getTargetOfNamespaceExportDeclaration(node as NamespaceExportDeclaration, dontRecursivelyResolve); + return getTargetOfNamespaceExportDeclaration( + node as NamespaceExportDeclaration, + dontRecursivelyResolve + ); case SyntaxKind.ShorthandPropertyAssignment: - return resolveEntityName((node as ShorthandPropertyAssignment).name, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, /*ignoreErrors*/ true, dontRecursivelyResolve); + return resolveEntityName( + (node as ShorthandPropertyAssignment).name, + SymbolFlags.Value | + SymbolFlags.Type | + SymbolFlags.Namespace, + /*ignoreErrors*/ true, + dontRecursivelyResolve + ); case SyntaxKind.PropertyAssignment: - return getTargetOfAliasLikeExpression((node as PropertyAssignment).initializer, dontRecursivelyResolve); + return getTargetOfAliasLikeExpression( + (node as PropertyAssignment).initializer, + dontRecursivelyResolve + ); case SyntaxKind.ElementAccessExpression: case SyntaxKind.PropertyAccessExpression: - return getTargetOfAccessExpression(node as AccessExpression, dontRecursivelyResolve); + return getTargetOfAccessExpression( + node as AccessExpression, + dontRecursivelyResolve + ); default: return Debug.fail(); } @@ -4240,19 +6570,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Indicates that a symbol is an alias that does not merge with a local declaration. * OR Is a JSContainer which may merge an alias with a local declaration */ - function isNonLocalAlias(symbol: Symbol | undefined, excludes = SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace): symbol is Symbol { + function isNonLocalAlias( + symbol: Symbol | undefined, + excludes = SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace + ): symbol is Symbol { if (!symbol) return false; - return (symbol.flags & (SymbolFlags.Alias | excludes)) === SymbolFlags.Alias || !!(symbol.flags & SymbolFlags.Alias && symbol.flags & SymbolFlags.Assignment); + return ( + (symbol.flags & (SymbolFlags.Alias | excludes)) === + SymbolFlags.Alias || + !!( + symbol.flags & SymbolFlags.Alias && + symbol.flags & SymbolFlags.Assignment + ) + ); } function resolveSymbol(symbol: Symbol, dontResolveAlias?: boolean): Symbol; - function resolveSymbol(symbol: Symbol | undefined, dontResolveAlias?: boolean): Symbol | undefined; - function resolveSymbol(symbol: Symbol | undefined, dontResolveAlias?: boolean): Symbol | undefined { - return !dontResolveAlias && isNonLocalAlias(symbol) ? resolveAlias(symbol) : symbol; + function resolveSymbol( + symbol: Symbol | undefined, + dontResolveAlias?: boolean + ): Symbol | undefined; + function resolveSymbol( + symbol: Symbol | undefined, + dontResolveAlias?: boolean + ): Symbol | undefined { + return !dontResolveAlias && isNonLocalAlias(symbol) + ? resolveAlias(symbol) + : symbol; } function resolveAlias(symbol: Symbol): Symbol { - Debug.assert((symbol.flags & SymbolFlags.Alias) !== 0, "Should only get Alias here."); + Debug.assert( + (symbol.flags & SymbolFlags.Alias) !== 0, + "Should only get Alias here." + ); const links = getSymbolLinks(symbol); if (!links.aliasTarget) { links.aliasTarget = resolvingSymbol; @@ -4261,12 +6612,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const target = getTargetOfAliasDeclaration(node); if (links.aliasTarget === resolvingSymbol) { links.aliasTarget = target || unknownSymbol; + } else { + error( + node, + Diagnostics.Circular_definition_of_import_alias_0, + symbolToString(symbol) + ); } - else { - error(node, Diagnostics.Circular_definition_of_import_alias_0, symbolToString(symbol)); - } - } - else if (links.aliasTarget === resolvingSymbol) { + } else if (links.aliasTarget === resolvingSymbol) { links.aliasTarget = unknownSymbol; } return links.aliasTarget; @@ -4301,21 +6654,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @returns SymbolFlags.All if `symbol` is an alias that ultimately resolves to `unknown`; * combined flags of all alias targets otherwise. */ - function getSymbolFlags(symbol: Symbol, excludeTypeOnlyMeanings?: boolean, excludeLocalMeanings?: boolean): SymbolFlags { - const typeOnlyDeclaration = excludeTypeOnlyMeanings && getTypeOnlyAliasDeclaration(symbol); - const typeOnlyDeclarationIsExportStar = typeOnlyDeclaration && isExportDeclaration(typeOnlyDeclaration); - const typeOnlyResolution = typeOnlyDeclaration && ( - typeOnlyDeclarationIsExportStar - ? resolveExternalModuleName(typeOnlyDeclaration.moduleSpecifier, typeOnlyDeclaration.moduleSpecifier, /*ignoreErrors*/ true) - : resolveAlias(typeOnlyDeclaration.symbol) - ); - const typeOnlyExportStarTargets = typeOnlyDeclarationIsExportStar && typeOnlyResolution ? getExportsOfModule(typeOnlyResolution) : undefined; + function getSymbolFlags( + symbol: Symbol, + excludeTypeOnlyMeanings?: boolean, + excludeLocalMeanings?: boolean + ): SymbolFlags { + const typeOnlyDeclaration = + excludeTypeOnlyMeanings && getTypeOnlyAliasDeclaration(symbol); + const typeOnlyDeclarationIsExportStar = + typeOnlyDeclaration && isExportDeclaration(typeOnlyDeclaration); + const typeOnlyResolution = + typeOnlyDeclaration && + (typeOnlyDeclarationIsExportStar + ? resolveExternalModuleName( + typeOnlyDeclaration.moduleSpecifier, + typeOnlyDeclaration.moduleSpecifier, + /*ignoreErrors*/ true + ) + : resolveAlias(typeOnlyDeclaration.symbol)); + const typeOnlyExportStarTargets = + typeOnlyDeclarationIsExportStar && typeOnlyResolution + ? getExportsOfModule(typeOnlyResolution) + : undefined; let flags = excludeLocalMeanings ? SymbolFlags.None : symbol.flags; let seenSymbols; while (symbol.flags & SymbolFlags.Alias) { - const target = getExportSymbolOfValueSymbolIfExported(resolveAlias(symbol)); + const target = getExportSymbolOfValueSymbolIfExported( + resolveAlias(symbol) + ); if ( - !typeOnlyDeclarationIsExportStar && target === typeOnlyResolution || + (!typeOnlyDeclarationIsExportStar && + target === typeOnlyResolution) || typeOnlyExportStarTargets?.get(target.escapedName) === target ) { break; @@ -4332,8 +6701,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (target.flags & SymbolFlags.Alias) { if (seenSymbols) { seenSymbols.add(target); - } - else { + } else { seenSymbols = new Set([symbol, target]); } } @@ -4368,10 +6736,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { immediateTarget: Symbol | undefined, finalTarget: Symbol | undefined, overwriteEmpty: boolean, - exportStarDeclaration?: ExportDeclaration & { readonly isTypeOnly: true; readonly moduleSpecifier: Expression; }, - exportStarName?: __String, + exportStarDeclaration?: ExportDeclaration & { + readonly isTypeOnly: true; + readonly moduleSpecifier: Expression; + }, + exportStarName?: __String ): boolean { - if (!aliasDeclaration || isPropertyAccessExpression(aliasDeclaration)) return false; + if (!aliasDeclaration || isPropertyAccessExpression(aliasDeclaration)) + return false; // If the declaration itself is type-only, mark it and return. // No need to check what it resolves to. @@ -4391,21 +6763,52 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const links = getSymbolLinks(sourceSymbol); - return markSymbolOfAliasDeclarationIfTypeOnlyWorker(links, immediateTarget, overwriteEmpty) - || markSymbolOfAliasDeclarationIfTypeOnlyWorker(links, finalTarget, overwriteEmpty); + return ( + markSymbolOfAliasDeclarationIfTypeOnlyWorker( + links, + immediateTarget, + overwriteEmpty + ) || + markSymbolOfAliasDeclarationIfTypeOnlyWorker( + links, + finalTarget, + overwriteEmpty + ) + ); } - function markSymbolOfAliasDeclarationIfTypeOnlyWorker(aliasDeclarationLinks: SymbolLinks, target: Symbol | undefined, overwriteEmpty: boolean): boolean { - if (target && (aliasDeclarationLinks.typeOnlyDeclaration === undefined || overwriteEmpty && aliasDeclarationLinks.typeOnlyDeclaration === false)) { - const exportSymbol = target.exports?.get(InternalSymbolName.ExportEquals) ?? target; - const typeOnly = exportSymbol.declarations && find(exportSymbol.declarations, isTypeOnlyImportOrExportDeclaration); - aliasDeclarationLinks.typeOnlyDeclaration = typeOnly ?? getSymbolLinks(exportSymbol).typeOnlyDeclaration ?? false; + function markSymbolOfAliasDeclarationIfTypeOnlyWorker( + aliasDeclarationLinks: SymbolLinks, + target: Symbol | undefined, + overwriteEmpty: boolean + ): boolean { + if ( + target && + (aliasDeclarationLinks.typeOnlyDeclaration === undefined || + (overwriteEmpty && + aliasDeclarationLinks.typeOnlyDeclaration === false)) + ) { + const exportSymbol = + target.exports?.get(InternalSymbolName.ExportEquals) ?? target; + const typeOnly = + exportSymbol.declarations && + find( + exportSymbol.declarations, + isTypeOnlyImportOrExportDeclaration + ); + aliasDeclarationLinks.typeOnlyDeclaration = + typeOnly ?? + getSymbolLinks(exportSymbol).typeOnlyDeclaration ?? + false; } return !!aliasDeclarationLinks.typeOnlyDeclaration; } /** Indicates that a symbol directly or indirectly resolves to a type-only import or export. */ - function getTypeOnlyAliasDeclaration(symbol: Symbol, include?: SymbolFlags): TypeOnlyAliasDeclaration | undefined { + function getTypeOnlyAliasDeclaration( + symbol: Symbol, + include?: SymbolFlags + ): TypeOnlyAliasDeclaration | undefined { if (!(symbol.flags & SymbolFlags.Alias)) { return undefined; } @@ -4415,45 +6818,93 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { links.typeOnlyDeclaration = false; const resolved = resolveSymbol(symbol); // do this before the `resolveImmediate` below, as it uses a different circularity cache and we might hide a circularity error if we blindly get the immediate alias first // While usually the alias will have been marked during the pass by the full typecheck, we may still need to calculate the alias declaration now - markSymbolOfAliasDeclarationIfTypeOnly(symbol.declarations?.[0], getDeclarationOfAliasSymbol(symbol) && getImmediateAliasedSymbol(symbol), resolved, /*overwriteEmpty*/ true); + markSymbolOfAliasDeclarationIfTypeOnly( + symbol.declarations?.[0], + getDeclarationOfAliasSymbol(symbol) && + getImmediateAliasedSymbol(symbol), + resolved, + /*overwriteEmpty*/ true + ); } if (include === undefined) { return links.typeOnlyDeclaration || undefined; } if (links.typeOnlyDeclaration) { - const resolved = links.typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration - ? resolveSymbol(getExportsOfModule(links.typeOnlyDeclaration.symbol.parent!).get(links.typeOnlyExportStarName || symbol.escapedName))! - : resolveAlias(links.typeOnlyDeclaration.symbol); - return getSymbolFlags(resolved) & include ? links.typeOnlyDeclaration : undefined; + const resolved = + links.typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration + ? resolveSymbol( + getExportsOfModule( + links.typeOnlyDeclaration.symbol.parent! + ).get( + links.typeOnlyExportStarName || symbol.escapedName + ) + )! + : resolveAlias(links.typeOnlyDeclaration.symbol); + return getSymbolFlags(resolved) & include + ? links.typeOnlyDeclaration + : undefined; } return undefined; } // This function is only for imports with entity names - function getSymbolOfPartOfRightHandSideOfImportEquals(entityName: EntityName, dontResolveAlias?: boolean): Symbol | undefined { + function getSymbolOfPartOfRightHandSideOfImportEquals( + entityName: EntityName, + dontResolveAlias?: boolean + ): Symbol | undefined { // There are three things we might try to look for. In the following examples, // the search term is enclosed in |...|: // // import a = |b|; // Namespace // import a = |b.c|; // Value, type, namespace // import a = |b.c|.d; // Namespace - if (entityName.kind === SyntaxKind.Identifier && isRightSideOfQualifiedNameOrPropertyAccess(entityName)) { + if ( + entityName.kind === SyntaxKind.Identifier && + isRightSideOfQualifiedNameOrPropertyAccess(entityName) + ) { entityName = entityName.parent as QualifiedName; } // Check for case 1 and 3 in the above example - if (entityName.kind === SyntaxKind.Identifier || entityName.parent.kind === SyntaxKind.QualifiedName) { - return resolveEntityName(entityName, SymbolFlags.Namespace, /*ignoreErrors*/ false, dontResolveAlias); - } - else { + if ( + entityName.kind === SyntaxKind.Identifier || + entityName.parent.kind === SyntaxKind.QualifiedName + ) { + return resolveEntityName( + entityName, + SymbolFlags.Namespace, + /*ignoreErrors*/ false, + dontResolveAlias + ); + } else { // Case 2 in above example // entityName.kind could be a QualifiedName or a Missing identifier - Debug.assert(entityName.parent.kind === SyntaxKind.ImportEqualsDeclaration); - return resolveEntityName(entityName, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, /*ignoreErrors*/ false, dontResolveAlias); + Debug.assert( + entityName.parent.kind === SyntaxKind.ImportEqualsDeclaration + ); + return resolveEntityName( + entityName, + SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, + /*ignoreErrors*/ false, + dontResolveAlias + ); } } - function getFullyQualifiedName(symbol: Symbol, containingLocation?: Node): string { - return symbol.parent ? getFullyQualifiedName(symbol.parent, containingLocation) + "." + symbolToString(symbol) : symbolToString(symbol, containingLocation, /*meaning*/ undefined, SymbolFormatFlags.DoNotIncludeSymbolChain | SymbolFormatFlags.AllowAnyNodeKind); + function getFullyQualifiedName( + symbol: Symbol, + containingLocation?: Node + ): string { + return symbol.parent + ? getFullyQualifiedName(symbol.parent, containingLocation) + + "." + + symbolToString(symbol) + : symbolToString( + symbol, + containingLocation, + /*meaning*/ undefined, + SymbolFormatFlags.DoNotIncludeSymbolChain | + SymbolFormatFlags.AllowAnyNodeKind + ); } function getContainingQualifiedNameNode(node: QualifiedName) { @@ -4465,7 +6916,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function tryGetQualifiedNameAsValue(node: QualifiedName) { let left: Identifier | QualifiedName = getFirstIdentifier(node); - let symbol = resolveName(left, left, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*isUse*/ true); + let symbol = resolveName( + left, + left, + SymbolFlags.Value, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ true + ); if (!symbol) { return undefined; } @@ -4483,103 +6940,198 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** * Resolves a qualified name and any involved aliases. */ - function resolveEntityName(name: EntityNameOrEntityNameExpression, meaning: SymbolFlags, ignoreErrors?: boolean, dontResolveAlias?: boolean, location?: Node): Symbol | undefined { + function resolveEntityName( + name: EntityNameOrEntityNameExpression, + meaning: SymbolFlags, + ignoreErrors?: boolean, + dontResolveAlias?: boolean, + location?: Node + ): Symbol | undefined { if (nodeIsMissing(name)) { return undefined; } - const namespaceMeaning = SymbolFlags.Namespace | (isInJSFile(name) ? meaning & SymbolFlags.Value : 0); + const namespaceMeaning = + SymbolFlags.Namespace | + (isInJSFile(name) ? meaning & SymbolFlags.Value : 0); let symbol: Symbol | undefined; if (name.kind === SyntaxKind.Identifier) { - const message = meaning === namespaceMeaning || nodeIsSynthesized(name) ? Diagnostics.Cannot_find_namespace_0 : getCannotFindNameDiagnosticForName(getFirstIdentifier(name)); - const symbolFromJSPrototype = isInJSFile(name) && !nodeIsSynthesized(name) ? resolveEntityNameFromAssignmentDeclaration(name, meaning) : undefined; - symbol = getMergedSymbol(resolveName(location || name, name, meaning, ignoreErrors || symbolFromJSPrototype ? undefined : message, /*isUse*/ true, /*excludeGlobals*/ false)); + const message = + meaning === namespaceMeaning || nodeIsSynthesized(name) + ? Diagnostics.Cannot_find_namespace_0 + : getCannotFindNameDiagnosticForName( + getFirstIdentifier(name) + ); + const symbolFromJSPrototype = + isInJSFile(name) && !nodeIsSynthesized(name) + ? resolveEntityNameFromAssignmentDeclaration(name, meaning) + : undefined; + symbol = getMergedSymbol( + resolveName( + location || name, + name, + meaning, + ignoreErrors || symbolFromJSPrototype ? undefined : message, + /*isUse*/ true, + /*excludeGlobals*/ false + ) + ); if (!symbol) { return getMergedSymbol(symbolFromJSPrototype); } - } - else if (name.kind === SyntaxKind.QualifiedName || name.kind === SyntaxKind.PropertyAccessExpression) { - const left = name.kind === SyntaxKind.QualifiedName ? name.left : name.expression; - const right = name.kind === SyntaxKind.QualifiedName ? name.right : name.name; - let namespace = resolveEntityName(left, namespaceMeaning, ignoreErrors, /*dontResolveAlias*/ false, location); + } else if ( + name.kind === SyntaxKind.QualifiedName || + name.kind === SyntaxKind.PropertyAccessExpression + ) { + const left = + name.kind === SyntaxKind.QualifiedName + ? name.left + : name.expression; + const right = + name.kind === SyntaxKind.QualifiedName ? name.right : name.name; + let namespace = resolveEntityName( + left, + namespaceMeaning, + ignoreErrors, + /*dontResolveAlias*/ false, + location + ); if (!namespace || nodeIsMissing(right)) { return undefined; - } - else if (namespace === unknownSymbol) { + } else if (namespace === unknownSymbol) { return namespace; } if ( namespace.valueDeclaration && isInJSFile(namespace.valueDeclaration) && - getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Bundler && + getEmitModuleResolutionKind(compilerOptions) !== + ModuleResolutionKind.Bundler && isVariableDeclaration(namespace.valueDeclaration) && namespace.valueDeclaration.initializer && isCommonJsRequire(namespace.valueDeclaration.initializer) ) { - const moduleName = (namespace.valueDeclaration.initializer as CallExpression).arguments[0] as StringLiteral; - const moduleSym = resolveExternalModuleName(moduleName, moduleName); + const moduleName = ( + namespace.valueDeclaration.initializer as CallExpression + ).arguments[0] as StringLiteral; + const moduleSym = resolveExternalModuleName( + moduleName, + moduleName + ); if (moduleSym) { - const resolvedModuleSymbol = resolveExternalModuleSymbol(moduleSym); + const resolvedModuleSymbol = + resolveExternalModuleSymbol(moduleSym); if (resolvedModuleSymbol) { namespace = resolvedModuleSymbol; } } } - symbol = getMergedSymbol(getSymbol(getExportsOfSymbol(namespace), right.escapedText, meaning)); - if (!symbol && (namespace.flags & SymbolFlags.Alias)) { + symbol = getMergedSymbol( + getSymbol( + getExportsOfSymbol(namespace), + right.escapedText, + meaning + ) + ); + if (!symbol && namespace.flags & SymbolFlags.Alias) { // `namespace` can be resolved further if there was a symbol merge with a re-export - symbol = getMergedSymbol(getSymbol(getExportsOfSymbol(resolveAlias(namespace)), right.escapedText, meaning)); + symbol = getMergedSymbol( + getSymbol( + getExportsOfSymbol(resolveAlias(namespace)), + right.escapedText, + meaning + ) + ); } if (!symbol) { if (!ignoreErrors) { const namespaceName = getFullyQualifiedName(namespace); const declarationName = declarationNameToString(right); - const suggestionForNonexistentModule = getSuggestedSymbolForNonexistentModule(right, namespace); + const suggestionForNonexistentModule = + getSuggestedSymbolForNonexistentModule( + right, + namespace + ); if (suggestionForNonexistentModule) { - error(right, Diagnostics._0_has_no_exported_member_named_1_Did_you_mean_2, namespaceName, declarationName, symbolToString(suggestionForNonexistentModule)); + error( + right, + Diagnostics._0_has_no_exported_member_named_1_Did_you_mean_2, + namespaceName, + declarationName, + symbolToString(suggestionForNonexistentModule) + ); return undefined; } - const containingQualifiedName = isQualifiedName(name) && getContainingQualifiedNameNode(name); - const canSuggestTypeof = globalObjectType // <-- can't pull on types if global types aren't initialized yet - && (meaning & SymbolFlags.Type) - && containingQualifiedName - && !isTypeOfExpression(containingQualifiedName.parent) - && tryGetQualifiedNameAsValue(containingQualifiedName); + const containingQualifiedName = + isQualifiedName(name) && + getContainingQualifiedNameNode(name); + const canSuggestTypeof = + globalObjectType && // <-- can't pull on types if global types aren't initialized yet + meaning & SymbolFlags.Type && + containingQualifiedName && + !isTypeOfExpression(containingQualifiedName.parent) && + tryGetQualifiedNameAsValue(containingQualifiedName); if (canSuggestTypeof) { error( containingQualifiedName, Diagnostics._0_refers_to_a_value_but_is_being_used_as_a_type_here_Did_you_mean_typeof_0, - entityNameToString(containingQualifiedName), + entityNameToString(containingQualifiedName) ); return undefined; } - if (meaning & SymbolFlags.Namespace && isQualifiedName(name.parent)) { - const exportedTypeSymbol = getMergedSymbol(getSymbol(getExportsOfSymbol(namespace), right.escapedText, SymbolFlags.Type)); + if ( + meaning & SymbolFlags.Namespace && + isQualifiedName(name.parent) + ) { + const exportedTypeSymbol = getMergedSymbol( + getSymbol( + getExportsOfSymbol(namespace), + right.escapedText, + SymbolFlags.Type + ) + ); if (exportedTypeSymbol) { error( name.parent.right, 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, symbolToString(exportedTypeSymbol), - unescapeLeadingUnderscores(name.parent.right.escapedText), + unescapeLeadingUnderscores( + name.parent.right.escapedText + ) ); return undefined; } } - error(right, Diagnostics.Namespace_0_has_no_exported_member_1, namespaceName, declarationName); + error( + right, + Diagnostics.Namespace_0_has_no_exported_member_1, + namespaceName, + declarationName + ); } return undefined; } - } - else { + } else { Debug.assertNever(name, "Unknown entity name kind."); } - if (!nodeIsSynthesized(name) && isEntityName(name) && (symbol.flags & SymbolFlags.Alias || name.parent.kind === SyntaxKind.ExportAssignment)) { - markSymbolOfAliasDeclarationIfTypeOnly(getAliasDeclarationFromName(name), symbol, /*finalTarget*/ undefined, /*overwriteEmpty*/ true); + if ( + !nodeIsSynthesized(name) && + isEntityName(name) && + (symbol.flags & SymbolFlags.Alias || + name.parent.kind === SyntaxKind.ExportAssignment) + ) { + markSymbolOfAliasDeclarationIfTypeOnly( + getAliasDeclarationFromName(name), + symbol, + /*finalTarget*/ undefined, + /*overwriteEmpty*/ true + ); } - return (symbol.flags & meaning) || dontResolveAlias ? symbol : resolveAlias(symbol); + return symbol.flags & meaning || dontResolveAlias + ? symbol + : resolveAlias(symbol); } /** @@ -4588,29 +7140,55 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * name resolution won't work either. * 2. For property assignments like `{ x: function f () { } }`, try to resolve names in the scope of `f` too. */ - function resolveEntityNameFromAssignmentDeclaration(name: Identifier, meaning: SymbolFlags) { + function resolveEntityNameFromAssignmentDeclaration( + name: Identifier, + meaning: SymbolFlags + ) { if (isJSDocTypeReference(name.parent)) { - const secondaryLocation = getAssignmentDeclarationLocation(name.parent); + const secondaryLocation = getAssignmentDeclarationLocation( + name.parent + ); if (secondaryLocation) { - return resolveName(secondaryLocation, name, meaning, /*nameNotFoundMessage*/ undefined, /*isUse*/ true); + return resolveName( + secondaryLocation, + name, + meaning, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ true + ); } } } - function getAssignmentDeclarationLocation(node: TypeReferenceNode): Node | undefined { - const typeAlias = findAncestor(node, node => !(isJSDocNode(node) || node.flags & NodeFlags.JSDoc) ? "quit" : isJSDocTypeAlias(node)); + function getAssignmentDeclarationLocation( + node: TypeReferenceNode + ): Node | undefined { + const typeAlias = findAncestor(node, (node) => + !(isJSDocNode(node) || node.flags & NodeFlags.JSDoc) + ? "quit" + : isJSDocTypeAlias(node) + ); if (typeAlias) { return; } const host = getJSDocHost(node); - if (host && isExpressionStatement(host) && isPrototypePropertyAssignment(host.expression)) { + if ( + host && + isExpressionStatement(host) && + isPrototypePropertyAssignment(host.expression) + ) { // /** @param {K} p */ X.prototype.m = function () { } <-- look for K on X's declaration const symbol = getSymbolOfDeclaration(host.expression.left); if (symbol) { return getDeclarationOfJSPrototypeContainer(symbol); } } - if (host && isFunctionExpression(host) && isPrototypePropertyAssignment(host.parent) && isExpressionStatement(host.parent.parent)) { + if ( + host && + isFunctionExpression(host) && + isPrototypePropertyAssignment(host.parent) && + isExpressionStatement(host.parent.parent) + ) { // X.prototype.m = /** @param {K} p */ function () { } <-- look for K on X's declaration const symbol = getSymbolOfDeclaration(host.parent.left); if (symbol) { @@ -4618,12 +7196,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } if ( - host && (isObjectLiteralMethod(host) || isPropertyAssignment(host)) && + host && + (isObjectLiteralMethod(host) || isPropertyAssignment(host)) && isBinaryExpression(host.parent.parent) && - getAssignmentDeclarationKind(host.parent.parent) === AssignmentDeclarationKind.Prototype + getAssignmentDeclarationKind(host.parent.parent) === + AssignmentDeclarationKind.Prototype ) { // X.prototype = { /** @param {K} p */m() { } } <-- look for K on X's declaration - const symbol = getSymbolOfDeclaration(host.parent.parent.left as BindableStaticNameExpression); + const symbol = getSymbolOfDeclaration( + host.parent.parent.left as BindableStaticNameExpression + ); if (symbol) { return getDeclarationOfJSPrototypeContainer(symbol); } @@ -4640,9 +7222,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!decl) { return undefined; } - const initializer = isAssignmentDeclaration(decl) ? getAssignedExpandoInitializer(decl) : - hasOnlyExpressionInitializer(decl) ? getDeclaredExpandoInitializer(decl) : - undefined; + const initializer = isAssignmentDeclaration(decl) + ? getAssignedExpandoInitializer(decl) + : hasOnlyExpressionInitializer(decl) + ? getDeclaredExpandoInitializer(decl) + : undefined; return initializer || decl; } @@ -4654,10 +7238,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { */ function getExpandoSymbol(symbol: Symbol): Symbol | undefined { const decl = symbol.valueDeclaration; - if (!decl || !isInJSFile(decl) || symbol.flags & SymbolFlags.TypeAlias || getExpandoInitializer(decl, /*isPrototypeAssignment*/ false)) { + if ( + !decl || + !isInJSFile(decl) || + symbol.flags & SymbolFlags.TypeAlias || + getExpandoInitializer(decl, /*isPrototypeAssignment*/ false) + ) { return undefined; } - const init = isVariableDeclaration(decl) ? getDeclaredExpandoInitializer(decl) : getAssignedExpandoInitializer(decl); + const init = isVariableDeclaration(decl) + ? getDeclaredExpandoInitializer(decl) + : getAssignedExpandoInitializer(decl); if (init) { const initSymbol = getSymbolOfNode(init); if (initSymbol) { @@ -4666,108 +7257,251 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function resolveExternalModuleName(location: Node, moduleReferenceExpression: Expression, ignoreErrors?: boolean): Symbol | undefined { - const isClassic = getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Classic; - const errorMessage = isClassic ? - Diagnostics.Cannot_find_module_0_Did_you_mean_to_set_the_moduleResolution_option_to_nodenext_or_to_add_aliases_to_the_paths_option + function resolveExternalModuleName( + location: Node, + moduleReferenceExpression: Expression, + ignoreErrors?: boolean + ): Symbol | undefined { + const isClassic = + getEmitModuleResolutionKind(compilerOptions) === + ModuleResolutionKind.Classic; + const errorMessage = isClassic + ? Diagnostics.Cannot_find_module_0_Did_you_mean_to_set_the_moduleResolution_option_to_nodenext_or_to_add_aliases_to_the_paths_option : Diagnostics.Cannot_find_module_0_or_its_corresponding_type_declarations; - return resolveExternalModuleNameWorker(location, moduleReferenceExpression, ignoreErrors ? undefined : errorMessage, ignoreErrors); + return resolveExternalModuleNameWorker( + location, + moduleReferenceExpression, + ignoreErrors ? undefined : errorMessage, + ignoreErrors + ); } - function resolveExternalModuleNameWorker(location: Node, moduleReferenceExpression: Expression, moduleNotFoundError: DiagnosticMessage | undefined, ignoreErrors = false, isForAugmentation = false): Symbol | undefined { + function resolveExternalModuleNameWorker( + location: Node, + moduleReferenceExpression: Expression, + moduleNotFoundError: DiagnosticMessage | undefined, + ignoreErrors = false, + isForAugmentation = false + ): Symbol | undefined { return isStringLiteralLike(moduleReferenceExpression) - ? resolveExternalModule(location, moduleReferenceExpression.text, moduleNotFoundError, !ignoreErrors ? moduleReferenceExpression : undefined, isForAugmentation) + ? resolveExternalModule( + location, + moduleReferenceExpression.text, + moduleNotFoundError, + !ignoreErrors ? moduleReferenceExpression : undefined, + isForAugmentation + ) : undefined; } - function resolveExternalModule(location: Node, moduleReference: string, moduleNotFoundError: DiagnosticMessage | undefined, errorNode: Node | undefined, isForAugmentation = false): Symbol | undefined { + function resolveExternalModule( + location: Node, + moduleReference: string, + moduleNotFoundError: DiagnosticMessage | undefined, + errorNode: Node | undefined, + isForAugmentation = false + ): Symbol | undefined { if (errorNode && startsWith(moduleReference, "@types/")) { - const diag = Diagnostics.Cannot_import_type_declaration_files_Consider_importing_0_instead_of_1; - const withoutAtTypePrefix = removePrefix(moduleReference, "@types/"); + const diag = + Diagnostics.Cannot_import_type_declaration_files_Consider_importing_0_instead_of_1; + const withoutAtTypePrefix = removePrefix( + moduleReference, + "@types/" + ); error(errorNode, diag, withoutAtTypePrefix, moduleReference); } - const ambientModule = tryFindAmbientModule(moduleReference, /*withAugmentations*/ true); + const ambientModule = tryFindAmbientModule( + moduleReference, + /*withAugmentations*/ true + ); if (ambientModule) { return ambientModule; } const currentSourceFile = getSourceFileOfNode(location); const contextSpecifier = isStringLiteralLike(location) ? location - : (isModuleDeclaration(location) ? location : location.parent && isModuleDeclaration(location.parent) && location.parent.name === location ? location.parent : undefined)?.name || - (isLiteralImportTypeNode(location) ? location : undefined)?.argument.literal || - (isVariableDeclaration(location) && location.initializer && isRequireCall(location.initializer, /*requireStringLiteralLikeArgument*/ true) ? location.initializer.arguments[0] : undefined) || - findAncestor(location, isImportCall)?.arguments[0] || - findAncestor(location, or(isImportDeclaration, isJSDocImportTag, isExportDeclaration))?.moduleSpecifier || - findAncestor(location, isExternalModuleImportEqualsDeclaration)?.moduleReference.expression; - const mode = contextSpecifier && isStringLiteralLike(contextSpecifier) - ? host.getModeForUsageLocation(currentSourceFile, contextSpecifier) - : host.getDefaultResolutionModeForFile(currentSourceFile); - const moduleResolutionKind = getEmitModuleResolutionKind(compilerOptions); - const resolvedModule = host.getResolvedModule(currentSourceFile, moduleReference, mode)?.resolvedModule; - const resolutionDiagnostic = errorNode && resolvedModule && getResolutionDiagnostic(compilerOptions, resolvedModule, currentSourceFile); - const sourceFile = resolvedModule - && (!resolutionDiagnostic || resolutionDiagnostic === Diagnostics.Module_0_was_resolved_to_1_but_jsx_is_not_set) - && host.getSourceFile(resolvedModule.resolvedFileName); + : (isModuleDeclaration(location) + ? location + : location.parent && + isModuleDeclaration(location.parent) && + location.parent.name === location + ? location.parent + : undefined + )?.name || + (isLiteralImportTypeNode(location) ? location : undefined) + ?.argument.literal || + (isVariableDeclaration(location) && + location.initializer && + isRequireCall( + location.initializer, + /*requireStringLiteralLikeArgument*/ true + ) + ? location.initializer.arguments[0] + : undefined) || + findAncestor(location, isImportCall)?.arguments[0] || + findAncestor( + location, + or(isImportDeclaration, isJSDocImportTag, isExportDeclaration) + )?.moduleSpecifier || + findAncestor(location, isExternalModuleImportEqualsDeclaration) + ?.moduleReference.expression; + const mode = + contextSpecifier && isStringLiteralLike(contextSpecifier) + ? host.getModeForUsageLocation( + currentSourceFile, + contextSpecifier + ) + : host.getDefaultResolutionModeForFile(currentSourceFile); + const moduleResolutionKind = + getEmitModuleResolutionKind(compilerOptions); + const resolvedModule = host.getResolvedModule( + currentSourceFile, + moduleReference, + mode + )?.resolvedModule; + const resolutionDiagnostic = + errorNode && + resolvedModule && + getResolutionDiagnostic( + compilerOptions, + resolvedModule, + currentSourceFile + ); + const sourceFile = + resolvedModule && + (!resolutionDiagnostic || + resolutionDiagnostic === + Diagnostics.Module_0_was_resolved_to_1_but_jsx_is_not_set) && + host.getSourceFile(resolvedModule.resolvedFileName); if (sourceFile) { // If there's a resolutionDiagnostic we need to report it even if a sourceFile is found. if (resolutionDiagnostic) { - error(errorNode, resolutionDiagnostic, moduleReference, resolvedModule.resolvedFileName); + error( + errorNode, + resolutionDiagnostic, + moduleReference, + resolvedModule.resolvedFileName + ); } - if (resolvedModule.resolvedUsingTsExtension && isDeclarationFileName(moduleReference)) { - const importOrExport = findAncestor(location, isImportDeclaration)?.importClause || - findAncestor(location, or(isImportEqualsDeclaration, isExportDeclaration)); - if (errorNode && importOrExport && !importOrExport.isTypeOnly || findAncestor(location, isImportCall)) { + if ( + resolvedModule.resolvedUsingTsExtension && + isDeclarationFileName(moduleReference) + ) { + const importOrExport = + findAncestor(location, isImportDeclaration)?.importClause || + findAncestor( + location, + or(isImportEqualsDeclaration, isExportDeclaration) + ); + if ( + (errorNode && + importOrExport && + !importOrExport.isTypeOnly) || + findAncestor(location, isImportCall) + ) { error( errorNode, Diagnostics.A_declaration_file_cannot_be_imported_without_import_type_Did_you_mean_to_import_an_implementation_file_0_instead, - getSuggestedImportSource(Debug.checkDefined(tryExtractTSExtension(moduleReference))), + getSuggestedImportSource( + Debug.checkDefined( + tryExtractTSExtension(moduleReference) + ) + ) ); } - } - else if (resolvedModule.resolvedUsingTsExtension && !shouldAllowImportingTsExtension(compilerOptions, currentSourceFile.fileName)) { - const importOrExport = findAncestor(location, isImportDeclaration)?.importClause || - findAncestor(location, or(isImportEqualsDeclaration, isExportDeclaration)); - if (errorNode && !(importOrExport?.isTypeOnly || findAncestor(location, isImportTypeNode))) { - const tsExtension = Debug.checkDefined(tryExtractTSExtension(moduleReference)); - error(errorNode, Diagnostics.An_import_path_can_only_end_with_a_0_extension_when_allowImportingTsExtensions_is_enabled, tsExtension); + } else if ( + resolvedModule.resolvedUsingTsExtension && + !shouldAllowImportingTsExtension( + compilerOptions, + currentSourceFile.fileName + ) + ) { + const importOrExport = + findAncestor(location, isImportDeclaration)?.importClause || + findAncestor( + location, + or(isImportEqualsDeclaration, isExportDeclaration) + ); + if ( + errorNode && + !( + importOrExport?.isTypeOnly || + findAncestor(location, isImportTypeNode) + ) + ) { + const tsExtension = Debug.checkDefined( + tryExtractTSExtension(moduleReference) + ); + error( + errorNode, + Diagnostics.An_import_path_can_only_end_with_a_0_extension_when_allowImportingTsExtensions_is_enabled, + tsExtension + ); } - } - else if ( - compilerOptions.rewriteRelativeImportExtensions - && !(location.flags & NodeFlags.Ambient) - && !isDeclarationFileName(moduleReference) - && !isLiteralImportTypeNode(location) - && !isPartOfTypeOnlyImportOrExportDeclaration(location) + } else if ( + compilerOptions.rewriteRelativeImportExtensions && + !(location.flags & NodeFlags.Ambient) && + !isDeclarationFileName(moduleReference) && + !isLiteralImportTypeNode(location) && + !isPartOfTypeOnlyImportOrExportDeclaration(location) ) { - const shouldRewrite = shouldRewriteModuleSpecifier(moduleReference, compilerOptions); + const shouldRewrite = shouldRewriteModuleSpecifier( + moduleReference, + compilerOptions + ); if (!resolvedModule.resolvedUsingTsExtension && shouldRewrite) { error( errorNode, Diagnostics.This_relative_import_path_is_unsafe_to_rewrite_because_it_looks_like_a_file_name_but_actually_resolves_to_0, - getRelativePathFromFile(getNormalizedAbsolutePath(currentSourceFile.fileName, host.getCurrentDirectory()), resolvedModule.resolvedFileName, hostGetCanonicalFileName(host)), + getRelativePathFromFile( + getNormalizedAbsolutePath( + currentSourceFile.fileName, + host.getCurrentDirectory() + ), + resolvedModule.resolvedFileName, + hostGetCanonicalFileName(host) + ) ); - } - else if (resolvedModule.resolvedUsingTsExtension && !shouldRewrite && sourceFileMayBeEmitted(sourceFile, host)) { + } else if ( + resolvedModule.resolvedUsingTsExtension && + !shouldRewrite && + sourceFileMayBeEmitted(sourceFile, host) + ) { error( errorNode, Diagnostics.This_import_uses_a_0_extension_to_resolve_to_an_input_TypeScript_file_but_will_not_be_rewritten_during_emit_because_it_is_not_a_relative_path, - getAnyExtensionFromPath(moduleReference), + getAnyExtensionFromPath(moduleReference) ); - } - else if (resolvedModule.resolvedUsingTsExtension && shouldRewrite) { - const redirect = host.getRedirectFromSourceFile(sourceFile.path)?.resolvedRef; + } else if ( + resolvedModule.resolvedUsingTsExtension && + shouldRewrite + ) { + const redirect = host.getRedirectFromSourceFile( + sourceFile.path + )?.resolvedRef; if (redirect) { const ignoreCase = !host.useCaseSensitiveFileNames(); const ownRootDir = host.getCommonSourceDirectory(); - const otherRootDir = getCommonSourceDirectoryOfConfig(redirect.commandLine, ignoreCase); - const rootDirPath = getRelativePathFromDirectory(ownRootDir, otherRootDir, ignoreCase); - const outDirPath = getRelativePathFromDirectory(compilerOptions.outDir || ownRootDir, redirect.commandLine.options.outDir || otherRootDir, ignoreCase); + const otherRootDir = getCommonSourceDirectoryOfConfig( + redirect.commandLine, + ignoreCase + ); + const rootDirPath = getRelativePathFromDirectory( + ownRootDir, + otherRootDir, + ignoreCase + ); + const outDirPath = getRelativePathFromDirectory( + compilerOptions.outDir || ownRootDir, + redirect.commandLine.options.outDir || otherRootDir, + ignoreCase + ); if (rootDirPath !== outDirPath) { error( errorNode, - Diagnostics.This_import_path_is_unsafe_to_rewrite_because_it_resolves_to_another_project_and_the_relative_path_between_the_projects_output_files_is_not_the_same_as_the_relative_path_between_its_input_files, + Diagnostics.This_import_path_is_unsafe_to_rewrite_because_it_resolves_to_another_project_and_the_relative_path_between_the_projects_output_files_is_not_the_same_as_the_relative_path_between_its_input_files ); } } @@ -4775,56 +7509,125 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (sourceFile.symbol) { - if (errorNode && resolvedModule.isExternalLibraryImport && !resolutionExtensionIsTSOrJson(resolvedModule.extension)) { - errorOnImplicitAnyModule(/*isError*/ false, errorNode, currentSourceFile, mode, resolvedModule, moduleReference); + if ( + errorNode && + resolvedModule.isExternalLibraryImport && + !resolutionExtensionIsTSOrJson(resolvedModule.extension) + ) { + errorOnImplicitAnyModule( + /*isError*/ false, + errorNode, + currentSourceFile, + mode, + resolvedModule, + moduleReference + ); } - if (errorNode && (moduleKind === ModuleKind.Node16 || moduleKind === ModuleKind.Node18)) { - const isSyncImport = (currentSourceFile.impliedNodeFormat === ModuleKind.CommonJS && !findAncestor(location, isImportCall)) || !!findAncestor(location, isImportEqualsDeclaration); - const overrideHost = findAncestor(location, l => isImportTypeNode(l) || isExportDeclaration(l) || isImportDeclaration(l) || isJSDocImportTag(l)); + if ( + errorNode && + (moduleKind === ModuleKind.Node16 || + moduleKind === ModuleKind.Node18) + ) { + const isSyncImport = + (currentSourceFile.impliedNodeFormat === + ModuleKind.CommonJS && + !findAncestor(location, isImportCall)) || + !!findAncestor(location, isImportEqualsDeclaration); + const overrideHost = findAncestor( + location, + (l) => + isImportTypeNode(l) || + isExportDeclaration(l) || + isImportDeclaration(l) || + isJSDocImportTag(l) + ); // An override clause will take effect for type-only imports and import types, and allows importing the types across formats, regardless of // normal mode restrictions - if (isSyncImport && sourceFile.impliedNodeFormat === ModuleKind.ESNext && !hasResolutionModeOverride(overrideHost)) { + if ( + isSyncImport && + sourceFile.impliedNodeFormat === ModuleKind.ESNext && + !hasResolutionModeOverride(overrideHost) + ) { if (findAncestor(location, isImportEqualsDeclaration)) { // ImportEquals in a ESM file resolving to another ESM file - 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); - } - else { + 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 + ); + } else { // CJS file resolving to an ESM file let diagnosticDetails; - const ext = tryGetExtensionFromPath(currentSourceFile.fileName); - if (ext === Extension.Ts || ext === Extension.Js || ext === Extension.Tsx || ext === Extension.Jsx) { - diagnosticDetails = createModeMismatchDetails(currentSourceFile); + const ext = tryGetExtensionFromPath( + currentSourceFile.fileName + ); + if ( + ext === Extension.Ts || + ext === Extension.Js || + ext === Extension.Tsx || + ext === Extension.Jsx + ) { + diagnosticDetails = + createModeMismatchDetails( + currentSourceFile + ); } - const message = overrideHost?.kind === SyntaxKind.ImportDeclaration && overrideHost.importClause?.isTypeOnly ? Diagnostics.Type_only_import_of_an_ECMAScript_module_from_a_CommonJS_module_must_have_a_resolution_mode_attribute : - overrideHost?.kind === SyntaxKind.ImportType ? Diagnostics.Type_import_of_an_ECMAScript_module_from_a_CommonJS_module_must_have_a_resolution_mode_attribute : - 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; - diagnostics.add(createDiagnosticForNodeFromMessageChain( - getSourceFileOfNode(errorNode), - errorNode, - chainDiagnosticMessages(diagnosticDetails, message, moduleReference), - )); + const message = + overrideHost?.kind === + SyntaxKind.ImportDeclaration && + overrideHost.importClause?.isTypeOnly + ? Diagnostics.Type_only_import_of_an_ECMAScript_module_from_a_CommonJS_module_must_have_a_resolution_mode_attribute + : overrideHost?.kind === + SyntaxKind.ImportType + ? Diagnostics.Type_import_of_an_ECMAScript_module_from_a_CommonJS_module_must_have_a_resolution_mode_attribute + : 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; + diagnostics.add( + createDiagnosticForNodeFromMessageChain( + getSourceFileOfNode(errorNode), + errorNode, + chainDiagnosticMessages( + diagnosticDetails, + message, + moduleReference + ) + ) + ); } } } // merged symbol is module declaration symbol combined with all augmentations return getMergedSymbol(sourceFile.symbol); } - if (errorNode && moduleNotFoundError && !isSideEffectImport(errorNode)) { + if ( + errorNode && + moduleNotFoundError && + !isSideEffectImport(errorNode) + ) { // report errors only if it was requested - error(errorNode, Diagnostics.File_0_is_not_a_module, sourceFile.fileName); + error( + errorNode, + Diagnostics.File_0_is_not_a_module, + sourceFile.fileName + ); } return undefined; } if (patternAmbientModules) { - const pattern = findBestPatternMatch(patternAmbientModules, _ => _.pattern, moduleReference); + const pattern = findBestPatternMatch( + patternAmbientModules, + (_) => _.pattern, + moduleReference + ); if (pattern) { // If the module reference matched a pattern ambient module ('*.foo') but there's also a // module augmentation by the specific name requested ('a.foo'), we store the merged symbol // by the augmentation name ('a.foo'), because asking for *.foo should not give you exports // from a.foo. - const augmentation = patternAmbientModuleAugmentations && patternAmbientModuleAugmentations.get(moduleReference); + const augmentation = + patternAmbientModuleAugmentations && + patternAmbientModuleAugmentations.get(moduleReference); if (augmentation) { return getMergedSymbol(augmentation); } @@ -4837,13 +7640,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // May be an untyped module. If so, ignore resolutionDiagnostic. - if (resolvedModule && !resolutionExtensionIsTSOrJson(resolvedModule.extension) && resolutionDiagnostic === undefined || resolutionDiagnostic === Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type) { + if ( + (resolvedModule && + !resolutionExtensionIsTSOrJson(resolvedModule.extension) && + resolutionDiagnostic === undefined) || + resolutionDiagnostic === + Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type + ) { if (isForAugmentation) { - const diag = Diagnostics.Invalid_module_name_in_augmentation_Module_0_resolves_to_an_untyped_module_at_1_which_cannot_be_augmented; - error(errorNode, diag, moduleReference, resolvedModule!.resolvedFileName); - } - else { - errorOnImplicitAnyModule(/*isError*/ noImplicitAny && !!moduleNotFoundError, errorNode, currentSourceFile, mode, resolvedModule!, moduleReference); + const diag = + Diagnostics.Invalid_module_name_in_augmentation_Module_0_resolves_to_an_untyped_module_at_1_which_cannot_be_augmented; + error( + errorNode, + diag, + moduleReference, + resolvedModule!.resolvedFileName + ); + } else { + errorOnImplicitAnyModule( + /*isError*/ noImplicitAny && !!moduleNotFoundError, + errorNode, + currentSourceFile, + mode, + resolvedModule!, + moduleReference + ); } // Failed imports and untyped modules are both treated in an untyped manner; only difference is whether we give a diagnostic first. return undefined; @@ -4852,19 +7673,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (moduleNotFoundError) { // See if this was possibly a projectReference redirect if (resolvedModule) { - const redirect = host.getRedirectFromSourceFile(resolvedModule.resolvedFileName); + const redirect = host.getRedirectFromSourceFile( + resolvedModule.resolvedFileName + ); if (redirect?.outputDts) { - error(errorNode, Diagnostics.Output_file_0_has_not_been_built_from_source_file_1, redirect.outputDts, resolvedModule.resolvedFileName); + error( + errorNode, + Diagnostics.Output_file_0_has_not_been_built_from_source_file_1, + redirect.outputDts, + resolvedModule.resolvedFileName + ); return undefined; } } if (resolutionDiagnostic) { - error(errorNode, resolutionDiagnostic, moduleReference, resolvedModule.resolvedFileName); - } - else { - const isExtensionlessRelativePathImport = pathIsRelative(moduleReference) && !hasExtension(moduleReference); - const resolutionIsNode16OrNext = moduleResolutionKind === ModuleResolutionKind.Node16 || + error( + errorNode, + resolutionDiagnostic, + moduleReference, + resolvedModule.resolvedFileName + ); + } else { + const isExtensionlessRelativePathImport = + pathIsRelative(moduleReference) && + !hasExtension(moduleReference); + const resolutionIsNode16OrNext = + moduleResolutionKind === ModuleResolutionKind.Node16 || moduleResolutionKind === ModuleResolutionKind.NodeNext; if ( !getResolveJsonModule(compilerOptions) && @@ -4872,24 +7707,61 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { moduleResolutionKind !== ModuleResolutionKind.Classic && hasJsonModuleEmitEnabled(compilerOptions) ) { - error(errorNode, Diagnostics.Cannot_find_module_0_Consider_using_resolveJsonModule_to_import_module_with_json_extension, moduleReference); - } - else if (mode === ModuleKind.ESNext && resolutionIsNode16OrNext && isExtensionlessRelativePathImport) { - const absoluteRef = getNormalizedAbsolutePath(moduleReference, getDirectoryPath(currentSourceFile.path)); - const suggestedExt = suggestedExtensions.find(([actualExt, _importExt]) => host.fileExists(absoluteRef + actualExt))?.[1]; + error( + errorNode, + Diagnostics.Cannot_find_module_0_Consider_using_resolveJsonModule_to_import_module_with_json_extension, + moduleReference + ); + } else if ( + mode === ModuleKind.ESNext && + resolutionIsNode16OrNext && + isExtensionlessRelativePathImport + ) { + const absoluteRef = getNormalizedAbsolutePath( + moduleReference, + getDirectoryPath(currentSourceFile.path) + ); + const suggestedExt = suggestedExtensions.find( + ([actualExt, _importExt]) => + host.fileExists(absoluteRef + actualExt) + )?.[1]; if (suggestedExt) { - error(errorNode, Diagnostics.Relative_import_paths_need_explicit_file_extensions_in_ECMAScript_imports_when_moduleResolution_is_node16_or_nodenext_Did_you_mean_0, moduleReference + suggestedExt); - } - else { - 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); - } - } - else { - if (host.getResolvedModule(currentSourceFile, moduleReference, mode)?.alternateResult) { - const errorInfo = createModuleNotFoundChain(currentSourceFile, host, moduleReference, mode, moduleReference); - errorOrSuggestion(/*isError*/ true, errorNode, chainDiagnosticMessages(errorInfo, moduleNotFoundError, moduleReference)); + error( + errorNode, + Diagnostics.Relative_import_paths_need_explicit_file_extensions_in_ECMAScript_imports_when_moduleResolution_is_node16_or_nodenext_Did_you_mean_0, + moduleReference + suggestedExt + ); + } else { + 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 + ); } - else { + } else { + if ( + host.getResolvedModule( + currentSourceFile, + moduleReference, + mode + )?.alternateResult + ) { + const errorInfo = createModuleNotFoundChain( + currentSourceFile, + host, + moduleReference, + mode, + moduleReference + ); + errorOrSuggestion( + /*isError*/ true, + errorNode, + chainDiagnosticMessages( + errorInfo, + moduleNotFoundError, + moduleReference + ) + ); + } else { error(errorNode, moduleNotFoundError, moduleReference); } } @@ -4898,30 +7770,62 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; function getSuggestedImportSource(tsExtension: string) { - const importSourceWithoutExtension = removeExtension(moduleReference, tsExtension); + const importSourceWithoutExtension = removeExtension( + moduleReference, + tsExtension + ); /** * Direct users to import source with .js extension if outputting an ES module. * @see https://github.com/microsoft/TypeScript/issues/42151 */ - if (emitModuleKindIsNonNodeESM(moduleKind) || mode === ModuleKind.ESNext) { - const preferTs = isDeclarationFileName(moduleReference) && shouldAllowImportingTsExtension(compilerOptions); - const ext = tsExtension === Extension.Mts || tsExtension === Extension.Dmts ? preferTs ? ".mts" : ".mjs" : - tsExtension === Extension.Cts || tsExtension === Extension.Dmts ? preferTs ? ".cts" : ".cjs" : - preferTs ? ".ts" : ".js"; + if ( + emitModuleKindIsNonNodeESM(moduleKind) || + mode === ModuleKind.ESNext + ) { + const preferTs = + isDeclarationFileName(moduleReference) && + shouldAllowImportingTsExtension(compilerOptions); + const ext = + tsExtension === Extension.Mts || + tsExtension === Extension.Dmts + ? preferTs + ? ".mts" + : ".mjs" + : tsExtension === Extension.Cts || + tsExtension === Extension.Dmts + ? preferTs + ? ".cts" + : ".cjs" + : preferTs + ? ".ts" + : ".js"; return importSourceWithoutExtension + ext; } return importSourceWithoutExtension; } } - function errorOnImplicitAnyModule(isError: boolean, errorNode: Node, sourceFile: SourceFile, mode: ResolutionMode, { packageId, resolvedFileName }: ResolvedModuleFull, moduleReference: string): void { + function errorOnImplicitAnyModule( + isError: boolean, + errorNode: Node, + sourceFile: SourceFile, + mode: ResolutionMode, + { packageId, resolvedFileName }: ResolvedModuleFull, + moduleReference: string + ): void { if (isSideEffectImport(errorNode)) { return; } let errorInfo: DiagnosticMessageChain | undefined; if (!isExternalModuleNameRelative(moduleReference) && packageId) { - errorInfo = createModuleNotFoundChain(sourceFile, host, moduleReference, mode, packageId.name); + errorInfo = createModuleNotFoundChain( + sourceFile, + host, + moduleReference, + mode, + packageId.name + ); } errorOrSuggestion( isError, @@ -4930,38 +7834,70 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { errorInfo, Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type, moduleReference, - resolvedFileName, - ), + resolvedFileName + ) ); } - function resolveExternalModuleSymbol(moduleSymbol: Symbol, dontResolveAlias?: boolean): Symbol; - function resolveExternalModuleSymbol(moduleSymbol: Symbol | undefined, dontResolveAlias?: boolean): Symbol | undefined; - function resolveExternalModuleSymbol(moduleSymbol: Symbol | undefined, dontResolveAlias?: boolean): Symbol | undefined { + function resolveExternalModuleSymbol( + moduleSymbol: Symbol, + dontResolveAlias?: boolean + ): Symbol; + function resolveExternalModuleSymbol( + moduleSymbol: Symbol | undefined, + dontResolveAlias?: boolean + ): Symbol | undefined; + function resolveExternalModuleSymbol( + moduleSymbol: Symbol | undefined, + dontResolveAlias?: boolean + ): Symbol | undefined { if (moduleSymbol?.exports) { - const exportEquals = resolveSymbol(moduleSymbol.exports.get(InternalSymbolName.ExportEquals), dontResolveAlias); - const exported = getCommonJsExportEquals(getMergedSymbol(exportEquals), getMergedSymbol(moduleSymbol)); + const exportEquals = resolveSymbol( + moduleSymbol.exports.get(InternalSymbolName.ExportEquals), + dontResolveAlias + ); + const exported = getCommonJsExportEquals( + getMergedSymbol(exportEquals), + getMergedSymbol(moduleSymbol) + ); return getMergedSymbol(exported) || moduleSymbol; } return undefined; } - function getCommonJsExportEquals(exported: Symbol | undefined, moduleSymbol: Symbol): Symbol | undefined { - if (!exported || exported === unknownSymbol || exported === moduleSymbol || moduleSymbol.exports!.size === 1 || exported.flags & SymbolFlags.Alias) { + function getCommonJsExportEquals( + exported: Symbol | undefined, + moduleSymbol: Symbol + ): Symbol | undefined { + if ( + !exported || + exported === unknownSymbol || + exported === moduleSymbol || + moduleSymbol.exports!.size === 1 || + exported.flags & SymbolFlags.Alias + ) { return exported; } const links = getSymbolLinks(exported); if (links.cjsExportMerged) { return links.cjsExportMerged; } - const merged = exported.flags & SymbolFlags.Transient ? exported : cloneSymbol(exported); + const merged = + exported.flags & SymbolFlags.Transient + ? exported + : cloneSymbol(exported); merged.flags = merged.flags | SymbolFlags.ValueModule; if (merged.exports === undefined) { merged.exports = createSymbolTable(); } moduleSymbol.exports!.forEach((s, name) => { if (name === InternalSymbolName.ExportEquals) return; - merged.exports!.set(name, merged.exports!.has(name) ? mergeSymbol(merged.exports!.get(name)!, s) : s); + merged.exports!.set( + name, + merged.exports!.has(name) + ? mergeSymbol(merged.exports!.get(name)!, s) + : s + ); }); if (merged === exported) { // We just mutated a symbol, reset any cached links we may have already set @@ -4970,65 +7906,145 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { getSymbolLinks(merged).resolvedMembers = undefined; } getSymbolLinks(merged).cjsExportMerged = merged; - return links.cjsExportMerged = merged; + return (links.cjsExportMerged = merged); } // An external module with an 'export =' declaration may be referenced as an ES6 module provided the 'export =' // references a symbol that is at least declared as a module or a variable. The target of the 'export =' may // combine other declarations with the module or variable (e.g. a class/module, function/module, interface/variable). - function resolveESModuleSymbol(moduleSymbol: Symbol | undefined, referencingLocation: Node, dontResolveAlias: boolean, suppressInteropError: boolean): Symbol | undefined { - const symbol = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias); + function resolveESModuleSymbol( + moduleSymbol: Symbol | undefined, + referencingLocation: Node, + dontResolveAlias: boolean, + suppressInteropError: boolean + ): Symbol | undefined { + const symbol = resolveExternalModuleSymbol( + moduleSymbol, + dontResolveAlias + ); if (!dontResolveAlias && symbol) { - if (!suppressInteropError && !(symbol.flags & (SymbolFlags.Module | SymbolFlags.Variable)) && !getDeclarationOfKind(symbol, SyntaxKind.SourceFile)) { - const compilerOptionName = moduleKind >= ModuleKind.ES2015 - ? "allowSyntheticDefaultImports" - : "esModuleInterop"; + if ( + !suppressInteropError && + !(symbol.flags & (SymbolFlags.Module | SymbolFlags.Variable)) && + !getDeclarationOfKind(symbol, SyntaxKind.SourceFile) + ) { + const compilerOptionName = + moduleKind >= ModuleKind.ES2015 + ? "allowSyntheticDefaultImports" + : "esModuleInterop"; - 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); + 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 + ); return symbol; } const referenceParent = referencingLocation.parent; - const namespaceImport = isImportDeclaration(referenceParent) && getNamespaceDeclarationNode(referenceParent); + const namespaceImport = + isImportDeclaration(referenceParent) && + getNamespaceDeclarationNode(referenceParent); if (namespaceImport || isImportCall(referenceParent)) { - const reference = isImportCall(referenceParent) ? referenceParent.arguments[0] : referenceParent.moduleSpecifier; + const reference = isImportCall(referenceParent) + ? referenceParent.arguments[0] + : referenceParent.moduleSpecifier; const type = getTypeOfSymbol(symbol); - const defaultOnlyType = getTypeWithSyntheticDefaultOnly(type, symbol, moduleSymbol!, reference); + const defaultOnlyType = getTypeWithSyntheticDefaultOnly( + type, + symbol, + moduleSymbol!, + reference + ); if (defaultOnlyType) { - return cloneTypeAsModuleType(symbol, defaultOnlyType, referenceParent); + return cloneTypeAsModuleType( + symbol, + defaultOnlyType, + referenceParent + ); } - const targetFile = moduleSymbol?.declarations?.find(isSourceFile); - const usageMode = getEmitSyntaxForModuleSpecifierExpression(reference); + const targetFile = + moduleSymbol?.declarations?.find(isSourceFile); + const usageMode = + getEmitSyntaxForModuleSpecifierExpression(reference); let exportModuleDotExportsSymbol: Symbol | undefined; if ( - namespaceImport && targetFile && - ModuleKind.Node20 <= moduleKind && moduleKind <= ModuleKind.NodeNext && - usageMode === ModuleKind.CommonJS && host.getImpliedNodeFormatForEmit(targetFile) === ModuleKind.ESNext && - (exportModuleDotExportsSymbol = resolveExportByName(symbol, "module.exports" as __String, namespaceImport, dontResolveAlias)) + namespaceImport && + targetFile && + ModuleKind.Node20 <= moduleKind && + moduleKind <= ModuleKind.NodeNext && + usageMode === ModuleKind.CommonJS && + host.getImpliedNodeFormatForEmit(targetFile) === + ModuleKind.ESNext && + (exportModuleDotExportsSymbol = resolveExportByName( + symbol, + "module.exports" as __String, + namespaceImport, + dontResolveAlias + )) ) { - if (!suppressInteropError && !(symbol.flags & (SymbolFlags.Module | SymbolFlags.Variable))) { - error(referencingLocation, Diagnostics.This_module_can_only_be_referenced_with_ECMAScript_imports_Slashexports_by_turning_on_the_0_flag_and_referencing_its_default_export, "esModuleInterop"); + if ( + !suppressInteropError && + !( + symbol.flags & + (SymbolFlags.Module | SymbolFlags.Variable) + ) + ) { + error( + referencingLocation, + Diagnostics.This_module_can_only_be_referenced_with_ECMAScript_imports_Slashexports_by_turning_on_the_0_flag_and_referencing_its_default_export, + "esModuleInterop" + ); } - if (getESModuleInterop(compilerOptions) && hasSignatures(type)) { - return cloneTypeAsModuleType(exportModuleDotExportsSymbol, type, referenceParent); + if ( + getESModuleInterop(compilerOptions) && + hasSignatures(type) + ) { + return cloneTypeAsModuleType( + exportModuleDotExportsSymbol, + type, + referenceParent + ); } return exportModuleDotExportsSymbol; } - const isEsmCjsRef = targetFile && isESMFormatImportImportingCommonjsFormatFile(usageMode, host.getImpliedNodeFormatForEmit(targetFile)); + const isEsmCjsRef = + targetFile && + isESMFormatImportImportingCommonjsFormatFile( + usageMode, + host.getImpliedNodeFormatForEmit(targetFile) + ); if (getESModuleInterop(compilerOptions) || isEsmCjsRef) { if ( hasSignatures(type) || - getPropertyOfType(type, InternalSymbolName.Default, /*skipObjectFunctionPropertyAugment*/ true) || + getPropertyOfType( + type, + InternalSymbolName.Default, + /*skipObjectFunctionPropertyAugment*/ true + ) || isEsmCjsRef ) { - const moduleType = type.flags & TypeFlags.StructuredType - ? getTypeWithSyntheticDefaultImportType(type, symbol, moduleSymbol!, reference) - : createDefaultPropertyWrapperForModule(symbol, symbol.parent); - return cloneTypeAsModuleType(symbol, moduleType, referenceParent); + const moduleType = + type.flags & TypeFlags.StructuredType + ? getTypeWithSyntheticDefaultImportType( + type, + symbol, + moduleSymbol!, + reference + ) + : createDefaultPropertyWrapperForModule( + symbol, + symbol.parent + ); + return cloneTypeAsModuleType( + symbol, + moduleType, + referenceParent + ); } } } @@ -5037,29 +8053,50 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function hasSignatures(type: Type): boolean { - return some(getSignaturesOfStructuredType(type, SignatureKind.Call)) || some(getSignaturesOfStructuredType(type, SignatureKind.Construct)); + return ( + some(getSignaturesOfStructuredType(type, SignatureKind.Call)) || + some(getSignaturesOfStructuredType(type, SignatureKind.Construct)) + ); } /** * Create a new symbol which has the module's type less the call and construct signatures */ - function cloneTypeAsModuleType(symbol: Symbol, moduleType: Type, referenceParent: ImportDeclaration | ImportCall) { + function cloneTypeAsModuleType( + symbol: Symbol, + moduleType: Type, + referenceParent: ImportDeclaration | ImportCall + ) { const result = createSymbol(symbol.flags, symbol.escapedName); - result.declarations = symbol.declarations ? symbol.declarations.slice() : []; + result.declarations = symbol.declarations + ? symbol.declarations.slice() + : []; result.parent = symbol.parent; result.links.target = symbol; result.links.originatingImport = referenceParent; - if (symbol.valueDeclaration) result.valueDeclaration = symbol.valueDeclaration; + if (symbol.valueDeclaration) + result.valueDeclaration = symbol.valueDeclaration; if (symbol.constEnumOnlyModule) result.constEnumOnlyModule = true; if (symbol.members) result.members = new Map(symbol.members); if (symbol.exports) result.exports = new Map(symbol.exports); - const resolvedModuleType = resolveStructuredTypeMembers(moduleType as StructuredType); // Should already be resolved from the signature checks above - result.links.type = createAnonymousType(result, resolvedModuleType.members, emptyArray, emptyArray, resolvedModuleType.indexInfos); + const resolvedModuleType = resolveStructuredTypeMembers( + moduleType as StructuredType + ); // Should already be resolved from the signature checks above + result.links.type = createAnonymousType( + result, + resolvedModuleType.members, + emptyArray, + emptyArray, + resolvedModuleType.indexInfos + ); return result; } function hasExportAssignmentSymbol(moduleSymbol: Symbol): boolean { - return moduleSymbol.exports!.get(InternalSymbolName.ExportEquals) !== undefined; + return ( + moduleSymbol.exports!.get(InternalSymbolName.ExportEquals) !== + undefined + ); } function getExportsOfModuleAsArray(moduleSymbol: Symbol): Symbol[] { @@ -5078,7 +8115,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return exports; } - function forEachExportAndPropertyOfModule(moduleSymbol: Symbol, cb: (symbol: Symbol, key: __String) => void): void { + function forEachExportAndPropertyOfModule( + moduleSymbol: Symbol, + cb: (symbol: Symbol, key: __String) => void + ): void { const exports = getExportsOfModule(moduleSymbol); exports.forEach((symbol, key) => { if (!isReservedMemberName(key)) { @@ -5096,14 +8136,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function tryGetMemberInModuleExports(memberName: __String, moduleSymbol: Symbol): Symbol | undefined { + function tryGetMemberInModuleExports( + memberName: __String, + moduleSymbol: Symbol + ): Symbol | undefined { const symbolTable = getExportsOfModule(moduleSymbol); if (symbolTable) { return symbolTable.get(memberName); } } - function tryGetMemberInModuleExportsAndProperties(memberName: __String, moduleSymbol: Symbol): Symbol | undefined { + function tryGetMemberInModuleExportsAndProperties( + memberName: __String, + moduleSymbol: Symbol + ): Symbol | undefined { const symbol = tryGetMemberInModuleExports(memberName, moduleSymbol); if (symbol) { return symbol; @@ -5115,27 +8161,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const type = getTypeOfSymbol(exportEquals); - return shouldTreatPropertiesOfExternalModuleAsExports(type) ? getPropertyOfType(type, memberName) : undefined; + return shouldTreatPropertiesOfExternalModuleAsExports(type) + ? getPropertyOfType(type, memberName) + : undefined; } - function shouldTreatPropertiesOfExternalModuleAsExports(resolvedExternalModuleType: Type) { - return !(resolvedExternalModuleType.flags & TypeFlags.Primitive || + function shouldTreatPropertiesOfExternalModuleAsExports( + resolvedExternalModuleType: Type + ) { + return !( + resolvedExternalModuleType.flags & TypeFlags.Primitive || getObjectFlags(resolvedExternalModuleType) & ObjectFlags.Class || // `isArrayOrTupleLikeType` is too expensive to use in this auto-imports hot path isArrayType(resolvedExternalModuleType) || - isTupleType(resolvedExternalModuleType)); + isTupleType(resolvedExternalModuleType) + ); } function getExportsOfSymbol(symbol: Symbol): SymbolTable { - return symbol.flags & SymbolFlags.LateBindingContainer ? getResolvedMembersOrExportsOfSymbol(symbol, MembersOrExportsResolutionKind.resolvedExports) : - symbol.flags & SymbolFlags.Module ? getExportsOfModule(symbol) : - symbol.exports || emptySymbols; + return symbol.flags & SymbolFlags.LateBindingContainer + ? getResolvedMembersOrExportsOfSymbol( + symbol, + MembersOrExportsResolutionKind.resolvedExports + ) + : symbol.flags & SymbolFlags.Module + ? getExportsOfModule(symbol) + : symbol.exports || emptySymbols; } function getExportsOfModule(moduleSymbol: Symbol): SymbolTable { const links = getSymbolLinks(moduleSymbol); if (!links.resolvedExports) { - const { exports, typeOnlyExportStarMap } = getExportsOfModuleWorker(moduleSymbol); + const { exports, typeOnlyExportStarMap } = + getExportsOfModuleWorker(moduleSymbol); links.resolvedExports = exports; links.typeOnlyExportStarMap = typeOnlyExportStarMap; } @@ -5153,7 +8211,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Extends one symbol table with another while collecting information on name collisions for error message generation into the `lookupTable` argument * Not passing `lookupTable` and `exportNode` disables this collection, and just extends the tables */ - function extendExportSymbols(target: SymbolTable, source: SymbolTable | undefined, lookupTable?: ExportCollisionTrackerTable, exportNode?: ExportDeclaration) { + function extendExportSymbols( + target: SymbolTable, + source: SymbolTable | undefined, + lookupTable?: ExportCollisionTrackerTable, + exportNode?: ExportDeclaration + ) { if (!source) return; source.forEach((sourceSymbol, id) => { if (id === InternalSymbolName.Default) return; @@ -5163,16 +8226,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { target.set(id, sourceSymbol); if (lookupTable && exportNode) { lookupTable.set(id, { - specifierText: getTextOfNode(exportNode.moduleSpecifier!), + specifierText: getTextOfNode( + exportNode.moduleSpecifier! + ), }); } - } - else if (lookupTable && exportNode && targetSymbol && resolveSymbol(targetSymbol) !== resolveSymbol(sourceSymbol)) { + } else if ( + lookupTable && + exportNode && + targetSymbol && + resolveSymbol(targetSymbol) !== resolveSymbol(sourceSymbol) + ) { const collisionTracker = lookupTable.get(id)!; if (!collisionTracker.exportsWithDuplicate) { collisionTracker.exportsWithDuplicate = [exportNode]; - } - else { + } else { collisionTracker.exportsWithDuplicate.push(exportNode); } } @@ -5181,7 +8249,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getExportsOfModuleWorker(moduleSymbol: Symbol) { const visitedSymbols: Symbol[] = []; - let typeOnlyExportStarMap: Map<__String, ExportDeclaration & { readonly isTypeOnly: true; readonly moduleSpecifier: Expression; }> | undefined; + let typeOnlyExportStarMap: + | Map< + __String, + ExportDeclaration & { + readonly isTypeOnly: true; + readonly moduleSpecifier: Expression; + } + > + | undefined; const nonTypeOnlyNames = new Set<__String>(); // A module defined by an 'export=' consists of one export that needs to be resolved @@ -5189,7 +8265,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const exports = visit(moduleSymbol) || emptySymbols; if (typeOnlyExportStarMap) { - nonTypeOnlyNames.forEach(name => typeOnlyExportStarMap!.delete(name)); + nonTypeOnlyNames.forEach((name) => + typeOnlyExportStarMap!.delete(name) + ); } return { @@ -5199,47 +8277,74 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // The ES6 spec permits export * declarations in a module to circularly reference the module itself. For example, // module 'a' can 'export * from "b"' and 'b' can 'export * from "a"' without error. - function visit(symbol: Symbol | undefined, exportStar?: ExportDeclaration, isTypeOnly?: boolean): SymbolTable | undefined { + function visit( + symbol: Symbol | undefined, + exportStar?: ExportDeclaration, + isTypeOnly?: boolean + ): SymbolTable | undefined { if (!isTypeOnly && symbol?.exports) { // Add non-type-only names before checking if we've visited this module, // because we might have visited it via an 'export type *', and visiting // again with 'export *' will override the type-onlyness of its exports. symbol.exports.forEach((_, name) => nonTypeOnlyNames.add(name)); } - if (!(symbol && symbol.exports && pushIfUnique(visitedSymbols, symbol))) { + if ( + !( + symbol && + symbol.exports && + pushIfUnique(visitedSymbols, symbol) + ) + ) { return; } const symbols = new Map(symbol.exports); // All export * declarations are collected in an __export symbol by the binder - const exportStars = symbol.exports.get(InternalSymbolName.ExportStar); + const exportStars = symbol.exports.get( + InternalSymbolName.ExportStar + ); if (exportStars) { const nestedSymbols = createSymbolTable(); const lookupTable: ExportCollisionTrackerTable = new Map(); if (exportStars.declarations) { for (const node of exportStars.declarations) { - const resolvedModule = resolveExternalModuleName(node, (node as ExportDeclaration).moduleSpecifier!); - const exportedSymbols = visit(resolvedModule, node as ExportDeclaration, isTypeOnly || (node as ExportDeclaration).isTypeOnly); + const resolvedModule = resolveExternalModuleName( + node, + (node as ExportDeclaration).moduleSpecifier! + ); + const exportedSymbols = visit( + resolvedModule, + node as ExportDeclaration, + isTypeOnly || (node as ExportDeclaration).isTypeOnly + ); extendExportSymbols( nestedSymbols, exportedSymbols, lookupTable, - node as ExportDeclaration, + node as ExportDeclaration ); } } lookupTable.forEach(({ exportsWithDuplicate }, id) => { // It's not an error if the file with multiple `export *`s with duplicate names exports a member with that name itself - if (id === "export=" || !(exportsWithDuplicate && exportsWithDuplicate.length) || symbols.has(id)) { + if ( + id === "export=" || + !( + exportsWithDuplicate && exportsWithDuplicate.length + ) || + symbols.has(id) + ) { return; } for (const node of exportsWithDuplicate) { - diagnostics.add(createDiagnosticForNode( - node, - Diagnostics.Module_0_has_already_exported_a_member_named_1_Consider_explicitly_re_exporting_to_resolve_the_ambiguity, - lookupTable.get(id)!.specifierText, - unescapeLeadingUnderscores(id), - )); + diagnostics.add( + createDiagnosticForNode( + node, + Diagnostics.Module_0_has_already_exported_a_member_named_1_Consider_explicitly_re_exporting_to_resolve_the_ambiguity, + lookupTable.get(id)!.specifierText, + unescapeLeadingUnderscores(id) + ) + ); } }); extendExportSymbols(symbols, nestedSymbols); @@ -5249,7 +8354,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { symbols.forEach((_, escapedName) => typeOnlyExportStarMap!.set( escapedName, - exportStar as ExportDeclaration & { readonly isTypeOnly: true; readonly moduleSpecifier: Expression; }, + exportStar as ExportDeclaration & { + readonly isTypeOnly: true; + readonly moduleSpecifier: Expression; + } ) ); } @@ -5261,7 +8369,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getMergedSymbol(symbol: Symbol | undefined): Symbol | undefined; function getMergedSymbol(symbol: Symbol | undefined): Symbol | undefined { let merged: Symbol; - return symbol && symbol.mergeId && (merged = mergedSymbols[symbol.mergeId]) ? merged : symbol; + return symbol && + symbol.mergeId && + (merged = mergedSymbols[symbol.mergeId]) + ? merged + : symbol; } function getSymbolOfDeclaration(node: Declaration): Symbol { @@ -5277,35 +8389,54 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getParentOfSymbol(symbol: Symbol): Symbol | undefined { - return getMergedSymbol(symbol.parent && getLateBoundSymbol(symbol.parent)); + return getMergedSymbol( + symbol.parent && getLateBoundSymbol(symbol.parent) + ); } function getFunctionExpressionParentSymbolOrSymbol(symbol: Symbol) { - return symbol.valueDeclaration?.kind === SyntaxKind.ArrowFunction || symbol.valueDeclaration?.kind === SyntaxKind.FunctionExpression + return symbol.valueDeclaration?.kind === SyntaxKind.ArrowFunction || + symbol.valueDeclaration?.kind === SyntaxKind.FunctionExpression ? getSymbolOfNode(symbol.valueDeclaration.parent) || symbol : symbol; } - function getAlternativeContainingModules(symbol: Symbol, enclosingDeclaration: Node): Symbol[] { + function getAlternativeContainingModules( + symbol: Symbol, + enclosingDeclaration: Node + ): Symbol[] { const containingFile = getSourceFileOfNode(enclosingDeclaration); const id = getNodeId(containingFile); const links = getSymbolLinks(symbol); let results: Symbol[] | undefined; - if (links.extendedContainersByFile && (results = links.extendedContainersByFile.get(id))) { + if ( + links.extendedContainersByFile && + (results = links.extendedContainersByFile.get(id)) + ) { return results; } if (containingFile && containingFile.imports) { // Try to make an import using an import already in the enclosing file, if possible for (const importRef of containingFile.imports) { if (nodeIsSynthesized(importRef)) continue; // Synthetic names can't be resolved by `resolveExternalModuleName` - they'll cause a debug assert if they error - const resolvedModule = resolveExternalModuleName(enclosingDeclaration, importRef, /*ignoreErrors*/ true); + const resolvedModule = resolveExternalModuleName( + enclosingDeclaration, + importRef, + /*ignoreErrors*/ true + ); if (!resolvedModule) continue; - const ref = getAliasForSymbolInContainer(resolvedModule, symbol); + const ref = getAliasForSymbolInContainer( + resolvedModule, + symbol + ); if (!ref) continue; results = append(results, resolvedModule); } if (length(results)) { - (links.extendedContainersByFile || (links.extendedContainersByFile = new Map())).set(id, results!); + ( + links.extendedContainersByFile || + (links.extendedContainersByFile = new Map()) + ).set(id, results!); return results!; } } @@ -5321,32 +8452,51 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!ref) continue; results = append(results, sym); } - return links.extendedContainers = results || emptyArray; + return (links.extendedContainers = results || emptyArray); } /** * Attempts to find the symbol corresponding to the container a symbol is in - usually this * is just its' `.parent`, but for locals, this value is `undefined` */ - function getContainersOfSymbol(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags): Symbol[] | undefined { + function getContainersOfSymbol( + symbol: Symbol, + enclosingDeclaration: Node | undefined, + meaning: SymbolFlags + ): Symbol[] | undefined { const container = getParentOfSymbol(symbol); // Type parameters end up in the `members` lists but are not externally visible if (container && !(symbol.flags & SymbolFlags.TypeParameter)) { return getWithAlternativeContainers(container); } - const candidates = mapDefined(symbol.declarations, d => { + const candidates = mapDefined(symbol.declarations, (d) => { if (!isAmbientModule(d) && d.parent) { // direct children of a module if (hasNonGlobalAugmentationExternalModuleSymbol(d.parent)) { return getSymbolOfDeclaration(d.parent as Declaration); } // export ='d member of an ambient module - if (isModuleBlock(d.parent) && d.parent.parent && resolveExternalModuleSymbol(getSymbolOfDeclaration(d.parent.parent)) === symbol) { + if ( + isModuleBlock(d.parent) && + d.parent.parent && + resolveExternalModuleSymbol( + getSymbolOfDeclaration(d.parent.parent) + ) === symbol + ) { return getSymbolOfDeclaration(d.parent.parent); } } - if (isClassExpression(d) && isBinaryExpression(d.parent) && d.parent.operatorToken.kind === SyntaxKind.EqualsToken && isAccessExpression(d.parent.left) && isEntityNameExpression(d.parent.left.expression)) { - if (isModuleExportsAccessExpression(d.parent.left) || isExportsIdentifier(d.parent.left.expression)) { + if ( + isClassExpression(d) && + isBinaryExpression(d.parent) && + d.parent.operatorToken.kind === SyntaxKind.EqualsToken && + isAccessExpression(d.parent.left) && + isEntityNameExpression(d.parent.left.expression) + ) { + if ( + isModuleExportsAccessExpression(d.parent.left) || + isExportsIdentifier(d.parent.left.expression) + ) { return getSymbolOfDeclaration(getSourceFileOfNode(d)); } checkExpressionCached(d.parent.left.expression); @@ -5356,13 +8506,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!length(candidates)) { return undefined; } - const containers = mapDefined(candidates, candidate => getAliasForSymbolInContainer(candidate, symbol) ? candidate : undefined); + const containers = mapDefined(candidates, (candidate) => + getAliasForSymbolInContainer(candidate, symbol) + ? candidate + : undefined + ); let bestContainers: Symbol[] = []; let alternativeContainers: Symbol[] = []; for (const container of containers) { - const [bestMatch, ...rest] = getWithAlternativeContainers(container); + const [bestMatch, ...rest] = + getWithAlternativeContainers(container); bestContainers = append(bestContainers, bestMatch); alternativeContainers = addRange(alternativeContainers, rest); } @@ -5370,56 +8525,106 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return concatenate(bestContainers, alternativeContainers); function getWithAlternativeContainers(container: Symbol) { - const additionalContainers = mapDefined(container.declarations, fileSymbolIfFileSymbolExportEqualsContainer); - const reexportContainers = enclosingDeclaration && getAlternativeContainingModules(symbol, enclosingDeclaration); - const objectLiteralContainer = getVariableDeclarationOfObjectLiteral(container, meaning); + const additionalContainers = mapDefined( + container.declarations, + fileSymbolIfFileSymbolExportEqualsContainer + ); + const reexportContainers = + enclosingDeclaration && + getAlternativeContainingModules(symbol, enclosingDeclaration); + const objectLiteralContainer = + getVariableDeclarationOfObjectLiteral(container, meaning); if ( enclosingDeclaration && container.flags & getQualifiedLeftMeaning(meaning) && - getAccessibleSymbolChain(container, enclosingDeclaration, SymbolFlags.Namespace, /*useOnlyExternalAliasing*/ false) + getAccessibleSymbolChain( + container, + enclosingDeclaration, + SymbolFlags.Namespace, + /*useOnlyExternalAliasing*/ false + ) ) { - return append(concatenate(concatenate([container], additionalContainers), reexportContainers), objectLiteralContainer); // This order expresses a preference for the real container if it is in scope + return append( + concatenate( + concatenate([container], additionalContainers), + reexportContainers + ), + objectLiteralContainer + ); // This order expresses a preference for the real container if it is in scope } // 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 // which may be acting like a namespace (eg, `Symbol` acts like a namespace when looking up `Symbol.toStringTag`) - const firstVariableMatch = !(container.flags & getQualifiedLeftMeaning(meaning)) - && container.flags & SymbolFlags.Type - && getDeclaredTypeOfSymbol(container).flags & TypeFlags.Object - && meaning === SymbolFlags.Value - ? forEachSymbolTableInScope(enclosingDeclaration, t => { - return forEachEntry(t, s => { - if (s.flags & getQualifiedLeftMeaning(meaning) && getTypeOfSymbol(s) === getDeclaredTypeOfSymbol(container)) { - return s; - } - }); - }) : undefined; - let res = firstVariableMatch ? [firstVariableMatch, ...additionalContainers, container] : [...additionalContainers, container]; + const firstVariableMatch = + !(container.flags & getQualifiedLeftMeaning(meaning)) && + container.flags & SymbolFlags.Type && + getDeclaredTypeOfSymbol(container).flags & TypeFlags.Object && + meaning === SymbolFlags.Value + ? forEachSymbolTableInScope(enclosingDeclaration, (t) => { + return forEachEntry(t, (s) => { + if ( + s.flags & getQualifiedLeftMeaning(meaning) && + getTypeOfSymbol(s) === + getDeclaredTypeOfSymbol(container) + ) { + return s; + } + }); + }) + : undefined; + let res = firstVariableMatch + ? [firstVariableMatch, ...additionalContainers, container] + : [...additionalContainers, container]; res = append(res, objectLiteralContainer); res = addRange(res, reexportContainers); return res; } function fileSymbolIfFileSymbolExportEqualsContainer(d: Declaration) { - return container && getFileSymbolIfFileSymbolExportEqualsContainer(d, container); + return ( + container && + getFileSymbolIfFileSymbolExportEqualsContainer(d, container) + ); } } - function getVariableDeclarationOfObjectLiteral(symbol: Symbol, meaning: SymbolFlags) { + function getVariableDeclarationOfObjectLiteral( + symbol: Symbol, + meaning: SymbolFlags + ) { // If we're trying to reference some object literal in, eg `var a = { x: 1 }`, the symbol for the literal, `__object`, is distinct // from the symbol of the declaration it is being assigned to. Since we can use the declaration to refer to the literal, however, // we'd like to make that connection here - potentially causing us to paint the declaration's visibility, and therefore the literal. - const firstDecl: Node | false = !!length(symbol.declarations) && first(symbol.declarations!); - if (meaning & SymbolFlags.Value && firstDecl && firstDecl.parent && isVariableDeclaration(firstDecl.parent)) { - if (isObjectLiteralExpression(firstDecl) && firstDecl === firstDecl.parent.initializer || isTypeLiteralNode(firstDecl) && firstDecl === firstDecl.parent.type) { + const firstDecl: Node | false = + !!length(symbol.declarations) && first(symbol.declarations!); + if ( + meaning & SymbolFlags.Value && + firstDecl && + firstDecl.parent && + isVariableDeclaration(firstDecl.parent) + ) { + if ( + (isObjectLiteralExpression(firstDecl) && + firstDecl === firstDecl.parent.initializer) || + (isTypeLiteralNode(firstDecl) && + firstDecl === firstDecl.parent.type) + ) { return getSymbolOfDeclaration(firstDecl.parent); } } } - function getFileSymbolIfFileSymbolExportEqualsContainer(d: Declaration, container: Symbol) { + function getFileSymbolIfFileSymbolExportEqualsContainer( + d: Declaration, + container: Symbol + ) { const fileSymbol = getExternalModuleContainer(d); - const exported = fileSymbol && fileSymbol.exports && fileSymbol.exports.get(InternalSymbolName.ExportEquals); - return exported && getSymbolIfSameReference(exported, container) ? fileSymbol : undefined; + const exported = + fileSymbol && + fileSymbol.exports && + fileSymbol.exports.get(InternalSymbolName.ExportEquals); + return exported && getSymbolIfSameReference(exported, container) + ? fileSymbol + : undefined; } function getAliasForSymbolInContainer(container: Symbol, symbol: Symbol) { @@ -5429,7 +8634,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Check if container is a thing with an `export=` which points directly at `symbol`, and if so, return // the container itself as the alias for the symbol - const exportEquals = container.exports && container.exports.get(InternalSymbolName.ExportEquals); + const exportEquals = + container.exports && + container.exports.get(InternalSymbolName.ExportEquals); if (exportEquals && getSymbolIfSameReference(exportEquals, symbol)) { return container; } @@ -5438,7 +8645,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (quick && getSymbolIfSameReference(quick, symbol)) { return quick; } - return forEachEntry(exports, exported => { + return forEachEntry(exports, (exported) => { if (getSymbolIfSameReference(exported, symbol)) { return exported; } @@ -5449,21 +8656,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Checks if two symbols, through aliasing and/or merging, refer to the same thing */ function getSymbolIfSameReference(s1: Symbol, s2: Symbol) { - if (getMergedSymbol(resolveSymbol(getMergedSymbol(s1))) === getMergedSymbol(resolveSymbol(getMergedSymbol(s2)))) { + if ( + getMergedSymbol(resolveSymbol(getMergedSymbol(s1))) === + getMergedSymbol(resolveSymbol(getMergedSymbol(s2))) + ) { return s1; } } function getExportSymbolOfValueSymbolIfExported(symbol: Symbol): Symbol; - function getExportSymbolOfValueSymbolIfExported(symbol: Symbol | undefined): Symbol | undefined; - function getExportSymbolOfValueSymbolIfExported(symbol: Symbol | undefined): Symbol | undefined { - return getMergedSymbol(symbol && (symbol.flags & SymbolFlags.ExportValue) !== 0 && symbol.exportSymbol || symbol); + function getExportSymbolOfValueSymbolIfExported( + symbol: Symbol | undefined + ): Symbol | undefined; + function getExportSymbolOfValueSymbolIfExported( + symbol: Symbol | undefined + ): Symbol | undefined { + return getMergedSymbol( + (symbol && + (symbol.flags & SymbolFlags.ExportValue) !== 0 && + symbol.exportSymbol) || + symbol + ); } - function symbolIsValue(symbol: Symbol, includeTypeOnlyMembers?: boolean): boolean { + function symbolIsValue( + symbol: Symbol, + includeTypeOnlyMembers?: boolean + ): boolean { return !!( symbol.flags & SymbolFlags.Value || - symbol.flags & SymbolFlags.Alias && getSymbolFlags(symbol, !includeTypeOnlyMembers) & SymbolFlags.Value + (symbol.flags & SymbolFlags.Alias && + getSymbolFlags(symbol, !includeTypeOnlyMembers) & + SymbolFlags.Value) ); } @@ -5485,25 +8709,45 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return new Type(checker, flags); } - function createIntrinsicType(kind: TypeFlags, intrinsicName: string, objectFlags = ObjectFlags.None, debugIntrinsicName?: string): IntrinsicType { + function createIntrinsicType( + kind: TypeFlags, + intrinsicName: string, + objectFlags = ObjectFlags.None, + debugIntrinsicName?: string + ): IntrinsicType { checkIntrinsicName(intrinsicName, debugIntrinsicName); const type = createType(kind) as IntrinsicType; type.intrinsicName = intrinsicName; type.debugIntrinsicName = debugIntrinsicName; - type.objectFlags = objectFlags | ObjectFlags.CouldContainTypeVariablesComputed | ObjectFlags.IsGenericTypeComputed | ObjectFlags.IsUnknownLikeUnionComputed | ObjectFlags.IsNeverIntersectionComputed; + type.objectFlags = + objectFlags | + ObjectFlags.CouldContainTypeVariablesComputed | + ObjectFlags.IsGenericTypeComputed | + ObjectFlags.IsUnknownLikeUnionComputed | + ObjectFlags.IsNeverIntersectionComputed; return type; } function checkIntrinsicName(name: string, debug: string | undefined) { const key = `${name},${debug ?? ""}`; if (seenIntrinsicNames.has(key)) { - Debug.fail(`Duplicate intrinsic type name ${name}${debug ? ` (${debug})` : ""}; you may need to pass a name to createIntrinsicType.`); + Debug.fail( + `Duplicate intrinsic type name ${name}${ + debug ? ` (${debug})` : "" + }; you may need to pass a name to createIntrinsicType.` + ); } seenIntrinsicNames.add(key); } - function createObjectType(objectFlags: ObjectFlags, symbol?: Symbol): ObjectType { - const type = createTypeWithSymbol(TypeFlags.Object, symbol!) as ObjectType; + function createObjectType( + objectFlags: ObjectFlags, + symbol?: Symbol + ): ObjectType { + const type = createTypeWithSymbol( + TypeFlags.Object, + symbol! + ) as ObjectType; type.objectFlags = objectFlags; type.members = undefined; type.properties = undefined; @@ -5514,11 +8758,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function createTypeofType() { - return getUnionType(arrayFrom(typeofNEFacts.keys(), getStringLiteralType)); + return getUnionType( + arrayFrom(typeofNEFacts.keys(), getStringLiteralType) + ); } function createTypeParameter(symbol?: Symbol) { - return createTypeWithSymbol(TypeFlags.TypeParameter, symbol!) as TypeParameter; + return createTypeWithSymbol( + TypeFlags.TypeParameter, + symbol! + ) as TypeParameter; } // A reserved member name starts with two underscores, but the third character cannot be an underscore, @@ -5526,11 +8775,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // with at least two underscores. The @ character indicates that the name is denoted by a well known ES // Symbol instance and the # character indicates that the name is a PrivateIdentifier. function isReservedMemberName(name: __String) { - return (name as string).charCodeAt(0) === CharacterCodes._ && + return ( + (name as string).charCodeAt(0) === CharacterCodes._ && (name as string).charCodeAt(1) === CharacterCodes._ && (name as string).charCodeAt(2) !== CharacterCodes._ && (name as string).charCodeAt(2) !== CharacterCodes.at && - (name as string).charCodeAt(2) !== CharacterCodes.hash; + (name as string).charCodeAt(2) !== CharacterCodes.hash + ); } function getNamedMembers(members: SymbolTable): Symbol[] { @@ -5553,7 +8804,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return index ? concatenate(result, [index]) : result; } - function setStructuredTypeMembers(type: StructuredType, members: SymbolTable, callSignatures: readonly Signature[], constructSignatures: readonly Signature[], indexInfos: readonly IndexInfo[]): ResolvedType { + function setStructuredTypeMembers( + type: StructuredType, + members: SymbolTable, + callSignatures: readonly Signature[], + constructSignatures: readonly Signature[], + indexInfos: readonly IndexInfo[] + ): ResolvedType { const resolved = type as ResolvedType; resolved.members = members; resolved.properties = emptyArray; @@ -5561,37 +8818,79 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { resolved.constructSignatures = constructSignatures; resolved.indexInfos = indexInfos; // This can loop back to getPropertyOfType() which would crash if `callSignatures` & `constructSignatures` are not initialized. - if (members !== emptySymbols) resolved.properties = getNamedMembers(members); + if (members !== emptySymbols) + resolved.properties = getNamedMembers(members); return resolved; } - function createAnonymousType(symbol: Symbol | undefined, members: SymbolTable, callSignatures: readonly Signature[], constructSignatures: readonly Signature[], indexInfos: readonly IndexInfo[]): ResolvedType { - return setStructuredTypeMembers(createObjectType(ObjectFlags.Anonymous, symbol), members, callSignatures, constructSignatures, indexInfos); + function createAnonymousType( + symbol: Symbol | undefined, + members: SymbolTable, + callSignatures: readonly Signature[], + constructSignatures: readonly Signature[], + indexInfos: readonly IndexInfo[] + ): ResolvedType { + return setStructuredTypeMembers( + createObjectType(ObjectFlags.Anonymous, symbol), + members, + callSignatures, + constructSignatures, + indexInfos + ); } - function getResolvedTypeWithoutAbstractConstructSignatures(type: ResolvedType) { + function getResolvedTypeWithoutAbstractConstructSignatures( + type: ResolvedType + ) { if (type.constructSignatures.length === 0) return type; - if (type.objectTypeWithoutAbstractConstructSignatures) return type.objectTypeWithoutAbstractConstructSignatures; - const constructSignatures = filter(type.constructSignatures, signature => !(signature.flags & SignatureFlags.Abstract)); + if (type.objectTypeWithoutAbstractConstructSignatures) + return type.objectTypeWithoutAbstractConstructSignatures; + const constructSignatures = filter( + type.constructSignatures, + (signature) => !(signature.flags & SignatureFlags.Abstract) + ); if (type.constructSignatures === constructSignatures) return type; const typeCopy = createAnonymousType( type.symbol, type.members, type.callSignatures, some(constructSignatures) ? constructSignatures : emptyArray, - type.indexInfos, + type.indexInfos ); type.objectTypeWithoutAbstractConstructSignatures = typeCopy; typeCopy.objectTypeWithoutAbstractConstructSignatures = typeCopy; return typeCopy; } - function forEachSymbolTableInScope(enclosingDeclaration: Node | undefined, callback: (symbolTable: SymbolTable, ignoreQualification?: boolean, isLocalNameLookup?: boolean, scopeNode?: Node) => T): T { + function forEachSymbolTableInScope( + enclosingDeclaration: Node | undefined, + callback: ( + symbolTable: SymbolTable, + ignoreQualification?: boolean, + isLocalNameLookup?: boolean, + scopeNode?: Node + ) => T + ): T { let result: T; - for (let location = enclosingDeclaration; location; location = location.parent) { + for ( + let location = enclosingDeclaration; + location; + location = location.parent + ) { // Locals of a source file are not in scope (because they get merged into the global symbol table) - if (canHaveLocals(location) && location.locals && !isGlobalSourceFile(location)) { - if (result = callback(location.locals, /*ignoreQualification*/ undefined, /*isLocalNameLookup*/ true, location)) { + if ( + canHaveLocals(location) && + location.locals && + !isGlobalSourceFile(location) + ) { + if ( + (result = callback( + location.locals, + /*ignoreQualification*/ undefined, + /*isLocalNameLookup*/ true, + location + )) + ) { return result; } } @@ -5600,13 +8899,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!isExternalOrCommonJsModule(location as SourceFile)) { break; } - // falls through + // falls through case SyntaxKind.ModuleDeclaration: - const sym = getSymbolOfDeclaration(location as ModuleDeclaration); + const sym = getSymbolOfDeclaration( + location as ModuleDeclaration + ); // `sym` may not have exports if this module declaration is backed by the symbol for a `const` that's being rewritten // into a namespace - in such cases, it's best to just let the namespace appear empty (the const members couldn't have referred // to one another anyway) - if (result = callback(sym?.exports || emptySymbols, /*ignoreQualification*/ undefined, /*isLocalNameLookup*/ true, location)) { + if ( + (result = callback( + sym?.exports || emptySymbols, + /*ignoreQualification*/ undefined, + /*isLocalNameLookup*/ true, + location + )) + ) { return result; } break; @@ -5622,35 +8930,72 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // trigger resolving late-bound names, which we may already be in the process of doing while we're here! let table: Map<__String, Symbol> | undefined; // TODO: Should this filtered table be cached in some way? - (getSymbolOfDeclaration(location as ClassLikeDeclaration | InterfaceDeclaration).members || emptySymbols).forEach((memberSymbol, key) => { - if (memberSymbol.flags & (SymbolFlags.Type & ~SymbolFlags.Assignment)) { - (table || (table = createSymbolTable())).set(key, memberSymbol); + ( + getSymbolOfDeclaration( + location as + | ClassLikeDeclaration + | InterfaceDeclaration + ).members || emptySymbols + ).forEach((memberSymbol, key) => { + if ( + memberSymbol.flags & + (SymbolFlags.Type & ~SymbolFlags.Assignment) + ) { + (table || (table = createSymbolTable())).set( + key, + memberSymbol + ); } }); - if (table && (result = callback(table, /*ignoreQualification*/ undefined, /*isLocalNameLookup*/ false, location))) { + if ( + table && + (result = callback( + table, + /*ignoreQualification*/ undefined, + /*isLocalNameLookup*/ false, + location + )) + ) { return result; } break; } } - return callback(globals, /*ignoreQualification*/ undefined, /*isLocalNameLookup*/ true); + return callback( + globals, + /*ignoreQualification*/ undefined, + /*isLocalNameLookup*/ true + ); } function getQualifiedLeftMeaning(rightMeaning: SymbolFlags) { // If we are looking in value space, the parent meaning is value, other wise it is namespace - return rightMeaning === SymbolFlags.Value ? SymbolFlags.Value : SymbolFlags.Namespace; + return rightMeaning === SymbolFlags.Value + ? SymbolFlags.Value + : SymbolFlags.Namespace; } - function getAccessibleSymbolChain(symbol: Symbol | undefined, enclosingDeclaration: Node | undefined, meaning: SymbolFlags, useOnlyExternalAliasing: boolean, visitedSymbolTablesMap = new Map()): Symbol[] | undefined { + function getAccessibleSymbolChain( + symbol: Symbol | undefined, + enclosingDeclaration: Node | undefined, + meaning: SymbolFlags, + useOnlyExternalAliasing: boolean, + visitedSymbolTablesMap = new Map() + ): Symbol[] | undefined { if (!(symbol && !isPropertyOrMethodDeclarationSymbol(symbol))) { return undefined; } const links = getSymbolLinks(symbol); const cache = (links.accessibleChainCache ||= new Map()); // Go from enclosingDeclaration to the first scope we check, so the cache is keyed off the scope and thus shared more - const firstRelevantLocation = forEachSymbolTableInScope(enclosingDeclaration, (_, __, ___, node) => node); - const key = `${useOnlyExternalAliasing ? 0 : 1}|${firstRelevantLocation ? getNodeId(firstRelevantLocation) : 0}|${meaning}`; + const firstRelevantLocation = forEachSymbolTableInScope( + enclosingDeclaration, + (_, __, ___, node) => node + ); + const key = `${useOnlyExternalAliasing ? 0 : 1}|${ + firstRelevantLocation ? getNodeId(firstRelevantLocation) : 0 + }|${meaning}`; if (cache.has(key)) { return cache.get(key); } @@ -5658,99 +9003,226 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const id = getSymbolId(symbol); let visitedSymbolTables = visitedSymbolTablesMap.get(id); if (!visitedSymbolTables) { - visitedSymbolTablesMap.set(id, visitedSymbolTables = []); + visitedSymbolTablesMap.set(id, (visitedSymbolTables = [])); } - const result = forEachSymbolTableInScope(enclosingDeclaration, getAccessibleSymbolChainFromSymbolTable); + const result = forEachSymbolTableInScope( + enclosingDeclaration, + getAccessibleSymbolChainFromSymbolTable + ); cache.set(key, result); return result; /** * @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) */ - function getAccessibleSymbolChainFromSymbolTable(symbols: SymbolTable, ignoreQualification?: boolean, isLocalNameLookup?: boolean): Symbol[] | undefined { + function getAccessibleSymbolChainFromSymbolTable( + symbols: SymbolTable, + ignoreQualification?: boolean, + isLocalNameLookup?: boolean + ): Symbol[] | undefined { if (!pushIfUnique(visitedSymbolTables!, symbols)) { return undefined; } - const result = trySymbolTable(symbols, ignoreQualification, isLocalNameLookup); + const result = trySymbolTable( + symbols, + ignoreQualification, + isLocalNameLookup + ); visitedSymbolTables!.pop(); return result; } - function canQualifySymbol(symbolFromSymbolTable: Symbol, meaning: SymbolFlags) { + function canQualifySymbol( + symbolFromSymbolTable: Symbol, + meaning: SymbolFlags + ) { // If the symbol is equivalent and doesn't need further qualification, this symbol is accessible - return !needsQualification(symbolFromSymbolTable, enclosingDeclaration, meaning) || + return ( + !needsQualification( + symbolFromSymbolTable, + enclosingDeclaration, + meaning + ) || // If symbol needs qualification, make sure that parent is accessible, if it is then this symbol is accessible too - !!getAccessibleSymbolChain(symbolFromSymbolTable.parent, enclosingDeclaration, getQualifiedLeftMeaning(meaning), useOnlyExternalAliasing, visitedSymbolTablesMap); + !!getAccessibleSymbolChain( + symbolFromSymbolTable.parent, + enclosingDeclaration, + getQualifiedLeftMeaning(meaning), + useOnlyExternalAliasing, + visitedSymbolTablesMap + ) + ); } - function isAccessible(symbolFromSymbolTable: Symbol, resolvedAliasSymbol?: Symbol, ignoreQualification?: boolean) { - return (symbol === (resolvedAliasSymbol || symbolFromSymbolTable) || getMergedSymbol(symbol) === getMergedSymbol(resolvedAliasSymbol || symbolFromSymbolTable)) && + function isAccessible( + symbolFromSymbolTable: Symbol, + resolvedAliasSymbol?: Symbol, + ignoreQualification?: boolean + ) { + return ( + (symbol === (resolvedAliasSymbol || symbolFromSymbolTable) || + getMergedSymbol(symbol) === + getMergedSymbol( + resolvedAliasSymbol || symbolFromSymbolTable + )) && // if the symbolFromSymbolTable is not external module (it could be if it was determined as ambient external module and would be in globals table) // and if symbolFromSymbolTable or alias resolution matches the symbol, // check the symbol can be qualified, it is only then this symbol is accessible - !some(symbolFromSymbolTable.declarations, hasNonGlobalAugmentationExternalModuleSymbol) && - (ignoreQualification || canQualifySymbol(getMergedSymbol(symbolFromSymbolTable), meaning)); + !some( + symbolFromSymbolTable.declarations, + hasNonGlobalAugmentationExternalModuleSymbol + ) && + (ignoreQualification || + canQualifySymbol( + getMergedSymbol(symbolFromSymbolTable), + meaning + )) + ); } - function trySymbolTable(symbols: SymbolTable, ignoreQualification: boolean | undefined, isLocalNameLookup: boolean | undefined): Symbol[] | undefined { + function trySymbolTable( + symbols: SymbolTable, + ignoreQualification: boolean | undefined, + isLocalNameLookup: boolean | undefined + ): Symbol[] | undefined { // If symbol is directly available by its name in the symbol table - if (isAccessible(symbols.get(symbol!.escapedName)!, /*resolvedAliasSymbol*/ undefined, ignoreQualification)) { + if ( + isAccessible( + symbols.get(symbol!.escapedName)!, + /*resolvedAliasSymbol*/ undefined, + ignoreQualification + ) + ) { return [symbol!]; } // Check if symbol is any of the aliases in scope - const result = forEachEntry(symbols, symbolFromSymbolTable => { + const result = forEachEntry(symbols, (symbolFromSymbolTable) => { if ( - symbolFromSymbolTable.flags & SymbolFlags.Alias - && symbolFromSymbolTable.escapedName !== InternalSymbolName.ExportEquals - && symbolFromSymbolTable.escapedName !== InternalSymbolName.Default - && !(isUMDExportSymbol(symbolFromSymbolTable) && enclosingDeclaration && isExternalModule(getSourceFileOfNode(enclosingDeclaration))) + symbolFromSymbolTable.flags & SymbolFlags.Alias && + symbolFromSymbolTable.escapedName !== + InternalSymbolName.ExportEquals && + symbolFromSymbolTable.escapedName !== + InternalSymbolName.Default && + !( + isUMDExportSymbol(symbolFromSymbolTable) && + enclosingDeclaration && + isExternalModule( + getSourceFileOfNode(enclosingDeclaration) + ) + ) && // If `!useOnlyExternalAliasing`, we can use any type of alias to get the name - && (!useOnlyExternalAliasing || some(symbolFromSymbolTable.declarations, isExternalModuleImportEqualsDeclaration)) + (!useOnlyExternalAliasing || + some( + symbolFromSymbolTable.declarations, + isExternalModuleImportEqualsDeclaration + )) && // 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 - && (isLocalNameLookup ? !some(symbolFromSymbolTable.declarations, isNamespaceReexportDeclaration) : true) + (isLocalNameLookup + ? !some( + symbolFromSymbolTable.declarations, + isNamespaceReexportDeclaration + ) + : true) && // While exports are generally considered to be in scope, export-specifier declared symbols are _not_ // See similar comment in `resolveName` for details - && (ignoreQualification || !getDeclarationOfKind(symbolFromSymbolTable, SyntaxKind.ExportSpecifier)) + (ignoreQualification || + !getDeclarationOfKind( + symbolFromSymbolTable, + SyntaxKind.ExportSpecifier + )) ) { - const resolvedImportedSymbol = resolveAlias(symbolFromSymbolTable); - const candidate = getCandidateListForSymbol(symbolFromSymbolTable, resolvedImportedSymbol, ignoreQualification); + const resolvedImportedSymbol = resolveAlias( + symbolFromSymbolTable + ); + const candidate = getCandidateListForSymbol( + symbolFromSymbolTable, + resolvedImportedSymbol, + ignoreQualification + ); if (candidate) { return candidate; } } - if (symbolFromSymbolTable.escapedName === symbol!.escapedName && symbolFromSymbolTable.exportSymbol) { - if (isAccessible(getMergedSymbol(symbolFromSymbolTable.exportSymbol), /*resolvedAliasSymbol*/ undefined, ignoreQualification)) { + if ( + symbolFromSymbolTable.escapedName === symbol!.escapedName && + symbolFromSymbolTable.exportSymbol + ) { + if ( + isAccessible( + getMergedSymbol(symbolFromSymbolTable.exportSymbol), + /*resolvedAliasSymbol*/ undefined, + ignoreQualification + ) + ) { return [symbol!]; } } }); // 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 - return result || (symbols === globals ? getCandidateListForSymbol(globalThisSymbol, globalThisSymbol, ignoreQualification) : undefined); + return ( + result || + (symbols === globals + ? getCandidateListForSymbol( + globalThisSymbol, + globalThisSymbol, + ignoreQualification + ) + : undefined) + ); } - function getCandidateListForSymbol(symbolFromSymbolTable: Symbol, resolvedImportedSymbol: Symbol, ignoreQualification: boolean | undefined) { - if (isAccessible(symbolFromSymbolTable, resolvedImportedSymbol, ignoreQualification)) { + function getCandidateListForSymbol( + symbolFromSymbolTable: Symbol, + resolvedImportedSymbol: Symbol, + ignoreQualification: boolean | undefined + ) { + if ( + isAccessible( + symbolFromSymbolTable, + resolvedImportedSymbol, + ignoreQualification + ) + ) { return [symbolFromSymbolTable]; } // Look in the exported members, if we can find accessibleSymbolChain, symbol is accessible using this chain // but only if the symbolFromSymbolTable can be qualified const candidateTable = getExportsOfSymbol(resolvedImportedSymbol); - const accessibleSymbolsFromExports = candidateTable && getAccessibleSymbolChainFromSymbolTable(candidateTable, /*ignoreQualification*/ true); - if (accessibleSymbolsFromExports && canQualifySymbol(symbolFromSymbolTable, getQualifiedLeftMeaning(meaning))) { - return [symbolFromSymbolTable].concat(accessibleSymbolsFromExports); + const accessibleSymbolsFromExports = + candidateTable && + getAccessibleSymbolChainFromSymbolTable( + candidateTable, + /*ignoreQualification*/ true + ); + if ( + accessibleSymbolsFromExports && + canQualifySymbol( + symbolFromSymbolTable, + getQualifiedLeftMeaning(meaning) + ) + ) { + return [symbolFromSymbolTable].concat( + accessibleSymbolsFromExports + ); } } } - function needsQualification(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags) { + function needsQualification( + symbol: Symbol, + enclosingDeclaration: Node | undefined, + meaning: SymbolFlags + ) { let qualify = false; - forEachSymbolTableInScope(enclosingDeclaration, symbolTable => { + forEachSymbolTableInScope(enclosingDeclaration, (symbolTable) => { // If symbol of this name is not available in the symbol table we are ok - let symbolFromSymbolTable = getMergedSymbol(symbolTable.get(symbol.escapedName)); + let symbolFromSymbolTable = getMergedSymbol( + symbolTable.get(symbol.escapedName) + ); if (!symbolFromSymbolTable) { // Continue to the next symbol table return false; @@ -5762,9 +9234,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Qualify if the symbol from symbol table has same meaning as expected - const shouldResolveAlias = symbolFromSymbolTable.flags & SymbolFlags.Alias && !getDeclarationOfKind(symbolFromSymbolTable, SyntaxKind.ExportSpecifier); - symbolFromSymbolTable = shouldResolveAlias ? resolveAlias(symbolFromSymbolTable) : symbolFromSymbolTable; - const flags = shouldResolveAlias ? getSymbolFlags(symbolFromSymbolTable) : symbolFromSymbolTable.flags; + const shouldResolveAlias = + symbolFromSymbolTable.flags & SymbolFlags.Alias && + !getDeclarationOfKind( + symbolFromSymbolTable, + SyntaxKind.ExportSpecifier + ); + symbolFromSymbolTable = shouldResolveAlias + ? resolveAlias(symbolFromSymbolTable) + : symbolFromSymbolTable; + const flags = shouldResolveAlias + ? getSymbolFlags(symbolFromSymbolTable) + : symbolFromSymbolTable.flags; if (flags & meaning) { qualify = true; return true; @@ -5795,38 +9276,86 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function isTypeSymbolAccessible(typeSymbol: Symbol, enclosingDeclaration: Node | undefined): boolean { - const access = isSymbolAccessibleWorker(typeSymbol, enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false, /*allowModules*/ true); + function isTypeSymbolAccessible( + typeSymbol: Symbol, + enclosingDeclaration: Node | undefined + ): boolean { + const access = isSymbolAccessibleWorker( + typeSymbol, + enclosingDeclaration, + SymbolFlags.Type, + /*shouldComputeAliasesToMakeVisible*/ false, + /*allowModules*/ true + ); return access.accessibility === SymbolAccessibility.Accessible; } - function isValueSymbolAccessible(typeSymbol: Symbol, enclosingDeclaration: Node | undefined): boolean { - const access = isSymbolAccessibleWorker(typeSymbol, enclosingDeclaration, SymbolFlags.Value, /*shouldComputeAliasesToMakeVisible*/ false, /*allowModules*/ true); + function isValueSymbolAccessible( + typeSymbol: Symbol, + enclosingDeclaration: Node | undefined + ): boolean { + const access = isSymbolAccessibleWorker( + typeSymbol, + enclosingDeclaration, + SymbolFlags.Value, + /*shouldComputeAliasesToMakeVisible*/ false, + /*allowModules*/ true + ); return access.accessibility === SymbolAccessibility.Accessible; } - function isSymbolAccessibleByFlags(typeSymbol: Symbol, enclosingDeclaration: Node | undefined, flags: SymbolFlags): boolean { - const access = isSymbolAccessibleWorker(typeSymbol, enclosingDeclaration, flags, /*shouldComputeAliasesToMakeVisible*/ false, /*allowModules*/ false); + function isSymbolAccessibleByFlags( + typeSymbol: Symbol, + enclosingDeclaration: Node | undefined, + flags: SymbolFlags + ): boolean { + const access = isSymbolAccessibleWorker( + typeSymbol, + enclosingDeclaration, + flags, + /*shouldComputeAliasesToMakeVisible*/ false, + /*allowModules*/ false + ); return access.accessibility === SymbolAccessibility.Accessible; } - function isAnySymbolAccessible(symbols: Symbol[] | undefined, enclosingDeclaration: Node | undefined, initialSymbol: Symbol, meaning: SymbolFlags, shouldComputeAliasesToMakeVisible: boolean, allowModules: boolean): SymbolAccessibilityResult | undefined { + function isAnySymbolAccessible( + symbols: Symbol[] | undefined, + enclosingDeclaration: Node | undefined, + initialSymbol: Symbol, + meaning: SymbolFlags, + shouldComputeAliasesToMakeVisible: boolean, + allowModules: boolean + ): SymbolAccessibilityResult | undefined { if (!length(symbols)) return; let hadAccessibleChain: Symbol | undefined; let earlyModuleBail = false; for (const symbol of symbols!) { // Symbol is accessible if it by itself is accessible - const accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaning, /*useOnlyExternalAliasing*/ false); + const accessibleSymbolChain = getAccessibleSymbolChain( + symbol, + enclosingDeclaration, + meaning, + /*useOnlyExternalAliasing*/ false + ); if (accessibleSymbolChain) { hadAccessibleChain = symbol; - const hasAccessibleDeclarations = hasVisibleDeclarations(accessibleSymbolChain[0], shouldComputeAliasesToMakeVisible); + const hasAccessibleDeclarations = hasVisibleDeclarations( + accessibleSymbolChain[0], + shouldComputeAliasesToMakeVisible + ); if (hasAccessibleDeclarations) { return hasAccessibleDeclarations; } } if (allowModules) { - if (some(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol)) { + if ( + some( + symbol.declarations, + hasNonGlobalAugmentationExternalModuleSymbol + ) + ) { if (shouldComputeAliasesToMakeVisible) { earlyModuleBail = true; // Generally speaking, we want to use the aliases that already exist to refer to a module, if present @@ -5855,8 +9384,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // But it can't, hence the accessible is going to be undefined, but that doesn't mean m.c is inaccessible // It is accessible if the parent m is accessible because then m.c can be accessed through qualification - const containers = getContainersOfSymbol(symbol, enclosingDeclaration, meaning); - const parentResult = isAnySymbolAccessible(containers, enclosingDeclaration, initialSymbol, initialSymbol === symbol ? getQualifiedLeftMeaning(meaning) : meaning, shouldComputeAliasesToMakeVisible, allowModules); + const containers = getContainersOfSymbol( + symbol, + enclosingDeclaration, + meaning + ); + const parentResult = isAnySymbolAccessible( + containers, + enclosingDeclaration, + initialSymbol, + initialSymbol === symbol + ? getQualifiedLeftMeaning(meaning) + : meaning, + shouldComputeAliasesToMakeVisible, + allowModules + ); if (parentResult) { return parentResult; } @@ -5871,8 +9413,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (hadAccessibleChain) { return { accessibility: SymbolAccessibility.NotAccessible, - errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning), - errorModuleName: hadAccessibleChain !== initialSymbol ? symbolToString(hadAccessibleChain, enclosingDeclaration, SymbolFlags.Namespace) : undefined, + errorSymbolName: symbolToString( + initialSymbol, + enclosingDeclaration, + meaning + ), + errorModuleName: + hadAccessibleChain !== initialSymbol + ? symbolToString( + hadAccessibleChain, + enclosingDeclaration, + SymbolFlags.Namespace + ) + : undefined, }; } } @@ -5885,29 +9438,63 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param meaning a SymbolFlags to check if such meaning of the symbol is accessible * @param shouldComputeAliasToMakeVisible a boolean value to indicate whether to return aliases to be mark visible in case the symbol is accessible */ - function isSymbolAccessible(symbol: Symbol | undefined, enclosingDeclaration: Node | undefined, meaning: SymbolFlags, shouldComputeAliasesToMakeVisible: boolean): SymbolAccessibilityResult { - return isSymbolAccessibleWorker(symbol, enclosingDeclaration, meaning, shouldComputeAliasesToMakeVisible, /*allowModules*/ true); + function isSymbolAccessible( + symbol: Symbol | undefined, + enclosingDeclaration: Node | undefined, + meaning: SymbolFlags, + shouldComputeAliasesToMakeVisible: boolean + ): SymbolAccessibilityResult { + return isSymbolAccessibleWorker( + symbol, + enclosingDeclaration, + meaning, + shouldComputeAliasesToMakeVisible, + /*allowModules*/ true + ); } - function isSymbolAccessibleWorker(symbol: Symbol | undefined, enclosingDeclaration: Node | undefined, meaning: SymbolFlags, shouldComputeAliasesToMakeVisible: boolean, allowModules: boolean): SymbolAccessibilityResult { + function isSymbolAccessibleWorker( + symbol: Symbol | undefined, + enclosingDeclaration: Node | undefined, + meaning: SymbolFlags, + shouldComputeAliasesToMakeVisible: boolean, + allowModules: boolean + ): SymbolAccessibilityResult { if (symbol && enclosingDeclaration) { - const result = isAnySymbolAccessible([symbol], enclosingDeclaration, symbol, meaning, shouldComputeAliasesToMakeVisible, allowModules); + const result = isAnySymbolAccessible( + [symbol], + enclosingDeclaration, + symbol, + meaning, + shouldComputeAliasesToMakeVisible, + allowModules + ); if (result) { return result; } // This could be a symbol that is not exported in the external module // or it could be a symbol from different external module that is not aliased and hence cannot be named - const symbolExternalModule = forEach(symbol.declarations, getExternalModuleContainer); + const symbolExternalModule = forEach( + symbol.declarations, + getExternalModuleContainer + ); if (symbolExternalModule) { - const enclosingExternalModule = getExternalModuleContainer(enclosingDeclaration); + const enclosingExternalModule = + getExternalModuleContainer(enclosingDeclaration); if (symbolExternalModule !== enclosingExternalModule) { // name from different external module that is not visible return { accessibility: SymbolAccessibility.CannotBeNamed, - errorSymbolName: symbolToString(symbol, enclosingDeclaration, meaning), + errorSymbolName: symbolToString( + symbol, + enclosingDeclaration, + meaning + ), errorModuleName: symbolToString(symbolExternalModule), - errorNode: isInJSFile(enclosingDeclaration) ? enclosingDeclaration : undefined, + errorNode: isInJSFile(enclosingDeclaration) + ? enclosingDeclaration + : undefined, }; } } @@ -5915,7 +9502,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Just a local name that is not accessible return { accessibility: SymbolAccessibility.NotAccessible, - errorSymbolName: symbolToString(symbol, enclosingDeclaration, meaning), + errorSymbolName: symbolToString( + symbol, + enclosingDeclaration, + meaning + ), }; } @@ -5924,23 +9515,50 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getExternalModuleContainer(declaration: Node) { const node = findAncestor(declaration, hasExternalModuleSymbol); - return node && getSymbolOfDeclaration(node as AmbientModuleDeclaration | SourceFile); + return ( + node && + getSymbolOfDeclaration( + node as AmbientModuleDeclaration | SourceFile + ) + ); } function hasExternalModuleSymbol(declaration: Node) { - return isAmbientModule(declaration) || (declaration.kind === SyntaxKind.SourceFile && isExternalOrCommonJsModule(declaration as SourceFile)); + return ( + isAmbientModule(declaration) || + (declaration.kind === SyntaxKind.SourceFile && + isExternalOrCommonJsModule(declaration as SourceFile)) + ); } function hasNonGlobalAugmentationExternalModuleSymbol(declaration: Node) { - return isModuleWithStringLiteralName(declaration) || (declaration.kind === SyntaxKind.SourceFile && isExternalOrCommonJsModule(declaration as SourceFile)); + return ( + isModuleWithStringLiteralName(declaration) || + (declaration.kind === SyntaxKind.SourceFile && + isExternalOrCommonJsModule(declaration as SourceFile)) + ); } - function hasVisibleDeclarations(symbol: Symbol, shouldComputeAliasToMakeVisible: boolean): SymbolVisibilityResult | undefined { + function hasVisibleDeclarations( + symbol: Symbol, + shouldComputeAliasToMakeVisible: boolean + ): SymbolVisibilityResult | undefined { let aliasesToMakeVisible: LateVisibilityPaintedStatement[] | undefined; - if (!every(filter(symbol.declarations, d => d.kind !== SyntaxKind.Identifier), getIsDeclarationVisible)) { + if ( + !every( + filter( + symbol.declarations, + (d) => d.kind !== SyntaxKind.Identifier + ), + getIsDeclarationVisible + ) + ) { return undefined; } - return { accessibility: SymbolAccessibility.Accessible, aliasesToMakeVisible }; + return { + accessibility: SymbolAccessibility.Accessible, + aliasesToMakeVisible, + }; function getIsDeclarationVisible(declaration: Declaration) { if (!isDeclarationVisible(declaration)) { @@ -5950,39 +9568,66 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const anyImportSyntax = getAnyImportSyntax(declaration); if ( anyImportSyntax && - !hasSyntacticModifier(anyImportSyntax, ModifierFlags.Export) && // import clause without export + !hasSyntacticModifier( + anyImportSyntax, + ModifierFlags.Export + ) && // import clause without export isDeclarationVisible(anyImportSyntax.parent) ) { return addVisibleAlias(declaration, anyImportSyntax); - } - else if ( - isVariableDeclaration(declaration) && isVariableStatement(declaration.parent.parent) && - !hasSyntacticModifier(declaration.parent.parent, ModifierFlags.Export) && // unexported variable statement + } else if ( + isVariableDeclaration(declaration) && + isVariableStatement(declaration.parent.parent) && + !hasSyntacticModifier( + declaration.parent.parent, + ModifierFlags.Export + ) && // unexported variable statement isDeclarationVisible(declaration.parent.parent.parent) ) { - return addVisibleAlias(declaration, declaration.parent.parent); - } - else if ( - isLateVisibilityPaintedStatement(declaration) // unexported top-level statement - && !hasSyntacticModifier(declaration, ModifierFlags.Export) - && isDeclarationVisible(declaration.parent) + return addVisibleAlias( + declaration, + declaration.parent.parent + ); + } else if ( + isLateVisibilityPaintedStatement(declaration) && // unexported top-level statement + !hasSyntacticModifier(declaration, ModifierFlags.Export) && + isDeclarationVisible(declaration.parent) ) { return addVisibleAlias(declaration, declaration); - } - else if (isBindingElement(declaration)) { + } else if (isBindingElement(declaration)) { if ( - symbol.flags & SymbolFlags.Alias && isInJSFile(declaration) && declaration.parent?.parent // exported import-like top-level JS require statement - && isVariableDeclaration(declaration.parent.parent) - && declaration.parent.parent.parent?.parent && isVariableStatement(declaration.parent.parent.parent.parent) - && !hasSyntacticModifier(declaration.parent.parent.parent.parent, ModifierFlags.Export) - && declaration.parent.parent.parent.parent.parent // check if the thing containing the variable statement is visible (ie, the file) - && isDeclarationVisible(declaration.parent.parent.parent.parent.parent) + symbol.flags & SymbolFlags.Alias && + isInJSFile(declaration) && + declaration.parent?.parent && // exported import-like top-level JS require statement + isVariableDeclaration(declaration.parent.parent) && + declaration.parent.parent.parent?.parent && + isVariableStatement( + declaration.parent.parent.parent.parent + ) && + !hasSyntacticModifier( + declaration.parent.parent.parent.parent, + ModifierFlags.Export + ) && + declaration.parent.parent.parent.parent.parent && // check if the thing containing the variable statement is visible (ie, the file) + isDeclarationVisible( + declaration.parent.parent.parent.parent.parent + ) ) { - return addVisibleAlias(declaration, declaration.parent.parent.parent.parent); - } - else if (symbol.flags & SymbolFlags.BlockScopedVariable) { - const variableStatement = findAncestor(declaration, isVariableStatement)!; - if (hasSyntacticModifier(variableStatement, ModifierFlags.Export)) { + return addVisibleAlias( + declaration, + declaration.parent.parent.parent.parent + ); + } else if (symbol.flags & SymbolFlags.BlockScopedVariable) { + const variableStatement = findAncestor( + declaration, + isVariableStatement + )!; + if ( + hasSyntacticModifier( + variableStatement, + ModifierFlags.Export + ) + ) { return true; } if (!isDeclarationVisible(variableStatement.parent)) { @@ -5999,56 +9644,101 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; } - function addVisibleAlias(declaration: Declaration, aliasingStatement: LateVisibilityPaintedStatement) { + function addVisibleAlias( + declaration: Declaration, + aliasingStatement: LateVisibilityPaintedStatement + ) { // In function "buildTypeDisplay" where we decide whether to write type-alias or serialize types, // we want to just check if type- alias is accessible or not but we don't care about emitting those alias at that time // since we will do the emitting later in trackSymbol. if (shouldComputeAliasToMakeVisible) { getNodeLinks(declaration).isVisible = true; - aliasesToMakeVisible = appendIfUnique(aliasesToMakeVisible, aliasingStatement); + aliasesToMakeVisible = appendIfUnique( + aliasesToMakeVisible, + aliasingStatement + ); } return true; } } - function getMeaningOfEntityNameReference(entityName: EntityNameOrEntityNameExpression): SymbolFlags { + function getMeaningOfEntityNameReference( + entityName: EntityNameOrEntityNameExpression + ): SymbolFlags { // get symbol of the first identifier of the entityName let meaning: SymbolFlags; if ( entityName.parent.kind === SyntaxKind.TypeQuery || - entityName.parent.kind === SyntaxKind.ExpressionWithTypeArguments && !isPartOfTypeNode(entityName.parent) || + (entityName.parent.kind === + SyntaxKind.ExpressionWithTypeArguments && + !isPartOfTypeNode(entityName.parent)) || entityName.parent.kind === SyntaxKind.ComputedPropertyName || - entityName.parent.kind === SyntaxKind.TypePredicate && (entityName.parent as TypePredicateNode).parameterName === entityName + (entityName.parent.kind === SyntaxKind.TypePredicate && + (entityName.parent as TypePredicateNode).parameterName === + entityName) ) { // Typeof value meaning = SymbolFlags.Value | SymbolFlags.ExportValue; - } - else if ( - entityName.kind === SyntaxKind.QualifiedName || entityName.kind === SyntaxKind.PropertyAccessExpression || + } else if ( + entityName.kind === SyntaxKind.QualifiedName || + entityName.kind === SyntaxKind.PropertyAccessExpression || entityName.parent.kind === SyntaxKind.ImportEqualsDeclaration || - (entityName.parent.kind === SyntaxKind.QualifiedName && (entityName.parent as QualifiedName).left === entityName) || - (entityName.parent.kind === SyntaxKind.PropertyAccessExpression && (entityName.parent as PropertyAccessExpression).expression === entityName) || - (entityName.parent.kind === SyntaxKind.ElementAccessExpression && (entityName.parent as ElementAccessExpression).expression === entityName) + (entityName.parent.kind === SyntaxKind.QualifiedName && + (entityName.parent as QualifiedName).left === entityName) || + (entityName.parent.kind === SyntaxKind.PropertyAccessExpression && + (entityName.parent as PropertyAccessExpression).expression === + entityName) || + (entityName.parent.kind === SyntaxKind.ElementAccessExpression && + (entityName.parent as ElementAccessExpression).expression === + entityName) ) { // Left identifier from type reference or TypeAlias // Entity name of the import declaration meaning = SymbolFlags.Namespace; - } - else { + } else { // Type Reference or TypeAlias entity = Identifier meaning = SymbolFlags.Type; } return meaning; } - function isEntityNameVisible(entityName: EntityNameOrEntityNameExpression, enclosingDeclaration: Node, shouldComputeAliasToMakeVisible = true): SymbolVisibilityResult { + function isEntityNameVisible( + entityName: EntityNameOrEntityNameExpression, + enclosingDeclaration: Node, + shouldComputeAliasToMakeVisible = true + ): SymbolVisibilityResult { const meaning = getMeaningOfEntityNameReference(entityName); const firstIdentifier = getFirstIdentifier(entityName); - const symbol = resolveName(enclosingDeclaration, firstIdentifier.escapedText, meaning, /*nameNotFoundMessage*/ undefined, /*isUse*/ false); - if (symbol && symbol.flags & SymbolFlags.TypeParameter && meaning & SymbolFlags.Type) { + const symbol = resolveName( + enclosingDeclaration, + firstIdentifier.escapedText, + meaning, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ false + ); + if ( + symbol && + symbol.flags & SymbolFlags.TypeParameter && + meaning & SymbolFlags.Type + ) { return { accessibility: SymbolAccessibility.Accessible }; } - if (!symbol && isThisIdentifier(firstIdentifier) && isSymbolAccessible(getSymbolOfDeclaration(getThisContainer(firstIdentifier, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false)), firstIdentifier, meaning, /*shouldComputeAliasesToMakeVisible*/ false).accessibility === SymbolAccessibility.Accessible) { + if ( + !symbol && + isThisIdentifier(firstIdentifier) && + isSymbolAccessible( + getSymbolOfDeclaration( + getThisContainer( + firstIdentifier, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false + ) + ), + firstIdentifier, + meaning, + /*shouldComputeAliasesToMakeVisible*/ false + ).accessibility === SymbolAccessibility.Accessible + ) { return { accessibility: SymbolAccessibility.Accessible }; } @@ -6060,14 +9750,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { }; } // Verify if the symbol is accessible - return hasVisibleDeclarations(symbol, shouldComputeAliasToMakeVisible) || { - accessibility: SymbolAccessibility.NotAccessible, - errorSymbolName: getTextOfNode(firstIdentifier), - errorNode: firstIdentifier, - }; + return ( + hasVisibleDeclarations(symbol, shouldComputeAliasToMakeVisible) || { + accessibility: SymbolAccessibility.NotAccessible, + errorSymbolName: getTextOfNode(firstIdentifier), + errorNode: firstIdentifier, + } + ); } - function symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags: SymbolFormatFlags = SymbolFormatFlags.AllowAnyNodeKind, writer?: EmitTextWriter): string { + function symbolToString( + symbol: Symbol, + enclosingDeclaration?: Node, + meaning?: SymbolFlags, + flags: SymbolFormatFlags = SymbolFormatFlags.AllowAnyNodeKind, + writer?: EmitTextWriter + ): string { let nodeFlags = NodeBuilderFlags.IgnoreErrors; let internalNodeFlags = InternalNodeBuilderFlags.None; if (flags & SymbolFormatFlags.UseOnlyExternalAliasing) { @@ -6080,22 +9778,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { nodeFlags |= NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope; } if (flags & SymbolFormatFlags.DoNotIncludeSymbolChain) { - internalNodeFlags |= InternalNodeBuilderFlags.DoNotIncludeSymbolChain; + internalNodeFlags |= + InternalNodeBuilderFlags.DoNotIncludeSymbolChain; } if (flags & SymbolFormatFlags.WriteComputedProps) { internalNodeFlags |= InternalNodeBuilderFlags.WriteComputedProps; } - const builder = flags & SymbolFormatFlags.AllowAnyNodeKind ? nodeBuilder.symbolToNode : nodeBuilder.symbolToEntityName; - return writer ? symbolToStringWorker(writer).getText() : usingSingleLineStringWriter(symbolToStringWorker); + const builder = + flags & SymbolFormatFlags.AllowAnyNodeKind + ? nodeBuilder.symbolToNode + : nodeBuilder.symbolToEntityName; + return writer + ? symbolToStringWorker(writer).getText() + : usingSingleLineStringWriter(symbolToStringWorker); function symbolToStringWorker(writer: EmitTextWriter) { - const entity = builder(symbol, meaning!, enclosingDeclaration, nodeFlags, internalNodeFlags)!; // TODO: GH#18217 + const entity = builder( + symbol, + meaning!, + enclosingDeclaration, + nodeFlags, + internalNodeFlags + )!; // TODO: GH#18217 // add neverAsciiEscape for GH#39027 - const printer = enclosingDeclaration?.kind === SyntaxKind.SourceFile - ? createPrinterWithRemoveCommentsNeverAsciiEscape() - : createPrinterWithRemoveComments(); - const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); - printer.writeNode(EmitHint.Unspecified, entity, /*sourceFile*/ sourceFile, writer); + const printer = + enclosingDeclaration?.kind === SyntaxKind.SourceFile + ? createPrinterWithRemoveCommentsNeverAsciiEscape() + : createPrinterWithRemoveComments(); + const sourceFile = + enclosingDeclaration && + getSourceFileOfNode(enclosingDeclaration); + printer.writeNode( + EmitHint.Unspecified, + entity, + /*sourceFile*/ sourceFile, + writer + ); return writer; } } @@ -6108,32 +9826,49 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { writer?: EmitTextWriter, maximumLength?: number, verbosityLevel?: number, - out?: WriterContextOut, + out?: WriterContextOut ): string { - return writer ? signatureToStringWorker(writer).getText() : usingSingleLineStringWriter(signatureToStringWorker); + return writer + ? signatureToStringWorker(writer).getText() + : usingSingleLineStringWriter(signatureToStringWorker); function signatureToStringWorker(writer: EmitTextWriter) { let sigOutput: SyntaxKind; if (flags & TypeFormatFlags.WriteArrowStyleSignature) { - sigOutput = kind === SignatureKind.Construct ? SyntaxKind.ConstructorType : SyntaxKind.FunctionType; - } - else { - sigOutput = kind === SignatureKind.Construct ? SyntaxKind.ConstructSignature : SyntaxKind.CallSignature; + sigOutput = + kind === SignatureKind.Construct + ? SyntaxKind.ConstructorType + : SyntaxKind.FunctionType; + } else { + sigOutput = + kind === SignatureKind.Construct + ? SyntaxKind.ConstructSignature + : SyntaxKind.CallSignature; } const sig = nodeBuilder.signatureToSignatureDeclaration( signature, sigOutput, enclosingDeclaration, - toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName, + toNodeBuilderFlags(flags) | + NodeBuilderFlags.IgnoreErrors | + NodeBuilderFlags.WriteTypeParametersInQualifiedName, /*internalFlags*/ undefined, /*tracker*/ undefined, maximumLength, verbosityLevel, - out, + out ); - const printer = createPrinterWithRemoveCommentsOmitTrailingSemicolon(); - const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); - printer.writeNode(EmitHint.Unspecified, sig!, /*sourceFile*/ sourceFile, getTrailingSemicolonDeferringWriter(writer)); // TODO: GH#18217 + const printer = + createPrinterWithRemoveCommentsOmitTrailingSemicolon(); + const sourceFile = + enclosingDeclaration && + getSourceFileOfNode(enclosingDeclaration); + printer.writeNode( + EmitHint.Unspecified, + sig!, + /*sourceFile*/ sourceFile, + getTrailingSemicolonDeferringWriter(writer) + ); // TODO: GH#18217 return writer; } } @@ -6141,42 +9876,67 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function typeToString( type: Type, enclosingDeclaration?: Node, - flags: TypeFormatFlags = TypeFormatFlags.AllowUniqueESSymbolType | TypeFormatFlags.UseAliasDefinedOutsideCurrentScope, + flags: TypeFormatFlags = TypeFormatFlags.AllowUniqueESSymbolType | + TypeFormatFlags.UseAliasDefinedOutsideCurrentScope, writer: EmitTextWriter = createTextWriter(""), maximumLength?: number, verbosityLevel?: number, - out?: WriterContextOut, + out?: WriterContextOut ): string { - const noTruncation = compilerOptions.noErrorTruncation || + const noTruncation = + compilerOptions.noErrorTruncation || flags & TypeFormatFlags.NoTruncation; const typeNode = nodeBuilder.typeToTypeNode( type, enclosingDeclaration, - toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | (noTruncation ? NodeBuilderFlags.NoTruncation : 0), + toNodeBuilderFlags(flags) | + NodeBuilderFlags.IgnoreErrors | + (noTruncation ? NodeBuilderFlags.NoTruncation : 0), /*internalFlags*/ undefined, /*tracker*/ undefined, maximumLength, verbosityLevel, - out, + out ); - if (typeNode === undefined) return Debug.fail("should always get typenode"); + if (typeNode === undefined) + return Debug.fail("should always get typenode"); // The unresolved type gets a synthesized comment on `any` to hint to users that it's not a plain `any`. // Otherwise, we always strip comments out. - const printer = type !== unresolvedType ? createPrinterWithRemoveComments() : createPrinterWithDefaults(); - const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); - printer.writeNode(EmitHint.Unspecified, typeNode, /*sourceFile*/ sourceFile, writer); + const printer = + type !== unresolvedType + ? createPrinterWithRemoveComments() + : createPrinterWithDefaults(); + const sourceFile = + enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); + printer.writeNode( + EmitHint.Unspecified, + typeNode, + /*sourceFile*/ sourceFile, + writer + ); const result = writer.getText(); - const maxLength = maximumLength || (noTruncation ? noTruncationMaximumTruncationLength * 2 : defaultMaximumTruncationLength * 2); + const maxLength = + maximumLength || + (noTruncation + ? noTruncationMaximumTruncationLength * 2 + : defaultMaximumTruncationLength * 2); if (maxLength && result && result.length >= maxLength) { return result.substr(0, maxLength - "...".length) + "..."; } return result; } - function getTypeNamesForErrorDisplay(left: Type, right: Type): [string, string] { - let leftStr = symbolValueDeclarationIsContextSensitive(left.symbol) ? typeToString(left, left.symbol.valueDeclaration) : typeToString(left); - let rightStr = symbolValueDeclarationIsContextSensitive(right.symbol) ? typeToString(right, right.symbol.valueDeclaration) : typeToString(right); + function getTypeNamesForErrorDisplay( + left: Type, + right: Type + ): [string, string] { + let leftStr = symbolValueDeclarationIsContextSensitive(left.symbol) + ? typeToString(left, left.symbol.valueDeclaration) + : typeToString(left); + let rightStr = symbolValueDeclarationIsContextSensitive(right.symbol) + ? typeToString(right, right.symbol.valueDeclaration) + : typeToString(right); if (leftStr === rightStr) { leftStr = getTypeNameForErrorDisplay(left); rightStr = getTypeNameForErrorDisplay(right); @@ -6185,19 +9945,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getTypeNameForErrorDisplay(type: Type) { - return typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType); + return typeToString( + type, + /*enclosingDeclaration*/ undefined, + TypeFormatFlags.UseFullyQualifiedType + ); } function symbolValueDeclarationIsContextSensitive(symbol: Symbol): boolean { - return symbol && !!symbol.valueDeclaration && isExpression(symbol.valueDeclaration) && !isContextSensitive(symbol.valueDeclaration); + return ( + symbol && + !!symbol.valueDeclaration && + isExpression(symbol.valueDeclaration) && + !isContextSensitive(symbol.valueDeclaration) + ); } - function toNodeBuilderFlags(flags = TypeFormatFlags.None): NodeBuilderFlags { + function toNodeBuilderFlags( + flags = TypeFormatFlags.None + ): NodeBuilderFlags { return flags & TypeFormatFlags.NodeBuilderFlagsMask; } function isClassInstanceSide(type: Type) { - return !!type.symbol && !!(type.symbol.flags & SymbolFlags.Class) && (type === getDeclaredTypeOfClassOrInterface(type.symbol) || (!!(type.flags & TypeFlags.Object) && !!(getObjectFlags(type) & ObjectFlags.IsClassInstanceClone))); + return ( + !!type.symbol && + !!(type.symbol.flags & SymbolFlags.Class) && + (type === getDeclaredTypeOfClassOrInterface(type.symbol) || + (!!(type.flags & TypeFlags.Object) && + !!( + getObjectFlags(type) & ObjectFlags.IsClassInstanceClone + ))) + ); } /** * Same as getTypeFromTypeNode, but for use in createNodeBuilder @@ -6212,25 +9991,52 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { evaluateEntityNameExpression, isExpandoFunctionDeclaration, hasLateBindableName, - shouldRemoveDeclaration(context: SyntacticTypeNodeBuilderContext, node: DynamicNamedDeclaration) { - return !((context as NodeBuilderContext).internalFlags & InternalNodeBuilderFlags.AllowUnresolvedNames && isEntityNameExpression(node.name.expression) && checkComputedPropertyName(node.name).flags & TypeFlags.Any); + shouldRemoveDeclaration( + context: SyntacticTypeNodeBuilderContext, + node: DynamicNamedDeclaration + ) { + return !( + (context as NodeBuilderContext).internalFlags & + InternalNodeBuilderFlags.AllowUnresolvedNames && + isEntityNameExpression(node.name.expression) && + checkComputedPropertyName(node.name).flags & TypeFlags.Any + ); }, createRecoveryBoundary(context) { return createRecoveryBoundary(context as NodeBuilderContext); }, isDefinitelyReferenceToGlobalSymbolObject, - getAllAccessorDeclarations: getAllAccessorDeclarationsForDeclaration, - requiresAddingImplicitUndefined(declaration: ParameterDeclaration | JSDocParameterTag | PropertyDeclaration | PropertySignature | JSDocPropertyTag, symbol: Symbol | undefined, enclosingDeclaration: Node | undefined): boolean { + getAllAccessorDeclarations: + getAllAccessorDeclarationsForDeclaration, + requiresAddingImplicitUndefined( + declaration: + | ParameterDeclaration + | JSDocParameterTag + | PropertyDeclaration + | PropertySignature + | JSDocPropertyTag, + symbol: Symbol | undefined, + enclosingDeclaration: Node | undefined + ): boolean { switch (declaration.kind) { case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: case SyntaxKind.JSDocPropertyTag: symbol ??= getSymbolOfDeclaration(declaration); const type = getTypeOfSymbol(symbol); - return !!(symbol.flags & SymbolFlags.Property && symbol.flags & SymbolFlags.Optional && isOptionalDeclaration(declaration) && (symbol as MappedSymbol).links?.mappedType && containsNonMissingUndefinedType(type)); + return !!( + symbol.flags & SymbolFlags.Property && + symbol.flags & SymbolFlags.Optional && + isOptionalDeclaration(declaration) && + (symbol as MappedSymbol).links?.mappedType && + containsNonMissingUndefinedType(type) + ); case SyntaxKind.Parameter: case SyntaxKind.JSDocParameterTag: - return requiresAddingImplicitUndefined(declaration, enclosingDeclaration); + return requiresAddingImplicitUndefined( + declaration, + enclosingDeclaration + ); default: Debug.assertNever(declaration); } @@ -6239,104 +10045,260 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { isUndefinedIdentifierExpression(node: Identifier) { return getSymbolAtLocation(node) === undefinedSymbol; }, - isEntityNameVisible(context, entityName, shouldComputeAliasToMakeVisible) { - return isEntityNameVisible(entityName, context.enclosingDeclaration!, shouldComputeAliasToMakeVisible); + isEntityNameVisible( + context, + entityName, + shouldComputeAliasToMakeVisible + ) { + return isEntityNameVisible( + entityName, + context.enclosingDeclaration!, + shouldComputeAliasToMakeVisible + ); }, serializeExistingTypeNode(context, typeNode, addUndefined) { - return serializeExistingTypeNode(context as NodeBuilderContext, typeNode, !!addUndefined); + return serializeExistingTypeNode( + context as NodeBuilderContext, + typeNode, + !!addUndefined + ); }, - serializeReturnTypeForSignature(syntacticContext, signatureDeclaration, symbol) { + serializeReturnTypeForSignature( + syntacticContext, + signatureDeclaration, + symbol + ) { const context = syntacticContext as NodeBuilderContext; - const signature = getSignatureFromDeclaration(signatureDeclaration); + const signature = + getSignatureFromDeclaration(signatureDeclaration); symbol ??= getSymbolOfDeclaration(signatureDeclaration); - const returnType = context.enclosingSymbolTypes.get(getSymbolId(symbol)) ?? instantiateType(getReturnTypeOfSignature(signature), context.mapper); - return serializeInferredReturnTypeForSignature(context, signature, returnType); + const returnType = + context.enclosingSymbolTypes.get(getSymbolId(symbol)) ?? + instantiateType( + getReturnTypeOfSignature(signature), + context.mapper + ); + return serializeInferredReturnTypeForSignature( + context, + signature, + returnType + ); }, serializeTypeOfExpression(syntacticContext, expr) { const context = syntacticContext as NodeBuilderContext; - const type = instantiateType(getWidenedType(getRegularTypeOfExpression(expr)), context.mapper); + const type = instantiateType( + getWidenedType(getRegularTypeOfExpression(expr)), + context.mapper + ); return typeToTypeNodeHelper(type, context); }, serializeTypeOfDeclaration(syntacticContext, declaration, symbol) { // Get type of the symbol if this is the valid symbol otherwise get type at location const context = syntacticContext as NodeBuilderContext; symbol ??= getSymbolOfDeclaration(declaration); - let type = context.enclosingSymbolTypes?.get(getSymbolId(symbol)); + let type = context.enclosingSymbolTypes?.get( + getSymbolId(symbol) + ); if (type === undefined) { - type = symbol.flags & SymbolFlags.Accessor && declaration.kind === SyntaxKind.SetAccessor ? instantiateType(getWriteTypeOfSymbol(symbol), context.mapper) : - symbol && !(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.Signature)) - ? instantiateType(getWidenedLiteralType(getTypeOfSymbol(symbol)), context.mapper) - : errorType; - } - const addUndefinedForParameter = declaration && (isParameter(declaration) || isJSDocParameterTag(declaration)) && requiresAddingImplicitUndefined(declaration, context.enclosingDeclaration); + type = + symbol.flags & SymbolFlags.Accessor && + declaration.kind === SyntaxKind.SetAccessor + ? instantiateType( + getWriteTypeOfSymbol(symbol), + context.mapper + ) + : symbol && + !( + symbol.flags & + (SymbolFlags.TypeLiteral | + SymbolFlags.Signature) + ) + ? instantiateType( + getWidenedLiteralType( + getTypeOfSymbol(symbol) + ), + context.mapper + ) + : errorType; + } + const addUndefinedForParameter = + declaration && + (isParameter(declaration) || + isJSDocParameterTag(declaration)) && + requiresAddingImplicitUndefined( + declaration, + context.enclosingDeclaration + ); if (addUndefinedForParameter) { type = getOptionalType(type); } - return serializeInferredTypeForDeclaration(symbol, context, type); + return serializeInferredTypeForDeclaration( + symbol, + context, + type + ); }, serializeNameOfParameter(context, parameter) { - return parameterToParameterDeclarationName(getSymbolOfDeclaration(parameter), parameter, context as NodeBuilderContext); + return parameterToParameterDeclarationName( + getSymbolOfDeclaration(parameter), + parameter, + context as NodeBuilderContext + ); }, serializeEntityName(syntacticContext, node) { const context = syntacticContext as NodeBuilderContext; const symbol = getSymbolAtLocation(node, /*ignoreErrors*/ true); if (!symbol) return undefined; - if (!isValueSymbolAccessible(symbol, context.enclosingDeclaration)) return undefined; - return symbolToExpression(symbol, context, SymbolFlags.Value | SymbolFlags.ExportValue); + if ( + !isValueSymbolAccessible( + symbol, + context.enclosingDeclaration + ) + ) + return undefined; + return symbolToExpression( + symbol, + context, + SymbolFlags.Value | SymbolFlags.ExportValue + ); }, serializeTypeName(context, node, isTypeOf, typeArguments) { - return serializeTypeName(context as NodeBuilderContext, node, isTypeOf, typeArguments); + return serializeTypeName( + context as NodeBuilderContext, + node, + isTypeOf, + typeArguments + ); }, - getJsDocPropertyOverride(syntacticContext, jsDocTypeLiteral, jsDocProperty) { + getJsDocPropertyOverride( + syntacticContext, + jsDocTypeLiteral, + jsDocProperty + ) { const context = syntacticContext as NodeBuilderContext; - const name = isIdentifier(jsDocProperty.name) ? jsDocProperty.name : jsDocProperty.name.right; - const typeViaParent = getTypeOfPropertyOfType(getTypeFromTypeNode(context, jsDocTypeLiteral), name.escapedText); - const overrideTypeNode = typeViaParent && jsDocProperty.typeExpression && getTypeFromTypeNode(context, jsDocProperty.typeExpression.type) !== typeViaParent ? typeToTypeNodeHelper(typeViaParent, context) : undefined; + const name = isIdentifier(jsDocProperty.name) + ? jsDocProperty.name + : jsDocProperty.name.right; + const typeViaParent = getTypeOfPropertyOfType( + getTypeFromTypeNode(context, jsDocTypeLiteral), + name.escapedText + ); + const overrideTypeNode = + typeViaParent && + jsDocProperty.typeExpression && + getTypeFromTypeNode( + context, + jsDocProperty.typeExpression.type + ) !== typeViaParent + ? typeToTypeNodeHelper(typeViaParent, context) + : undefined; return overrideTypeNode; }, enterNewScope(context, node) { if (isFunctionLike(node) || isJSDocSignature(node)) { const signature = getSignatureFromDeclaration(node); - return enterNewScope(context as NodeBuilderContext, node, signature.parameters, signature.typeParameters); - } - else { - const typeParameters = isConditionalTypeNode(node) ? getInferTypeParameters(node) : - [getDeclaredTypeOfTypeParameter(getSymbolOfDeclaration(node.typeParameter))]; - return enterNewScope(context as NodeBuilderContext, node, /*expandedParams*/ undefined, typeParameters); + return enterNewScope( + context as NodeBuilderContext, + node, + signature.parameters, + signature.typeParameters + ); + } else { + const typeParameters = isConditionalTypeNode(node) + ? getInferTypeParameters(node) + : [ + getDeclaredTypeOfTypeParameter( + getSymbolOfDeclaration(node.typeParameter) + ), + ]; + return enterNewScope( + context as NodeBuilderContext, + node, + /*expandedParams*/ undefined, + typeParameters + ); } }, - markNodeReuse(context: SyntacticTypeNodeBuilderContext, range: T, location: Node | undefined) { - return setTextRange(context as NodeBuilderContext, range, location); + markNodeReuse( + context: SyntacticTypeNodeBuilderContext, + range: T, + location: Node | undefined + ) { + return setTextRange( + context as NodeBuilderContext, + range, + location + ); }, - trackExistingEntityName(context: SyntacticTypeNodeBuilderContext, node: T) { - return trackExistingEntityName(node, context as NodeBuilderContext); + trackExistingEntityName( + context: SyntacticTypeNodeBuilderContext, + node: T + ) { + return trackExistingEntityName( + node, + context as NodeBuilderContext + ); }, - trackComputedName(context: SyntacticTypeNodeBuilderContext, accessExpression: EntityNameOrEntityNameExpression) { - trackComputedName(accessExpression, context.enclosingDeclaration, context as NodeBuilderContext); + trackComputedName( + context: SyntacticTypeNodeBuilderContext, + accessExpression: EntityNameOrEntityNameExpression + ) { + trackComputedName( + accessExpression, + context.enclosingDeclaration, + context as NodeBuilderContext + ); }, getModuleSpecifierOverride(syntacticContext, parent, lit) { const context = syntacticContext as NodeBuilderContext; - if (context.bundled || context.enclosingFile !== getSourceFileOfNode(lit)) { + if ( + context.bundled || + context.enclosingFile !== getSourceFileOfNode(lit) + ) { let name = lit.text; const originalName = name; const nodeSymbol = getNodeLinks(parent).resolvedSymbol; - const meaning = parent.isTypeOf ? SymbolFlags.Value : SymbolFlags.Type; - const parentSymbol = nodeSymbol - && isSymbolAccessible(nodeSymbol, context.enclosingDeclaration, meaning, /*shouldComputeAliasesToMakeVisible*/ false).accessibility === SymbolAccessibility.Accessible - && lookupSymbolChain(nodeSymbol, context, meaning, /*yieldModuleSymbol*/ true)[0]; + const meaning = parent.isTypeOf + ? SymbolFlags.Value + : SymbolFlags.Type; + const parentSymbol = + nodeSymbol && + isSymbolAccessible( + nodeSymbol, + context.enclosingDeclaration, + meaning, + /*shouldComputeAliasesToMakeVisible*/ false + ).accessibility === SymbolAccessibility.Accessible && + lookupSymbolChain( + nodeSymbol, + context, + meaning, + /*yieldModuleSymbol*/ true + )[0]; if (parentSymbol && isExternalModuleSymbol(parentSymbol)) { - name = getSpecifierForModuleSymbol(parentSymbol, context); - } - else { - const targetFile = getExternalModuleFileFromDeclaration(parent); + name = getSpecifierForModuleSymbol( + parentSymbol, + context + ); + } else { + const targetFile = + getExternalModuleFileFromDeclaration(parent); if (targetFile) { - name = getSpecifierForModuleSymbol(targetFile.symbol, context); + name = getSpecifierForModuleSymbol( + targetFile.symbol, + context + ); } } if (name.includes("/node_modules/")) { context.encounteredError = true; - if (context.tracker.reportLikelyUnsafeImportRequiredError) { - context.tracker.reportLikelyUnsafeImportRequiredError(name); + if ( + context.tracker + .reportLikelyUnsafeImportRequiredError + ) { + context.tracker.reportLikelyUnsafeImportRequiredError( + name + ); } } if (name !== originalName) { @@ -6345,26 +10307,41 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } }, canReuseTypeNode(context, typeNode) { - return canReuseTypeNode(context as NodeBuilderContext, typeNode); + return canReuseTypeNode( + context as NodeBuilderContext, + typeNode + ); }, - canReuseTypeNodeAnnotation(syntacticContext: SyntacticTypeNodeBuilderContext, node: Declaration, existing: TypeNode, symbol: Symbol, requiresAddingUndefined?: boolean) { + canReuseTypeNodeAnnotation( + syntacticContext: SyntacticTypeNodeBuilderContext, + node: Declaration, + existing: TypeNode, + symbol: Symbol, + requiresAddingUndefined?: boolean + ) { const context = syntacticContext as NodeBuilderContext; if (context.enclosingDeclaration === undefined) return false; symbol ??= getSymbolOfDeclaration(node); - let type = context.enclosingSymbolTypes?.get(getSymbolId(symbol)); + let type = context.enclosingSymbolTypes?.get( + getSymbolId(symbol) + ); if (type === undefined) { if (symbol.flags & SymbolFlags.Accessor) { - type = node.kind === SyntaxKind.SetAccessor ? getWriteTypeOfSymbol(symbol) : getTypeOfAccessors(symbol); - } - else if (isValueSignatureDeclaration(node)) { - type = getReturnTypeOfSignature(getSignatureFromDeclaration(node)); - } - else { + type = + node.kind === SyntaxKind.SetAccessor + ? getWriteTypeOfSymbol(symbol) + : getTypeOfAccessors(symbol); + } else if (isValueSignatureDeclaration(node)) { + type = getReturnTypeOfSignature( + getSignatureFromDeclaration(node) + ); + } else { type = getTypeOfSymbol(symbol); } } - let annotationType = getTypeFromTypeNodeWithoutContext(existing); + let annotationType = + getTypeFromTypeNodeWithoutContext(existing); if (isErrorType(annotationType)) { // allow "reusing" type nodes that resolve to error types // those can't truly be reused but it prevents cascading errors in isolatedDeclarations @@ -6372,38 +10349,328 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; } if (requiresAddingUndefined && annotationType) { - annotationType = addOptionality(annotationType, !isParameter(node)); + annotationType = addOptionality( + annotationType, + !isParameter(node) + ); } - return !!annotationType && typeNodeIsEquivalentToType(node, type, annotationType) && existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount(existing, type); + return ( + !!annotationType && + typeNodeIsEquivalentToType(node, type, annotationType) && + existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount( + existing, + type + ) + ); }, }; return { syntacticBuilderResolver, - typeToTypeNode: (type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, internalFlags?: InternalNodeBuilderFlags, tracker?: SymbolTracker, maximumLength?: number, verbosityLevel?: number, out?: WriterContextOut) => withContext(enclosingDeclaration, flags, internalFlags, tracker, maximumLength, verbosityLevel, context => typeToTypeNodeHelper(type, context), out), - typePredicateToTypePredicateNode: (typePredicate: TypePredicate, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, internalFlags?: InternalNodeBuilderFlags, tracker?: SymbolTracker) => withContext(enclosingDeclaration, flags, internalFlags, tracker, /*maximumLength*/ undefined, /*verbosityLevel*/ undefined, context => typePredicateToTypePredicateNodeHelper(typePredicate, context)), - serializeTypeForDeclaration: (declaration: HasInferredType, symbol: Symbol, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, internalFlags?: InternalNodeBuilderFlags, tracker?: SymbolTracker) => withContext(enclosingDeclaration, flags, internalFlags, tracker, /*maximumLength*/ undefined, /*verbosityLevel*/ undefined, context => syntacticNodeBuilder.serializeTypeOfDeclaration(declaration, symbol, context)), - serializeReturnTypeForSignature: (signature: SignatureDeclaration, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, internalFlags?: InternalNodeBuilderFlags, tracker?: SymbolTracker) => withContext(enclosingDeclaration, flags, internalFlags, tracker, /*maximumLength*/ undefined, /*verbosityLevel*/ undefined, context => syntacticNodeBuilder.serializeReturnTypeForSignature(signature, getSymbolOfDeclaration(signature), context)), - serializeTypeForExpression: (expr: Expression, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, internalFlags?: InternalNodeBuilderFlags, tracker?: SymbolTracker) => withContext(enclosingDeclaration, flags, internalFlags, tracker, /*maximumLength*/ undefined, /*verbosityLevel*/ undefined, context => syntacticNodeBuilder.serializeTypeOfExpression(expr, context)), - indexInfoToIndexSignatureDeclaration: (indexInfo: IndexInfo, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, internalFlags?: InternalNodeBuilderFlags, tracker?: SymbolTracker) => withContext(enclosingDeclaration, flags, internalFlags, tracker, /*maximumLength*/ undefined, /*verbosityLevel*/ undefined, context => indexInfoToIndexSignatureDeclarationHelper(indexInfo, context, /*typeNode*/ undefined)), - signatureToSignatureDeclaration: (signature: Signature, kind: SignatureDeclaration["kind"], enclosingDeclaration?: Node, flags?: NodeBuilderFlags, internalFlags?: InternalNodeBuilderFlags, tracker?: SymbolTracker, maximumLength?: number, verbosityLevel?: number, out?: WriterContextOut) => withContext(enclosingDeclaration, flags, internalFlags, tracker, maximumLength, verbosityLevel, context => signatureToSignatureDeclarationHelper(signature, kind, context), out), - symbolToEntityName: (symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, internalFlags?: InternalNodeBuilderFlags, tracker?: SymbolTracker) => withContext(enclosingDeclaration, flags, internalFlags, tracker, /*maximumLength*/ undefined, /*verbosityLevel*/ undefined, context => symbolToName(symbol, context, meaning, /*expectsIdentifier*/ false)), - symbolToExpression: (symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, internalFlags?: InternalNodeBuilderFlags, tracker?: SymbolTracker) => withContext(enclosingDeclaration, flags, internalFlags, tracker, /*maximumLength*/ undefined, /*verbosityLevel*/ undefined, context => symbolToExpression(symbol, context, meaning)), - symbolToTypeParameterDeclarations: (symbol: Symbol, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, internalFlags?: InternalNodeBuilderFlags, tracker?: SymbolTracker) => withContext(enclosingDeclaration, flags, internalFlags, tracker, /*maximumLength*/ undefined, /*verbosityLevel*/ undefined, context => typeParametersToTypeParameterDeclarations(symbol, context)), - symbolToParameterDeclaration: (symbol: Symbol, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, internalFlags?: InternalNodeBuilderFlags, tracker?: SymbolTracker) => withContext(enclosingDeclaration, flags, internalFlags, tracker, /*maximumLength*/ undefined, /*verbosityLevel*/ undefined, context => symbolToParameterDeclaration(symbol, context)), - typeParameterToDeclaration: (parameter: TypeParameter, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, internalFlags?: InternalNodeBuilderFlags, tracker?: SymbolTracker, maximumLength?: number, verbosityLevel?: number, out?: WriterContextOut) => withContext(enclosingDeclaration, flags, internalFlags, tracker, maximumLength, verbosityLevel, context => typeParameterToDeclaration(parameter, context), out), - symbolTableToDeclarationStatements: (symbolTable: SymbolTable, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, internalFlags?: InternalNodeBuilderFlags, tracker?: SymbolTracker) => withContext(enclosingDeclaration, flags, internalFlags, tracker, /*maximumLength*/ undefined, /*verbosityLevel*/ undefined, context => symbolTableToDeclarationStatements(symbolTable, context)), - symbolToNode: (symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, internalFlags?: InternalNodeBuilderFlags, tracker?: SymbolTracker) => withContext(enclosingDeclaration, flags, internalFlags, tracker, /*maximumLength*/ undefined, /*verbosityLevel*/ undefined, context => symbolToNode(symbol, context, meaning)), + typeToTypeNode: ( + type: Type, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + internalFlags?: InternalNodeBuilderFlags, + tracker?: SymbolTracker, + maximumLength?: number, + verbosityLevel?: number, + out?: WriterContextOut + ) => + withContext( + enclosingDeclaration, + flags, + internalFlags, + tracker, + maximumLength, + verbosityLevel, + (context) => typeToTypeNodeHelper(type, context), + out + ), + typePredicateToTypePredicateNode: ( + typePredicate: TypePredicate, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + internalFlags?: InternalNodeBuilderFlags, + tracker?: SymbolTracker + ) => + withContext( + enclosingDeclaration, + flags, + internalFlags, + tracker, + /*maximumLength*/ undefined, + /*verbosityLevel*/ undefined, + (context) => + typePredicateToTypePredicateNodeHelper( + typePredicate, + context + ) + ), + serializeTypeForDeclaration: ( + declaration: HasInferredType, + symbol: Symbol, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + internalFlags?: InternalNodeBuilderFlags, + tracker?: SymbolTracker + ) => + withContext( + enclosingDeclaration, + flags, + internalFlags, + tracker, + /*maximumLength*/ undefined, + /*verbosityLevel*/ undefined, + (context) => + syntacticNodeBuilder.serializeTypeOfDeclaration( + declaration, + symbol, + context + ) + ), + serializeReturnTypeForSignature: ( + signature: SignatureDeclaration, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + internalFlags?: InternalNodeBuilderFlags, + tracker?: SymbolTracker + ) => + withContext( + enclosingDeclaration, + flags, + internalFlags, + tracker, + /*maximumLength*/ undefined, + /*verbosityLevel*/ undefined, + (context) => + syntacticNodeBuilder.serializeReturnTypeForSignature( + signature, + getSymbolOfDeclaration(signature), + context + ) + ), + serializeTypeForExpression: ( + expr: Expression, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + internalFlags?: InternalNodeBuilderFlags, + tracker?: SymbolTracker + ) => + withContext( + enclosingDeclaration, + flags, + internalFlags, + tracker, + /*maximumLength*/ undefined, + /*verbosityLevel*/ undefined, + (context) => + syntacticNodeBuilder.serializeTypeOfExpression( + expr, + context + ) + ), + indexInfoToIndexSignatureDeclaration: ( + indexInfo: IndexInfo, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + internalFlags?: InternalNodeBuilderFlags, + tracker?: SymbolTracker + ) => + withContext( + enclosingDeclaration, + flags, + internalFlags, + tracker, + /*maximumLength*/ undefined, + /*verbosityLevel*/ undefined, + (context) => + indexInfoToIndexSignatureDeclarationHelper( + indexInfo, + context, + /*typeNode*/ undefined + ) + ), + signatureToSignatureDeclaration: ( + signature: Signature, + kind: SignatureDeclaration["kind"], + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + internalFlags?: InternalNodeBuilderFlags, + tracker?: SymbolTracker, + maximumLength?: number, + verbosityLevel?: number, + out?: WriterContextOut + ) => + withContext( + enclosingDeclaration, + flags, + internalFlags, + tracker, + maximumLength, + verbosityLevel, + (context) => + signatureToSignatureDeclarationHelper( + signature, + kind, + context + ), + out + ), + symbolToEntityName: ( + symbol: Symbol, + meaning: SymbolFlags, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + internalFlags?: InternalNodeBuilderFlags, + tracker?: SymbolTracker + ) => + withContext( + enclosingDeclaration, + flags, + internalFlags, + tracker, + /*maximumLength*/ undefined, + /*verbosityLevel*/ undefined, + (context) => + symbolToName( + symbol, + context, + meaning, + /*expectsIdentifier*/ false + ) + ), + symbolToExpression: ( + symbol: Symbol, + meaning: SymbolFlags, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + internalFlags?: InternalNodeBuilderFlags, + tracker?: SymbolTracker + ) => + withContext( + enclosingDeclaration, + flags, + internalFlags, + tracker, + /*maximumLength*/ undefined, + /*verbosityLevel*/ undefined, + (context) => symbolToExpression(symbol, context, meaning) + ), + symbolToTypeParameterDeclarations: ( + symbol: Symbol, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + internalFlags?: InternalNodeBuilderFlags, + tracker?: SymbolTracker + ) => + withContext( + enclosingDeclaration, + flags, + internalFlags, + tracker, + /*maximumLength*/ undefined, + /*verbosityLevel*/ undefined, + (context) => + typeParametersToTypeParameterDeclarations( + symbol, + context + ) + ), + symbolToParameterDeclaration: ( + symbol: Symbol, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + internalFlags?: InternalNodeBuilderFlags, + tracker?: SymbolTracker + ) => + withContext( + enclosingDeclaration, + flags, + internalFlags, + tracker, + /*maximumLength*/ undefined, + /*verbosityLevel*/ undefined, + (context) => symbolToParameterDeclaration(symbol, context) + ), + typeParameterToDeclaration: ( + parameter: TypeParameter, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + internalFlags?: InternalNodeBuilderFlags, + tracker?: SymbolTracker, + maximumLength?: number, + verbosityLevel?: number, + out?: WriterContextOut + ) => + withContext( + enclosingDeclaration, + flags, + internalFlags, + tracker, + maximumLength, + verbosityLevel, + (context) => typeParameterToDeclaration(parameter, context), + out + ), + symbolTableToDeclarationStatements: ( + symbolTable: SymbolTable, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + internalFlags?: InternalNodeBuilderFlags, + tracker?: SymbolTracker + ) => + withContext( + enclosingDeclaration, + flags, + internalFlags, + tracker, + /*maximumLength*/ undefined, + /*verbosityLevel*/ undefined, + (context) => + symbolTableToDeclarationStatements(symbolTable, context) + ), + symbolToNode: ( + symbol: Symbol, + meaning: SymbolFlags, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + internalFlags?: InternalNodeBuilderFlags, + tracker?: SymbolTracker + ) => + withContext( + enclosingDeclaration, + flags, + internalFlags, + tracker, + /*maximumLength*/ undefined, + /*verbosityLevel*/ undefined, + (context) => symbolToNode(symbol, context, meaning) + ), symbolToDeclarations, }; - function getTypeFromTypeNode(context: NodeBuilderContext, node: TypeNode, noMappedTypes?: false): Type; - function getTypeFromTypeNode(context: NodeBuilderContext, node: TypeNode, noMappedTypes: true): Type | undefined; - function getTypeFromTypeNode(context: NodeBuilderContext, node: TypeNode, noMappedTypes?: boolean): Type | undefined { + function getTypeFromTypeNode( + context: NodeBuilderContext, + node: TypeNode, + noMappedTypes?: false + ): Type; + function getTypeFromTypeNode( + context: NodeBuilderContext, + node: TypeNode, + noMappedTypes: true + ): Type | undefined; + function getTypeFromTypeNode( + context: NodeBuilderContext, + node: TypeNode, + noMappedTypes?: boolean + ): Type | undefined { const type = getTypeFromTypeNodeWithoutContext(node); if (!context.mapper) return type; const mappedType = instantiateType(type, context.mapper); - return noMappedTypes && mappedType !== type ? undefined : mappedType; + return noMappedTypes && mappedType !== type + ? undefined + : mappedType; } /** @@ -6415,8 +10682,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * * It also calls `setOriginalNode` to setup a `.original` pointer, since you basically *always* want these in the node builder. */ - function setTextRange(context: NodeBuilderContext, range: T, location: Node | undefined): T { - if (!nodeIsSynthesized(range) || !(range.flags & NodeFlags.Synthesized) || !context.enclosingFile || context.enclosingFile !== getSourceFileOfNode(getOriginalNode(range))) { + function setTextRange( + context: NodeBuilderContext, + range: T, + location: Node | undefined + ): T { + if ( + !nodeIsSynthesized(range) || + !(range.flags & NodeFlags.Synthesized) || + !context.enclosingFile || + context.enclosingFile !== + getSourceFileOfNode(getOriginalNode(range)) + ) { range = factory.cloneNode(range); // if `range` is synthesized or originates in another file, copy it so it definitely has synthetic positions } if (range === location) return range; @@ -6432,28 +10709,53 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { setOriginalNode(range, location); } // only set positions if range comes from the same file since copying text across files isn't supported by the emitter - if (context.enclosingFile && context.enclosingFile === getSourceFileOfNode(getOriginalNode(location))) { + if ( + context.enclosingFile && + context.enclosingFile === + getSourceFileOfNode(getOriginalNode(location)) + ) { return setTextRangeWorker(range, location); } return range; } - function symbolToNode(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags) { - if (context.internalFlags & InternalNodeBuilderFlags.WriteComputedProps) { + function symbolToNode( + symbol: Symbol, + context: NodeBuilderContext, + meaning: SymbolFlags + ) { + if ( + context.internalFlags & + InternalNodeBuilderFlags.WriteComputedProps + ) { if (symbol.valueDeclaration) { const name = getNameOfDeclaration(symbol.valueDeclaration); if (name && isComputedPropertyName(name)) return name; } const nameType = getSymbolLinks(symbol).nameType; - if (nameType && nameType.flags & (TypeFlags.EnumLiteral | TypeFlags.UniqueESSymbol)) { - context.enclosingDeclaration = nameType.symbol.valueDeclaration; - return factory.createComputedPropertyName(symbolToExpression(nameType.symbol, context, meaning)); + if ( + nameType && + nameType.flags & + (TypeFlags.EnumLiteral | TypeFlags.UniqueESSymbol) + ) { + context.enclosingDeclaration = + nameType.symbol.valueDeclaration; + return factory.createComputedPropertyName( + symbolToExpression(nameType.symbol, context, meaning) + ); } } return symbolToExpression(symbol, context, meaning); } - function symbolToDeclarations(symbol: Symbol, meaning: SymbolFlags, flags: NodeBuilderFlags, maximumLength?: number, verbosityLevel?: number, out?: WriterContextOut): Declaration[] { + function symbolToDeclarations( + symbol: Symbol, + meaning: SymbolFlags, + flags: NodeBuilderFlags, + maximumLength?: number, + verbosityLevel?: number, + out?: WriterContextOut + ): Declaration[] { const nodes = withContext( /*enclosingDeclaration*/ undefined, flags, @@ -6461,29 +10763,52 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /*tracker*/ undefined, maximumLength, verbosityLevel, - context => symbolToDeclarationsWorker(symbol, context), - out, + (context) => symbolToDeclarationsWorker(symbol, context), + out ); - return mapDefined(nodes, node => { + return mapDefined(nodes, (node) => { switch (node.kind) { case SyntaxKind.ClassDeclaration: - return simplifyClassDeclaration(node as ClassDeclaration, symbol); + return simplifyClassDeclaration( + node as ClassDeclaration, + symbol + ); case SyntaxKind.EnumDeclaration: - return simplifyModifiers(node as EnumDeclaration, isEnumDeclaration, symbol); + return simplifyModifiers( + node as EnumDeclaration, + isEnumDeclaration, + symbol + ); case SyntaxKind.InterfaceDeclaration: - return simplifyInterfaceDeclaration(node as InterfaceDeclaration, symbol, meaning); + return simplifyInterfaceDeclaration( + node as InterfaceDeclaration, + symbol, + meaning + ); case SyntaxKind.ModuleDeclaration: - return simplifyModifiers(node as ModuleDeclaration, isModuleDeclaration, symbol); + return simplifyModifiers( + node as ModuleDeclaration, + isModuleDeclaration, + symbol + ); default: return undefined; } }); } - function simplifyClassDeclaration(classDecl: ClassDeclaration, symbol: Symbol): Declaration { + function simplifyClassDeclaration( + classDecl: ClassDeclaration, + symbol: Symbol + ): Declaration { const classDeclarations = filter(symbol.declarations, isClassLike); - const originalClassDecl = classDeclarations && classDeclarations.length > 0 ? classDeclarations[0] : classDecl; - const modifiers = getEffectiveModifierFlags(originalClassDecl) & ~(ModifierFlags.Export | ModifierFlags.Ambient); + const originalClassDecl = + classDeclarations && classDeclarations.length > 0 + ? classDeclarations[0] + : classDecl; + const modifiers = + getEffectiveModifierFlags(originalClassDecl) & + ~(ModifierFlags.Export | ModifierFlags.Ambient); const isAnonymous = isClassExpression(originalClassDecl); if (isAnonymous) { classDecl = factory.updateClassDeclaration( @@ -6492,33 +10817,54 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /*name*/ undefined, classDecl.typeParameters, classDecl.heritageClauses, - classDecl.members, + classDecl.members ); } return factory.replaceModifiers(classDecl, modifiers); } - function simplifyModifiers(newDecl: Declaration & HasModifiers, isDeclKind: (d: Declaration) => boolean, symbol: Symbol): Declaration & HasModifiers { + function simplifyModifiers( + newDecl: Declaration & HasModifiers, + isDeclKind: (d: Declaration) => boolean, + symbol: Symbol + ): Declaration & HasModifiers { const decls = filter(symbol.declarations, isDeclKind); - const declWithModifiers = decls && decls.length > 0 ? decls[0] : newDecl; - const modifiers = getEffectiveModifierFlags(declWithModifiers) & ~(ModifierFlags.Export | ModifierFlags.Ambient); + const declWithModifiers = + decls && decls.length > 0 ? decls[0] : newDecl; + const modifiers = + getEffectiveModifierFlags(declWithModifiers) & + ~(ModifierFlags.Export | ModifierFlags.Ambient); return factory.replaceModifiers(newDecl, modifiers); } - function simplifyInterfaceDeclaration(interfaceDecl: InterfaceDeclaration, symbol: Symbol, meaning: SymbolFlags): Declaration | undefined { + function simplifyInterfaceDeclaration( + interfaceDecl: InterfaceDeclaration, + symbol: Symbol, + meaning: SymbolFlags + ): Declaration | undefined { if (!(meaning & SymbolFlags.Interface)) { return undefined; } - return simplifyModifiers(interfaceDecl, isInterfaceDeclaration, symbol); + return simplifyModifiers( + interfaceDecl, + isInterfaceDeclaration, + symbol + ); } - function symbolToDeclarationsWorker(symbol: Symbol, context: NodeBuilderContext): Statement[] { + function symbolToDeclarationsWorker( + symbol: Symbol, + context: NodeBuilderContext + ): Statement[] { // We're already expanding the type: set it in the stack to avoid expanding it again. const type = getDeclaredTypeOfSymbol(symbol); context.typeStack.push(type.id); context.typeStack.push(-1); const table = createSymbolTable([symbol]); - const statements = symbolTableToDeclarationStatements(table, context); + const statements = symbolTableToDeclarationStatements( + table, + context + ); context.typeStack.pop(); context.typeStack.pop(); return statements; @@ -6532,17 +10878,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { maximumLength: number | undefined, verbosityLevel: number | undefined, cb: (context: NodeBuilderContext) => T, - out?: WriterContextOut, + out?: WriterContextOut ): T | undefined { - const moduleResolverHost = tracker?.trackSymbol ? tracker.moduleResolverHost : - (internalFlags || InternalNodeBuilderFlags.None) & InternalNodeBuilderFlags.DoNotIncludeSymbolChain ? createBasicNodeBuilderModuleSpecifierResolutionHost(host) : - undefined; + const moduleResolverHost = tracker?.trackSymbol + ? tracker.moduleResolverHost + : (internalFlags || InternalNodeBuilderFlags.None) & + InternalNodeBuilderFlags.DoNotIncludeSymbolChain + ? createBasicNodeBuilderModuleSpecifierResolutionHost(host) + : undefined; flags = flags || NodeBuilderFlags.None; - const maxTruncationLength = maximumLength || - (flags & NodeBuilderFlags.NoTruncation ? noTruncationMaximumTruncationLength : defaultMaximumTruncationLength); + const maxTruncationLength = + maximumLength || + (flags & NodeBuilderFlags.NoTruncation + ? noTruncationMaximumTruncationLength + : defaultMaximumTruncationLength); const context: NodeBuilderContext = { enclosingDeclaration, - enclosingFile: enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration), + enclosingFile: + enclosingDeclaration && + getSourceFileOfNode(enclosingDeclaration), flags, internalFlags: internalFlags || InternalNodeBuilderFlags.None, tracker: undefined!, @@ -6556,7 +10910,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { inferTypeParameters: undefined, approximateLength: 0, trackedSymbols: undefined, - bundled: !!compilerOptions.outFile && !!enclosingDeclaration && isExternalOrCommonJsModule(getSourceFileOfNode(enclosingDeclaration)), + bundled: + !!compilerOptions.outFile && + !!enclosingDeclaration && + isExternalOrCommonJsModule( + getSourceFileOfNode(enclosingDeclaration) + ), truncating: false, usedSymbolNames: undefined, remappedSymbolNames: undefined, @@ -6577,19 +10936,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { truncated: false, }, }; - context.tracker = new SymbolTrackerImpl(context, tracker, moduleResolverHost); + context.tracker = new SymbolTrackerImpl( + context, + tracker, + moduleResolverHost + ); const resultingNode = cb(context); - if (context.truncating && context.flags & NodeBuilderFlags.NoTruncation) { + if ( + context.truncating && + context.flags & NodeBuilderFlags.NoTruncation + ) { context.tracker.reportTruncationError(); } if (out) { - out.canIncreaseExpansionDepth = context.out.canIncreaseExpansionDepth; + out.canIncreaseExpansionDepth = + context.out.canIncreaseExpansionDepth; out.truncated = context.out.truncated; } return context.encounteredError ? undefined : resultingNode; } - function addSymbolTypeToContext(context: NodeBuilderContext, symbol: Symbol, type: Type) { + function addSymbolTypeToContext( + context: NodeBuilderContext, + symbol: Symbol, + type: Type + ) { const id = getSymbolId(symbol); const oldType = context.enclosingSymbolTypes.get(id); context.enclosingSymbolTypes.set(id, type); @@ -6597,8 +10968,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function restore() { if (oldType) { context.enclosingSymbolTypes.set(id, oldType); - } - else { + } else { context.enclosingSymbolTypes.delete(id); } } @@ -6617,33 +10987,48 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function checkTruncationLengthIfExpanding(context: NodeBuilderContext): boolean { - return context.maxExpansionDepth >= 0 && checkTruncationLength(context); + function checkTruncationLengthIfExpanding( + context: NodeBuilderContext + ): boolean { + return ( + context.maxExpansionDepth >= 0 && checkTruncationLength(context) + ); } function checkTruncationLength(context: NodeBuilderContext): boolean { if (context.truncating) return context.truncating; - return context.truncating = context.approximateLength > context.maxTruncationLength; + return (context.truncating = + context.approximateLength > context.maxTruncationLength); } /** * Returns true if it's possible the type or one of its components can be expanded. */ - function canPossiblyExpandType(type: Type, context: NodeBuilderContext): boolean { + function canPossiblyExpandType( + type: Type, + context: NodeBuilderContext + ): boolean { for (let i = 0; i < context.typeStack.length - 1; i++) { if (context.typeStack[i] === type.id) { return false; } } - return context.depth < context.maxExpansionDepth || - context.depth === context.maxExpansionDepth && !context.out.canIncreaseExpansionDepth; + return ( + context.depth < context.maxExpansionDepth || + (context.depth === context.maxExpansionDepth && + !context.out.canIncreaseExpansionDepth) + ); } /** * Determines if the input type should be expanded, based on how many layers of names we're allowed to expand. * @param isAlias - Whether we're expanding a type alias or not. */ - function shouldExpandType(type: Type, context: NodeBuilderContext, isAlias = false): boolean { + function shouldExpandType( + type: Type, + context: NodeBuilderContext, + isAlias = false + ): boolean { if (!isAlias && isLibType(type)) { return false; } @@ -6660,7 +11045,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function typeToTypeNodeHelper(type: Type, context: NodeBuilderContext): TypeNode { + function typeToTypeNodeHelper( + type: Type, + context: NodeBuilderContext + ): TypeNode { const restoreFlags = saveRestoreFlags(context); if (type) context.typeStack.push(type.id); const typeNode = typeToTypeNodeWorker(type, context); @@ -6669,8 +11057,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return typeNode; } - function typeToTypeNodeWorker(type: Type, context: NodeBuilderContext): TypeNode { - if (cancellationToken && cancellationToken.throwIfCancellationRequested) { + function typeToTypeNodeWorker( + type: Type, + context: NodeBuilderContext + ): TypeNode { + if ( + cancellationToken && + cancellationToken.throwIfCancellationRequested + ) { cancellationToken.throwIfCancellationRequested(); } const inTypeAlias = context.flags & NodeBuilderFlags.InTypeAlias; @@ -6678,7 +11072,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let expandingEnum = false; if (!type) { - if (!(context.flags & NodeBuilderFlags.AllowEmptyUnionOrIntersection)) { + if ( + !( + context.flags & + NodeBuilderFlags.AllowEmptyUnionOrIntersection + ) + ) { context.encounteredError = true; return undefined!; // TODO: GH#18217 } @@ -6692,13 +11091,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (type.flags & TypeFlags.Any) { if (type.aliasSymbol) { - return factory.createTypeReferenceNode(symbolToEntityNameNode(type.aliasSymbol), mapToTypeNodes(type.aliasTypeArguments, context)); + return factory.createTypeReferenceNode( + symbolToEntityNameNode(type.aliasSymbol), + mapToTypeNodes(type.aliasTypeArguments, context) + ); } if (type === unresolvedType) { - return addSyntheticLeadingComment(factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), SyntaxKind.MultiLineCommentTrivia, "unresolved"); + return addSyntheticLeadingComment( + factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), + SyntaxKind.MultiLineCommentTrivia, + "unresolved" + ); } context.approximateLength += 3; - return factory.createKeywordTypeNode(type === intrinsicMarkerType ? SyntaxKind.IntrinsicKeyword : SyntaxKind.AnyKeyword); + return factory.createKeywordTypeNode( + type === intrinsicMarkerType + ? SyntaxKind.IntrinsicKeyword + : SyntaxKind.AnyKeyword + ); } if (type.flags & TypeFlags.Unknown) { return factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword); @@ -6722,7 +11132,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (type.flags & TypeFlags.EnumLike) { if (type.symbol.flags & SymbolFlags.EnumMember) { const parentSymbol = getParentOfSymbol(type.symbol)!; - const parentName = symbolToTypeNode(parentSymbol, context, SymbolFlags.Type); + const parentName = symbolToTypeNode( + parentSymbol, + context, + SymbolFlags.Type + ); if (getDeclaredTypeOfSymbol(parentSymbol) === type) { return parentName; } @@ -6730,56 +11144,117 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isIdentifierText(memberName, ScriptTarget.ES5)) { return appendReferenceToType( parentName as TypeReferenceNode | ImportTypeNode, - factory.createTypeReferenceNode(memberName, /*typeArguments*/ undefined), + factory.createTypeReferenceNode( + memberName, + /*typeArguments*/ undefined + ) ); } if (isImportTypeNode(parentName)) { (parentName as any).isTypeOf = true; // mutably update, node is freshly manufactured anyhow - return factory.createIndexedAccessTypeNode(parentName, factory.createLiteralTypeNode(factory.createStringLiteral(memberName))); - } - else if (isTypeReferenceNode(parentName)) { - return factory.createIndexedAccessTypeNode(factory.createTypeQueryNode(parentName.typeName), factory.createLiteralTypeNode(factory.createStringLiteral(memberName))); - } - else { - return Debug.fail("Unhandled type node kind returned from `symbolToTypeNode`."); + return factory.createIndexedAccessTypeNode( + parentName, + factory.createLiteralTypeNode( + factory.createStringLiteral(memberName) + ) + ); + } else if (isTypeReferenceNode(parentName)) { + return factory.createIndexedAccessTypeNode( + factory.createTypeQueryNode(parentName.typeName), + factory.createLiteralTypeNode( + factory.createStringLiteral(memberName) + ) + ); + } else { + return Debug.fail( + "Unhandled type node kind returned from `symbolToTypeNode`." + ); } } if (!shouldExpandType(type, context)) { - return symbolToTypeNode(type.symbol, context, SymbolFlags.Type); - } - else { + return symbolToTypeNode( + type.symbol, + context, + SymbolFlags.Type + ); + } else { expandingEnum = true; } } if (type.flags & TypeFlags.StringLiteral) { - context.approximateLength += (type as StringLiteralType).value.length + 2; - return factory.createLiteralTypeNode(setEmitFlags(factory.createStringLiteral((type as StringLiteralType).value, !!(context.flags & NodeBuilderFlags.UseSingleQuotesForStringLiteralType)), EmitFlags.NoAsciiEscaping)); + context.approximateLength += + (type as StringLiteralType).value.length + 2; + return factory.createLiteralTypeNode( + setEmitFlags( + factory.createStringLiteral( + (type as StringLiteralType).value, + !!( + context.flags & + NodeBuilderFlags.UseSingleQuotesForStringLiteralType + ) + ), + EmitFlags.NoAsciiEscaping + ) + ); } if (type.flags & TypeFlags.NumberLiteral) { const value = (type as NumberLiteralType).value; context.approximateLength += ("" + value).length; - return factory.createLiteralTypeNode(value < 0 ? factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, factory.createNumericLiteral(-value)) : factory.createNumericLiteral(value)); + return factory.createLiteralTypeNode( + value < 0 + ? factory.createPrefixUnaryExpression( + SyntaxKind.MinusToken, + factory.createNumericLiteral(-value) + ) + : factory.createNumericLiteral(value) + ); } if (type.flags & TypeFlags.BigIntLiteral) { - context.approximateLength += (pseudoBigIntToString((type as BigIntLiteralType).value).length) + 1; - return factory.createLiteralTypeNode(factory.createBigIntLiteral((type as BigIntLiteralType).value)); + context.approximateLength += + pseudoBigIntToString((type as BigIntLiteralType).value) + .length + 1; + return factory.createLiteralTypeNode( + factory.createBigIntLiteral( + (type as BigIntLiteralType).value + ) + ); } if (type.flags & TypeFlags.BooleanLiteral) { - context.approximateLength += (type as IntrinsicType).intrinsicName.length; - return factory.createLiteralTypeNode((type as IntrinsicType).intrinsicName === "true" ? factory.createTrue() : factory.createFalse()); + context.approximateLength += ( + type as IntrinsicType + ).intrinsicName.length; + return factory.createLiteralTypeNode( + (type as IntrinsicType).intrinsicName === "true" + ? factory.createTrue() + : factory.createFalse() + ); } if (type.flags & TypeFlags.UniqueESSymbol) { - if (!(context.flags & NodeBuilderFlags.AllowUniqueESSymbolType)) { - if (isValueSymbolAccessible(type.symbol, context.enclosingDeclaration)) { + if ( + !(context.flags & NodeBuilderFlags.AllowUniqueESSymbolType) + ) { + if ( + isValueSymbolAccessible( + type.symbol, + context.enclosingDeclaration + ) + ) { context.approximateLength += 6; - return symbolToTypeNode(type.symbol, context, SymbolFlags.Value); + return symbolToTypeNode( + type.symbol, + context, + SymbolFlags.Value + ); } if (context.tracker.reportInaccessibleUniqueSymbolError) { context.tracker.reportInaccessibleUniqueSymbolError(); } } context.approximateLength += 13; - return factory.createTypeOperatorNode(SyntaxKind.UniqueKeyword, factory.createKeywordTypeNode(SyntaxKind.SymbolKeyword)); + return factory.createTypeOperatorNode( + SyntaxKind.UniqueKeyword, + factory.createKeywordTypeNode(SyntaxKind.SymbolKeyword) + ); } if (type.flags & TypeFlags.Void) { context.approximateLength += 4; @@ -6787,7 +11262,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (type.flags & TypeFlags.Undefined) { context.approximateLength += 9; - return factory.createKeywordTypeNode(SyntaxKind.UndefinedKeyword); + return factory.createKeywordTypeNode( + SyntaxKind.UndefinedKeyword + ); } if (type.flags & TypeFlags.Null) { context.approximateLength += 4; @@ -6807,7 +11284,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (isThisTypeParameter(type)) { if (context.flags & NodeBuilderFlags.InObjectTypeLiteral) { - if (!context.encounteredError && !(context.flags & NodeBuilderFlags.AllowThisInObjectLiteral)) { + if ( + !context.encounteredError && + !( + context.flags & + NodeBuilderFlags.AllowThisInObjectLiteral + ) + ) { context.encounteredError = true; } context.tracker.reportInaccessibleThisError?.(); @@ -6816,14 +11299,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return factory.createThisTypeNode(); } - if (!inTypeAlias && type.aliasSymbol && (context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope || isTypeSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration))) { + if ( + !inTypeAlias && + type.aliasSymbol && + (context.flags & + NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope || + isTypeSymbolAccessible( + type.aliasSymbol, + context.enclosingDeclaration + )) + ) { if (!shouldExpandType(type, context, /*isAlias*/ true)) { - const typeArgumentNodes = mapToTypeNodes(type.aliasTypeArguments, context); - if (isReservedMemberName(type.aliasSymbol.escapedName) && !(type.aliasSymbol.flags & SymbolFlags.Class)) return factory.createTypeReferenceNode(factory.createIdentifier(""), typeArgumentNodes); - if (length(typeArgumentNodes) === 1 && type.aliasSymbol === globalArrayType.symbol) { - return factory.createArrayTypeNode(typeArgumentNodes![0]); + const typeArgumentNodes = mapToTypeNodes( + type.aliasTypeArguments, + context + ); + if ( + isReservedMemberName(type.aliasSymbol.escapedName) && + !(type.aliasSymbol.flags & SymbolFlags.Class) + ) + return factory.createTypeReferenceNode( + factory.createIdentifier(""), + typeArgumentNodes + ); + if ( + length(typeArgumentNodes) === 1 && + type.aliasSymbol === globalArrayType.symbol + ) { + return factory.createArrayTypeNode( + typeArgumentNodes![0] + ); } - return symbolToTypeNode(type.aliasSymbol, context, SymbolFlags.Type, typeArgumentNodes); + return symbolToTypeNode( + type.aliasSymbol, + context, + SymbolFlags.Type, + typeArgumentNodes + ); } context.depth += 1; } @@ -6834,62 +11346,141 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { Debug.assert(!!(type.flags & TypeFlags.Object)); if (shouldExpandType(type, context)) { context.depth += 1; - return createAnonymousTypeNode(type as TypeReference, /*forceClassExpansion*/ true, /*forceExpansion*/ true); + return createAnonymousTypeNode( + type as TypeReference, + /*forceClassExpansion*/ true, + /*forceExpansion*/ true + ); } - return (type as TypeReference).node ? visitAndTransformType(type as TypeReference, typeReferenceToTypeNode) : typeReferenceToTypeNode(type as TypeReference); + return (type as TypeReference).node + ? visitAndTransformType( + type as TypeReference, + typeReferenceToTypeNode + ) + : typeReferenceToTypeNode(type as TypeReference); } - if (type.flags & TypeFlags.TypeParameter || objectFlags & ObjectFlags.ClassOrInterface) { - if (type.flags & TypeFlags.TypeParameter && contains(context.inferTypeParameters, type)) { - context.approximateLength += symbolName(type.symbol).length + 6; + if ( + type.flags & TypeFlags.TypeParameter || + objectFlags & ObjectFlags.ClassOrInterface + ) { + if ( + type.flags & TypeFlags.TypeParameter && + contains(context.inferTypeParameters, type) + ) { + context.approximateLength += + symbolName(type.symbol).length + 6; let constraintNode: TypeNode | undefined; - const constraint = getConstraintOfTypeParameter(type as TypeParameter); + const constraint = getConstraintOfTypeParameter( + type as TypeParameter + ); if (constraint) { // If the infer type has a constraint that is not the same as the constraint // we would have normally inferred based on context, we emit the constraint // using `infer T extends ?`. We omit inferred constraints from type references // as they may be elided. - const inferredConstraint = getInferredTypeParameterConstraint(type as TypeParameter, /*omitTypeReferences*/ true); - if (!(inferredConstraint && isTypeIdenticalTo(constraint, inferredConstraint))) { + const inferredConstraint = + getInferredTypeParameterConstraint( + type as TypeParameter, + /*omitTypeReferences*/ true + ); + if ( + !( + inferredConstraint && + isTypeIdenticalTo( + constraint, + inferredConstraint + ) + ) + ) { context.approximateLength += 9; - constraintNode = constraint && typeToTypeNodeHelper(constraint, context); + constraintNode = + constraint && + typeToTypeNodeHelper(constraint, context); } } - return factory.createInferTypeNode(typeParameterToDeclarationWithConstraint(type as TypeParameter, context, constraintNode)); + return factory.createInferTypeNode( + typeParameterToDeclarationWithConstraint( + type as TypeParameter, + context, + constraintNode + ) + ); } if ( - context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams && + context.flags & + NodeBuilderFlags.GenerateNamesForShadowedTypeParams && type.flags & TypeFlags.TypeParameter ) { const name = typeParameterToName(type, context); context.approximateLength += idText(name).length; - return factory.createTypeReferenceNode(factory.createIdentifier(idText(name)), /*typeArguments*/ undefined); + return factory.createTypeReferenceNode( + factory.createIdentifier(idText(name)), + /*typeArguments*/ undefined + ); } - if (objectFlags & ObjectFlags.ClassOrInterface && shouldExpandType(type, context)) { + if ( + objectFlags & ObjectFlags.ClassOrInterface && + shouldExpandType(type, context) + ) { context.depth += 1; - return createAnonymousTypeNode(type as InterfaceType, /*forceClassExpansion*/ true, /*forceExpansion*/ true); + return createAnonymousTypeNode( + type as InterfaceType, + /*forceClassExpansion*/ true, + /*forceExpansion*/ true + ); } // Ignore constraint/default when creating a usage (as opposed to declaration) of a type parameter. if (type.symbol) { - return symbolToTypeNode(type.symbol, context, SymbolFlags.Type); + return symbolToTypeNode( + type.symbol, + context, + SymbolFlags.Type + ); } - const name = (type === markerSuperTypeForCheck || type === markerSubTypeForCheck) && varianceTypeParameter && varianceTypeParameter.symbol ? - (type === markerSubTypeForCheck ? "sub-" : "super-") + symbolName(varianceTypeParameter.symbol) : "?"; - return factory.createTypeReferenceNode(factory.createIdentifier(name), /*typeArguments*/ undefined); + const name = + (type === markerSuperTypeForCheck || + type === markerSubTypeForCheck) && + varianceTypeParameter && + varianceTypeParameter.symbol + ? (type === markerSubTypeForCheck ? "sub-" : "super-") + + symbolName(varianceTypeParameter.symbol) + : "?"; + return factory.createTypeReferenceNode( + factory.createIdentifier(name), + /*typeArguments*/ undefined + ); } if (type.flags & TypeFlags.Union && (type as UnionType).origin) { type = (type as UnionType).origin!; } if (type.flags & (TypeFlags.Union | TypeFlags.Intersection)) { - const types = type.flags & TypeFlags.Union ? formatUnionTypes((type as UnionType).types, expandingEnum) : (type as IntersectionType).types; + const types = + type.flags & TypeFlags.Union + ? formatUnionTypes( + (type as UnionType).types, + expandingEnum + ) + : (type as IntersectionType).types; if (length(types) === 1) { return typeToTypeNodeHelper(types[0], context); } - const typeNodes = mapToTypeNodes(types, context, /*isBareList*/ true); + const typeNodes = mapToTypeNodes( + types, + context, + /*isBareList*/ true + ); if (typeNodes && typeNodes.length > 0) { - return type.flags & TypeFlags.Union ? factory.createUnionTypeNode(typeNodes) : factory.createIntersectionTypeNode(typeNodes); - } - else { - if (!context.encounteredError && !(context.flags & NodeBuilderFlags.AllowEmptyUnionOrIntersection)) { + return type.flags & TypeFlags.Union + ? factory.createUnionTypeNode(typeNodes) + : factory.createIntersectionTypeNode(typeNodes); + } else { + if ( + !context.encounteredError && + !( + context.flags & + NodeBuilderFlags.AllowEmptyUnionOrIntersection + ) + ) { context.encounteredError = true; } return undefined!; // TODO: GH#18217 @@ -6903,8 +11494,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (type.flags & TypeFlags.Index) { const indexedType = (type as IndexType).type; context.approximateLength += 6; - const indexTypeNode = typeToTypeNodeHelper(indexedType, context); - return factory.createTypeOperatorNode(SyntaxKind.KeyOfKeyword, indexTypeNode); + const indexTypeNode = typeToTypeNodeHelper( + indexedType, + context + ); + return factory.createTypeOperatorNode( + SyntaxKind.KeyOfKeyword, + indexTypeNode + ); } if (type.flags & TypeFlags.TemplateLiteral) { const texts = (type as TemplateLiteralType).texts; @@ -6914,48 +11511,122 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { map(types, (t, i) => factory.createTemplateLiteralTypeSpan( typeToTypeNodeHelper(t, context), - (i < types.length - 1 ? factory.createTemplateMiddle : factory.createTemplateTail)(texts[i + 1]), - )), + (i < types.length - 1 + ? factory.createTemplateMiddle + : factory.createTemplateTail)(texts[i + 1]) + ) + ) ); context.approximateLength += 2; - return factory.createTemplateLiteralType(templateHead, templateSpans); + return factory.createTemplateLiteralType( + templateHead, + templateSpans + ); } if (type.flags & TypeFlags.StringMapping) { - const typeNode = typeToTypeNodeHelper((type as StringMappingType).type, context); - return symbolToTypeNode((type as StringMappingType).symbol, context, SymbolFlags.Type, [typeNode]); + const typeNode = typeToTypeNodeHelper( + (type as StringMappingType).type, + context + ); + return symbolToTypeNode( + (type as StringMappingType).symbol, + context, + SymbolFlags.Type, + [typeNode] + ); } if (type.flags & TypeFlags.IndexedAccess) { - const objectTypeNode = typeToTypeNodeHelper((type as IndexedAccessType).objectType, context); - const indexTypeNode = typeToTypeNodeHelper((type as IndexedAccessType).indexType, context); + const objectTypeNode = typeToTypeNodeHelper( + (type as IndexedAccessType).objectType, + context + ); + const indexTypeNode = typeToTypeNodeHelper( + (type as IndexedAccessType).indexType, + context + ); context.approximateLength += 2; - return factory.createIndexedAccessTypeNode(objectTypeNode, indexTypeNode); + return factory.createIndexedAccessTypeNode( + objectTypeNode, + indexTypeNode + ); } if (type.flags & TypeFlags.Conditional) { - return visitAndTransformType(type, type => conditionalTypeToTypeNode(type as ConditionalType)); + return visitAndTransformType(type, (type) => + conditionalTypeToTypeNode(type as ConditionalType) + ); } if (type.flags & TypeFlags.Substitution) { - const typeNode = typeToTypeNodeHelper((type as SubstitutionType).baseType, context); - const noInferSymbol = isNoInferType(type) && getGlobalTypeSymbol("NoInfer" as __String, /*reportErrors*/ false); - return noInferSymbol ? symbolToTypeNode(noInferSymbol, context, SymbolFlags.Type, [typeNode]) : typeNode; + const typeNode = typeToTypeNodeHelper( + (type as SubstitutionType).baseType, + context + ); + const noInferSymbol = + isNoInferType(type) && + getGlobalTypeSymbol( + "NoInfer" as __String, + /*reportErrors*/ false + ); + return noInferSymbol + ? symbolToTypeNode( + noInferSymbol, + context, + SymbolFlags.Type, + [typeNode] + ) + : typeNode; } return Debug.fail("Should be unreachable."); function conditionalTypeToTypeNode(type: ConditionalType) { - const checkTypeNode = typeToTypeNodeHelper(type.checkType, context); + const checkTypeNode = typeToTypeNodeHelper( + type.checkType, + context + ); context.approximateLength += 15; - if (context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams && type.root.isDistributive && !(type.checkType.flags & TypeFlags.TypeParameter)) { - const newParam = createTypeParameter(createSymbol(SymbolFlags.TypeParameter, "T" as __String)); + if ( + context.flags & + NodeBuilderFlags.GenerateNamesForShadowedTypeParams && + type.root.isDistributive && + !(type.checkType.flags & TypeFlags.TypeParameter) + ) { + const newParam = createTypeParameter( + createSymbol(SymbolFlags.TypeParameter, "T" as __String) + ); const name = typeParameterToName(newParam, context); - const newTypeVariable = factory.createTypeReferenceNode(name); + const newTypeVariable = + factory.createTypeReferenceNode(name); context.approximateLength += 37; // 15 each for two added conditionals, 7 for an added infer type - const newMapper = prependTypeMapping(type.root.checkType, newParam, type.mapper); + const newMapper = prependTypeMapping( + type.root.checkType, + newParam, + type.mapper + ); const saveInferTypeParameters = context.inferTypeParameters; context.inferTypeParameters = type.root.inferTypeParameters; - const extendsTypeNode = typeToTypeNodeHelper(instantiateType(type.root.extendsType, newMapper), context); + const extendsTypeNode = typeToTypeNodeHelper( + instantiateType(type.root.extendsType, newMapper), + context + ); context.inferTypeParameters = saveInferTypeParameters; - const trueTypeNode = typeToTypeNodeOrCircularityElision(instantiateType(getTypeFromTypeNode(context, type.root.node.trueType), newMapper)); - const falseTypeNode = typeToTypeNodeOrCircularityElision(instantiateType(getTypeFromTypeNode(context, type.root.node.falseType), newMapper)); + const trueTypeNode = typeToTypeNodeOrCircularityElision( + instantiateType( + getTypeFromTypeNode( + context, + type.root.node.trueType + ), + newMapper + ) + ); + const falseTypeNode = typeToTypeNodeOrCircularityElision( + instantiateType( + getTypeFromTypeNode( + context, + type.root.node.falseType + ), + newMapper + ) + ); // outermost conditional makes `T` a type parameter, allowing the inner conditionals to be distributive // second conditional makes `T` have `T & checkType` substitution, so it is correctly usable as the checkType @@ -6969,35 +11640,70 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // may also work with `infer ... extends ...` in, but would produce declarations only compatible with the latest TS. return factory.createConditionalTypeNode( checkTypeNode, - factory.createInferTypeNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, factory.cloneNode(newTypeVariable.typeName) as Identifier)), + factory.createInferTypeNode( + factory.createTypeParameterDeclaration( + /*modifiers*/ undefined, + factory.cloneNode( + newTypeVariable.typeName + ) as Identifier + ) + ), factory.createConditionalTypeNode( - factory.createTypeReferenceNode(factory.cloneNode(name)), + factory.createTypeReferenceNode( + factory.cloneNode(name) + ), typeToTypeNodeHelper(type.checkType, context), - factory.createConditionalTypeNode(newTypeVariable, extendsTypeNode, trueTypeNode, falseTypeNode), - factory.createKeywordTypeNode(SyntaxKind.NeverKeyword), + factory.createConditionalTypeNode( + newTypeVariable, + extendsTypeNode, + trueTypeNode, + falseTypeNode + ), + factory.createKeywordTypeNode( + SyntaxKind.NeverKeyword + ) ), - factory.createKeywordTypeNode(SyntaxKind.NeverKeyword), + factory.createKeywordTypeNode(SyntaxKind.NeverKeyword) ); } const saveInferTypeParameters = context.inferTypeParameters; context.inferTypeParameters = type.root.inferTypeParameters; - const extendsTypeNode = typeToTypeNodeHelper(type.extendsType, context); + const extendsTypeNode = typeToTypeNodeHelper( + type.extendsType, + context + ); context.inferTypeParameters = saveInferTypeParameters; - const trueTypeNode = typeToTypeNodeOrCircularityElision(getTrueTypeFromConditionalType(type)); - const falseTypeNode = typeToTypeNodeOrCircularityElision(getFalseTypeFromConditionalType(type)); - return factory.createConditionalTypeNode(checkTypeNode, extendsTypeNode, trueTypeNode, falseTypeNode); + const trueTypeNode = typeToTypeNodeOrCircularityElision( + getTrueTypeFromConditionalType(type) + ); + const falseTypeNode = typeToTypeNodeOrCircularityElision( + getFalseTypeFromConditionalType(type) + ); + return factory.createConditionalTypeNode( + checkTypeNode, + extendsTypeNode, + trueTypeNode, + falseTypeNode + ); } function typeToTypeNodeOrCircularityElision(type: Type) { if (type.flags & TypeFlags.Union) { if (context.visitedTypes?.has(getTypeId(type))) { - if (!(context.flags & NodeBuilderFlags.AllowAnonymousIdentifier)) { + if ( + !( + context.flags & + NodeBuilderFlags.AllowAnonymousIdentifier + ) + ) { context.encounteredError = true; context.tracker?.reportCyclicStructureError?.(); } return createElidedInformationPlaceholder(context); } - return visitAndTransformType(type, type => typeToTypeNodeHelper(type, context)); + return visitAndTransformType(type, (type) => + typeToTypeNodeHelper(type, context) + ); } return typeToTypeNodeHelper(type, context); } @@ -7006,94 +11712,247 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return !!getHomomorphicTypeVariable(type); } - function isHomomorphicMappedTypeWithNonHomomorphicInstantiation(type: MappedType) { - return !!type.target && isMappedTypeHomomorphic(type.target as MappedType) && !isMappedTypeHomomorphic(type); + function isHomomorphicMappedTypeWithNonHomomorphicInstantiation( + type: MappedType + ) { + return ( + !!type.target && + isMappedTypeHomomorphic(type.target as MappedType) && + !isMappedTypeHomomorphic(type) + ); } function createMappedTypeNodeFromType(type: MappedType) { Debug.assert(!!(type.flags & TypeFlags.Object)); - const readonlyToken = type.declaration.readonlyToken ? factory.createToken(type.declaration.readonlyToken.kind) as ReadonlyKeyword | PlusToken | MinusToken : undefined; - const questionToken = type.declaration.questionToken ? factory.createToken(type.declaration.questionToken.kind) as QuestionToken | PlusToken | MinusToken : undefined; + const readonlyToken = type.declaration.readonlyToken + ? (factory.createToken( + type.declaration.readonlyToken.kind + ) as ReadonlyKeyword | PlusToken | MinusToken) + : undefined; + const questionToken = type.declaration.questionToken + ? (factory.createToken( + type.declaration.questionToken.kind + ) as QuestionToken | PlusToken | MinusToken) + : undefined; let appropriateConstraintTypeNode: TypeNode; let newTypeVariable: TypeReferenceNode | undefined; let templateType = getTemplateTypeFromMappedType(type); const typeParameter = getTypeParameterFromMappedType(type); // If the mapped type isn't `keyof` constraint-declared, _but_ still has modifiers preserved, and its naive instantiation won't preserve modifiers because its constraint isn't `keyof` constrained, we have work to do - const needsModifierPreservingWrapper = !isMappedTypeWithKeyofConstraintDeclaration(type) - && !(getModifiersTypeFromMappedType(type).flags & TypeFlags.Unknown) - && context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams - && !(getConstraintTypeFromMappedType(type).flags & TypeFlags.TypeParameter && getConstraintOfTypeParameter(getConstraintTypeFromMappedType(type))?.flags! & TypeFlags.Index); + const needsModifierPreservingWrapper = + !isMappedTypeWithKeyofConstraintDeclaration(type) && + !( + getModifiersTypeFromMappedType(type).flags & + TypeFlags.Unknown + ) && + context.flags & + NodeBuilderFlags.GenerateNamesForShadowedTypeParams && + !( + getConstraintTypeFromMappedType(type).flags & + TypeFlags.TypeParameter && + getConstraintOfTypeParameter( + getConstraintTypeFromMappedType(type) + )?.flags! & TypeFlags.Index + ); if (isMappedTypeWithKeyofConstraintDeclaration(type)) { // We have a { [P in keyof T]: X } // We do this to ensure we retain the toplevel keyof-ness of the type which may be lost due to keyof distribution during `getConstraintTypeFromMappedType` - if (isHomomorphicMappedTypeWithNonHomomorphicInstantiation(type) && context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams) { - const newConstraintParam = createTypeParameter(createSymbol(SymbolFlags.TypeParameter, "T" as __String)); - const name = typeParameterToName(newConstraintParam, context); + if ( + isHomomorphicMappedTypeWithNonHomomorphicInstantiation( + type + ) && + context.flags & + NodeBuilderFlags.GenerateNamesForShadowedTypeParams + ) { + const newConstraintParam = createTypeParameter( + createSymbol( + SymbolFlags.TypeParameter, + "T" as __String + ) + ); + const name = typeParameterToName( + newConstraintParam, + context + ); const target = type.target as MappedType; newTypeVariable = factory.createTypeReferenceNode(name); templateType = instantiateType( getTemplateTypeFromMappedType(target), - makeArrayTypeMapper([getTypeParameterFromMappedType(target), getModifiersTypeFromMappedType(target)], [typeParameter, newConstraintParam]), + makeArrayTypeMapper( + [ + getTypeParameterFromMappedType(target), + getModifiersTypeFromMappedType(target), + ], + [typeParameter, newConstraintParam] + ) ); } - appropriateConstraintTypeNode = factory.createTypeOperatorNode(SyntaxKind.KeyOfKeyword, newTypeVariable || typeToTypeNodeHelper(getModifiersTypeFromMappedType(type), context)); - } - else if (needsModifierPreservingWrapper) { + appropriateConstraintTypeNode = + factory.createTypeOperatorNode( + SyntaxKind.KeyOfKeyword, + newTypeVariable || + typeToTypeNodeHelper( + getModifiersTypeFromMappedType(type), + context + ) + ); + } else if (needsModifierPreservingWrapper) { // So, step 1: new type variable - const newParam = createTypeParameter(createSymbol(SymbolFlags.TypeParameter, "T" as __String)); + const newParam = createTypeParameter( + createSymbol(SymbolFlags.TypeParameter, "T" as __String) + ); const name = typeParameterToName(newParam, context); newTypeVariable = factory.createTypeReferenceNode(name); // step 2: make that new type variable itself the constraint node, making the mapped type `{[K in T_1]: Template}` appropriateConstraintTypeNode = newTypeVariable; + } else { + appropriateConstraintTypeNode = typeToTypeNodeHelper( + getConstraintTypeFromMappedType(type), + context + ); } - else { - appropriateConstraintTypeNode = typeToTypeNodeHelper(getConstraintTypeFromMappedType(type), context); - } - const typeParameterNode = typeParameterToDeclarationWithConstraint(typeParameter, context, appropriateConstraintTypeNode); + const typeParameterNode = + typeParameterToDeclarationWithConstraint( + typeParameter, + context, + appropriateConstraintTypeNode + ); // nameType and templateType nodes have to be in the new scope - const cleanup = enterNewScope(context, type.declaration, /*expandedParams*/ undefined, [getDeclaredTypeOfTypeParameter(getSymbolOfDeclaration(type.declaration.typeParameter))]); - const nameTypeNode = type.declaration.nameType ? typeToTypeNodeHelper(getNameTypeFromMappedType(type)!, context) : undefined; - const templateTypeNode = typeToTypeNodeHelper(removeMissingType(templateType, !!(getMappedTypeModifiers(type) & MappedTypeModifiers.IncludeOptional)), context); + const cleanup = enterNewScope( + context, + type.declaration, + /*expandedParams*/ undefined, + [ + getDeclaredTypeOfTypeParameter( + getSymbolOfDeclaration( + type.declaration.typeParameter + ) + ), + ] + ); + const nameTypeNode = type.declaration.nameType + ? typeToTypeNodeHelper( + getNameTypeFromMappedType(type)!, + context + ) + : undefined; + const templateTypeNode = typeToTypeNodeHelper( + removeMissingType( + templateType, + !!( + getMappedTypeModifiers(type) & + MappedTypeModifiers.IncludeOptional + ) + ), + context + ); cleanup(); - const mappedTypeNode = factory.createMappedTypeNode(readonlyToken, typeParameterNode, nameTypeNode, questionToken, templateTypeNode, /*members*/ undefined); + const mappedTypeNode = factory.createMappedTypeNode( + readonlyToken, + typeParameterNode, + nameTypeNode, + questionToken, + templateTypeNode, + /*members*/ undefined + ); context.approximateLength += 10; - const result = setEmitFlags(mappedTypeNode, EmitFlags.SingleLine); - if (isHomomorphicMappedTypeWithNonHomomorphicInstantiation(type) && context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams) { + const result = setEmitFlags( + mappedTypeNode, + EmitFlags.SingleLine + ); + if ( + isHomomorphicMappedTypeWithNonHomomorphicInstantiation( + type + ) && + context.flags & + NodeBuilderFlags.GenerateNamesForShadowedTypeParams + ) { // homomorphic mapped type with a non-homomorphic naive inlining // wrap it with a conditional like `SomeModifiersType extends infer U ? {..the mapped type...} : never` to ensure the resulting // type stays homomorphic - const originalConstraint = instantiateType(getConstraintOfTypeParameter(getTypeFromTypeNode(context, (type.declaration.typeParameter.constraint! as TypeOperatorNode).type) as TypeParameter) || unknownType, type.mapper); + const originalConstraint = instantiateType( + getConstraintOfTypeParameter( + getTypeFromTypeNode( + context, + ( + type.declaration.typeParameter + .constraint! as TypeOperatorNode + ).type + ) as TypeParameter + ) || unknownType, + type.mapper + ); return factory.createConditionalTypeNode( - typeToTypeNodeHelper(getModifiersTypeFromMappedType(type), context), - factory.createInferTypeNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, factory.cloneNode(newTypeVariable!.typeName) as Identifier, originalConstraint.flags & TypeFlags.Unknown ? undefined : typeToTypeNodeHelper(originalConstraint, context))), + typeToTypeNodeHelper( + getModifiersTypeFromMappedType(type), + context + ), + factory.createInferTypeNode( + factory.createTypeParameterDeclaration( + /*modifiers*/ undefined, + factory.cloneNode( + newTypeVariable!.typeName + ) as Identifier, + originalConstraint.flags & TypeFlags.Unknown + ? undefined + : typeToTypeNodeHelper( + originalConstraint, + context + ) + ) + ), result, - factory.createKeywordTypeNode(SyntaxKind.NeverKeyword), + factory.createKeywordTypeNode(SyntaxKind.NeverKeyword) ); - } - else if (needsModifierPreservingWrapper) { + } else if (needsModifierPreservingWrapper) { // and step 3: once the mapped type is reconstructed, create a `ConstraintType extends infer T_1 extends keyof ModifiersType ? {[K in T_1]: Template} : never` // subtly different from the `keyof` constraint case, by including the `keyof` constraint on the `infer` type parameter, it doesn't rely on the constraint type being itself // constrained to a `keyof` type to preserve its modifier-preserving behavior. This is all basically because we preserve modifiers for a wider set of mapped types than // just homomorphic ones. return factory.createConditionalTypeNode( - typeToTypeNodeHelper(getConstraintTypeFromMappedType(type), context), - factory.createInferTypeNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, factory.cloneNode(newTypeVariable!.typeName) as Identifier, factory.createTypeOperatorNode(SyntaxKind.KeyOfKeyword, typeToTypeNodeHelper(getModifiersTypeFromMappedType(type), context)))), + typeToTypeNodeHelper( + getConstraintTypeFromMappedType(type), + context + ), + factory.createInferTypeNode( + factory.createTypeParameterDeclaration( + /*modifiers*/ undefined, + factory.cloneNode( + newTypeVariable!.typeName + ) as Identifier, + factory.createTypeOperatorNode( + SyntaxKind.KeyOfKeyword, + typeToTypeNodeHelper( + getModifiersTypeFromMappedType(type), + context + ) + ) + ) + ), result, - factory.createKeywordTypeNode(SyntaxKind.NeverKeyword), + factory.createKeywordTypeNode(SyntaxKind.NeverKeyword) ); } return result; } - function createAnonymousTypeNode(type: ObjectType, forceClassExpansion = false, forceExpansion = false): TypeNode { + function createAnonymousTypeNode( + type: ObjectType, + forceClassExpansion = false, + forceExpansion = false + ): TypeNode { const typeId = type.id; const symbol = type.symbol; if (symbol) { - const isInstantiationExpressionType = !!(getObjectFlags(type) & ObjectFlags.InstantiationExpressionType); + const isInstantiationExpressionType = !!( + getObjectFlags(type) & + ObjectFlags.InstantiationExpressionType + ); if (isInstantiationExpressionType) { - const instantiationExpressionType = type as InstantiationExpressionType; + const instantiationExpressionType = + type as InstantiationExpressionType; const existing = instantiationExpressionType.node; // instantiationExpressionType.node is unreliable for constituents of unions and intersections. // declare const Err: typeof ErrImpl & (() => T); @@ -7102,8 +11961,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // ErrAlias = typeof Err = typeof ErrImpl & (() => number) // The problem is each constituent of the intersection will be associated with typeof Err // And when extracting a type for typeof ErrImpl from typeof Err does not make sense. - if (isTypeQueryNode(existing) && getTypeFromTypeNode(context, existing) === type) { - const typeNode = syntacticNodeBuilder.tryReuseExistingTypeNode(context, existing); + if ( + isTypeQueryNode(existing) && + getTypeFromTypeNode(context, existing) === type + ) { + const typeNode = + syntacticNodeBuilder.tryReuseExistingTypeNode( + context, + existing + ); if (typeNode) { return typeNode; } @@ -7111,32 +11977,54 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (context.visitedTypes?.has(typeId)) { return createElidedInformationPlaceholder(context); } - return visitAndTransformType(type, createTypeNodeFromObjectType); + return visitAndTransformType( + type, + createTypeNodeFromObjectType + ); } - const isInstanceType = isClassInstanceSide(type) ? SymbolFlags.Type : SymbolFlags.Value; + const isInstanceType = isClassInstanceSide(type) + ? SymbolFlags.Type + : SymbolFlags.Value; if (isJSConstructor(symbol.valueDeclaration)) { // Instance and static types share the same symbol; only add 'typeof' for the static side. - return symbolToTypeNode(symbol, context, isInstanceType); + return symbolToTypeNode( + symbol, + context, + isInstanceType + ); } // Always use 'typeof T' for type of class, enum, and module objects else if ( !forceExpansion && - (symbol.flags & SymbolFlags.Class - && !forceClassExpansion - && !getBaseTypeVariableOfClass(symbol) - && !(symbol.valueDeclaration - && isClassLike(symbol.valueDeclaration) - && context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral - && (!isClassDeclaration(symbol.valueDeclaration) - || isSymbolAccessible(symbol, context.enclosingDeclaration, isInstanceType, /*shouldComputeAliasesToMakeVisible*/ false).accessibility !== SymbolAccessibility.Accessible)) - || symbol.flags & (SymbolFlags.Enum | SymbolFlags.ValueModule) - || shouldWriteTypeOfFunctionSymbol()) + ((symbol.flags & SymbolFlags.Class && + !forceClassExpansion && + !getBaseTypeVariableOfClass(symbol) && + !( + symbol.valueDeclaration && + isClassLike(symbol.valueDeclaration) && + context.flags & + NodeBuilderFlags.WriteClassExpressionAsTypeLiteral && + (!isClassDeclaration(symbol.valueDeclaration) || + isSymbolAccessible( + symbol, + context.enclosingDeclaration, + isInstanceType, + /*shouldComputeAliasesToMakeVisible*/ false + ).accessibility !== + SymbolAccessibility.Accessible) + )) || + symbol.flags & + (SymbolFlags.Enum | SymbolFlags.ValueModule) || + shouldWriteTypeOfFunctionSymbol()) ) { if (shouldExpandType(type, context)) { context.depth += 1; - } - else { - return symbolToTypeNode(symbol, context, isInstanceType); + } else { + return symbolToTypeNode( + symbol, + context, + isInstanceType + ); } } if (context.visitedTypes?.has(typeId)) { @@ -7144,41 +12032,87 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const typeAlias = getTypeAliasForTypeLiteral(type); if (typeAlias) { // The specified symbol flags need to be reinterpreted as type flags - return symbolToTypeNode(typeAlias, context, SymbolFlags.Type); - } - else { + return symbolToTypeNode( + typeAlias, + context, + SymbolFlags.Type + ); + } else { return createElidedInformationPlaceholder(context); } + } else { + return visitAndTransformType( + type, + createTypeNodeFromObjectType + ); } - else { - return visitAndTransformType(type, createTypeNodeFromObjectType); - } - } - else { + } else { // Anonymous types without a symbol are never circular. return createTypeNodeFromObjectType(type); } function shouldWriteTypeOfFunctionSymbol() { - const isStaticMethodSymbol = !!(symbol.flags & SymbolFlags.Method) && // typeof static method - some(symbol.declarations, declaration => isStatic(declaration) && !isLateBindableIndexSignature(getNameOfDeclaration(declaration)!)); - const isNonLocalFunctionSymbol = !!(symbol.flags & SymbolFlags.Function) && + const isStaticMethodSymbol = + !!(symbol.flags & SymbolFlags.Method) && // typeof static method + some( + symbol.declarations, + (declaration) => + isStatic(declaration) && + !isLateBindableIndexSignature( + getNameOfDeclaration(declaration)! + ) + ); + const isNonLocalFunctionSymbol = + !!(symbol.flags & SymbolFlags.Function) && (symbol.parent || // is exported function symbol - forEach(symbol.declarations, declaration => declaration.parent.kind === SyntaxKind.SourceFile || declaration.parent.kind === SyntaxKind.ModuleBlock)); + forEach( + symbol.declarations, + (declaration) => + declaration.parent.kind === + SyntaxKind.SourceFile || + declaration.parent.kind === + SyntaxKind.ModuleBlock + )); if (isStaticMethodSymbol || isNonLocalFunctionSymbol) { // typeof is allowed only for static/non local functions - return (!!(context.flags & NodeBuilderFlags.UseTypeOfFunction) || (context.visitedTypes?.has(typeId))) && // it is type of the symbol uses itself recursively - (!(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 - } - } - } - - function visitAndTransformType(type: T, transform: (type: T) => TypeNode) { + return ( + (!!( + context.flags & + NodeBuilderFlags.UseTypeOfFunction + ) || + context.visitedTypes?.has(typeId)) && // it is type of the symbol uses itself recursively + (!( + 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 + } + } + } + + function visitAndTransformType( + type: T, + transform: (type: T) => TypeNode + ) { const typeId = type.id; - const isConstructorObject = getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & SymbolFlags.Class; - const id = getObjectFlags(type) & ObjectFlags.Reference && (type as TypeReference & T).node ? "N" + getNodeId((type as TypeReference & T).node!) : - type.flags & TypeFlags.Conditional ? "N" + getNodeId((type as ConditionalType & T).root.node) : - type.symbol ? (isConstructorObject ? "+" : "") + getSymbolId(type.symbol) : - undefined; + const isConstructorObject = + getObjectFlags(type) & ObjectFlags.Anonymous && + type.symbol && + type.symbol.flags & SymbolFlags.Class; + const id = + getObjectFlags(type) & ObjectFlags.Reference && + (type as TypeReference & T).node + ? "N" + getNodeId((type as TypeReference & T).node!) + : type.flags & TypeFlags.Conditional + ? "N" + + getNodeId((type as ConditionalType & T).root.node) + : type.symbol + ? (isConstructorObject ? "+" : "") + + getSymbolId(type.symbol) + : undefined; // Since instantiations of the same anonymous type have the same symbol, tracking symbols instead // of types allows us to catch circular references to instantiations of the same anonymous type if (!context.visitedTypes) { @@ -7189,8 +12123,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Don't rely on type cache if we're expand a type, because we need to compute `canIncreaseExpansionDepth`. - const links = context.maxExpansionDepth >= 0 ? undefined : context.enclosingDeclaration && getNodeLinks(context.enclosingDeclaration); - const key = `${getTypeId(type)}|${context.flags}|${context.internalFlags}`; + const links = + context.maxExpansionDepth >= 0 + ? undefined + : context.enclosingDeclaration && + getNodeLinks(context.enclosingDeclaration); + const key = `${getTypeId(type)}|${context.flags}|${ + context.internalFlags + }`; if (links) { links.serializedTypes ||= new Map(); } @@ -7202,8 +12142,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { context.tracker.trackSymbol( symbol, enclosingDeclaration, - meaning, - ), + meaning + ) ); if (cachedResult.truncating) { context.truncating = true; @@ -7242,10 +12182,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; function deepCloneOrReuseNode(node: T): T { - if (!nodeIsSynthesized(node) && getParseTreeNode(node) === node) { + if ( + !nodeIsSynthesized(node) && + getParseTreeNode(node) === node + ) { return node; } - return setTextRange(context, factory.cloneNode(visitEachChildWorker(node, deepCloneOrReuseNode, /*context*/ undefined, deepCloneOrReuseNodes, deepCloneOrReuseNode)), node); + return setTextRange( + context, + factory.cloneNode( + visitEachChildWorker( + node, + deepCloneOrReuseNode, + /*context*/ undefined, + deepCloneOrReuseNodes, + deepCloneOrReuseNode + ) + ), + node + ); } function deepCloneOrReuseNodes( @@ -7253,61 +12208,116 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { visitor: Visitor, test?: (node: Node) => boolean, start?: number, - count?: number, + count?: number ): NodeArray | undefined { if (nodes && nodes.length === 0) { // Ensure we explicitly make a copy of an empty array; visitNodes will not do this unless the array has elements, // which can lead to us reusing the same empty NodeArray more than once within the same AST during type noding. - return setTextRangeWorker(factory.createNodeArray(/*elements*/ undefined, nodes.hasTrailingComma), nodes); + return setTextRangeWorker( + factory.createNodeArray( + /*elements*/ undefined, + nodes.hasTrailingComma + ), + nodes + ); } return visitNodes(nodes, visitor, test, start, count); } } function createTypeNodeFromObjectType(type: ObjectType): TypeNode { - if (isGenericMappedType(type) || (type as MappedType).containsError) { + if ( + isGenericMappedType(type) || + (type as MappedType).containsError + ) { return createMappedTypeNodeFromType(type as MappedType); } const resolved = resolveStructuredTypeMembers(type); - if (!resolved.properties.length && !resolved.indexInfos.length) { - if (!resolved.callSignatures.length && !resolved.constructSignatures.length) { + if ( + !resolved.properties.length && + !resolved.indexInfos.length + ) { + if ( + !resolved.callSignatures.length && + !resolved.constructSignatures.length + ) { context.approximateLength += 2; - return setEmitFlags(factory.createTypeLiteralNode(/*members*/ undefined), EmitFlags.SingleLine); + return setEmitFlags( + factory.createTypeLiteralNode( + /*members*/ undefined + ), + EmitFlags.SingleLine + ); } - if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) { + if ( + resolved.callSignatures.length === 1 && + !resolved.constructSignatures.length + ) { const signature = resolved.callSignatures[0]; - const signatureNode = signatureToSignatureDeclarationHelper(signature, SyntaxKind.FunctionType, context) as FunctionTypeNode; + const signatureNode = + signatureToSignatureDeclarationHelper( + signature, + SyntaxKind.FunctionType, + context + ) as FunctionTypeNode; return signatureNode; } - if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) { + if ( + resolved.constructSignatures.length === 1 && + !resolved.callSignatures.length + ) { const signature = resolved.constructSignatures[0]; - const signatureNode = signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructorType, context) as ConstructorTypeNode; + const signatureNode = + signatureToSignatureDeclarationHelper( + signature, + SyntaxKind.ConstructorType, + context + ) as ConstructorTypeNode; return signatureNode; } } - const abstractSignatures = filter(resolved.constructSignatures, signature => !!(signature.flags & SignatureFlags.Abstract)); + const abstractSignatures = filter( + resolved.constructSignatures, + (signature) => !!(signature.flags & SignatureFlags.Abstract) + ); if (some(abstractSignatures)) { - const types = map(abstractSignatures, getOrCreateTypeFromSignature); + const types = map( + abstractSignatures, + getOrCreateTypeFromSignature + ); // count the number of type elements excluding abstract constructors - const typeElementCount = resolved.callSignatures.length + - (resolved.constructSignatures.length - abstractSignatures.length) + + const typeElementCount = + resolved.callSignatures.length + + (resolved.constructSignatures.length - + abstractSignatures.length) + resolved.indexInfos.length + // exclude `prototype` when writing a class expression as a type literal, as per // the logic in `createTypeNodesFromResolvedType`. - (context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral ? - countWhere(resolved.properties, p => !(p.flags & SymbolFlags.Prototype)) : - length(resolved.properties)); + (context.flags & + NodeBuilderFlags.WriteClassExpressionAsTypeLiteral + ? countWhere( + resolved.properties, + (p) => !(p.flags & SymbolFlags.Prototype) + ) + : length(resolved.properties)); // don't include an empty object literal if there were no other static-side // properties to write, i.e. `abstract class C { }` becomes `abstract new () => {}` // and not `(abstract new () => {}) & {}` if (typeElementCount) { // create a copy of the object type without any abstract construct signatures. - types.push(getResolvedTypeWithoutAbstractConstructSignatures(resolved)); + types.push( + getResolvedTypeWithoutAbstractConstructSignatures( + resolved + ) + ); } - return typeToTypeNodeHelper(getIntersectionType(types), context); + return typeToTypeNodeHelper( + getIntersectionType(types), + context + ); } const restoreFlags = saveRestoreFlags(context); @@ -7316,89 +12326,215 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { restoreFlags(); const typeLiteralNode = factory.createTypeLiteralNode(members); context.approximateLength += 2; - setEmitFlags(typeLiteralNode, (context.flags & NodeBuilderFlags.MultilineObjectLiterals) ? 0 : EmitFlags.SingleLine); + setEmitFlags( + typeLiteralNode, + context.flags & NodeBuilderFlags.MultilineObjectLiterals + ? 0 + : EmitFlags.SingleLine + ); return typeLiteralNode; } function typeReferenceToTypeNode(type: TypeReference) { let typeArguments: readonly Type[] = getTypeArguments(type); - if (type.target === globalArrayType || type.target === globalReadonlyArrayType) { - if (context.flags & NodeBuilderFlags.WriteArrayAsGenericType) { - const typeArgumentNode = typeToTypeNodeHelper(typeArguments[0], context); - return factory.createTypeReferenceNode(type.target === globalArrayType ? "Array" : "ReadonlyArray", [typeArgumentNode]); + if ( + type.target === globalArrayType || + type.target === globalReadonlyArrayType + ) { + if ( + context.flags & NodeBuilderFlags.WriteArrayAsGenericType + ) { + const typeArgumentNode = typeToTypeNodeHelper( + typeArguments[0], + context + ); + return factory.createTypeReferenceNode( + type.target === globalArrayType + ? "Array" + : "ReadonlyArray", + [typeArgumentNode] + ); } - const elementType = typeToTypeNodeHelper(typeArguments[0], context); + const elementType = typeToTypeNodeHelper( + typeArguments[0], + context + ); const arrayType = factory.createArrayTypeNode(elementType); - return type.target === globalArrayType ? arrayType : factory.createTypeOperatorNode(SyntaxKind.ReadonlyKeyword, arrayType); - } - else if (type.target.objectFlags & ObjectFlags.Tuple) { - typeArguments = sameMap(typeArguments, (t, i) => removeMissingType(t, !!((type.target as TupleType).elementFlags[i] & ElementFlags.Optional))); + return type.target === globalArrayType + ? arrayType + : factory.createTypeOperatorNode( + SyntaxKind.ReadonlyKeyword, + arrayType + ); + } else if (type.target.objectFlags & ObjectFlags.Tuple) { + typeArguments = sameMap(typeArguments, (t, i) => + removeMissingType( + t, + !!( + (type.target as TupleType).elementFlags[i] & + ElementFlags.Optional + ) + ) + ); if (typeArguments.length > 0) { const arity = getTypeReferenceArity(type); - const tupleConstituentNodes = mapToTypeNodes(typeArguments.slice(0, arity), context); + const tupleConstituentNodes = mapToTypeNodes( + typeArguments.slice(0, arity), + context + ); if (tupleConstituentNodes) { - const { labeledElementDeclarations } = type.target as TupleType; - for (let i = 0; i < tupleConstituentNodes.length; i++) { - const flags = (type.target as TupleType).elementFlags[i]; - const labeledElementDeclaration = labeledElementDeclarations?.[i]; + const { labeledElementDeclarations } = + type.target as TupleType; + for ( + let i = 0; + i < tupleConstituentNodes.length; + i++ + ) { + const flags = (type.target as TupleType) + .elementFlags[i]; + const labeledElementDeclaration = + labeledElementDeclarations?.[i]; if (labeledElementDeclaration) { - tupleConstituentNodes[i] = factory.createNamedTupleMember( - flags & ElementFlags.Variable ? factory.createToken(SyntaxKind.DotDotDotToken) : undefined, - factory.createIdentifier(unescapeLeadingUnderscores(getTupleElementLabel(labeledElementDeclaration))), - flags & ElementFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined, - flags & ElementFlags.Rest ? factory.createArrayTypeNode(tupleConstituentNodes[i]) : - tupleConstituentNodes[i], - ); - } - else { - tupleConstituentNodes[i] = flags & ElementFlags.Variable ? factory.createRestTypeNode(flags & ElementFlags.Rest ? factory.createArrayTypeNode(tupleConstituentNodes[i]) : tupleConstituentNodes[i]) : - flags & ElementFlags.Optional ? factory.createOptionalTypeNode(tupleConstituentNodes[i]) : - tupleConstituentNodes[i]; + tupleConstituentNodes[i] = + factory.createNamedTupleMember( + flags & ElementFlags.Variable + ? factory.createToken( + SyntaxKind.DotDotDotToken + ) + : undefined, + factory.createIdentifier( + unescapeLeadingUnderscores( + getTupleElementLabel( + labeledElementDeclaration + ) + ) + ), + flags & ElementFlags.Optional + ? factory.createToken( + SyntaxKind.QuestionToken + ) + : undefined, + flags & ElementFlags.Rest + ? factory.createArrayTypeNode( + tupleConstituentNodes[i] + ) + : tupleConstituentNodes[i] + ); + } else { + tupleConstituentNodes[i] = + flags & ElementFlags.Variable + ? factory.createRestTypeNode( + flags & ElementFlags.Rest + ? factory.createArrayTypeNode( + tupleConstituentNodes[ + i + ] + ) + : tupleConstituentNodes[i] + ) + : flags & ElementFlags.Optional + ? factory.createOptionalTypeNode( + tupleConstituentNodes[i] + ) + : tupleConstituentNodes[i]; } } - const tupleTypeNode = setEmitFlags(factory.createTupleTypeNode(tupleConstituentNodes), EmitFlags.SingleLine); - return (type.target as TupleType).readonly ? factory.createTypeOperatorNode(SyntaxKind.ReadonlyKeyword, tupleTypeNode) : tupleTypeNode; + const tupleTypeNode = setEmitFlags( + factory.createTupleTypeNode( + tupleConstituentNodes + ), + EmitFlags.SingleLine + ); + return (type.target as TupleType).readonly + ? factory.createTypeOperatorNode( + SyntaxKind.ReadonlyKeyword, + tupleTypeNode + ) + : tupleTypeNode; } } - if (context.encounteredError || (context.flags & NodeBuilderFlags.AllowEmptyTuple)) { - const tupleTypeNode = setEmitFlags(factory.createTupleTypeNode([]), EmitFlags.SingleLine); - return (type.target as TupleType).readonly ? factory.createTypeOperatorNode(SyntaxKind.ReadonlyKeyword, tupleTypeNode) : tupleTypeNode; + if ( + context.encounteredError || + context.flags & NodeBuilderFlags.AllowEmptyTuple + ) { + const tupleTypeNode = setEmitFlags( + factory.createTupleTypeNode([]), + EmitFlags.SingleLine + ); + return (type.target as TupleType).readonly + ? factory.createTypeOperatorNode( + SyntaxKind.ReadonlyKeyword, + tupleTypeNode + ) + : tupleTypeNode; } context.encounteredError = true; return undefined!; // TODO: GH#18217 - } - else if ( - context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral && + } else if ( + context.flags & + NodeBuilderFlags.WriteClassExpressionAsTypeLiteral && type.symbol.valueDeclaration && isClassLike(type.symbol.valueDeclaration) && - !isValueSymbolAccessible(type.symbol, context.enclosingDeclaration) + !isValueSymbolAccessible( + type.symbol, + context.enclosingDeclaration + ) ) { return createAnonymousTypeNode(type); - } - else { + } else { const outerTypeParameters = type.target.outerTypeParameters; let i = 0; - let resultType: TypeReferenceNode | ImportTypeNode | undefined; + let resultType: + | TypeReferenceNode + | ImportTypeNode + | undefined; if (outerTypeParameters) { const length = outerTypeParameters.length; while (i < length) { // Find group of type arguments for type parameters with the same declaring container. const start = i; - const parent = getParentSymbolOfTypeParameter(outerTypeParameters[i])!; + const parent = getParentSymbolOfTypeParameter( + outerTypeParameters[i] + )!; do { i++; - } - while (i < length && getParentSymbolOfTypeParameter(outerTypeParameters[i]) === parent); + } while ( + i < length && + getParentSymbolOfTypeParameter( + outerTypeParameters[i] + ) === parent + ); // When type parameters are their own type arguments for the whole group (i.e. we have // the default outer type arguments), we don't show the group. - if (!rangeEquals(outerTypeParameters, typeArguments, start, i)) { - const typeArgumentSlice = mapToTypeNodes(typeArguments.slice(start, i), context); + if ( + !rangeEquals( + outerTypeParameters, + typeArguments, + start, + i + ) + ) { + const typeArgumentSlice = mapToTypeNodes( + typeArguments.slice(start, i), + context + ); const restoreFlags = saveRestoreFlags(context); - context.flags |= NodeBuilderFlags.ForbidIndexedAccessSymbolReferences; - const ref = symbolToTypeNode(parent, context, SymbolFlags.Type, typeArgumentSlice) as TypeReferenceNode | ImportTypeNode; + context.flags |= + NodeBuilderFlags.ForbidIndexedAccessSymbolReferences; + const ref = symbolToTypeNode( + parent, + context, + SymbolFlags.Type, + typeArgumentSlice + ) as TypeReferenceNode | ImportTypeNode; restoreFlags(); - resultType = !resultType ? ref : appendReferenceToType(resultType, ref as TypeReferenceNode); + resultType = !resultType + ? ref + : appendReferenceToType( + resultType, + ref as TypeReferenceNode + ); } } } @@ -7406,27 +12542,68 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (typeArguments.length > 0) { let typeParameterCount = 0; if (type.target.typeParameters) { - typeParameterCount = Math.min(type.target.typeParameters.length, typeArguments.length); + typeParameterCount = Math.min( + type.target.typeParameters.length, + typeArguments.length + ); // Maybe we should do this for more types, but for now we only elide type arguments that are // identical to their associated type parameters' defaults for `Iterable`, `IterableIterator`, // `AsyncIterable`, and `AsyncIterableIterator` to provide backwards-compatible .d.ts emit due // to each now having three type parameters instead of only one. if ( - isReferenceToType(type, getGlobalIterableType(/*reportErrors*/ false)) || - isReferenceToType(type, getGlobalIterableIteratorType(/*reportErrors*/ false)) || - isReferenceToType(type, getGlobalAsyncIterableType(/*reportErrors*/ false)) || - isReferenceToType(type, getGlobalAsyncIterableIteratorType(/*reportErrors*/ false)) + isReferenceToType( + type, + getGlobalIterableType( + /*reportErrors*/ false + ) + ) || + isReferenceToType( + type, + getGlobalIterableIteratorType( + /*reportErrors*/ false + ) + ) || + isReferenceToType( + type, + getGlobalAsyncIterableType( + /*reportErrors*/ false + ) + ) || + isReferenceToType( + type, + getGlobalAsyncIterableIteratorType( + /*reportErrors*/ false + ) + ) ) { if ( - !type.node || !isTypeReferenceNode(type.node) || !type.node.typeArguments || - type.node.typeArguments.length < typeParameterCount + !type.node || + !isTypeReferenceNode(type.node) || + !type.node.typeArguments || + type.node.typeArguments.length < + typeParameterCount ) { while (typeParameterCount > 0) { - const typeArgument = typeArguments[typeParameterCount - 1]; - const typeParameter = type.target.typeParameters[typeParameterCount - 1]; - const defaultType = getDefaultFromTypeParameter(typeParameter); - if (!defaultType || !isTypeIdenticalTo(typeArgument, defaultType)) { + const typeArgument = + typeArguments[ + typeParameterCount - 1 + ]; + const typeParameter = + type.target.typeParameters[ + typeParameterCount - 1 + ]; + const defaultType = + getDefaultFromTypeParameter( + typeParameter + ); + if ( + !defaultType || + !isTypeIdenticalTo( + typeArgument, + defaultType + ) + ) { break; } typeParameterCount--; @@ -7435,30 +12612,62 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - typeArgumentNodes = mapToTypeNodes(typeArguments.slice(i, typeParameterCount), context); + typeArgumentNodes = mapToTypeNodes( + typeArguments.slice(i, typeParameterCount), + context + ); } const restoreFlags = saveRestoreFlags(context); - context.flags |= NodeBuilderFlags.ForbidIndexedAccessSymbolReferences; - const finalRef = symbolToTypeNode(type.symbol, context, SymbolFlags.Type, typeArgumentNodes); + context.flags |= + NodeBuilderFlags.ForbidIndexedAccessSymbolReferences; + const finalRef = symbolToTypeNode( + type.symbol, + context, + SymbolFlags.Type, + typeArgumentNodes + ); restoreFlags(); - return !resultType ? finalRef : appendReferenceToType(resultType, finalRef as TypeReferenceNode); + return !resultType + ? finalRef + : appendReferenceToType( + resultType, + finalRef as TypeReferenceNode + ); } } - function appendReferenceToType(root: TypeReferenceNode | ImportTypeNode, ref: TypeReferenceNode): TypeReferenceNode | ImportTypeNode { + function appendReferenceToType( + root: TypeReferenceNode | ImportTypeNode, + ref: TypeReferenceNode + ): TypeReferenceNode | ImportTypeNode { if (isImportTypeNode(root)) { // first shift type arguments let typeArguments = root.typeArguments; let qualifier = root.qualifier; if (qualifier) { if (isIdentifier(qualifier)) { - if (typeArguments !== getIdentifierTypeArguments(qualifier)) { - qualifier = setIdentifierTypeArguments(factory.cloneNode(qualifier), typeArguments); + if ( + typeArguments !== + getIdentifierTypeArguments(qualifier) + ) { + qualifier = setIdentifierTypeArguments( + factory.cloneNode(qualifier), + typeArguments + ); } - } - else { - if (typeArguments !== getIdentifierTypeArguments(qualifier.right)) { - qualifier = factory.updateQualifiedName(qualifier, qualifier.left, setIdentifierTypeArguments(factory.cloneNode(qualifier.right), typeArguments)); + } else { + if ( + typeArguments !== + getIdentifierTypeArguments(qualifier.right) + ) { + qualifier = factory.updateQualifiedName( + qualifier, + qualifier.left, + setIdentifierTypeArguments( + factory.cloneNode(qualifier.right), + typeArguments + ) + ); } } } @@ -7466,7 +12675,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // then move qualifiers const ids = getAccessStack(ref); for (const id of ids) { - qualifier = qualifier ? factory.createQualifiedName(qualifier, id) : id; + qualifier = qualifier + ? factory.createQualifiedName(qualifier, id) + : id; } return factory.updateImportTypeNode( root, @@ -7474,21 +12685,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { root.attributes, qualifier, typeArguments, - root.isTypeOf, + root.isTypeOf ); - } - else { + } else { // first shift type arguments let typeArguments = root.typeArguments; let typeName = root.typeName; if (isIdentifier(typeName)) { - if (typeArguments !== getIdentifierTypeArguments(typeName)) { - typeName = setIdentifierTypeArguments(factory.cloneNode(typeName), typeArguments); + if ( + typeArguments !== + getIdentifierTypeArguments(typeName) + ) { + typeName = setIdentifierTypeArguments( + factory.cloneNode(typeName), + typeArguments + ); } - } - else { - if (typeArguments !== getIdentifierTypeArguments(typeName.right)) { - typeName = factory.updateQualifiedName(typeName, typeName.left, setIdentifierTypeArguments(factory.cloneNode(typeName.right), typeArguments)); + } else { + if ( + typeArguments !== + getIdentifierTypeArguments(typeName.right) + ) { + typeName = factory.updateQualifiedName( + typeName, + typeName.left, + setIdentifierTypeArguments( + factory.cloneNode(typeName.right), + typeArguments + ) + ); } } typeArguments = ref.typeArguments; @@ -7500,7 +12725,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return factory.updateTypeReferenceNode( root, typeName, - typeArguments, + typeArguments ); } } @@ -7516,56 +12741,142 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return ids; } - function indexInfoToObjectComputedNamesOrSignatureDeclaration(indexInfo: IndexInfo, context: NodeBuilderContext, typeNode: TypeNode | undefined): [IndexSignatureDeclaration] | PropertySignature[] { + function indexInfoToObjectComputedNamesOrSignatureDeclaration( + indexInfo: IndexInfo, + context: NodeBuilderContext, + typeNode: TypeNode | undefined + ): [IndexSignatureDeclaration] | PropertySignature[] { if (indexInfo.components) { // Index info is derived from object or class computed property names (plus explicit named members) - we can clone those instead of writing out the result computed index signature - const allComponentComputedNamesSerializable = every(indexInfo.components, e => { - return !!(e.name && isComputedPropertyName(e.name) && isEntityNameExpression(e.name.expression) && context.enclosingDeclaration && isEntityNameVisible(e.name.expression, context.enclosingDeclaration, /*shouldComputeAliasToMakeVisible*/ false)?.accessibility === SymbolAccessibility.Accessible); - }); + const allComponentComputedNamesSerializable = every( + indexInfo.components, + (e) => { + return !!( + e.name && + isComputedPropertyName(e.name) && + isEntityNameExpression(e.name.expression) && + context.enclosingDeclaration && + isEntityNameVisible( + e.name.expression, + context.enclosingDeclaration, + /*shouldComputeAliasToMakeVisible*/ false + )?.accessibility === + SymbolAccessibility.Accessible + ); + } + ); if (allComponentComputedNamesSerializable) { // Only use computed name serialization form if all components are visible and take the `a.b.c` form - const newComponents = filter(indexInfo.components, e => { - // skip late bound props that contribute to the index signature - they'll be created by property creation anyway - return !hasLateBindableName(e); - }); - return map(newComponents, e => { + const newComponents = filter( + indexInfo.components, + (e) => { + // skip late bound props that contribute to the index signature - they'll be created by property creation anyway + return !hasLateBindableName(e); + } + ); + return map(newComponents, (e) => { // Still need to track visibility even if we've already checked it to paint references as used - trackComputedName(e.name.expression as EntityNameExpression, context.enclosingDeclaration, context); + trackComputedName( + e.name.expression as EntityNameExpression, + context.enclosingDeclaration, + context + ); return setTextRange( context, factory.createPropertySignature( - indexInfo.isReadonly ? [factory.createModifier(SyntaxKind.ReadonlyKeyword)] : undefined, + indexInfo.isReadonly + ? [ + factory.createModifier( + SyntaxKind.ReadonlyKeyword + ), + ] + : undefined, e.name, - (isPropertySignature(e) || isPropertyDeclaration(e) || isMethodSignature(e) || isMethodDeclaration(e) || isGetAccessor(e) || isSetAccessor(e)) && e.questionToken ? factory.createToken(SyntaxKind.QuestionToken) : undefined, - typeNode || typeToTypeNodeHelper(getTypeOfSymbol(e.symbol), context), + (isPropertySignature(e) || + isPropertyDeclaration(e) || + isMethodSignature(e) || + isMethodDeclaration(e) || + isGetAccessor(e) || + isSetAccessor(e)) && + e.questionToken + ? factory.createToken( + SyntaxKind.QuestionToken + ) + : undefined, + typeNode || + typeToTypeNodeHelper( + getTypeOfSymbol(e.symbol), + context + ) ), - e, + e ); }); } } - return [indexInfoToIndexSignatureDeclarationHelper(indexInfo, context, typeNode)]; + return [ + indexInfoToIndexSignatureDeclarationHelper( + indexInfo, + context, + typeNode + ), + ]; } - function createTypeNodesFromResolvedType(resolvedType: ResolvedType): TypeElement[] | undefined { + function createTypeNodesFromResolvedType( + resolvedType: ResolvedType + ): TypeElement[] | undefined { if (checkTruncationLength(context)) { context.out.truncated = true; if (context.flags & NodeBuilderFlags.NoTruncation) { - return [addSyntheticTrailingComment(factory.createNotEmittedTypeElement(), SyntaxKind.MultiLineCommentTrivia, "elided")]; + return [ + addSyntheticTrailingComment( + factory.createNotEmittedTypeElement(), + SyntaxKind.MultiLineCommentTrivia, + "elided" + ), + ]; } - return [factory.createPropertySignature(/*modifiers*/ undefined, "...", /*questionToken*/ undefined, /*type*/ undefined)]; + return [ + factory.createPropertySignature( + /*modifiers*/ undefined, + "...", + /*questionToken*/ undefined, + /*type*/ undefined + ), + ]; } context.typeStack.push(-1); const typeElements: TypeElement[] = []; for (const signature of resolvedType.callSignatures) { - typeElements.push(signatureToSignatureDeclarationHelper(signature, SyntaxKind.CallSignature, context) as CallSignatureDeclaration); + typeElements.push( + signatureToSignatureDeclarationHelper( + signature, + SyntaxKind.CallSignature, + context + ) as CallSignatureDeclaration + ); } for (const signature of resolvedType.constructSignatures) { if (signature.flags & SignatureFlags.Abstract) continue; - typeElements.push(signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructSignature, context) as ConstructSignatureDeclaration); + typeElements.push( + signatureToSignatureDeclarationHelper( + signature, + SyntaxKind.ConstructSignature, + context + ) as ConstructSignatureDeclaration + ); } for (const info of resolvedType.indexInfos) { - typeElements.push(...indexInfoToObjectComputedNamesOrSignatureDeclaration(info, context, resolvedType.objectFlags & ObjectFlags.ReverseMapped ? createElidedInformationPlaceholder(context) : undefined)); + typeElements.push( + ...indexInfoToObjectComputedNamesOrSignatureDeclaration( + info, + context, + resolvedType.objectFlags & ObjectFlags.ReverseMapped + ? createElidedInformationPlaceholder(context) + : undefined + ) + ); } const properties = resolvedType.properties; @@ -7576,46 +12887,100 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let i = 0; for (const propertySymbol of properties) { - if (isExpanding(context) && propertySymbol.flags & SymbolFlags.Prototype) { + if ( + isExpanding(context) && + propertySymbol.flags & SymbolFlags.Prototype + ) { continue; } i++; - if (context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral) { + if ( + context.flags & + NodeBuilderFlags.WriteClassExpressionAsTypeLiteral + ) { if (propertySymbol.flags & SymbolFlags.Prototype) { continue; } - if (getDeclarationModifierFlagsFromSymbol(propertySymbol) & (ModifierFlags.Private | ModifierFlags.Protected) && context.tracker.reportPrivateInBaseOfClassExpression) { - context.tracker.reportPrivateInBaseOfClassExpression(unescapeLeadingUnderscores(propertySymbol.escapedName)); + if ( + getDeclarationModifierFlagsFromSymbol( + propertySymbol + ) & + (ModifierFlags.Private | + ModifierFlags.Protected) && + context.tracker.reportPrivateInBaseOfClassExpression + ) { + context.tracker.reportPrivateInBaseOfClassExpression( + unescapeLeadingUnderscores( + propertySymbol.escapedName + ) + ); } } - if (checkTruncationLength(context) && (i + 2 < properties.length - 1)) { + if ( + checkTruncationLength(context) && + i + 2 < properties.length - 1 + ) { context.out.truncated = true; if (context.flags & NodeBuilderFlags.NoTruncation) { const typeElement = typeElements.pop()!; - typeElements.push(addSyntheticTrailingComment(typeElement, SyntaxKind.MultiLineCommentTrivia, `... ${properties.length - i} more elided ...`)); - } - else { - typeElements.push(factory.createPropertySignature(/*modifiers*/ undefined, `... ${properties.length - i} more ...`, /*questionToken*/ undefined, /*type*/ undefined)); + typeElements.push( + addSyntheticTrailingComment( + typeElement, + SyntaxKind.MultiLineCommentTrivia, + `... ${ + properties.length - i + } more elided ...` + ) + ); + } else { + typeElements.push( + factory.createPropertySignature( + /*modifiers*/ undefined, + `... ${properties.length - i} more ...`, + /*questionToken*/ undefined, + /*type*/ undefined + ) + ); } - addPropertyToElementList(properties[properties.length - 1], context, typeElements); + addPropertyToElementList( + properties[properties.length - 1], + context, + typeElements + ); break; } - addPropertyToElementList(propertySymbol, context, typeElements); + addPropertyToElementList( + propertySymbol, + context, + typeElements + ); } context.typeStack.pop(); return typeElements.length ? typeElements : undefined; } } - function createElidedInformationPlaceholder(context: NodeBuilderContext) { + function createElidedInformationPlaceholder( + context: NodeBuilderContext + ) { context.approximateLength += 3; if (!(context.flags & NodeBuilderFlags.NoTruncation)) { - return factory.createTypeReferenceNode(factory.createIdentifier("..."), /*typeArguments*/ undefined); + return factory.createTypeReferenceNode( + factory.createIdentifier("..."), + /*typeArguments*/ undefined + ); } - return addSyntheticLeadingComment(factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), SyntaxKind.MultiLineCommentTrivia, "elided"); + return addSyntheticLeadingComment( + factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), + SyntaxKind.MultiLineCommentTrivia, + "elided" + ); } - function shouldUsePlaceholderForProperty(propertySymbol: Symbol, context: NodeBuilderContext) { + function shouldUsePlaceholderForProperty( + propertySymbol: Symbol, + context: NodeBuilderContext + ) { // Use placeholders for reverse mapped types we've either // (1) already descended into, or // (2) are nested reverse mappings within a mapping over a non-anonymous type, or @@ -7627,22 +12992,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // come from mappings over library functions. // Condition (3) limits printing of possibly infinitely deep reverse mapped types. const depth = 3; - return !!(getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped) - && ( - contains(context.reverseMappedStack, propertySymbol as ReverseMappedSymbol) - || ( - context.reverseMappedStack?.[0] - && !(getObjectFlags(last(context.reverseMappedStack).links.propertyType) & ObjectFlags.Anonymous) - ) - || isDeeplyNestedReverseMappedTypeProperty() - ); + return ( + !!(getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped) && + (contains( + context.reverseMappedStack, + propertySymbol as ReverseMappedSymbol + ) || + (context.reverseMappedStack?.[0] && + !( + getObjectFlags( + last(context.reverseMappedStack).links + .propertyType + ) & ObjectFlags.Anonymous + )) || + isDeeplyNestedReverseMappedTypeProperty()) + ); function isDeeplyNestedReverseMappedTypeProperty() { if ((context.reverseMappedStack?.length ?? 0) < depth) { return false; } for (let i = 0; i < depth; i++) { - const prop = context.reverseMappedStack![context.reverseMappedStack!.length - 1 - i]; - if (prop.links.mappedType.symbol !== (propertySymbol as ReverseMappedSymbol).links.mappedType.symbol) { + const prop = + context.reverseMappedStack![ + context.reverseMappedStack!.length - 1 - i + ]; + if ( + prop.links.mappedType.symbol !== + (propertySymbol as ReverseMappedSymbol).links.mappedType + .symbol + ) { return false; } } @@ -7650,68 +13028,161 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function addPropertyToElementList(propertySymbol: Symbol, context: NodeBuilderContext, typeElements: TypeElement[]) { - const propertyIsReverseMapped = !!(getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped); - const propertyType = shouldUsePlaceholderForProperty(propertySymbol, context) ? - anyType : getNonMissingTypeOfSymbol(propertySymbol); + function addPropertyToElementList( + propertySymbol: Symbol, + context: NodeBuilderContext, + typeElements: TypeElement[] + ) { + const propertyIsReverseMapped = !!( + getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped + ); + const propertyType = shouldUsePlaceholderForProperty( + propertySymbol, + context + ) + ? anyType + : getNonMissingTypeOfSymbol(propertySymbol); const saveEnclosingDeclaration = context.enclosingDeclaration; context.enclosingDeclaration = undefined; - if (context.tracker.canTrackSymbol && isLateBoundName(propertySymbol.escapedName)) { + if ( + context.tracker.canTrackSymbol && + isLateBoundName(propertySymbol.escapedName) + ) { if (propertySymbol.declarations) { const decl = first(propertySymbol.declarations); if (hasLateBindableName(decl)) { if (isBinaryExpression(decl)) { const name = getNameOfDeclaration(decl); - if (name && isElementAccessExpression(name) && isPropertyAccessEntityNameExpression(name.argumentExpression)) { - trackComputedName(name.argumentExpression, saveEnclosingDeclaration, context); + if ( + name && + isElementAccessExpression(name) && + isPropertyAccessEntityNameExpression( + name.argumentExpression + ) + ) { + trackComputedName( + name.argumentExpression, + saveEnclosingDeclaration, + context + ); } - } - else { - trackComputedName(decl.name.expression, saveEnclosingDeclaration, context); + } else { + trackComputedName( + decl.name.expression, + saveEnclosingDeclaration, + context + ); } } - } - else { - context.tracker.reportNonSerializableProperty(symbolToString(propertySymbol)); + } else { + context.tracker.reportNonSerializableProperty( + symbolToString(propertySymbol) + ); } } - context.enclosingDeclaration = propertySymbol.valueDeclaration || propertySymbol.declarations?.[0] || saveEnclosingDeclaration; - const propertyName = getPropertyNameNodeForSymbol(propertySymbol, context); + context.enclosingDeclaration = + propertySymbol.valueDeclaration || + propertySymbol.declarations?.[0] || + saveEnclosingDeclaration; + const propertyName = getPropertyNameNodeForSymbol( + propertySymbol, + context + ); context.enclosingDeclaration = saveEnclosingDeclaration; context.approximateLength += symbolName(propertySymbol).length + 1; if (propertySymbol.flags & SymbolFlags.Accessor) { const writeType = getWriteTypeOfSymbol(propertySymbol); - if (propertyType !== writeType && !isErrorType(propertyType) && !isErrorType(writeType)) { + if ( + propertyType !== writeType && + !isErrorType(propertyType) && + !isErrorType(writeType) + ) { const symbolMapper = getSymbolLinks(propertySymbol).mapper; - const getterDeclaration = getDeclarationOfKind(propertySymbol, SyntaxKind.GetAccessor)!; - const getterSignature = getSignatureFromDeclaration(getterDeclaration); + const getterDeclaration = + getDeclarationOfKind( + propertySymbol, + SyntaxKind.GetAccessor + )!; + const getterSignature = + getSignatureFromDeclaration(getterDeclaration); typeElements.push( setCommentRange( context, - signatureToSignatureDeclarationHelper(symbolMapper ? instantiateSignature(getterSignature, symbolMapper) : getterSignature, SyntaxKind.GetAccessor, context, { name: propertyName }) as GetAccessorDeclaration, - getterDeclaration, - ), + signatureToSignatureDeclarationHelper( + symbolMapper + ? instantiateSignature( + getterSignature, + symbolMapper + ) + : getterSignature, + SyntaxKind.GetAccessor, + context, + { name: propertyName } + ) as GetAccessorDeclaration, + getterDeclaration + ) ); - const setterDeclaration = getDeclarationOfKind(propertySymbol, SyntaxKind.SetAccessor)!; - const setterSignature = getSignatureFromDeclaration(setterDeclaration); + const setterDeclaration = + getDeclarationOfKind( + propertySymbol, + SyntaxKind.SetAccessor + )!; + const setterSignature = + getSignatureFromDeclaration(setterDeclaration); typeElements.push( setCommentRange( context, - signatureToSignatureDeclarationHelper(symbolMapper ? instantiateSignature(setterSignature, symbolMapper) : setterSignature, SyntaxKind.SetAccessor, context, { name: propertyName }) as SetAccessorDeclaration, - setterDeclaration, - ), + signatureToSignatureDeclarationHelper( + symbolMapper + ? instantiateSignature( + setterSignature, + symbolMapper + ) + : setterSignature, + SyntaxKind.SetAccessor, + context, + { name: propertyName } + ) as SetAccessorDeclaration, + setterDeclaration + ) ); return; } } - const optionalToken = propertySymbol.flags & SymbolFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined; - if (propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(propertyType).length && !isReadonlySymbol(propertySymbol)) { - const signatures = getSignaturesOfType(filterType(propertyType, t => !(t.flags & TypeFlags.Undefined)), SignatureKind.Call); + const optionalToken = + propertySymbol.flags & SymbolFlags.Optional + ? factory.createToken(SyntaxKind.QuestionToken) + : undefined; + if ( + propertySymbol.flags & + (SymbolFlags.Function | SymbolFlags.Method) && + !getPropertiesOfObjectType(propertyType).length && + !isReadonlySymbol(propertySymbol) + ) { + const signatures = getSignaturesOfType( + filterType( + propertyType, + (t) => !(t.flags & TypeFlags.Undefined) + ), + SignatureKind.Call + ); for (const signature of signatures) { - const methodDeclaration = signatureToSignatureDeclarationHelper(signature, SyntaxKind.MethodSignature, context, { name: propertyName, questionToken: optionalToken }) as MethodSignature; - typeElements.push(preserveCommentsOn(methodDeclaration, signature.declaration || propertySymbol.valueDeclaration)); + const methodDeclaration = + signatureToSignatureDeclarationHelper( + signature, + SyntaxKind.MethodSignature, + context, + { name: propertyName, questionToken: optionalToken } + ) as MethodSignature; + typeElements.push( + preserveCommentsOn( + methodDeclaration, + signature.declaration || + propertySymbol.valueDeclaration + ) + ); } if (signatures.length || !optionalToken) { return; @@ -7720,19 +13191,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let propertyTypeNode: TypeNode; if (shouldUsePlaceholderForProperty(propertySymbol, context)) { propertyTypeNode = createElidedInformationPlaceholder(context); - } - else { + } else { if (propertyIsReverseMapped) { context.reverseMappedStack ||= []; - context.reverseMappedStack.push(propertySymbol as ReverseMappedSymbol); + context.reverseMappedStack.push( + propertySymbol as ReverseMappedSymbol + ); } - propertyTypeNode = propertyType ? serializeTypeForDeclaration(context, /*declaration*/ undefined, propertyType, propertySymbol) : factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); + propertyTypeNode = propertyType + ? serializeTypeForDeclaration( + context, + /*declaration*/ undefined, + propertyType, + propertySymbol + ) + : factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); if (propertyIsReverseMapped) { context.reverseMappedStack!.pop(); } } - const modifiers = isReadonlySymbol(propertySymbol) ? [factory.createToken(SyntaxKind.ReadonlyKeyword)] : undefined; + const modifiers = isReadonlySymbol(propertySymbol) + ? [factory.createToken(SyntaxKind.ReadonlyKeyword)] + : undefined; if (modifiers) { context.approximateLength += 9; } @@ -7740,20 +13221,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { modifiers, propertyName, optionalToken, - propertyTypeNode, + propertyTypeNode ); - typeElements.push(preserveCommentsOn(propertySignature, propertySymbol.valueDeclaration)); + typeElements.push( + preserveCommentsOn( + propertySignature, + propertySymbol.valueDeclaration + ) + ); - function preserveCommentsOn(node: T, range: Node | undefined) { - const jsdocPropertyTag = propertySymbol.declarations?.find((d): d is JSDocPropertyTag => d.kind === SyntaxKind.JSDocPropertyTag); + function preserveCommentsOn( + node: T, + range: Node | undefined + ) { + const jsdocPropertyTag = propertySymbol.declarations?.find( + (d): d is JSDocPropertyTag => + d.kind === SyntaxKind.JSDocPropertyTag + ); if (jsdocPropertyTag) { - const commentText = getTextOfJSDocComment(jsdocPropertyTag.comment); + const commentText = getTextOfJSDocComment( + jsdocPropertyTag.comment + ); if (commentText) { - setSyntheticLeadingComments(node, [{ kind: SyntaxKind.MultiLineCommentTrivia, text: "*\n * " + commentText.replace(/\n/g, "\n * ") + "\n ", pos: -1, end: -1, hasTrailingNewLine: true }]); - } - } - else if (range) { + setSyntheticLeadingComments(node, [ + { + kind: SyntaxKind.MultiLineCommentTrivia, + text: + "*\n * " + + commentText.replace(/\n/g, "\n * ") + + "\n ", + pos: -1, + end: -1, + hasTrailingNewLine: true, + }, + ]); + } + } else if (range) { // Copy comments to node for declaration emit setCommentRange(context, node, range); } @@ -7761,50 +13265,100 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function setCommentRange(context: NodeBuilderContext, node: T, range: Node): T { - if (context.enclosingFile && context.enclosingFile === getSourceFileOfNode(range)) { + function setCommentRange( + context: NodeBuilderContext, + node: T, + range: Node + ): T { + if ( + context.enclosingFile && + context.enclosingFile === getSourceFileOfNode(range) + ) { // Copy comments to node for declaration emit return setCommentRangeWorker(node, range); } return node; } - function mapToTypeNodes(types: readonly Type[] | undefined, context: NodeBuilderContext, isBareList?: boolean): TypeNode[] | undefined { + function mapToTypeNodes( + types: readonly Type[] | undefined, + context: NodeBuilderContext, + isBareList?: boolean + ): TypeNode[] | undefined { if (some(types)) { if (checkTruncationLength(context)) { context.out.truncated = true; if (!isBareList) { return [ context.flags & NodeBuilderFlags.NoTruncation - ? addSyntheticLeadingComment(factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), SyntaxKind.MultiLineCommentTrivia, "elided") - : factory.createTypeReferenceNode("...", /*typeArguments*/ undefined), + ? addSyntheticLeadingComment( + factory.createKeywordTypeNode( + SyntaxKind.AnyKeyword + ), + SyntaxKind.MultiLineCommentTrivia, + "elided" + ) + : factory.createTypeReferenceNode( + "...", + /*typeArguments*/ undefined + ), ]; - } - else if (types.length > 2) { + } else if (types.length > 2) { return [ typeToTypeNodeHelper(types[0], context), context.flags & NodeBuilderFlags.NoTruncation - ? addSyntheticLeadingComment(factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), SyntaxKind.MultiLineCommentTrivia, `... ${types.length - 2} more elided ...`) - : factory.createTypeReferenceNode(`... ${types.length - 2} more ...`, /*typeArguments*/ undefined), - typeToTypeNodeHelper(types[types.length - 1], context), + ? addSyntheticLeadingComment( + factory.createKeywordTypeNode( + SyntaxKind.AnyKeyword + ), + SyntaxKind.MultiLineCommentTrivia, + `... ${types.length - 2} more elided ...` + ) + : factory.createTypeReferenceNode( + `... ${types.length - 2} more ...`, + /*typeArguments*/ undefined + ), + typeToTypeNodeHelper( + types[types.length - 1], + context + ), ]; } } - const mayHaveNameCollisions = !(context.flags & NodeBuilderFlags.UseFullyQualifiedType); + const mayHaveNameCollisions = !( + context.flags & NodeBuilderFlags.UseFullyQualifiedType + ); /** Map from type reference identifier text to [type, index in `result` where the type node is] */ - const seenNames = mayHaveNameCollisions ? createMultiMap<__String, [Type, number]>() : undefined; + const seenNames = mayHaveNameCollisions + ? createMultiMap<__String, [Type, number]>() + : undefined; const result: TypeNode[] = []; let i = 0; for (const type of types) { i++; - if (checkTruncationLength(context) && (i + 2 < types.length - 1)) { + if ( + checkTruncationLength(context) && + i + 2 < types.length - 1 + ) { context.out.truncated = true; result.push( context.flags & NodeBuilderFlags.NoTruncation - ? addSyntheticLeadingComment(factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), SyntaxKind.MultiLineCommentTrivia, `... ${types.length - i} more elided ...`) - : factory.createTypeReferenceNode(`... ${types.length - i} more ...`, /*typeArguments*/ undefined), + ? addSyntheticLeadingComment( + factory.createKeywordTypeNode( + SyntaxKind.AnyKeyword + ), + SyntaxKind.MultiLineCommentTrivia, + `... ${types.length - i} more elided ...` + ) + : factory.createTypeReferenceNode( + `... ${types.length - i} more ...`, + /*typeArguments*/ undefined + ) + ); + const typeNode = typeToTypeNodeHelper( + types[types.length - 1], + context ); - const typeNode = typeToTypeNodeHelper(types[types.length - 1], context); if (typeNode) { result.push(typeNode); } @@ -7815,7 +13369,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (typeNode) { result.push(typeNode); if (seenNames && isIdentifierTypeReference(typeNode)) { - seenNames.add(typeNode.typeName.escapedText, [type, result.length - 1]); + seenNames.add(typeNode.typeName.escapedText, [ + type, + result.length - 1, + ]); } } } @@ -7830,10 +13387,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // `UseFullyQualifiedType` flag enabled. const restoreFlags = saveRestoreFlags(context); context.flags |= NodeBuilderFlags.UseFullyQualifiedType; - seenNames.forEach(types => { - if (!arrayIsHomogeneous(types, ([a], [b]) => typesAreSameReference(a, b))) { + seenNames.forEach((types) => { + if ( + !arrayIsHomogeneous(types, ([a], [b]) => + typesAreSameReference(a, b) + ) + ) { for (const [type, resultIndex] of types) { - result[resultIndex] = typeToTypeNodeHelper(type, context); + result[resultIndex] = typeToTypeNodeHelper( + type, + context + ); } } }); @@ -7845,14 +13409,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function typesAreSameReference(a: Type, b: Type): boolean { - return a === b - || !!a.symbol && a.symbol === b.symbol - || !!a.aliasSymbol && a.aliasSymbol === b.aliasSymbol; + return ( + a === b || + (!!a.symbol && a.symbol === b.symbol) || + (!!a.aliasSymbol && a.aliasSymbol === b.aliasSymbol) + ); } - function indexInfoToIndexSignatureDeclarationHelper(indexInfo: IndexInfo, context: NodeBuilderContext, typeNode: TypeNode | undefined): IndexSignatureDeclaration { + function indexInfoToIndexSignatureDeclarationHelper( + indexInfo: IndexInfo, + context: NodeBuilderContext, + typeNode: TypeNode | undefined + ): IndexSignatureDeclaration { const name = getNameFromIndexInfo(indexInfo) || "x"; - const indexerTypeNode = typeToTypeNodeHelper(indexInfo.keyType, context); + const indexerTypeNode = typeToTypeNodeHelper( + indexInfo.keyType, + context + ); const indexingParameter = factory.createParameterDeclaration( /*modifiers*/ undefined, @@ -7860,19 +13433,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { name, /*questionToken*/ undefined, indexerTypeNode, - /*initializer*/ undefined, + /*initializer*/ undefined ); if (!typeNode) { - typeNode = typeToTypeNodeHelper(indexInfo.type || anyType, context); + typeNode = typeToTypeNodeHelper( + indexInfo.type || anyType, + context + ); } - if (!indexInfo.type && !(context.flags & NodeBuilderFlags.AllowEmptyIndexInfoType)) { + if ( + !indexInfo.type && + !(context.flags & NodeBuilderFlags.AllowEmptyIndexInfoType) + ) { context.encounteredError = true; } context.approximateLength += name.length + 4; return factory.createIndexSignature( - indexInfo.isReadonly ? [factory.createToken(SyntaxKind.ReadonlyKeyword)] : undefined, + indexInfo.isReadonly + ? [factory.createToken(SyntaxKind.ReadonlyKeyword)] + : undefined, [indexingParameter], - typeNode, + typeNode ); } @@ -7882,61 +13463,236 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { questionToken?: QuestionToken; } - function signatureToSignatureDeclarationHelper(signature: Signature, kind: SignatureDeclaration["kind"], context: NodeBuilderContext, options?: SignatureToSignatureDeclarationOptions): SignatureDeclaration { + function signatureToSignatureDeclarationHelper( + signature: Signature, + kind: SignatureDeclaration["kind"], + context: NodeBuilderContext, + options?: SignatureToSignatureDeclarationOptions + ): SignatureDeclaration { let typeParameters: TypeParameterDeclaration[] | undefined; let typeArguments: TypeNode[] | undefined; - const expandedParams = getExpandedParameters(signature, /*skipUnionExpanding*/ true)[0]; - const cleanup = enterNewScope(context, signature.declaration, expandedParams, signature.typeParameters, signature.parameters, signature.mapper); + const expandedParams = getExpandedParameters( + signature, + /*skipUnionExpanding*/ true + )[0]; + const cleanup = enterNewScope( + context, + signature.declaration, + expandedParams, + signature.typeParameters, + signature.parameters, + signature.mapper + ); context.approximateLength += 3; // Usually a signature contributes a few more characters than this, but 3 is the minimum - if (context.flags & NodeBuilderFlags.WriteTypeArgumentsOfSignature && signature.target && signature.mapper && signature.target.typeParameters) { - typeArguments = signature.target.typeParameters.map(parameter => typeToTypeNodeHelper(instantiateType(parameter, signature.mapper), context)); - } - else { - typeParameters = signature.typeParameters && signature.typeParameters.map(parameter => typeParameterToDeclaration(parameter, context)); + if ( + context.flags & + NodeBuilderFlags.WriteTypeArgumentsOfSignature && + signature.target && + signature.mapper && + signature.target.typeParameters + ) { + typeArguments = signature.target.typeParameters.map( + (parameter) => + typeToTypeNodeHelper( + instantiateType(parameter, signature.mapper), + context + ) + ); + } else { + typeParameters = + signature.typeParameters && + signature.typeParameters.map((parameter) => + typeParameterToDeclaration(parameter, context) + ); } const restoreFlags = saveRestoreFlags(context); context.flags &= ~NodeBuilderFlags.SuppressAnyReturnType; // SuppressAnyReturnType should only apply to the signature `return` position // If the expanded parameter list had a variadic in a non-trailing position, don't expand it - 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)); - const thisParameter = context.flags & NodeBuilderFlags.OmitThisParameter ? undefined : tryGetThisParameterDeclaration(signature, context); + 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 + ) + ); + const thisParameter = + context.flags & NodeBuilderFlags.OmitThisParameter + ? undefined + : tryGetThisParameterDeclaration(signature, context); if (thisParameter) { parameters.unshift(thisParameter); } restoreFlags(); - const returnTypeNode = serializeReturnTypeForSignature(context, signature); + const returnTypeNode = serializeReturnTypeForSignature( + context, + signature + ); let modifiers = options?.modifiers; - if ((kind === SyntaxKind.ConstructorType) && signature.flags & SignatureFlags.Abstract) { + if ( + kind === SyntaxKind.ConstructorType && + signature.flags & SignatureFlags.Abstract + ) { const flags = modifiersToFlags(modifiers); - modifiers = factory.createModifiersFromModifierFlags(flags | ModifierFlags.Abstract); - } - - const node = kind === SyntaxKind.CallSignature ? factory.createCallSignature(typeParameters, parameters, returnTypeNode) : - kind === SyntaxKind.ConstructSignature ? factory.createConstructSignature(typeParameters, parameters, returnTypeNode) : - kind === SyntaxKind.MethodSignature ? factory.createMethodSignature(modifiers, options?.name ?? factory.createIdentifier(""), options?.questionToken, typeParameters, parameters, returnTypeNode) : - kind === SyntaxKind.MethodDeclaration ? factory.createMethodDeclaration(modifiers, /*asteriskToken*/ undefined, options?.name ?? factory.createIdentifier(""), /*questionToken*/ undefined, typeParameters, parameters, returnTypeNode, /*body*/ undefined) : - kind === SyntaxKind.Constructor ? factory.createConstructorDeclaration(modifiers, parameters, /*body*/ undefined) : - kind === SyntaxKind.GetAccessor ? factory.createGetAccessorDeclaration(modifiers, options?.name ?? factory.createIdentifier(""), parameters, returnTypeNode, /*body*/ undefined) : - kind === SyntaxKind.SetAccessor ? factory.createSetAccessorDeclaration(modifiers, options?.name ?? factory.createIdentifier(""), parameters, /*body*/ undefined) : - kind === SyntaxKind.IndexSignature ? factory.createIndexSignature(modifiers, parameters, returnTypeNode) : - kind === SyntaxKind.JSDocFunctionType ? factory.createJSDocFunctionType(parameters, returnTypeNode) : - kind === SyntaxKind.FunctionType ? factory.createFunctionTypeNode(typeParameters, parameters, returnTypeNode ?? factory.createTypeReferenceNode(factory.createIdentifier(""))) : - kind === SyntaxKind.ConstructorType ? factory.createConstructorTypeNode(modifiers, typeParameters, parameters, returnTypeNode ?? factory.createTypeReferenceNode(factory.createIdentifier(""))) : - kind === SyntaxKind.FunctionDeclaration ? factory.createFunctionDeclaration(modifiers, /*asteriskToken*/ undefined, options?.name ? cast(options.name, isIdentifier) : factory.createIdentifier(""), typeParameters, parameters, returnTypeNode, /*body*/ undefined) : - kind === SyntaxKind.FunctionExpression ? factory.createFunctionExpression(modifiers, /*asteriskToken*/ undefined, options?.name ? cast(options.name, isIdentifier) : factory.createIdentifier(""), typeParameters, parameters, returnTypeNode, factory.createBlock([])) : - kind === SyntaxKind.ArrowFunction ? factory.createArrowFunction(modifiers, typeParameters, parameters, returnTypeNode, /*equalsGreaterThanToken*/ undefined, factory.createBlock([])) : - Debug.assertNever(kind); + modifiers = factory.createModifiersFromModifierFlags( + flags | ModifierFlags.Abstract + ); + } + + const node = + kind === SyntaxKind.CallSignature + ? factory.createCallSignature( + typeParameters, + parameters, + returnTypeNode + ) + : kind === SyntaxKind.ConstructSignature + ? factory.createConstructSignature( + typeParameters, + parameters, + returnTypeNode + ) + : kind === SyntaxKind.MethodSignature + ? factory.createMethodSignature( + modifiers, + options?.name ?? factory.createIdentifier(""), + options?.questionToken, + typeParameters, + parameters, + returnTypeNode + ) + : kind === SyntaxKind.MethodDeclaration + ? factory.createMethodDeclaration( + modifiers, + /*asteriskToken*/ undefined, + options?.name ?? factory.createIdentifier(""), + /*questionToken*/ undefined, + typeParameters, + parameters, + returnTypeNode, + /*body*/ undefined + ) + : kind === SyntaxKind.Constructor + ? factory.createConstructorDeclaration( + modifiers, + parameters, + /*body*/ undefined + ) + : kind === SyntaxKind.GetAccessor + ? factory.createGetAccessorDeclaration( + modifiers, + options?.name ?? factory.createIdentifier(""), + parameters, + returnTypeNode, + /*body*/ undefined + ) + : kind === SyntaxKind.SetAccessor + ? factory.createSetAccessorDeclaration( + modifiers, + options?.name ?? factory.createIdentifier(""), + parameters, + /*body*/ undefined + ) + : kind === SyntaxKind.IndexSignature + ? factory.createIndexSignature( + modifiers, + parameters, + returnTypeNode + ) + : kind === SyntaxKind.JSDocFunctionType + ? factory.createJSDocFunctionType( + parameters, + returnTypeNode + ) + : kind === SyntaxKind.FunctionType + ? factory.createFunctionTypeNode( + typeParameters, + parameters, + returnTypeNode ?? + factory.createTypeReferenceNode( + factory.createIdentifier("") + ) + ) + : kind === SyntaxKind.ConstructorType + ? factory.createConstructorTypeNode( + modifiers, + typeParameters, + parameters, + returnTypeNode ?? + factory.createTypeReferenceNode( + factory.createIdentifier("") + ) + ) + : kind === SyntaxKind.FunctionDeclaration + ? factory.createFunctionDeclaration( + modifiers, + /*asteriskToken*/ undefined, + options?.name + ? cast(options.name, isIdentifier) + : factory.createIdentifier(""), + typeParameters, + parameters, + returnTypeNode, + /*body*/ undefined + ) + : kind === SyntaxKind.FunctionExpression + ? factory.createFunctionExpression( + modifiers, + /*asteriskToken*/ undefined, + options?.name + ? cast(options.name, isIdentifier) + : factory.createIdentifier(""), + typeParameters, + parameters, + returnTypeNode, + factory.createBlock([]) + ) + : kind === SyntaxKind.ArrowFunction + ? factory.createArrowFunction( + modifiers, + typeParameters, + parameters, + returnTypeNode, + /*equalsGreaterThanToken*/ undefined, + factory.createBlock([]) + ) + : Debug.assertNever(kind); if (typeArguments) { node.typeArguments = factory.createNodeArray(typeArguments); } - if (signature.declaration?.kind === SyntaxKind.JSDocSignature && signature.declaration.parent.kind === SyntaxKind.JSDocOverloadTag) { - const comment = getTextOfNode(signature.declaration.parent.parent, /*includeTrivia*/ true).slice(2, -2).split(/\r\n|\n|\r/).map(line => line.replace(/^\s+/, " ")).join("\n"); - addSyntheticLeadingComment(node, SyntaxKind.MultiLineCommentTrivia, comment, /*hasTrailingNewLine*/ true); + if ( + signature.declaration?.kind === SyntaxKind.JSDocSignature && + signature.declaration.parent.kind === + SyntaxKind.JSDocOverloadTag + ) { + const comment = getTextOfNode( + signature.declaration.parent.parent, + /*includeTrivia*/ true + ) + .slice(2, -2) + .split(/\r\n|\n|\r/) + .map((line) => line.replace(/^\s+/, " ")) + .join("\n"); + addSyntheticLeadingComment( + node, + SyntaxKind.MultiLineCommentTrivia, + comment, + /*hasTrailingNewLine*/ true + ); } cleanup?.(); @@ -7944,7 +13700,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function createRecoveryBoundary(context: NodeBuilderContext) { - if (cancellationToken && cancellationToken.throwIfCancellationRequested) { + if ( + cancellationToken && + cancellationToken.throwIfCancellationRequested + ) { cancellationToken.throwIfCancellationRequested(); } @@ -7955,32 +13714,52 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const oldTrackedSymbols = context.trackedSymbols; context.trackedSymbols = undefined; const oldEncounteredError = context.encounteredError; - context.tracker = new SymbolTrackerImpl(context, { - ...oldTracker.inner, - reportCyclicStructureError() { - markError(() => oldTracker.reportCyclicStructureError()); - }, - reportInaccessibleThisError() { - markError(() => oldTracker.reportInaccessibleThisError()); - }, - reportInaccessibleUniqueSymbolError() { - markError(() => oldTracker.reportInaccessibleUniqueSymbolError()); - }, - reportLikelyUnsafeImportRequiredError(specifier) { - markError(() => oldTracker.reportLikelyUnsafeImportRequiredError(specifier)); - }, - reportNonSerializableProperty(name) { - markError(() => oldTracker.reportNonSerializableProperty(name)); - }, - reportPrivateInBaseOfClassExpression(propertyName) { - markError(() => oldTracker.reportPrivateInBaseOfClassExpression(propertyName)); - }, - trackSymbol(sym, decl, meaning) { - (trackedSymbols ??= []).push([sym, decl, meaning]); - return false; + context.tracker = new SymbolTrackerImpl( + context, + { + ...oldTracker.inner, + reportCyclicStructureError() { + markError(() => + oldTracker.reportCyclicStructureError() + ); + }, + reportInaccessibleThisError() { + markError(() => + oldTracker.reportInaccessibleThisError() + ); + }, + reportInaccessibleUniqueSymbolError() { + markError(() => + oldTracker.reportInaccessibleUniqueSymbolError() + ); + }, + reportLikelyUnsafeImportRequiredError(specifier) { + markError(() => + oldTracker.reportLikelyUnsafeImportRequiredError( + specifier + ) + ); + }, + reportNonSerializableProperty(name) { + markError(() => + oldTracker.reportNonSerializableProperty(name) + ); + }, + reportPrivateInBaseOfClassExpression(propertyName) { + markError(() => + oldTracker.reportPrivateInBaseOfClassExpression( + propertyName + ) + ); + }, + trackSymbol(sym, decl, meaning) { + (trackedSymbols ??= []).push([sym, decl, meaning]); + return false; + }, + moduleResolverHost: context.tracker.moduleResolverHost, }, - moduleResolverHost: context.tracker.moduleResolverHost, - }, context.tracker.moduleResolverHost); + context.tracker.moduleResolverHost + ); return { startRecoveryScope, @@ -8015,7 +13794,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { context.trackedSymbols = oldTrackedSymbols; context.encounteredError = oldEncounteredError; - unreportedErrors?.forEach(fn => fn()); + unreportedErrors?.forEach((fn) => fn()); if (hadError) { return false; } @@ -8024,8 +13803,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { context.tracker.trackSymbol( symbol, enclosingDeclaration, - meaning, - ), + meaning + ) ); return true; } @@ -8033,11 +13812,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function enterNewScope( context: NodeBuilderContext, - declaration: IntroducesNewScopeNode | ConditionalTypeNode | undefined, + declaration: + | IntroducesNewScopeNode + | ConditionalTypeNode + | undefined, expandedParams: readonly Symbol[] | undefined, typeParameters: readonly TypeParameter[] | undefined, originalParameters?: readonly Symbol[] | undefined, - mapper?: TypeMapper, + mapper?: TypeMapper ) { const cleanupContext = cloneNodeBuilderContext(context); // For regular function/method declarations, the enclosing declaration will already be signature.declaration, @@ -8076,91 +13858,130 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Note that we only check the most immediate enclosingDeclaration; the only place we // could potentially add another fake scope into the chain is right here, so we don't // traverse all ancestors. - cleanupParams = !some(expandedParams) ? undefined : pushFakeScope( - "params", - add => { - if (!expandedParams) return; - for (let pIndex = 0; pIndex < expandedParams.length; pIndex++) { - const param = expandedParams[pIndex]; - const originalParam = originalParameters?.[pIndex]; - if (originalParameters && originalParam !== param) { - // Can't reference parameters that come from an expansion - add(param.escapedName, unknownSymbol); - // Can't reference the original expanded parameter either - if (originalParam) { - add(originalParam.escapedName, unknownSymbol); - } - } - else if ( - !forEach(param.declarations, d => { - if (isParameter(d) && isBindingPattern(d.name)) { - bindPattern(d.name); - return true; - } - return undefined; - function bindPattern(p: BindingPattern): void { - forEach(p.elements, e => { - switch (e.kind) { - case SyntaxKind.OmittedExpression: - return; - case SyntaxKind.BindingElement: - return bindElement(e); - default: - return Debug.assertNever(e); - } - }); - } - function bindElement(e: BindingElement): void { - if (isBindingPattern(e.name)) { - return bindPattern(e.name); - } - const symbol = getSymbolOfDeclaration(e); - add(symbol.escapedName, symbol); - } - }) - ) { - add(param.escapedName, param); - } - } - }, - ); + cleanupParams = !some(expandedParams) + ? undefined + : pushFakeScope("params", (add) => { + if (!expandedParams) return; + for ( + let pIndex = 0; + pIndex < expandedParams.length; + pIndex++ + ) { + const param = expandedParams[pIndex]; + const originalParam = + originalParameters?.[pIndex]; + if ( + originalParameters && + originalParam !== param + ) { + // Can't reference parameters that come from an expansion + add(param.escapedName, unknownSymbol); + // Can't reference the original expanded parameter either + if (originalParam) { + add( + originalParam.escapedName, + unknownSymbol + ); + } + } else if ( + !forEach(param.declarations, (d) => { + if ( + isParameter(d) && + isBindingPattern(d.name) + ) { + bindPattern(d.name); + return true; + } + return undefined; + function bindPattern( + p: BindingPattern + ): void { + forEach(p.elements, (e) => { + switch (e.kind) { + case SyntaxKind.OmittedExpression: + return; + case SyntaxKind.BindingElement: + return bindElement(e); + default: + return Debug.assertNever( + e + ); + } + }); + } + function bindElement( + e: BindingElement + ): void { + if (isBindingPattern(e.name)) { + return bindPattern(e.name); + } + const symbol = + getSymbolOfDeclaration(e); + add(symbol.escapedName, symbol); + } + }) + ) { + add(param.escapedName, param); + } + } + }); - if (context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams && some(typeParameters)) { - cleanupTypeParams = pushFakeScope( - "typeParams", - add => { - for (const typeParam of typeParameters ?? emptyArray) { - const typeParamName = typeParameterToName(typeParam, context).escapedText; - add(typeParamName, typeParam.symbol); - } - }, - ); + if ( + context.flags & + NodeBuilderFlags.GenerateNamesForShadowedTypeParams && + some(typeParameters) + ) { + cleanupTypeParams = pushFakeScope("typeParams", (add) => { + for (const typeParam of typeParameters ?? emptyArray) { + const typeParamName = typeParameterToName( + typeParam, + context + ).escapedText; + add(typeParamName, typeParam.symbol); + } + }); } - function pushFakeScope(kind: "params" | "typeParams", addAll: (addSymbol: (name: __String, symbol: Symbol) => void) => void) { + function pushFakeScope( + kind: "params" | "typeParams", + addAll: ( + addSymbol: (name: __String, symbol: Symbol) => void + ) => void + ) { // We only ever need to look two declarations upward. Debug.assert(context.enclosingDeclaration); let existingFakeScope: Node | undefined; - if (getNodeLinks(context.enclosingDeclaration).fakeScopeForSignatureDeclaration === kind) { + if ( + getNodeLinks(context.enclosingDeclaration) + .fakeScopeForSignatureDeclaration === kind + ) { existingFakeScope = context.enclosingDeclaration; - } - else if (context.enclosingDeclaration.parent && getNodeLinks(context.enclosingDeclaration.parent).fakeScopeForSignatureDeclaration === kind) { + } else if ( + context.enclosingDeclaration.parent && + getNodeLinks(context.enclosingDeclaration.parent) + .fakeScopeForSignatureDeclaration === kind + ) { existingFakeScope = context.enclosingDeclaration.parent; } Debug.assertOptionalNode(existingFakeScope, isBlock); - const locals = existingFakeScope?.locals ?? createSymbolTable(); + const locals = + existingFakeScope?.locals ?? createSymbolTable(); let newLocals: __String[] | undefined; - let oldLocals: { name: __String; oldSymbol: Symbol; }[] | undefined; + let oldLocals: + | { name: __String; oldSymbol: Symbol }[] + | undefined; addAll((name, symbol) => { // Add cleanup information only if we don't own the fake scope if (existingFakeScope) { const oldSymbol = locals.get(name); if (!oldSymbol) { newLocals = append(newLocals, name); - } - else { - oldLocals = append(oldLocals, { name, oldSymbol }); + } else { + oldLocals = append(oldLocals, { + name, + oldSymbol, + }); } } locals.set(name, symbol); @@ -8170,17 +13991,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Use a Block for this; the type of the node doesn't matter so long as it // has locals, and this is cheaper/easier than using a function-ish Node. const fakeScope = factory.createBlock(emptyArray); - getNodeLinks(fakeScope).fakeScopeForSignatureDeclaration = kind; + getNodeLinks( + fakeScope + ).fakeScopeForSignatureDeclaration = kind; fakeScope.locals = locals; setParent(fakeScope, context.enclosingDeclaration); context.enclosingDeclaration = fakeScope; - } - else { + } else { // We did not create the current scope, so we have to clean it up return function undo() { - forEach(newLocals, s => locals.delete(s)); - forEach(oldLocals, s => locals.set(s.name, s.oldSymbol)); + forEach(newLocals, (s) => locals.delete(s)); + forEach(oldLocals, (s) => + locals.set(s.name, s.oldSymbol) + ); }; } } @@ -8195,9 +14019,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { }; } - function tryGetThisParameterDeclaration(signature: Signature, context: NodeBuilderContext) { + function tryGetThisParameterDeclaration( + signature: Signature, + context: NodeBuilderContext + ) { if (signature.thisParameter) { - return symbolToParameterDeclaration(signature.thisParameter, context); + return symbolToParameterDeclaration( + signature.thisParameter, + context + ); } if (signature.declaration && isInJSFile(signature.declaration)) { const thisTag = getJSDocThisTag(signature.declaration); @@ -8207,177 +14037,410 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /*dotDotDotToken*/ undefined, "this", /*questionToken*/ undefined, - typeToTypeNodeHelper(getTypeFromTypeNode(context, thisTag.typeExpression), context), + typeToTypeNodeHelper( + getTypeFromTypeNode( + context, + thisTag.typeExpression + ), + context + ) ); } } } - function typeParameterToDeclarationWithConstraint(type: TypeParameter, context: NodeBuilderContext, constraintNode: TypeNode | undefined): TypeParameterDeclaration { + function typeParameterToDeclarationWithConstraint( + type: TypeParameter, + context: NodeBuilderContext, + constraintNode: TypeNode | undefined + ): TypeParameterDeclaration { const restoreFlags = saveRestoreFlags(context); - context.flags &= ~NodeBuilderFlags.WriteTypeParametersInQualifiedName; // Avoids potential infinite loop when building for a claimspace with a generic - const modifiers = factory.createModifiersFromModifierFlags(getTypeParameterModifiers(type)); + context.flags &= + ~NodeBuilderFlags.WriteTypeParametersInQualifiedName; // Avoids potential infinite loop when building for a claimspace with a generic + const modifiers = factory.createModifiersFromModifierFlags( + getTypeParameterModifiers(type) + ); const name = typeParameterToName(type, context); const defaultParameter = getDefaultFromTypeParameter(type); - const defaultParameterNode = defaultParameter && typeToTypeNodeHelper(defaultParameter, context); + const defaultParameterNode = + defaultParameter && + typeToTypeNodeHelper(defaultParameter, context); restoreFlags(); - return factory.createTypeParameterDeclaration(modifiers, name, constraintNode, defaultParameterNode); + return factory.createTypeParameterDeclaration( + modifiers, + name, + constraintNode, + defaultParameterNode + ); } - function typeToTypeNodeHelperWithPossibleReusableTypeNode(type: Type, typeNode: TypeNode | undefined, context: NodeBuilderContext) { - return !canPossiblyExpandType(type, context) && typeNode && getTypeFromTypeNode(context, typeNode) === type && syntacticNodeBuilder.tryReuseExistingTypeNode(context, typeNode) - || typeToTypeNodeHelper(type, context); + function typeToTypeNodeHelperWithPossibleReusableTypeNode( + type: Type, + typeNode: TypeNode | undefined, + context: NodeBuilderContext + ) { + return ( + (!canPossiblyExpandType(type, context) && + typeNode && + getTypeFromTypeNode(context, typeNode) === type && + syntacticNodeBuilder.tryReuseExistingTypeNode( + context, + typeNode + )) || + typeToTypeNodeHelper(type, context) + ); } - function typeParameterToDeclaration(type: TypeParameter, context: NodeBuilderContext, constraint = getConstraintOfTypeParameter(type)): TypeParameterDeclaration { - const constraintNode = constraint && typeToTypeNodeHelperWithPossibleReusableTypeNode(constraint, getConstraintDeclaration(type), context); - return typeParameterToDeclarationWithConstraint(type, context, constraintNode); + function typeParameterToDeclaration( + type: TypeParameter, + context: NodeBuilderContext, + constraint = getConstraintOfTypeParameter(type) + ): TypeParameterDeclaration { + const constraintNode = + constraint && + typeToTypeNodeHelperWithPossibleReusableTypeNode( + constraint, + getConstraintDeclaration(type), + context + ); + return typeParameterToDeclarationWithConstraint( + type, + context, + constraintNode + ); } - function typePredicateToTypePredicateNodeHelper(typePredicate: TypePredicate, context: NodeBuilderContext): TypePredicateNode { - const assertsModifier = typePredicate.kind === TypePredicateKind.AssertsThis || typePredicate.kind === TypePredicateKind.AssertsIdentifier ? - factory.createToken(SyntaxKind.AssertsKeyword) : - undefined; - const parameterName = typePredicate.kind === TypePredicateKind.Identifier || typePredicate.kind === TypePredicateKind.AssertsIdentifier ? - setEmitFlags(factory.createIdentifier(typePredicate.parameterName), EmitFlags.NoAsciiEscaping) : - factory.createThisTypeNode(); - const typeNode = typePredicate.type && typeToTypeNodeHelper(typePredicate.type, context); - return factory.createTypePredicateNode(assertsModifier, parameterName, typeNode); + function typePredicateToTypePredicateNodeHelper( + typePredicate: TypePredicate, + context: NodeBuilderContext + ): TypePredicateNode { + const assertsModifier = + typePredicate.kind === TypePredicateKind.AssertsThis || + typePredicate.kind === TypePredicateKind.AssertsIdentifier + ? factory.createToken(SyntaxKind.AssertsKeyword) + : undefined; + const parameterName = + typePredicate.kind === TypePredicateKind.Identifier || + typePredicate.kind === TypePredicateKind.AssertsIdentifier + ? setEmitFlags( + factory.createIdentifier(typePredicate.parameterName), + EmitFlags.NoAsciiEscaping + ) + : factory.createThisTypeNode(); + const typeNode = + typePredicate.type && + typeToTypeNodeHelper(typePredicate.type, context); + return factory.createTypePredicateNode( + assertsModifier, + parameterName, + typeNode + ); } - function getEffectiveParameterDeclaration(parameterSymbol: Symbol): ParameterDeclaration | JSDocParameterTag | undefined { - const parameterDeclaration: ParameterDeclaration | JSDocParameterTag | undefined = getDeclarationOfKind(parameterSymbol, SyntaxKind.Parameter); + function getEffectiveParameterDeclaration( + parameterSymbol: Symbol + ): ParameterDeclaration | JSDocParameterTag | undefined { + const parameterDeclaration: + | ParameterDeclaration + | JSDocParameterTag + | undefined = getDeclarationOfKind( + parameterSymbol, + SyntaxKind.Parameter + ); if (parameterDeclaration) { return parameterDeclaration; } if (!isTransientSymbol(parameterSymbol)) { - return getDeclarationOfKind(parameterSymbol, SyntaxKind.JSDocParameterTag); + return getDeclarationOfKind( + parameterSymbol, + SyntaxKind.JSDocParameterTag + ); } } - function symbolToParameterDeclaration(parameterSymbol: Symbol, context: NodeBuilderContext, preserveModifierFlags?: boolean): ParameterDeclaration { - const parameterDeclaration = getEffectiveParameterDeclaration(parameterSymbol); + function symbolToParameterDeclaration( + parameterSymbol: Symbol, + context: NodeBuilderContext, + preserveModifierFlags?: boolean + ): ParameterDeclaration { + const parameterDeclaration = + getEffectiveParameterDeclaration(parameterSymbol); const parameterType = getTypeOfSymbol(parameterSymbol); - const parameterTypeNode = serializeTypeForDeclaration(context, parameterDeclaration, parameterType, parameterSymbol); - - const modifiers = !(context.flags & NodeBuilderFlags.OmitParameterModifiers) && preserveModifierFlags && parameterDeclaration && canHaveModifiers(parameterDeclaration) ? map(getModifiers(parameterDeclaration), factory.cloneNode) : undefined; - const isRest = parameterDeclaration && isRestParameter(parameterDeclaration) || getCheckFlags(parameterSymbol) & CheckFlags.RestParameter; - const dotDotDotToken = isRest ? factory.createToken(SyntaxKind.DotDotDotToken) : undefined; - const name = parameterToParameterDeclarationName(parameterSymbol, parameterDeclaration, context); - const isOptional = parameterDeclaration && isOptionalParameter(parameterDeclaration) || getCheckFlags(parameterSymbol) & CheckFlags.OptionalParameter; - const questionToken = isOptional ? factory.createToken(SyntaxKind.QuestionToken) : undefined; + const parameterTypeNode = serializeTypeForDeclaration( + context, + parameterDeclaration, + parameterType, + parameterSymbol + ); + + const modifiers = + !(context.flags & NodeBuilderFlags.OmitParameterModifiers) && + preserveModifierFlags && + parameterDeclaration && + canHaveModifiers(parameterDeclaration) + ? map(getModifiers(parameterDeclaration), factory.cloneNode) + : undefined; + const isRest = + (parameterDeclaration && + isRestParameter(parameterDeclaration)) || + getCheckFlags(parameterSymbol) & CheckFlags.RestParameter; + const dotDotDotToken = isRest + ? factory.createToken(SyntaxKind.DotDotDotToken) + : undefined; + const name = parameterToParameterDeclarationName( + parameterSymbol, + parameterDeclaration, + context + ); + const isOptional = + (parameterDeclaration && + isOptionalParameter(parameterDeclaration)) || + getCheckFlags(parameterSymbol) & CheckFlags.OptionalParameter; + const questionToken = isOptional + ? factory.createToken(SyntaxKind.QuestionToken) + : undefined; const parameterNode = factory.createParameterDeclaration( modifiers, dotDotDotToken, name, questionToken, parameterTypeNode, - /*initializer*/ undefined, + /*initializer*/ undefined ); context.approximateLength += symbolName(parameterSymbol).length + 3; return parameterNode; } - function parameterToParameterDeclarationName(parameterSymbol: Symbol, parameterDeclaration: ParameterDeclaration | JSDocParameterTag | undefined, context: NodeBuilderContext) { - return parameterDeclaration ? parameterDeclaration.name ? - parameterDeclaration.name.kind === SyntaxKind.Identifier ? setEmitFlags(factory.cloneNode(parameterDeclaration.name), EmitFlags.NoAsciiEscaping) : - parameterDeclaration.name.kind === SyntaxKind.QualifiedName ? setEmitFlags(factory.cloneNode(parameterDeclaration.name.right), EmitFlags.NoAsciiEscaping) : - cloneBindingName(parameterDeclaration.name) : - symbolName(parameterSymbol) : - symbolName(parameterSymbol); + function parameterToParameterDeclarationName( + parameterSymbol: Symbol, + parameterDeclaration: + | ParameterDeclaration + | JSDocParameterTag + | undefined, + context: NodeBuilderContext + ) { + return parameterDeclaration + ? parameterDeclaration.name + ? parameterDeclaration.name.kind === SyntaxKind.Identifier + ? setEmitFlags( + factory.cloneNode(parameterDeclaration.name), + EmitFlags.NoAsciiEscaping + ) + : parameterDeclaration.name.kind === + SyntaxKind.QualifiedName + ? setEmitFlags( + factory.cloneNode( + parameterDeclaration.name.right + ), + EmitFlags.NoAsciiEscaping + ) + : cloneBindingName(parameterDeclaration.name) + : symbolName(parameterSymbol) + : symbolName(parameterSymbol); function cloneBindingName(node: BindingName): BindingName { return elideInitializerAndSetEmitFlags(node) as BindingName; function elideInitializerAndSetEmitFlags(node: Node): Node { - if (context.tracker.canTrackSymbol && isComputedPropertyName(node) && isLateBindableName(node)) { - trackComputedName(node.expression, context.enclosingDeclaration, context); + if ( + context.tracker.canTrackSymbol && + isComputedPropertyName(node) && + isLateBindableName(node) + ) { + trackComputedName( + node.expression, + context.enclosingDeclaration, + context + ); } - let visited = visitEachChildWorker(node, elideInitializerAndSetEmitFlags, /*context*/ undefined, /*nodesVisitor*/ undefined, elideInitializerAndSetEmitFlags); + let visited = visitEachChildWorker( + node, + elideInitializerAndSetEmitFlags, + /*context*/ undefined, + /*nodesVisitor*/ undefined, + elideInitializerAndSetEmitFlags + ); if (isBindingElement(visited)) { visited = factory.updateBindingElement( visited, visited.dotDotDotToken, visited.propertyName, visited.name, - /*initializer*/ undefined, + /*initializer*/ undefined ); } if (!nodeIsSynthesized(visited)) { visited = factory.cloneNode(visited); } - return setEmitFlags(visited, EmitFlags.SingleLine | EmitFlags.NoAsciiEscaping); + return setEmitFlags( + visited, + EmitFlags.SingleLine | EmitFlags.NoAsciiEscaping + ); } } } - function trackComputedName(accessExpression: EntityNameOrEntityNameExpression, enclosingDeclaration: Node | undefined, context: NodeBuilderContext) { + function trackComputedName( + accessExpression: EntityNameOrEntityNameExpression, + enclosingDeclaration: Node | undefined, + context: NodeBuilderContext + ) { if (!context.tracker.canTrackSymbol) return; // get symbol of the first identifier of the entityName const firstIdentifier = getFirstIdentifier(accessExpression); - const name = resolveName(enclosingDeclaration, firstIdentifier.escapedText, SymbolFlags.Value | SymbolFlags.ExportValue, /*nameNotFoundMessage*/ undefined, /*isUse*/ true); + const name = resolveName( + enclosingDeclaration, + firstIdentifier.escapedText, + SymbolFlags.Value | SymbolFlags.ExportValue, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ true + ); if (name) { - context.tracker.trackSymbol(name, enclosingDeclaration, SymbolFlags.Value); - } - else { + context.tracker.trackSymbol( + name, + enclosingDeclaration, + SymbolFlags.Value + ); + } else { // Name does not resolve at target location, track symbol at dest location (should be inaccessible) - const fallback = resolveName(firstIdentifier, firstIdentifier.escapedText, SymbolFlags.Value | SymbolFlags.ExportValue, /*nameNotFoundMessage*/ undefined, /*isUse*/ true); + const fallback = resolveName( + firstIdentifier, + firstIdentifier.escapedText, + SymbolFlags.Value | SymbolFlags.ExportValue, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ true + ); if (fallback) { - context.tracker.trackSymbol(fallback, enclosingDeclaration, SymbolFlags.Value); + context.tracker.trackSymbol( + fallback, + enclosingDeclaration, + SymbolFlags.Value + ); } } } - function lookupSymbolChain(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, yieldModuleSymbol?: boolean) { - context.tracker.trackSymbol(symbol, context.enclosingDeclaration, meaning); - return lookupSymbolChainWorker(symbol, context, meaning, yieldModuleSymbol); + function lookupSymbolChain( + symbol: Symbol, + context: NodeBuilderContext, + meaning: SymbolFlags, + yieldModuleSymbol?: boolean + ) { + context.tracker.trackSymbol( + symbol, + context.enclosingDeclaration, + meaning + ); + return lookupSymbolChainWorker( + symbol, + context, + meaning, + yieldModuleSymbol + ); } - function lookupSymbolChainWorker(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, yieldModuleSymbol?: boolean) { + function lookupSymbolChainWorker( + symbol: Symbol, + context: NodeBuilderContext, + meaning: SymbolFlags, + yieldModuleSymbol?: boolean + ) { // Try to get qualified name if the symbol is not a type parameter and there is an enclosing declaration. let chain: Symbol[]; const isTypeParameter = symbol.flags & SymbolFlags.TypeParameter; - if (!isTypeParameter && (context.enclosingDeclaration || context.flags & NodeBuilderFlags.UseFullyQualifiedType) && !(context.internalFlags & InternalNodeBuilderFlags.DoNotIncludeSymbolChain)) { - chain = Debug.checkDefined(getSymbolChain(symbol, meaning, /*endOfChain*/ true)); + if ( + !isTypeParameter && + (context.enclosingDeclaration || + context.flags & NodeBuilderFlags.UseFullyQualifiedType) && + !( + context.internalFlags & + InternalNodeBuilderFlags.DoNotIncludeSymbolChain + ) + ) { + chain = Debug.checkDefined( + getSymbolChain(symbol, meaning, /*endOfChain*/ true) + ); Debug.assert(chain && chain.length > 0); - } - else { + } else { chain = [symbol]; } return chain; /** @param endOfChain Set to false for recursive calls; non-recursive calls should always output something. */ - function getSymbolChain(symbol: Symbol, meaning: SymbolFlags, endOfChain: boolean): Symbol[] | undefined { - let accessibleSymbolChain = getAccessibleSymbolChain(symbol, context.enclosingDeclaration, meaning, !!(context.flags & NodeBuilderFlags.UseOnlyExternalAliasing)); + function getSymbolChain( + symbol: Symbol, + meaning: SymbolFlags, + endOfChain: boolean + ): Symbol[] | undefined { + let accessibleSymbolChain = getAccessibleSymbolChain( + symbol, + context.enclosingDeclaration, + meaning, + !!(context.flags & NodeBuilderFlags.UseOnlyExternalAliasing) + ); let parentSpecifiers: (string | undefined)[]; if ( !accessibleSymbolChain || - needsQualification(accessibleSymbolChain[0], context.enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning)) + needsQualification( + accessibleSymbolChain[0], + context.enclosingDeclaration, + accessibleSymbolChain.length === 1 + ? meaning + : getQualifiedLeftMeaning(meaning) + ) ) { // Go up and add our parent. - const parents = getContainersOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol, context.enclosingDeclaration, meaning); + const parents = getContainersOfSymbol( + accessibleSymbolChain + ? accessibleSymbolChain[0] + : symbol, + context.enclosingDeclaration, + meaning + ); if (length(parents)) { - parentSpecifiers = parents!.map(symbol => - some(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol) + parentSpecifiers = parents!.map((symbol) => + some( + symbol.declarations, + hasNonGlobalAugmentationExternalModuleSymbol + ) ? getSpecifierForModuleSymbol(symbol, context) : undefined ); const indices = parents!.map((_, i) => i); indices.sort(sortByBestName); - const sortedParents = indices.map(i => parents![i]); + const sortedParents = indices.map((i) => parents![i]); for (const parent of sortedParents) { - const parentChain = getSymbolChain(parent, getQualifiedLeftMeaning(meaning), /*endOfChain*/ false); + const parentChain = getSymbolChain( + parent, + getQualifiedLeftMeaning(meaning), + /*endOfChain*/ false + ); if (parentChain) { if ( - parent.exports && parent.exports.get(InternalSymbolName.ExportEquals) && - getSymbolIfSameReference(parent.exports.get(InternalSymbolName.ExportEquals)!, symbol) + parent.exports && + parent.exports.get( + InternalSymbolName.ExportEquals + ) && + getSymbolIfSameReference( + parent.exports.get( + InternalSymbolName.ExportEquals + )!, + symbol + ) ) { // parentChain root _is_ symbol - symbol is a module export=, so it kinda looks like it's own parent // No need to lookup an alias for the symbol in itself accessibleSymbolChain = parentChain; break; } - accessibleSymbolChain = parentChain.concat(accessibleSymbolChain || [getAliasForSymbolInContainer(parent, symbol) || symbol]); + accessibleSymbolChain = parentChain.concat( + accessibleSymbolChain || [ + getAliasForSymbolInContainer( + parent, + symbol + ) || symbol, + ] + ); break; } } @@ -8391,10 +14454,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If this is the last part of outputting the symbol, always output. The cases apply only to parent symbols. endOfChain || // If a parent symbol is an anonymous type, don't write it. - !(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral)) + !( + symbol.flags & + (SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) + ) ) { // If a parent symbol is an external module, don't write it. (We prefer just `x` vs `"foo/bar".x`.) - if (!endOfChain && !yieldModuleSymbol && !!forEach(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol)) { + if ( + !endOfChain && + !yieldModuleSymbol && + !!forEach( + symbol.declarations, + hasNonGlobalAugmentationExternalModuleSymbol + ) + ) { return; } return [symbol]; @@ -8407,7 +14480,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const isBRelative = pathIsRelative(specifierB); if (pathIsRelative(specifierA) === isBRelative) { // Both relative or both non-relative, sort by number of parts - return moduleSpecifiers.countPathComponents(specifierA) - moduleSpecifiers.countPathComponents(specifierB); + return ( + moduleSpecifiers.countPathComponents( + specifierA + ) - + moduleSpecifiers.countPathComponents(specifierB) + ); } if (isBRelative) { // A is non-relative, B is relative: prefer A @@ -8421,16 +14499,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function typeParametersToTypeParameterDeclarations(symbol: Symbol, context: NodeBuilderContext) { - let typeParameterNodes: NodeArray | undefined; + function typeParametersToTypeParameterDeclarations( + symbol: Symbol, + context: NodeBuilderContext + ) { + let typeParameterNodes: + | NodeArray + | undefined; const targetSymbol = getTargetSymbol(symbol); - if (targetSymbol.flags & (SymbolFlags.Class | SymbolFlags.Interface | SymbolFlags.TypeAlias)) { - typeParameterNodes = factory.createNodeArray(map(getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol), tp => typeParameterToDeclaration(tp, context))); + if ( + targetSymbol.flags & + (SymbolFlags.Class | + SymbolFlags.Interface | + SymbolFlags.TypeAlias) + ) { + typeParameterNodes = factory.createNodeArray( + map( + getLocalTypeParametersOfClassOrInterfaceOrTypeAlias( + symbol + ), + (tp) => typeParameterToDeclaration(tp, context) + ) + ); } return typeParameterNodes; } - function lookupTypeParameterNodes(chain: Symbol[], index: number, context: NodeBuilderContext) { + function lookupTypeParameterNodes( + chain: Symbol[], + index: number, + context: NodeBuilderContext + ) { Debug.assert(chain && 0 <= index && index < chain.length); const symbol = chain[index]; const symbolId = getSymbolId(symbol); @@ -8439,22 +14538,44 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (context.mustCreateTypeParameterSymbolList) { context.mustCreateTypeParameterSymbolList = false; - context.typeParameterSymbolList = new Set(context.typeParameterSymbolList); + context.typeParameterSymbolList = new Set( + context.typeParameterSymbolList + ); } context.typeParameterSymbolList!.add(symbolId); - let typeParameterNodes: readonly TypeNode[] | readonly TypeParameterDeclaration[] | undefined; - if (context.flags & NodeBuilderFlags.WriteTypeParametersInQualifiedName && index < (chain.length - 1)) { + let typeParameterNodes: + | readonly TypeNode[] + | readonly TypeParameterDeclaration[] + | undefined; + if ( + context.flags & + NodeBuilderFlags.WriteTypeParametersInQualifiedName && + index < chain.length - 1 + ) { const parentSymbol = symbol; const nextSymbol = chain[index + 1]; if (getCheckFlags(nextSymbol) & CheckFlags.Instantiated) { const params = getTypeParametersOfClassOrInterface( - parentSymbol.flags & SymbolFlags.Alias ? resolveAlias(parentSymbol) : parentSymbol, + parentSymbol.flags & SymbolFlags.Alias + ? resolveAlias(parentSymbol) + : parentSymbol ); // NOTE: cast to TransientSymbol should be safe because only TransientSymbol can have CheckFlags.Instantiated - typeParameterNodes = mapToTypeNodes(map(params, t => getMappedType(t, (nextSymbol as TransientSymbol).links.mapper!)), context); - } - else { - typeParameterNodes = typeParametersToTypeParameterDeclarations(symbol, context); + typeParameterNodes = mapToTypeNodes( + map(params, (t) => + getMappedType( + t, + (nextSymbol as TransientSymbol).links.mapper! + ) + ), + context + ); + } else { + typeParameterNodes = + typeParametersToTypeParameterDeclarations( + symbol, + context + ); } } return typeParameterNodes; @@ -8463,19 +14584,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** * Given A[B][C][D], finds A[B] */ - function getTopmostIndexedAccessType(top: IndexedAccessTypeNode): IndexedAccessTypeNode { + function getTopmostIndexedAccessType( + top: IndexedAccessTypeNode + ): IndexedAccessTypeNode { if (isIndexedAccessTypeNode(top.objectType)) { return getTopmostIndexedAccessType(top.objectType); } return top; } - function getSpecifierForModuleSymbol(symbol: Symbol, context: NodeBuilderContext, overrideImportMode?: ResolutionMode) { - let file = getDeclarationOfKind(symbol, SyntaxKind.SourceFile); + function getSpecifierForModuleSymbol( + symbol: Symbol, + context: NodeBuilderContext, + overrideImportMode?: ResolutionMode + ) { + let file = getDeclarationOfKind( + symbol, + SyntaxKind.SourceFile + ); if (!file) { - const equivalentFileSymbol = firstDefined(symbol.declarations, d => getFileSymbolIfFileSymbolExportEqualsContainer(d, symbol)); + const equivalentFileSymbol = firstDefined( + symbol.declarations, + (d) => + getFileSymbolIfFileSymbolExportEqualsContainer( + d, + symbol + ) + ); if (equivalentFileSymbol) { - file = getDeclarationOfKind(equivalentFileSymbol, SyntaxKind.SourceFile); + file = getDeclarationOfKind( + equivalentFileSymbol, + SyntaxKind.SourceFile + ); } } if (file && file.moduleName !== undefined) { @@ -8483,26 +14623,54 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return file.moduleName; } if (!file) { - if (ambientModuleSymbolRegex.test(symbol.escapedName as string)) { - return (symbol.escapedName as string).substring(1, (symbol.escapedName as string).length - 1); + if ( + ambientModuleSymbolRegex.test(symbol.escapedName as string) + ) { + return (symbol.escapedName as string).substring( + 1, + (symbol.escapedName as string).length - 1 + ); } } if (!context.enclosingFile || !context.tracker.moduleResolverHost) { // If there's no context declaration, we can't lookup a non-ambient specifier, so we just use the symbol name - if (ambientModuleSymbolRegex.test(symbol.escapedName as string)) { - return (symbol.escapedName as string).substring(1, (symbol.escapedName as string).length - 1); + if ( + ambientModuleSymbolRegex.test(symbol.escapedName as string) + ) { + return (symbol.escapedName as string).substring( + 1, + (symbol.escapedName as string).length - 1 + ); } - return getSourceFileOfNode(getNonAugmentationDeclaration(symbol)!).fileName; // A resolver may not be provided for baselines and errors - in those cases we use the fileName in full + return getSourceFileOfNode( + getNonAugmentationDeclaration(symbol)! + ).fileName; // A resolver may not be provided for baselines and errors - in those cases we use the fileName in full } - const enclosingDeclaration = getOriginalNode(context.enclosingDeclaration); - const originalModuleSpecifier = canHaveModuleSpecifier(enclosingDeclaration) ? tryGetModuleSpecifierFromDeclaration(enclosingDeclaration) : undefined; + const enclosingDeclaration = getOriginalNode( + context.enclosingDeclaration + ); + const originalModuleSpecifier = canHaveModuleSpecifier( + enclosingDeclaration + ) + ? tryGetModuleSpecifierFromDeclaration(enclosingDeclaration) + : undefined; const contextFile = context.enclosingFile; - const resolutionMode = overrideImportMode - || originalModuleSpecifier && host.getModeForUsageLocation(contextFile, originalModuleSpecifier) - || contextFile && host.getDefaultResolutionModeForFile(contextFile); - const cacheKey = createModeAwareCacheKey(contextFile.path, resolutionMode); + const resolutionMode = + overrideImportMode || + (originalModuleSpecifier && + host.getModeForUsageLocation( + contextFile, + originalModuleSpecifier + )) || + (contextFile && + host.getDefaultResolutionModeForFile(contextFile)); + const cacheKey = createModeAwareCacheKey( + contextFile.path, + resolutionMode + ); const links = getSymbolLinks(symbol); - let specifier = links.specifierCache && links.specifierCache.get(cacheKey); + let specifier = + links.specifierCache && links.specifierCache.get(cacheKey); if (!specifier) { const isBundle = !!compilerOptions.outFile; // For declaration bundles, we need to generate absolute paths relative to the common source dir for imports, @@ -8510,21 +14678,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // using the `baseUrl` compiler option (which we would otherwise never use in declaration emit) and a non-relative // specifier preference const { moduleResolverHost } = context.tracker; - const specifierCompilerOptions = isBundle ? { ...compilerOptions, baseUrl: moduleResolverHost.getCommonSourceDirectory() } : compilerOptions; - specifier = first(moduleSpecifiers.getModuleSpecifiers( - symbol, - checker, - specifierCompilerOptions, - contextFile, - moduleResolverHost, - { - importModuleSpecifierPreference: isBundle ? "non-relative" : "project-relative", - importModuleSpecifierEnding: isBundle ? "minimal" - : resolutionMode === ModuleKind.ESNext ? "js" - : undefined, - }, - { overrideImportMode }, - )); + const specifierCompilerOptions = isBundle + ? { + ...compilerOptions, + baseUrl: + moduleResolverHost.getCommonSourceDirectory(), + } + : compilerOptions; + specifier = first( + moduleSpecifiers.getModuleSpecifiers( + symbol, + checker, + specifierCompilerOptions, + contextFile, + moduleResolverHost, + { + importModuleSpecifierPreference: isBundle + ? "non-relative" + : "project-relative", + importModuleSpecifierEnding: isBundle + ? "minimal" + : resolutionMode === ModuleKind.ESNext + ? "js" + : undefined, + }, + { overrideImportMode } + ) + ); links.specifierCache ??= new Map(); links.specifierCache.set(cacheKey, specifier); } @@ -8532,58 +14712,134 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function symbolToEntityNameNode(symbol: Symbol): EntityName { - const identifier = factory.createIdentifier(unescapeLeadingUnderscores(symbol.escapedName)); - return symbol.parent ? factory.createQualifiedName(symbolToEntityNameNode(symbol.parent), identifier) : identifier; + const identifier = factory.createIdentifier( + unescapeLeadingUnderscores(symbol.escapedName) + ); + return symbol.parent + ? factory.createQualifiedName( + symbolToEntityNameNode(symbol.parent), + identifier + ) + : identifier; } - function symbolToTypeNode(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, overrideTypeArguments?: readonly TypeNode[]): TypeNode { - const chain = lookupSymbolChain(symbol, context, meaning, !(context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope)); // If we're using aliases outside the current scope, dont bother with the module + function symbolToTypeNode( + symbol: Symbol, + context: NodeBuilderContext, + meaning: SymbolFlags, + overrideTypeArguments?: readonly TypeNode[] + ): TypeNode { + const chain = lookupSymbolChain( + symbol, + context, + meaning, + !( + context.flags & + NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope + ) + ); // If we're using aliases outside the current scope, dont bother with the module const isTypeOf = meaning === SymbolFlags.Value; - if (some(chain[0].declarations, hasNonGlobalAugmentationExternalModuleSymbol)) { + if ( + some( + chain[0].declarations, + hasNonGlobalAugmentationExternalModuleSymbol + ) + ) { // module is root, must use `ImportTypeNode` - const nonRootParts = chain.length > 1 ? createAccessFromSymbolChain(chain, chain.length - 1, 1) : undefined; - const typeParameterNodes = overrideTypeArguments || lookupTypeParameterNodes(chain, 0, context); - const contextFile = getSourceFileOfNode(getOriginalNode(context.enclosingDeclaration)); + const nonRootParts = + chain.length > 1 + ? createAccessFromSymbolChain( + chain, + chain.length - 1, + 1 + ) + : undefined; + const typeParameterNodes = + overrideTypeArguments || + lookupTypeParameterNodes(chain, 0, context); + const contextFile = getSourceFileOfNode( + getOriginalNode(context.enclosingDeclaration) + ); const targetFile = getSourceFileOfModule(chain[0]); let specifier: string | undefined; let attributes: ImportAttributes | undefined; - if (getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Node16 || getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeNext) { + if ( + getEmitModuleResolutionKind(compilerOptions) === + ModuleResolutionKind.Node16 || + getEmitModuleResolutionKind(compilerOptions) === + ModuleResolutionKind.NodeNext + ) { // An `import` type directed at an esm format file is only going to resolve in esm mode - set the esm mode assertion - if (targetFile?.impliedNodeFormat === ModuleKind.ESNext && targetFile.impliedNodeFormat !== contextFile?.impliedNodeFormat) { - specifier = getSpecifierForModuleSymbol(chain[0], context, ModuleKind.ESNext); + if ( + targetFile?.impliedNodeFormat === ModuleKind.ESNext && + targetFile.impliedNodeFormat !== + contextFile?.impliedNodeFormat + ) { + specifier = getSpecifierForModuleSymbol( + chain[0], + context, + ModuleKind.ESNext + ); attributes = factory.createImportAttributes( factory.createNodeArray([ factory.createImportAttribute( - factory.createStringLiteral("resolution-mode"), - factory.createStringLiteral("import"), + factory.createStringLiteral( + "resolution-mode" + ), + factory.createStringLiteral("import") ), - ]), + ]) ); } } if (!specifier) { specifier = getSpecifierForModuleSymbol(chain[0], context); } - if (!(context.flags & NodeBuilderFlags.AllowNodeModulesRelativePaths) && getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Classic && specifier.includes("/node_modules/")) { + if ( + !( + context.flags & + NodeBuilderFlags.AllowNodeModulesRelativePaths + ) && + getEmitModuleResolutionKind(compilerOptions) !== + ModuleResolutionKind.Classic && + specifier.includes("/node_modules/") + ) { const oldSpecifier = specifier; - if (getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Node16 || getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeNext) { + if ( + getEmitModuleResolutionKind(compilerOptions) === + ModuleResolutionKind.Node16 || + getEmitModuleResolutionKind(compilerOptions) === + ModuleResolutionKind.NodeNext + ) { // We might be able to write a portable import type using a mode override; try specifier generation again, but with a different mode set - const swappedMode = contextFile?.impliedNodeFormat === ModuleKind.ESNext ? ModuleKind.CommonJS : ModuleKind.ESNext; - specifier = getSpecifierForModuleSymbol(chain[0], context, swappedMode); + const swappedMode = + contextFile?.impliedNodeFormat === ModuleKind.ESNext + ? ModuleKind.CommonJS + : ModuleKind.ESNext; + specifier = getSpecifierForModuleSymbol( + chain[0], + context, + swappedMode + ); if (specifier.includes("/node_modules/")) { // Still unreachable :( specifier = oldSpecifier; - } - else { + } else { attributes = factory.createImportAttributes( factory.createNodeArray([ factory.createImportAttribute( - factory.createStringLiteral("resolution-mode"), - factory.createStringLiteral(swappedMode === ModuleKind.ESNext ? "import" : "require"), + factory.createStringLiteral( + "resolution-mode" + ), + factory.createStringLiteral( + swappedMode === ModuleKind.ESNext + ? "import" + : "require" + ) ), - ]), + ]) ); } } @@ -8592,43 +14848,86 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If ultimately we can only name the symbol with a reference that dives into a `node_modules` folder, we should error // since declaration files with these kinds of references are liable to fail when published :( context.encounteredError = true; - if (context.tracker.reportLikelyUnsafeImportRequiredError) { - context.tracker.reportLikelyUnsafeImportRequiredError(oldSpecifier); + if ( + context.tracker + .reportLikelyUnsafeImportRequiredError + ) { + context.tracker.reportLikelyUnsafeImportRequiredError( + oldSpecifier + ); } } } - const lit = factory.createLiteralTypeNode(factory.createStringLiteral(specifier)); + const lit = factory.createLiteralTypeNode( + factory.createStringLiteral(specifier) + ); context.approximateLength += specifier.length + 10; // specifier + import("") if (!nonRootParts || isEntityName(nonRootParts)) { if (nonRootParts) { - const lastId = isIdentifier(nonRootParts) ? nonRootParts : nonRootParts.right; - setIdentifierTypeArguments(lastId, /*typeArguments*/ undefined); + const lastId = isIdentifier(nonRootParts) + ? nonRootParts + : nonRootParts.right; + setIdentifierTypeArguments( + lastId, + /*typeArguments*/ undefined + ); } - return factory.createImportTypeNode(lit, attributes, nonRootParts as EntityName, typeParameterNodes as readonly TypeNode[], isTypeOf); - } - else { + return factory.createImportTypeNode( + lit, + attributes, + nonRootParts as EntityName, + typeParameterNodes as readonly TypeNode[], + isTypeOf + ); + } else { const splitNode = getTopmostIndexedAccessType(nonRootParts); - const qualifier = (splitNode.objectType as TypeReferenceNode).typeName; - return factory.createIndexedAccessTypeNode(factory.createImportTypeNode(lit, attributes, qualifier, typeParameterNodes as readonly TypeNode[], isTypeOf), splitNode.indexType); + const qualifier = ( + splitNode.objectType as TypeReferenceNode + ).typeName; + return factory.createIndexedAccessTypeNode( + factory.createImportTypeNode( + lit, + attributes, + qualifier, + typeParameterNodes as readonly TypeNode[], + isTypeOf + ), + splitNode.indexType + ); } } - const entityName = createAccessFromSymbolChain(chain, chain.length - 1, 0); + const entityName = createAccessFromSymbolChain( + chain, + chain.length - 1, + 0 + ); if (isIndexedAccessTypeNode(entityName)) { return entityName; // Indexed accesses can never be `typeof` } if (isTypeOf) { return factory.createTypeQueryNode(entityName); - } - else { - const lastId = isIdentifier(entityName) ? entityName : entityName.right; + } else { + const lastId = isIdentifier(entityName) + ? entityName + : entityName.right; const lastTypeArgs = getIdentifierTypeArguments(lastId); setIdentifierTypeArguments(lastId, /*typeArguments*/ undefined); - return factory.createTypeReferenceNode(entityName, lastTypeArgs as NodeArray); + return factory.createTypeReferenceNode( + entityName, + lastTypeArgs as NodeArray + ); } - function createAccessFromSymbolChain(chain: Symbol[], index: number, stopper: number): EntityName | IndexedAccessTypeNode { - const typeParameterNodes = index === (chain.length - 1) ? overrideTypeArguments : lookupTypeParameterNodes(chain, index, context); + function createAccessFromSymbolChain( + chain: Symbol[], + index: number, + stopper: number + ): EntityName | IndexedAccessTypeNode { + const typeParameterNodes = + index === chain.length - 1 + ? overrideTypeArguments + : lookupTypeParameterNodes(chain, index, context); const symbol = chain[index]; const parent = chain[index - 1]; @@ -8636,14 +14935,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (index === 0) { context.flags |= NodeBuilderFlags.InInitialEntityName; symbolName = getNameOfSymbolAsWritten(symbol, context); - context.approximateLength += (symbolName ? symbolName.length : 0) + 1; + context.approximateLength += + (symbolName ? symbolName.length : 0) + 1; context.flags ^= NodeBuilderFlags.InInitialEntityName; - } - else { + } else { if (parent && getExportsOfSymbol(parent)) { const exports = getExportsOfSymbol(parent); forEachEntry(exports, (ex, name) => { - if (getSymbolIfSameReference(ex, symbol) && !isLateBoundName(name) && name !== InternalSymbolName.ExportEquals) { + if ( + getSymbolIfSameReference(ex, symbol) && + !isLateBoundName(name) && + name !== InternalSymbolName.ExportEquals + ) { symbolName = unescapeLeadingUnderscores(name); return true; } @@ -8652,11 +14955,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (symbolName === undefined) { - const name = firstDefined(symbol.declarations, getNameOfDeclaration); - if (name && isComputedPropertyName(name) && isEntityName(name.expression)) { - const LHS = createAccessFromSymbolChain(chain, index - 1, stopper); + const name = firstDefined( + symbol.declarations, + getNameOfDeclaration + ); + if ( + name && + isComputedPropertyName(name) && + isEntityName(name.expression) + ) { + const LHS = createAccessFromSymbolChain( + chain, + index - 1, + stopper + ); if (isEntityName(LHS)) { - return factory.createIndexedAccessTypeNode(factory.createParenthesizedType(factory.createTypeQueryNode(LHS)), factory.createTypeQueryNode(name.expression)); + return factory.createIndexedAccessTypeNode( + factory.createParenthesizedType( + factory.createTypeQueryNode(LHS) + ), + factory.createTypeQueryNode(name.expression) + ); } return LHS; } @@ -8665,28 +14984,67 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { context.approximateLength += symbolName.length + 1; if ( - !(context.flags & NodeBuilderFlags.ForbidIndexedAccessSymbolReferences) && parent && - getMembersOfSymbol(parent) && getMembersOfSymbol(parent).get(symbol.escapedName) && - getSymbolIfSameReference(getMembersOfSymbol(parent).get(symbol.escapedName)!, symbol) + !( + context.flags & + NodeBuilderFlags.ForbidIndexedAccessSymbolReferences + ) && + parent && + getMembersOfSymbol(parent) && + getMembersOfSymbol(parent).get(symbol.escapedName) && + getSymbolIfSameReference( + getMembersOfSymbol(parent).get(symbol.escapedName)!, + symbol + ) ) { // Should use an indexed access - const LHS = createAccessFromSymbolChain(chain, index - 1, stopper); + const LHS = createAccessFromSymbolChain( + chain, + index - 1, + stopper + ); if (isIndexedAccessTypeNode(LHS)) { - return factory.createIndexedAccessTypeNode(LHS, factory.createLiteralTypeNode(factory.createStringLiteral(symbolName))); - } - else { - return factory.createIndexedAccessTypeNode(factory.createTypeReferenceNode(LHS, typeParameterNodes as readonly TypeNode[]), factory.createLiteralTypeNode(factory.createStringLiteral(symbolName))); + return factory.createIndexedAccessTypeNode( + LHS, + factory.createLiteralTypeNode( + factory.createStringLiteral(symbolName) + ) + ); + } else { + return factory.createIndexedAccessTypeNode( + factory.createTypeReferenceNode( + LHS, + typeParameterNodes as readonly TypeNode[] + ), + factory.createLiteralTypeNode( + factory.createStringLiteral(symbolName) + ) + ); } } - const identifier = setEmitFlags(factory.createIdentifier(symbolName), EmitFlags.NoAsciiEscaping); - if (typeParameterNodes) setIdentifierTypeArguments(identifier, factory.createNodeArray(typeParameterNodes)); + const identifier = setEmitFlags( + factory.createIdentifier(symbolName), + EmitFlags.NoAsciiEscaping + ); + if (typeParameterNodes) + setIdentifierTypeArguments( + identifier, + factory.createNodeArray< + TypeNode | TypeParameterDeclaration + >(typeParameterNodes) + ); identifier.symbol = symbol; if (index > stopper) { - const LHS = createAccessFromSymbolChain(chain, index - 1, stopper); + const LHS = createAccessFromSymbolChain( + chain, + index - 1, + stopper + ); if (!isEntityName(LHS)) { - return Debug.fail("Impossible construct - an export of an indexed access cannot be reachable"); + return Debug.fail( + "Impossible construct - an export of an indexed access cannot be reachable" + ); } return factory.createQualifiedName(LHS, identifier); } @@ -8694,22 +15052,44 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function typeParameterShadowsOtherTypeParameterInScope(escapedName: __String, context: NodeBuilderContext, type: TypeParameter) { - const result = resolveName(context.enclosingDeclaration, escapedName, SymbolFlags.Type, /*nameNotFoundMessage*/ undefined, /*isUse*/ false); + function typeParameterShadowsOtherTypeParameterInScope( + escapedName: __String, + context: NodeBuilderContext, + type: TypeParameter + ) { + const result = resolveName( + context.enclosingDeclaration, + escapedName, + SymbolFlags.Type, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ false + ); if (result && result.flags & SymbolFlags.TypeParameter) { return result !== type.symbol; } return false; } - function typeParameterToName(type: TypeParameter, context: NodeBuilderContext) { - if (context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams && context.typeParameterNames) { + function typeParameterToName( + type: TypeParameter, + context: NodeBuilderContext + ) { + if ( + context.flags & + NodeBuilderFlags.GenerateNamesForShadowedTypeParams && + context.typeParameterNames + ) { const cached = context.typeParameterNames.get(getTypeId(type)); if (cached) { return cached; } } - let result = symbolToName(type.symbol, context, SymbolFlags.Type, /*expectsIdentifier*/ true); + let result = symbolToName( + type.symbol, + context, + SymbolFlags.Type, + /*expectsIdentifier*/ true + ); if (!(result.kind & SyntaxKind.Identifier)) { return factory.createIdentifier("(Missing type parameter)"); } @@ -8717,11 +15097,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (decl && isTypeParameterDeclaration(decl)) { result = setTextRange(context, result, decl.name); } - if (context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams) { + if ( + context.flags & + NodeBuilderFlags.GenerateNamesForShadowedTypeParams + ) { const rawtext = result.escapedText as string; - let i = context.typeParameterNamesByTextNextNameCount?.get(rawtext) || 0; + let i = + context.typeParameterNamesByTextNextNameCount?.get( + rawtext + ) || 0; let text = rawtext; - while (context.typeParameterNamesByText?.has(text) || typeParameterShadowsOtherTypeParameterInScope(text as __String, context, type)) { + while ( + context.typeParameterNamesByText?.has(text) || + typeParameterShadowsOtherTypeParameterInScope( + text as __String, + context, + type + ) + ) { i++; text = `${rawtext}_${i}`; } @@ -8732,9 +15125,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (context.mustCreateTypeParametersNamesLookups) { context.mustCreateTypeParametersNamesLookups = false; - context.typeParameterNames = new Map(context.typeParameterNames); - context.typeParameterNamesByTextNextNameCount = new Map(context.typeParameterNamesByTextNextNameCount); - context.typeParameterNamesByText = new Set(context.typeParameterNamesByText); + context.typeParameterNames = new Map( + context.typeParameterNames + ); + context.typeParameterNamesByTextNextNameCount = new Map( + context.typeParameterNamesByTextNextNameCount + ); + context.typeParameterNamesByText = new Set( + context.typeParameterNamesByText + ); } // avoiding iterations of the above loop turns out to be worth it when `i` starts to get large, so we cache the max // `i` we've used thus far, to save work later @@ -8745,22 +15144,48 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function symbolToName(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, expectsIdentifier: true): Identifier; - function symbolToName(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, expectsIdentifier: false): EntityName; - function symbolToName(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, expectsIdentifier: boolean): EntityName { + function symbolToName( + symbol: Symbol, + context: NodeBuilderContext, + meaning: SymbolFlags, + expectsIdentifier: true + ): Identifier; + function symbolToName( + symbol: Symbol, + context: NodeBuilderContext, + meaning: SymbolFlags, + expectsIdentifier: false + ): EntityName; + function symbolToName( + symbol: Symbol, + context: NodeBuilderContext, + meaning: SymbolFlags, + expectsIdentifier: boolean + ): EntityName { const chain = lookupSymbolChain(symbol, context, meaning); if ( - expectsIdentifier && chain.length !== 1 - && !context.encounteredError - && !(context.flags & NodeBuilderFlags.AllowQualifiedNameInPlaceOfIdentifier) + expectsIdentifier && + chain.length !== 1 && + !context.encounteredError && + !( + context.flags & + NodeBuilderFlags.AllowQualifiedNameInPlaceOfIdentifier + ) ) { context.encounteredError = true; } return createEntityNameFromSymbolChain(chain, chain.length - 1); - function createEntityNameFromSymbolChain(chain: Symbol[], index: number): EntityName { - const typeParameterNodes = lookupTypeParameterNodes(chain, index, context); + function createEntityNameFromSymbolChain( + chain: Symbol[], + index: number + ): EntityName { + const typeParameterNodes = lookupTypeParameterNodes( + chain, + index, + context + ); const symbol = chain[index]; if (index === 0) { @@ -8771,21 +15196,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { context.flags ^= NodeBuilderFlags.InInitialEntityName; } - const identifier = setEmitFlags(factory.createIdentifier(symbolName), EmitFlags.NoAsciiEscaping); - if (typeParameterNodes) setIdentifierTypeArguments(identifier, factory.createNodeArray(typeParameterNodes)); + const identifier = setEmitFlags( + factory.createIdentifier(symbolName), + EmitFlags.NoAsciiEscaping + ); + if (typeParameterNodes) + setIdentifierTypeArguments( + identifier, + factory.createNodeArray< + TypeNode | TypeParameterDeclaration + >(typeParameterNodes) + ); identifier.symbol = symbol; - return index > 0 ? factory.createQualifiedName(createEntityNameFromSymbolChain(chain, index - 1), identifier) : identifier; + return index > 0 + ? factory.createQualifiedName( + createEntityNameFromSymbolChain(chain, index - 1), + identifier + ) + : identifier; } } - function symbolToExpression(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags) { + function symbolToExpression( + symbol: Symbol, + context: NodeBuilderContext, + meaning: SymbolFlags + ) { const chain = lookupSymbolChain(symbol, context, meaning); return createExpressionFromSymbolChain(chain, chain.length - 1); - function createExpressionFromSymbolChain(chain: Symbol[], index: number): Expression { - const typeParameterNodes = lookupTypeParameterNodes(chain, index, context); + function createExpressionFromSymbolChain( + chain: Symbol[], + index: number + ): Expression { + const typeParameterNodes = lookupTypeParameterNodes( + chain, + index, + context + ); const symbol = chain[index]; if (index === 0) { @@ -8797,42 +15247,90 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } let firstChar = symbolName.charCodeAt(0); - if (isSingleOrDoubleQuote(firstChar) && some(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol)) { - const specifier = getSpecifierForModuleSymbol(symbol, context); + if ( + isSingleOrDoubleQuote(firstChar) && + some( + symbol.declarations, + hasNonGlobalAugmentationExternalModuleSymbol + ) + ) { + const specifier = getSpecifierForModuleSymbol( + symbol, + context + ); context.approximateLength += 2 + specifier.length; // "specifier" return factory.createStringLiteral(specifier); } - if (index === 0 || canUsePropertyAccess(symbolName, languageVersion)) { - const identifier = setEmitFlags(factory.createIdentifier(symbolName), EmitFlags.NoAsciiEscaping); - if (typeParameterNodes) setIdentifierTypeArguments(identifier, factory.createNodeArray(typeParameterNodes)); + if ( + index === 0 || + canUsePropertyAccess(symbolName, languageVersion) + ) { + const identifier = setEmitFlags( + factory.createIdentifier(symbolName), + EmitFlags.NoAsciiEscaping + ); + if (typeParameterNodes) + setIdentifierTypeArguments( + identifier, + factory.createNodeArray< + TypeNode | TypeParameterDeclaration + >(typeParameterNodes) + ); identifier.symbol = symbol; context.approximateLength += 1 + symbolName.length; // .symbolName - return index > 0 ? factory.createPropertyAccessExpression(createExpressionFromSymbolChain(chain, index - 1), identifier) : identifier; - } - else { + return index > 0 + ? factory.createPropertyAccessExpression( + createExpressionFromSymbolChain(chain, index - 1), + identifier + ) + : identifier; + } else { if (firstChar === CharacterCodes.openBracket) { - symbolName = symbolName.substring(1, symbolName.length - 1); + symbolName = symbolName.substring( + 1, + symbolName.length - 1 + ); firstChar = symbolName.charCodeAt(0); } let expression: Expression | undefined; - if (isSingleOrDoubleQuote(firstChar) && !(symbol.flags & SymbolFlags.EnumMember)) { - const literalText = stripQuotes(symbolName).replace(/\\./g, s => s.substring(1)); + if ( + isSingleOrDoubleQuote(firstChar) && + !(symbol.flags & SymbolFlags.EnumMember) + ) { + const literalText = stripQuotes(symbolName).replace( + /\\./g, + (s) => s.substring(1) + ); context.approximateLength += literalText.length + 2; // "literalText" - expression = factory.createStringLiteral(literalText, firstChar === CharacterCodes.singleQuote); - } - else if (("" + +symbolName) === symbolName) { + expression = factory.createStringLiteral( + literalText, + firstChar === CharacterCodes.singleQuote + ); + } else if ("" + +symbolName === symbolName) { context.approximateLength += symbolName.length; // +symbolName expression = factory.createNumericLiteral(+symbolName); } if (!expression) { - const identifier = setEmitFlags(factory.createIdentifier(symbolName), EmitFlags.NoAsciiEscaping); - if (typeParameterNodes) setIdentifierTypeArguments(identifier, factory.createNodeArray(typeParameterNodes)); + const identifier = setEmitFlags( + factory.createIdentifier(symbolName), + EmitFlags.NoAsciiEscaping + ); + if (typeParameterNodes) + setIdentifierTypeArguments( + identifier, + factory.createNodeArray< + TypeNode | TypeParameterDeclaration + >(typeParameterNodes) + ); identifier.symbol = symbol; context.approximateLength += symbolName.length; // symbolName expression = identifier; } context.approximateLength += 2; // [] - return factory.createElementAccessExpression(createExpressionFromSymbolChain(chain, index - 1), expression); + return factory.createElementAccessExpression( + createExpressionFromSymbolChain(chain, index - 1), + expression + ); } } } @@ -8855,41 +15353,101 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isSingleQuotedStringNamed(d: Declaration) { const name = getNameOfDeclaration(d); - return !!(name && isStringLiteral(name) && (name.singleQuote || !nodeIsSynthesized(name) && startsWith(getTextOfNode(name, /*includeTrivia*/ false), "'"))); + return !!( + name && + isStringLiteral(name) && + (name.singleQuote || + (!nodeIsSynthesized(name) && + startsWith( + getTextOfNode(name, /*includeTrivia*/ false), + "'" + ))) + ); } - function getPropertyNameNodeForSymbol(symbol: Symbol, context: NodeBuilderContext) { + function getPropertyNameNodeForSymbol( + symbol: Symbol, + context: NodeBuilderContext + ) { const hashPrivateName = getClonedHashPrivateName(symbol); if (hashPrivateName) { return hashPrivateName; } - const stringNamed = !!length(symbol.declarations) && every(symbol.declarations, isStringNamed); - const singleQuote = !!length(symbol.declarations) && every(symbol.declarations, isSingleQuotedStringNamed); + const stringNamed = + !!length(symbol.declarations) && + every(symbol.declarations, isStringNamed); + const singleQuote = + !!length(symbol.declarations) && + every(symbol.declarations, isSingleQuotedStringNamed); const isMethod = !!(symbol.flags & SymbolFlags.Method); - const fromNameType = getPropertyNameNodeForSymbolFromNameType(symbol, context, singleQuote, stringNamed, isMethod); + const fromNameType = getPropertyNameNodeForSymbolFromNameType( + symbol, + context, + singleQuote, + stringNamed, + isMethod + ); if (fromNameType) { return fromNameType; } const rawName = unescapeLeadingUnderscores(symbol.escapedName); - return createPropertyNameNodeForIdentifierOrLiteral(rawName, getEmitScriptTarget(compilerOptions), singleQuote, stringNamed, isMethod); + return createPropertyNameNodeForIdentifierOrLiteral( + rawName, + getEmitScriptTarget(compilerOptions), + singleQuote, + stringNamed, + isMethod + ); } // See getNameForSymbolFromNameType for a stringy equivalent - function getPropertyNameNodeForSymbolFromNameType(symbol: Symbol, context: NodeBuilderContext, singleQuote: boolean, stringNamed: boolean, isMethod: boolean) { + function getPropertyNameNodeForSymbolFromNameType( + symbol: Symbol, + context: NodeBuilderContext, + singleQuote: boolean, + stringNamed: boolean, + isMethod: boolean + ) { const nameType = getSymbolLinks(symbol).nameType; if (nameType) { if (nameType.flags & TypeFlags.StringOrNumberLiteral) { - const name = "" + (nameType as StringLiteralType | NumberLiteralType).value; - if (!isIdentifierText(name, getEmitScriptTarget(compilerOptions)) && (stringNamed || !isNumericLiteralName(name))) { + const name = + "" + + (nameType as StringLiteralType | NumberLiteralType) + .value; + if ( + !isIdentifierText( + name, + getEmitScriptTarget(compilerOptions) + ) && + (stringNamed || !isNumericLiteralName(name)) + ) { return factory.createStringLiteral(name, !!singleQuote); } if (isNumericLiteralName(name) && startsWith(name, "-")) { - return factory.createComputedPropertyName(factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, factory.createNumericLiteral(-name))); + return factory.createComputedPropertyName( + factory.createPrefixUnaryExpression( + SyntaxKind.MinusToken, + factory.createNumericLiteral(-name) + ) + ); } - return createPropertyNameNodeForIdentifierOrLiteral(name, getEmitScriptTarget(compilerOptions), singleQuote, stringNamed, isMethod); + return createPropertyNameNodeForIdentifierOrLiteral( + name, + getEmitScriptTarget(compilerOptions), + singleQuote, + stringNamed, + isMethod + ); } if (nameType.flags & TypeFlags.UniqueESSymbol) { - return factory.createComputedPropertyName(symbolToExpression((nameType as UniqueESSymbolType).symbol, context, SymbolFlags.Value)); + return factory.createComputedPropertyName( + symbolToExpression( + (nameType as UniqueESSymbolType).symbol, + context, + SymbolFlags.Value + ) + ); } } } @@ -8907,29 +15465,54 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // we write it out like that, rather than as // export const x: (x: T) => T // export const y: (x: T_1) => T_1 - const oldMustCreateTypeParameterSymbolList = context.mustCreateTypeParameterSymbolList; - const oldMustCreateTypeParametersNamesLookups = context.mustCreateTypeParametersNamesLookups; + const oldMustCreateTypeParameterSymbolList = + context.mustCreateTypeParameterSymbolList; + const oldMustCreateTypeParametersNamesLookups = + context.mustCreateTypeParametersNamesLookups; context.mustCreateTypeParameterSymbolList = true; context.mustCreateTypeParametersNamesLookups = true; const oldTypeParameterNames = context.typeParameterNames; - const oldTypeParameterNamesByText = context.typeParameterNamesByText; - const oldTypeParameterNamesByTextNextNameCount = context.typeParameterNamesByTextNextNameCount; + const oldTypeParameterNamesByText = + context.typeParameterNamesByText; + const oldTypeParameterNamesByTextNextNameCount = + context.typeParameterNamesByTextNextNameCount; const oldTypeParameterSymbolList = context.typeParameterSymbolList; return () => { context.typeParameterNames = oldTypeParameterNames; context.typeParameterNamesByText = oldTypeParameterNamesByText; - context.typeParameterNamesByTextNextNameCount = oldTypeParameterNamesByTextNextNameCount; + context.typeParameterNamesByTextNextNameCount = + oldTypeParameterNamesByTextNextNameCount; context.typeParameterSymbolList = oldTypeParameterSymbolList; - context.mustCreateTypeParameterSymbolList = oldMustCreateTypeParameterSymbolList; - context.mustCreateTypeParametersNamesLookups = oldMustCreateTypeParametersNamesLookups; + context.mustCreateTypeParameterSymbolList = + oldMustCreateTypeParameterSymbolList; + context.mustCreateTypeParametersNamesLookups = + oldMustCreateTypeParametersNamesLookups; }; } - function getDeclarationWithTypeAnnotation(symbol: Symbol, enclosingDeclaration?: Node | undefined) { - return symbol.declarations && find(symbol.declarations, s => !!getNonlocalEffectiveTypeAnnotationNode(s) && (!enclosingDeclaration || !!findAncestor(s, n => n === enclosingDeclaration))); + function getDeclarationWithTypeAnnotation( + symbol: Symbol, + enclosingDeclaration?: Node | undefined + ) { + return ( + symbol.declarations && + find( + symbol.declarations, + (s) => + !!getNonlocalEffectiveTypeAnnotationNode(s) && + (!enclosingDeclaration || + !!findAncestor( + s, + (n) => n === enclosingDeclaration + )) + ) + ); } - function existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount(existing: TypeNode, type: Type) { + function existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount( + existing: TypeNode, + type: Type + ) { // In JS, you can say something like `Foo` and get a `Foo` implicitly - we don't want to preserve that original `Foo` in these cases, though. if (!(getObjectFlags(type) & ObjectFlags.Reference)) return true; if (!isTypeReferenceNode(existing)) return true; @@ -8938,12 +15521,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { void getTypeFromTypeReference(existing); // call to ensure symbol is resolved const symbol = getNodeLinks(existing).resolvedSymbol; const existingTarget = symbol && getDeclaredTypeOfSymbol(symbol); - if (!existingTarget || existingTarget !== (type as TypeReference).target) return true; - return length(existing.typeArguments) >= getMinTypeArgumentCount((type as TypeReference).target.typeParameters); + if ( + !existingTarget || + existingTarget !== (type as TypeReference).target + ) + return true; + return ( + length(existing.typeArguments) >= + getMinTypeArgumentCount( + (type as TypeReference).target.typeParameters + ) + ); } - function getEnclosingDeclarationIgnoringFakeScope(enclosingDeclaration: Node) { - while (getNodeLinks(enclosingDeclaration).fakeScopeForSignatureDeclaration) { + function getEnclosingDeclarationIgnoringFakeScope( + enclosingDeclaration: Node + ) { + while ( + getNodeLinks(enclosingDeclaration) + .fakeScopeForSignatureDeclaration + ) { enclosingDeclaration = enclosingDeclaration.parent; } return enclosingDeclaration; @@ -8953,10 +15550,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Unlike `typeToTypeNodeHelper`, this handles setting up the `AllowUniqueESSymbolType` flag * so a `unique symbol` is returned when appropriate for the input symbol, rather than `typeof sym` */ - function serializeInferredTypeForDeclaration(symbol: Symbol, context: NodeBuilderContext, type: Type) { + function serializeInferredTypeForDeclaration( + symbol: Symbol, + context: NodeBuilderContext, + type: Type + ) { if ( type.flags & TypeFlags.UniqueESSymbol && - type.symbol === symbol && (!context.enclosingDeclaration || some(symbol.declarations, d => getSourceFileOfNode(d) === context.enclosingFile)) + type.symbol === symbol && + (!context.enclosingDeclaration || + some( + symbol.declarations, + (d) => getSourceFileOfNode(d) === context.enclosingFile + )) ) { context.flags |= NodeBuilderFlags.AllowUniqueESSymbolType; } @@ -8971,21 +15577,44 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param type - The type to write; an existing annotation must match this type if it's used, otherwise this is the type serialized as a new type node * @param symbol - The symbol is used both to find an existing annotation if declaration is not provided, and to determine if `unique symbol` should be printed */ - function serializeTypeForDeclaration(context: NodeBuilderContext, declaration: Declaration | undefined, type: Type, symbol: Symbol) { + function serializeTypeForDeclaration( + context: NodeBuilderContext, + declaration: Declaration | undefined, + type: Type, + symbol: Symbol + ) { let result; - const addUndefinedForParameter = declaration && (isParameter(declaration) || isJSDocParameterTag(declaration)) && requiresAddingImplicitUndefined(declaration, context.enclosingDeclaration); - const decl = declaration ?? symbol.valueDeclaration ?? getDeclarationWithTypeAnnotation(symbol) ?? symbol.declarations?.[0]; + const addUndefinedForParameter = + declaration && + (isParameter(declaration) || + isJSDocParameterTag(declaration)) && + requiresAddingImplicitUndefined( + declaration, + context.enclosingDeclaration + ); + const decl = + declaration ?? + symbol.valueDeclaration ?? + getDeclarationWithTypeAnnotation(symbol) ?? + symbol.declarations?.[0]; if (!canPossiblyExpandType(type, context) && decl) { const restore = addSymbolTypeToContext(context, symbol, type); if (isAccessor(decl)) { - result = syntacticNodeBuilder.serializeTypeOfAccessor(decl, symbol, context); - } - else if ( - hasInferredType(decl) - && !nodeIsSynthesized(decl) - && !(getObjectFlags(type) & ObjectFlags.RequiresWidening) + result = syntacticNodeBuilder.serializeTypeOfAccessor( + decl, + symbol, + context + ); + } else if ( + hasInferredType(decl) && + !nodeIsSynthesized(decl) && + !(getObjectFlags(type) & ObjectFlags.RequiresWidening) ) { - result = syntacticNodeBuilder.serializeTypeOfDeclaration(decl, symbol, context); + result = syntacticNodeBuilder.serializeTypeOfDeclaration( + decl, + symbol, + context + ); } restore(); } @@ -8993,23 +15622,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (addUndefinedForParameter) { type = getOptionalType(type); } - result = serializeInferredTypeForDeclaration(symbol, context, type); + result = serializeInferredTypeForDeclaration( + symbol, + context, + type + ); } - return result ?? factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); + return ( + result ?? factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) + ); } - function typeNodeIsEquivalentToType(annotatedDeclaration: Node | undefined, type: Type, typeFromTypeNode: Type) { + function typeNodeIsEquivalentToType( + annotatedDeclaration: Node | undefined, + type: Type, + typeFromTypeNode: Type + ) { if (typeFromTypeNode === type) { return true; } if (!annotatedDeclaration) { return false; } - if ((isPropertySignature(annotatedDeclaration) || isPropertyDeclaration(annotatedDeclaration)) && annotatedDeclaration.questionToken) { - return getTypeWithFacts(type, TypeFacts.NEUndefined) === typeFromTypeNode; + if ( + (isPropertySignature(annotatedDeclaration) || + isPropertyDeclaration(annotatedDeclaration)) && + annotatedDeclaration.questionToken + ) { + return ( + getTypeWithFacts(type, TypeFacts.NEUndefined) === + typeFromTypeNode + ); } - if (isParameter(annotatedDeclaration) && hasEffectiveQuestionToken(annotatedDeclaration)) { - return getTypeWithFacts(type, TypeFacts.NEUndefined) === typeFromTypeNode; + if ( + isParameter(annotatedDeclaration) && + hasEffectiveQuestionToken(annotatedDeclaration) + ) { + return ( + getTypeWithFacts(type, TypeFacts.NEUndefined) === + typeFromTypeNode + ); } return false; } @@ -9017,27 +15669,53 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** * Serializes the return type of the signature by first trying to use the syntactic printer if possible and falling back to the checker type if not. */ - function serializeReturnTypeForSignature(context: NodeBuilderContext, signature: Signature) { - const suppressAny = context.flags & NodeBuilderFlags.SuppressAnyReturnType; + function serializeReturnTypeForSignature( + context: NodeBuilderContext, + signature: Signature + ) { + const suppressAny = + context.flags & NodeBuilderFlags.SuppressAnyReturnType; const restoreFlags = saveRestoreFlags(context); - if (suppressAny) context.flags &= ~NodeBuilderFlags.SuppressAnyReturnType; // suppress only toplevel `any`s + if (suppressAny) + context.flags &= ~NodeBuilderFlags.SuppressAnyReturnType; // suppress only toplevel `any`s let returnTypeNode: TypeNode | undefined; const returnType = getReturnTypeOfSignature(signature); if (!(suppressAny && isTypeAny(returnType))) { - if (signature.declaration && !nodeIsSynthesized(signature.declaration) && !canPossiblyExpandType(returnType, context)) { - const declarationSymbol = getSymbolOfDeclaration(signature.declaration); - const restore = addSymbolTypeToContext(context, declarationSymbol, returnType); - returnTypeNode = syntacticNodeBuilder.serializeReturnTypeForSignature(signature.declaration, declarationSymbol, context); + if ( + signature.declaration && + !nodeIsSynthesized(signature.declaration) && + !canPossiblyExpandType(returnType, context) + ) { + const declarationSymbol = getSymbolOfDeclaration( + signature.declaration + ); + const restore = addSymbolTypeToContext( + context, + declarationSymbol, + returnType + ); + returnTypeNode = + syntacticNodeBuilder.serializeReturnTypeForSignature( + signature.declaration, + declarationSymbol, + context + ); restore(); } if (!returnTypeNode) { - returnTypeNode = serializeInferredReturnTypeForSignature(context, signature, returnType); + returnTypeNode = serializeInferredReturnTypeForSignature( + context, + signature, + returnType + ); } } if (!returnTypeNode && !suppressAny) { - returnTypeNode = factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); + returnTypeNode = factory.createKeywordTypeNode( + SyntaxKind.AnyKeyword + ); } restoreFlags(); return returnTypeNode; @@ -9046,21 +15724,48 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** * Serializes the checker type of the signature (does not use the syntactic printer) */ - function serializeInferredReturnTypeForSignature(context: NodeBuilderContext, signature: Signature, returnType: Type) { - const oldSuppressReportInferenceFallback = context.suppressReportInferenceFallback; + function serializeInferredReturnTypeForSignature( + context: NodeBuilderContext, + signature: Signature, + returnType: Type + ) { + const oldSuppressReportInferenceFallback = + context.suppressReportInferenceFallback; context.suppressReportInferenceFallback = true; const typePredicate = getTypePredicateOfSignature(signature); - const returnTypeNode = typePredicate ? - typePredicateToTypePredicateNodeHelper(context.mapper ? instantiateTypePredicate(typePredicate, context.mapper) : typePredicate, context) : - typeToTypeNodeHelper(returnType, context); - context.suppressReportInferenceFallback = oldSuppressReportInferenceFallback; + const returnTypeNode = typePredicate + ? typePredicateToTypePredicateNodeHelper( + context.mapper + ? instantiateTypePredicate( + typePredicate, + context.mapper + ) + : typePredicate, + context + ) + : typeToTypeNodeHelper(returnType, context); + context.suppressReportInferenceFallback = + oldSuppressReportInferenceFallback; return returnTypeNode; } - function trackExistingEntityName(node: T, context: NodeBuilderContext, enclosingDeclaration = context.enclosingDeclaration) { + function trackExistingEntityName< + T extends EntityNameOrEntityNameExpression + >( + node: T, + context: NodeBuilderContext, + enclosingDeclaration = context.enclosingDeclaration + ) { let introducesError = false; const leftmost = getFirstIdentifier(node); - if (isInJSFile(node) && (isExportsIdentifier(leftmost) || isModuleExportsAccessExpression(leftmost.parent) || (isQualifiedName(leftmost.parent) && isModuleIdentifier(leftmost.parent.left) && isExportsIdentifier(leftmost.parent.right)))) { + if ( + isInJSFile(node) && + (isExportsIdentifier(leftmost) || + isModuleExportsAccessExpression(leftmost.parent) || + (isQualifiedName(leftmost.parent) && + isModuleIdentifier(leftmost.parent.left) && + isExportsIdentifier(leftmost.parent.right))) + ) { introducesError = true; return { introducesError, node }; } @@ -9068,14 +15773,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let sym: Symbol | undefined; if (isThisIdentifier(leftmost)) { // `this` isn't a bindable identifier - skip resolution, find a relevant `this` symbol directly and avoid exhaustive scope traversal - sym = getSymbolOfDeclaration(getThisContainer(leftmost, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false)); - if (isSymbolAccessible(sym, leftmost, meaning, /*shouldComputeAliasesToMakeVisible*/ false).accessibility !== SymbolAccessibility.Accessible) { + sym = getSymbolOfDeclaration( + getThisContainer( + leftmost, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false + ) + ); + if ( + isSymbolAccessible( + sym, + leftmost, + meaning, + /*shouldComputeAliasesToMakeVisible*/ false + ).accessibility !== SymbolAccessibility.Accessible + ) { introducesError = true; context.tracker.reportInaccessibleThisError(); } - return { introducesError, node: attachSymbolToLeftmostIdentifier(node) as T }; + return { + introducesError, + node: attachSymbolToLeftmostIdentifier(node) as T, + }; } - sym = resolveEntityName(leftmost, meaning, /*ignoreErrors*/ true, /*dontResolveAlias*/ true); + sym = resolveEntityName( + leftmost, + meaning, + /*ignoreErrors*/ true, + /*dontResolveAlias*/ true + ); if ( context.enclosingDeclaration && !(sym && sym.flags & SymbolFlags.TypeParameter) @@ -9086,14 +15812,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We also check for the unknownSymbol because when we create a fake scope some parameters may actually not be usable // either because they are the expanded rest parameter, // or because they are the newly added parameters from the tuple, which might have different meanings in the original context - const symAtLocation = resolveEntityName(leftmost, meaning, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, context.enclosingDeclaration); + const symAtLocation = resolveEntityName( + leftmost, + meaning, + /*ignoreErrors*/ true, + /*dontResolveAlias*/ true, + context.enclosingDeclaration + ); if ( // Check for unusable parameters symbols symAtLocation === unknownSymbol || // If the symbol is not found, but was not found in the original scope either we probably have an error, don't reuse the node (symAtLocation === undefined && sym !== undefined) || // If the symbol is found both in declaration scope and in current scope then it should point to the same reference - (symAtLocation && sym && !getSymbolIfSameReference(getExportSymbolOfValueSymbolIfExported(symAtLocation), sym)) + (symAtLocation && + sym && + !getSymbolIfSameReference( + getExportSymbolOfValueSymbolIfExported( + symAtLocation + ), + sym + )) ) { // In isolated declaration we will not do rest parameter expansion so there is no need to report on these. if (symAtLocation !== unknownSymbol) { @@ -9101,8 +15840,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } introducesError = true; return { introducesError, node, sym }; - } - else { + } else { sym = symAtLocation; } } @@ -9110,25 +15848,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (sym) { // If a parameter is resolvable in the current context it is also visible, so no need to go to symbol accesibility if ( - sym.flags & SymbolFlags.FunctionScopedVariable - && sym.valueDeclaration + sym.flags & SymbolFlags.FunctionScopedVariable && + sym.valueDeclaration ) { - if (isPartOfParameterDeclaration(sym.valueDeclaration) || isJSDocParameterTag(sym.valueDeclaration)) { - return { introducesError, node: attachSymbolToLeftmostIdentifier(node) as T }; + if ( + isPartOfParameterDeclaration(sym.valueDeclaration) || + isJSDocParameterTag(sym.valueDeclaration) + ) { + return { + introducesError, + node: attachSymbolToLeftmostIdentifier(node) as T, + }; } } if ( !(sym.flags & SymbolFlags.TypeParameter) && // Type parameters are visible in the current context if they are are resolvable !isDeclarationName(node) && - isSymbolAccessible(sym, enclosingDeclaration, meaning, /*shouldComputeAliasesToMakeVisible*/ false).accessibility !== SymbolAccessibility.Accessible + isSymbolAccessible( + sym, + enclosingDeclaration, + meaning, + /*shouldComputeAliasesToMakeVisible*/ false + ).accessibility !== SymbolAccessibility.Accessible ) { context.tracker.reportInferenceFallback(node); introducesError = true; + } else { + context.tracker.trackSymbol( + sym, + enclosingDeclaration, + meaning + ); } - else { - context.tracker.trackSymbol(sym, enclosingDeclaration, meaning); - } - return { introducesError, node: attachSymbolToLeftmostIdentifier(node) as T }; + return { + introducesError, + node: attachSymbolToLeftmostIdentifier(node) as T, + }; } return { introducesError, node }; @@ -9140,26 +15895,69 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function attachSymbolToLeftmostIdentifier(node: Node): Node { if (node === leftmost) { const type = getDeclaredTypeOfSymbol(sym!); - const name = sym!.flags & SymbolFlags.TypeParameter ? typeParameterToName(type, context) : factory.cloneNode(node as Identifier); + const name = + sym!.flags & SymbolFlags.TypeParameter + ? typeParameterToName(type, context) + : factory.cloneNode(node as Identifier); name.symbol = sym!; // for quickinfo, which uses identifier symbol information - return setTextRange(context, setEmitFlags(name, EmitFlags.NoAsciiEscaping), node); + return setTextRange( + context, + setEmitFlags(name, EmitFlags.NoAsciiEscaping), + node + ); } - const updated = visitEachChildWorker(node, c => attachSymbolToLeftmostIdentifier(c), /*context*/ undefined); + const updated = visitEachChildWorker( + node, + (c) => attachSymbolToLeftmostIdentifier(c), + /*context*/ undefined + ); return setTextRange(context, updated, node); } } - function serializeTypeName(context: NodeBuilderContext, node: EntityName, isTypeOf?: boolean, typeArguments?: readonly TypeNode[]) { + function serializeTypeName( + context: NodeBuilderContext, + node: EntityName, + isTypeOf?: boolean, + typeArguments?: readonly TypeNode[] + ) { const meaning = isTypeOf ? SymbolFlags.Value : SymbolFlags.Type; - const symbol = resolveEntityName(node, meaning, /*ignoreErrors*/ true); + const symbol = resolveEntityName( + node, + meaning, + /*ignoreErrors*/ true + ); if (!symbol) return undefined; - const resolvedSymbol = symbol.flags & SymbolFlags.Alias ? resolveAlias(symbol) : symbol; - if (isSymbolAccessible(symbol, context.enclosingDeclaration, meaning, /*shouldComputeAliasesToMakeVisible*/ false).accessibility !== SymbolAccessibility.Accessible) return undefined; - return symbolToTypeNode(resolvedSymbol, context, meaning, typeArguments); + const resolvedSymbol = + symbol.flags & SymbolFlags.Alias + ? resolveAlias(symbol) + : symbol; + if ( + isSymbolAccessible( + symbol, + context.enclosingDeclaration, + meaning, + /*shouldComputeAliasesToMakeVisible*/ false + ).accessibility !== SymbolAccessibility.Accessible + ) + return undefined; + return symbolToTypeNode( + resolvedSymbol, + context, + meaning, + typeArguments + ); } - function canReuseTypeNode(context: NodeBuilderContext, existing: TypeNode) { - const type = getTypeFromTypeNode(context, existing, /*noMappedTypes*/ true); + function canReuseTypeNode( + context: NodeBuilderContext, + existing: TypeNode + ) { + const type = getTypeFromTypeNode( + context, + existing, + /*noMappedTypes*/ true + ); if (!type) { return false; } @@ -9172,9 +15970,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { !nodeSymbol || !( // The import type resolved using jsdoc fallback logic - (!existing.isTypeOf && !(nodeSymbol.flags & SymbolFlags.Type)) || - // The import type had type arguments autofilled by js fallback logic - !(length(existing.typeArguments) >= getMinTypeArgumentCount(getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(nodeSymbol))) + ( + (!existing.isTypeOf && + !(nodeSymbol.flags & SymbolFlags.Type)) || + // The import type had type arguments autofilled by js fallback logic + !( + length(existing.typeArguments) >= + getMinTypeArgumentCount( + getLocalTypeParametersOfClassOrInterfaceOrTypeAlias( + nodeSymbol + ) + ) + ) + ) ) ); } @@ -9185,12 +15993,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!symbol) return false; if (symbol.flags & SymbolFlags.TypeParameter) { const declaredType = getDeclaredTypeOfSymbol(symbol); - return !(context.mapper && getMappedType(declaredType, context.mapper) !== declaredType); + return !( + context.mapper && + getMappedType(declaredType, context.mapper) !== + declaredType + ); } if (isInJSDoc(existing)) { - return existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount(existing, type) - && !getIntendedTypeFromJSDocTypeReference(existing) // We should probably allow the reuse of JSDoc reference types such as String Number etc - && !!(symbol.flags & SymbolFlags.Type); // JSDoc type annotations can reference values (meaning typeof value) as well as types. We only reuse type nodes + return ( + existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount( + existing, + type + ) && + !getIntendedTypeFromJSDocTypeReference(existing) && // We should probably allow the reuse of JSDoc reference types such as String Number etc + !!(symbol.flags & SymbolFlags.Type) + ); // JSDoc type annotations can reference values (meaning typeof value) as well as types. We only reuse type nodes } } if ( @@ -9198,30 +16015,68 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { existing.operator === SyntaxKind.UniqueKeyword && existing.type.kind === SyntaxKind.SymbolKeyword ) { - const effectiveEnclosingContext = context.enclosingDeclaration && getEnclosingDeclarationIgnoringFakeScope(context.enclosingDeclaration); - return !!findAncestor(existing, n => n === effectiveEnclosingContext); + const effectiveEnclosingContext = + context.enclosingDeclaration && + getEnclosingDeclarationIgnoringFakeScope( + context.enclosingDeclaration + ); + return !!findAncestor( + existing, + (n) => n === effectiveEnclosingContext + ); } return true; } - function serializeExistingTypeNode(context: NodeBuilderContext, typeNode: TypeNode, addUndefined: boolean) { + function serializeExistingTypeNode( + context: NodeBuilderContext, + typeNode: TypeNode, + addUndefined: boolean + ) { const type = getTypeFromTypeNode(context, typeNode); if ( addUndefined && - !someType(type, t => !!(t.flags & TypeFlags.Undefined)) && + !someType(type, (t) => !!(t.flags & TypeFlags.Undefined)) && canReuseTypeNode(context, typeNode) ) { - const clone = syntacticNodeBuilder.tryReuseExistingTypeNode(context, typeNode); + const clone = syntacticNodeBuilder.tryReuseExistingTypeNode( + context, + typeNode + ); if (clone) { - return factory.createUnionTypeNode([clone, factory.createKeywordTypeNode(SyntaxKind.UndefinedKeyword)]); + return factory.createUnionTypeNode([ + clone, + factory.createKeywordTypeNode( + SyntaxKind.UndefinedKeyword + ), + ]); } } return typeToTypeNodeHelper(type, context); } - function symbolTableToDeclarationStatements(symbolTable: SymbolTable, context: NodeBuilderContext): Statement[] { - const serializePropertySymbolForClass = makeSerializePropertySymbol(factory.createPropertyDeclaration, SyntaxKind.MethodDeclaration, /*useAccessors*/ true); - const serializePropertySymbolForInterfaceWorker = makeSerializePropertySymbol((mods, name, question, type) => factory.createPropertySignature(mods, name, question, type), SyntaxKind.MethodSignature, /*useAccessors*/ false); + function symbolTableToDeclarationStatements( + symbolTable: SymbolTable, + context: NodeBuilderContext + ): Statement[] { + const serializePropertySymbolForClass = + makeSerializePropertySymbol( + factory.createPropertyDeclaration, + SyntaxKind.MethodDeclaration, + /*useAccessors*/ true + ); + const serializePropertySymbolForInterfaceWorker = + makeSerializePropertySymbol( + (mods, name, question, type) => + factory.createPropertySignature( + mods, + name, + question, + type + ), + SyntaxKind.MethodSignature, + /*useAccessors*/ false + ); // TODO: Use `setOriginalNode` on original declaration names where possible so these declarations see some kind of // declaration mapping @@ -9238,41 +16093,77 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { ...oldcontext, usedSymbolNames: new Set(oldcontext.usedSymbolNames), remappedSymbolNames: new Map(), - remappedSymbolReferences: new Map(oldcontext.remappedSymbolReferences?.entries()), + remappedSymbolReferences: new Map( + oldcontext.remappedSymbolReferences?.entries() + ), tracker: undefined!, }; const tracker: SymbolTracker = { ...oldcontext.tracker.inner, trackSymbol: (sym, decl, meaning) => { - if (context.remappedSymbolNames?.has(getSymbolId(sym))) return false; // If the context has a remapped name for the symbol, it *should* mean it's been made visible - const accessibleResult = isSymbolAccessible(sym, decl, meaning, /*shouldComputeAliasesToMakeVisible*/ false); - if (accessibleResult.accessibility === SymbolAccessibility.Accessible) { + if (context.remappedSymbolNames?.has(getSymbolId(sym))) + return false; // If the context has a remapped name for the symbol, it *should* mean it's been made visible + const accessibleResult = isSymbolAccessible( + sym, + decl, + meaning, + /*shouldComputeAliasesToMakeVisible*/ false + ); + if ( + accessibleResult.accessibility === + SymbolAccessibility.Accessible + ) { // Lookup the root symbol of the chain of refs we'll use to access it and serialize it - const chain = lookupSymbolChainWorker(sym, context, meaning); + const chain = lookupSymbolChainWorker( + sym, + context, + meaning + ); if (!(sym.flags & SymbolFlags.Property)) { // Only include referenced privates in the same file. Weird JS aliases may expose privates // from other files - assume JS transforms will make those available via expected means const root = chain[0]; - const contextFile = getSourceFileOfNode(oldcontext.enclosingDeclaration); - if (some(root.declarations, d => getSourceFileOfNode(d) === contextFile)) { + const contextFile = getSourceFileOfNode( + oldcontext.enclosingDeclaration + ); + if ( + some( + root.declarations, + (d) => + getSourceFileOfNode(d) === contextFile + ) + ) { includePrivateSymbol(root); } } - } - else if (oldcontext.tracker.inner?.trackSymbol) { - return oldcontext.tracker.inner.trackSymbol(sym, decl, meaning); + } else if (oldcontext.tracker.inner?.trackSymbol) { + return oldcontext.tracker.inner.trackSymbol( + sym, + decl, + meaning + ); } return false; }, }; - context.tracker = new SymbolTrackerImpl(context, tracker, oldcontext.tracker.moduleResolverHost); + context.tracker = new SymbolTrackerImpl( + context, + tracker, + oldcontext.tracker.moduleResolverHost + ); forEachEntry(symbolTable, (symbol, name) => { const baseName = unescapeLeadingUnderscores(name); void getInternalSymbolName(symbol, baseName); // Called to cache values into `usedSymbolNames` and `remappedSymbolNames` }); let addingDeclare = !context.bundled; - const exportEquals = symbolTable.get(InternalSymbolName.ExportEquals); - if (exportEquals && symbolTable.size > 1 && exportEquals.flags & (SymbolFlags.Alias | SymbolFlags.Module)) { + const exportEquals = symbolTable.get( + InternalSymbolName.ExportEquals + ); + if ( + exportEquals && + symbolTable.size > 1 && + exportEquals.flags & (SymbolFlags.Alias | SymbolFlags.Module) + ) { symbolTable = createSymbolTable(); // Remove extraneous elements from root symbol table (they'll be mixed back in when the target of the `export=` is looked up) symbolTable.set(InternalSymbolName.ExportEquals, exportEquals); @@ -9281,29 +16172,55 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { visitSymbolTable(symbolTable); return mergeRedundantStatements(results); - function isIdentifierAndNotUndefined(node: Node | undefined): node is Identifier { + function isIdentifierAndNotUndefined( + node: Node | undefined + ): node is Identifier { return !!node && node.kind === SyntaxKind.Identifier; } function getNamesOfDeclaration(statement: Statement): Identifier[] { if (isVariableStatement(statement)) { - return filter(map(statement.declarationList.declarations, getNameOfDeclaration), isIdentifierAndNotUndefined); + return filter( + map( + statement.declarationList.declarations, + getNameOfDeclaration + ), + isIdentifierAndNotUndefined + ); } - return filter([getNameOfDeclaration(statement as DeclarationStatement)], isIdentifierAndNotUndefined); + return filter( + [getNameOfDeclaration(statement as DeclarationStatement)], + isIdentifierAndNotUndefined + ); } function flattenExportAssignedNamespace(statements: Statement[]) { const exportAssignment = find(statements, isExportAssignment); const nsIndex = findIndex(statements, isModuleDeclaration); - let ns = nsIndex !== -1 ? statements[nsIndex] as ModuleDeclaration : undefined; + let ns = + nsIndex !== -1 + ? (statements[nsIndex] as ModuleDeclaration) + : undefined; if ( - ns && exportAssignment && exportAssignment.isExportEquals && - isIdentifier(exportAssignment.expression) && isIdentifier(ns.name) && idText(ns.name) === idText(exportAssignment.expression) && - ns.body && isModuleBlock(ns.body) + ns && + exportAssignment && + exportAssignment.isExportEquals && + isIdentifier(exportAssignment.expression) && + isIdentifier(ns.name) && + idText(ns.name) === idText(exportAssignment.expression) && + ns.body && + isModuleBlock(ns.body) ) { // Pass 0: Correct situations where a module has both an `export = ns` and multiple top-level exports by stripping the export modifiers from // 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 - const excessExports = filter(statements, s => !!(getEffectiveModifierFlags(s) & ModifierFlags.Export)); + const excessExports = filter( + statements, + (s) => + !!( + getEffectiveModifierFlags(s) & + ModifierFlags.Export + ) + ); const name = ns.name; let body = ns.body; if (length(excessExports)) { @@ -9311,32 +16228,70 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { ns, ns.modifiers, ns.name, - body = factory.updateModuleBlock( + (body = factory.updateModuleBlock( body, factory.createNodeArray([ ...ns.body.statements, factory.createExportDeclaration( /*modifiers*/ undefined, /*isTypeOnly*/ false, - factory.createNamedExports(map(flatMap(excessExports, e => getNamesOfDeclaration(e)), id => factory.createExportSpecifier(/*isTypeOnly*/ false, /*propertyName*/ undefined, id))), - /*moduleSpecifier*/ undefined, + factory.createNamedExports( + map( + flatMap(excessExports, (e) => + getNamesOfDeclaration(e) + ), + (id) => + factory.createExportSpecifier( + /*isTypeOnly*/ false, + /*propertyName*/ undefined, + id + ) + ) + ), + /*moduleSpecifier*/ undefined ), - ]), - ), + ]) + )) ); - statements = [...statements.slice(0, nsIndex), ns, ...statements.slice(nsIndex + 1)]; + statements = [ + ...statements.slice(0, nsIndex), + ns, + ...statements.slice(nsIndex + 1), + ]; } // Pass 1: Flatten `export namespace _exports {} export = _exports;` so long as the `export=` only points at a single namespace declaration - if (!find(statements, s => s !== ns && nodeHasName(s, name))) { + if ( + !find( + statements, + (s) => s !== ns && nodeHasName(s, name) + ) + ) { results = []; // If the namespace contains no export assignments or declarations, and no declarations flagged with `export`, then _everything_ is exported - // to respect this as the top level, we need to add an `export` modifier to everything - const mixinExportFlag = !some(body.statements, s => hasSyntacticModifier(s, ModifierFlags.Export) || isExportAssignment(s) || isExportDeclaration(s)); - forEach(body.statements, s => { - addResult(s, mixinExportFlag ? ModifierFlags.Export : ModifierFlags.None); // Recalculates the ambient (and export, if applicable from above) flag + const mixinExportFlag = !some( + body.statements, + (s) => + hasSyntacticModifier(s, ModifierFlags.Export) || + isExportAssignment(s) || + isExportDeclaration(s) + ); + forEach(body.statements, (s) => { + addResult( + s, + mixinExportFlag + ? ModifierFlags.Export + : ModifierFlags.None + ); // Recalculates the ambient (and export, if applicable from above) flag }); - statements = [...filter(statements, s => s !== ns && s !== exportAssignment), ...results]; + statements = [ + ...filter( + statements, + (s) => s !== ns && s !== exportAssignment + ), + ...results, + ]; } } return statements; @@ -9344,34 +16299,80 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function mergeExportDeclarations(statements: Statement[]) { // Pass 2: Combine all `export {}` declarations - const exports = filter(statements, d => isExportDeclaration(d) && !d.moduleSpecifier && !!d.exportClause && isNamedExports(d.exportClause)) as ExportDeclaration[]; + const exports = filter( + statements, + (d) => + isExportDeclaration(d) && + !d.moduleSpecifier && + !!d.exportClause && + isNamedExports(d.exportClause) + ) as ExportDeclaration[]; if (length(exports) > 1) { - const nonExports = filter(statements, d => !isExportDeclaration(d) || !!d.moduleSpecifier || !d.exportClause); + const nonExports = filter( + statements, + (d) => + !isExportDeclaration(d) || + !!d.moduleSpecifier || + !d.exportClause + ); statements = [ ...nonExports, factory.createExportDeclaration( /*modifiers*/ undefined, /*isTypeOnly*/ false, - factory.createNamedExports(flatMap(exports, e => cast(e.exportClause, isNamedExports).elements)), - /*moduleSpecifier*/ undefined, + factory.createNamedExports( + flatMap( + exports, + (e) => + cast(e.exportClause, isNamedExports) + .elements + ) + ), + /*moduleSpecifier*/ undefined ), ]; } // Pass 2b: Also combine all `export {} from "..."` declarations as needed - const reexports = filter(statements, d => isExportDeclaration(d) && !!d.moduleSpecifier && !!d.exportClause && isNamedExports(d.exportClause)) as ExportDeclaration[]; + const reexports = filter( + statements, + (d) => + isExportDeclaration(d) && + !!d.moduleSpecifier && + !!d.exportClause && + isNamedExports(d.exportClause) + ) as ExportDeclaration[]; if (length(reexports) > 1) { - const groups = group(reexports, decl => isStringLiteral(decl.moduleSpecifier!) ? ">" + decl.moduleSpecifier.text : ">"); + const groups = group(reexports, (decl) => + isStringLiteral(decl.moduleSpecifier!) + ? ">" + decl.moduleSpecifier.text + : ">" + ); if (groups.length !== reexports.length) { for (const group of groups) { if (group.length > 1) { // remove group members from statements and then merge group members and add back to statements statements = [ - ...filter(statements, s => !group.includes(s as ExportDeclaration)), + ...filter( + statements, + (s) => + !group.includes( + s as ExportDeclaration + ) + ), factory.createExportDeclaration( /*modifiers*/ undefined, /*isTypeOnly*/ false, - factory.createNamedExports(flatMap(group, e => cast(e.exportClause, isNamedExports).elements)), - group[0].moduleSpecifier, + factory.createNamedExports( + flatMap( + group, + (e) => + cast( + e.exportClause, + isNamedExports + ).elements + ) + ), + group[0].moduleSpecifier ), ]; } @@ -9383,29 +16384,58 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function inlineExportModifiers(statements: Statement[]) { // Pass 3: Move all `export {}`'s to `export` modifiers where possible - const index = findIndex(statements, d => isExportDeclaration(d) && !d.moduleSpecifier && !d.attributes && !!d.exportClause && isNamedExports(d.exportClause)); + const index = findIndex( + statements, + (d) => + isExportDeclaration(d) && + !d.moduleSpecifier && + !d.attributes && + !!d.exportClause && + isNamedExports(d.exportClause) + ); if (index >= 0) { - const exportDecl = statements[index] as ExportDeclaration & { readonly exportClause: NamedExports; }; - const replacements = mapDefined(exportDecl.exportClause.elements, e => { - if (!e.propertyName && e.name.kind !== SyntaxKind.StringLiteral) { - // export {name} - look thru `statements` for `name`, and if all results can take an `export` modifier, do so and filter it - const name = e.name; - const indices = indicesOf(statements); - const associatedIndices = filter(indices, i => nodeHasName(statements[i], name)); - if (length(associatedIndices) && every(associatedIndices, i => canHaveExportModifier(statements[i]))) { - for (const index of associatedIndices) { - statements[index] = addExportModifier(statements[index] as Extract); + const exportDecl = statements[ + index + ] as ExportDeclaration & { + readonly exportClause: NamedExports; + }; + const replacements = mapDefined( + exportDecl.exportClause.elements, + (e) => { + if ( + !e.propertyName && + e.name.kind !== SyntaxKind.StringLiteral + ) { + // export {name} - look thru `statements` for `name`, and if all results can take an `export` modifier, do so and filter it + const name = e.name; + const indices = indicesOf(statements); + const associatedIndices = filter(indices, (i) => + nodeHasName(statements[i], name) + ); + if ( + length(associatedIndices) && + every(associatedIndices, (i) => + canHaveExportModifier(statements[i]) + ) + ) { + for (const index of associatedIndices) { + statements[index] = addExportModifier( + statements[index] as Extract< + HasModifiers, + Statement + > + ); + } + return undefined; } - return undefined; } + return e; } - return e; - }); + ); if (!length(replacements)) { // all clauses removed, remove the export declaration orderedRemoveItemAt(statements, index); - } - else { + } else { // some items filtered, others not - update the export declaration statements[index] = factory.updateExportDeclaration( exportDecl, @@ -9413,10 +16443,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { exportDecl.isTypeOnly, factory.updateNamedExports( exportDecl.exportClause, - replacements, + replacements ), exportDecl.moduleSpecifier, - exportDecl.attributes, + exportDecl.attributes ); } } @@ -9432,8 +16462,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // declaration privacy is respected. if ( enclosingDeclaration && - ((isSourceFile(enclosingDeclaration) && isExternalOrCommonJsModule(enclosingDeclaration)) || isModuleDeclaration(enclosingDeclaration)) && - (!some(statements, isExternalModuleIndicator) || (!hasScopeMarker(statements) && some(statements, needsScopeMarker))) + ((isSourceFile(enclosingDeclaration) && + isExternalOrCommonJsModule(enclosingDeclaration)) || + isModuleDeclaration(enclosingDeclaration)) && + (!some(statements, isExternalModuleIndicator) || + (!hasScopeMarker(statements) && + some(statements, needsScopeMarker))) ) { statements.push(createEmptyExports(factory)); } @@ -9441,16 +16475,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function addExportModifier(node: Extract) { - const flags = (getEffectiveModifierFlags(node) | ModifierFlags.Export) & ~ModifierFlags.Ambient; + const flags = + (getEffectiveModifierFlags(node) | ModifierFlags.Export) & + ~ModifierFlags.Ambient; return factory.replaceModifiers(node, flags); } - function removeExportModifier(node: Extract) { - const flags = getEffectiveModifierFlags(node) & ~ModifierFlags.Export; + function removeExportModifier( + node: Extract + ) { + const flags = + getEffectiveModifierFlags(node) & ~ModifierFlags.Export; return factory.replaceModifiers(node, flags); } - function visitSymbolTable(symbolTable: SymbolTable, suppressNewPrivateContext?: boolean, propertyAsAlias?: boolean) { + function visitSymbolTable( + symbolTable: SymbolTable, + suppressNewPrivateContext?: boolean, + propertyAsAlias?: boolean + ) { if (!suppressNewPrivateContext) { deferredPrivatesStack.push(new Map()); } @@ -9458,26 +16501,51 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const symbols = Array.from(symbolTable.values()); for (const symbol of symbols) { i++; - if (checkTruncationLengthIfExpanding(context) && (i + 2 < symbolTable.size - 1)) { + if ( + checkTruncationLengthIfExpanding(context) && + i + 2 < symbolTable.size - 1 + ) { context.out.truncated = true; - results.push(createTruncationStatement(`... (${symbolTable.size - i} more ...)`)); - serializeSymbol(symbols[symbols.length - 1], /*isPrivate*/ false, !!propertyAsAlias); + results.push( + createTruncationStatement( + `... (${symbolTable.size - i} more ...)` + ) + ); + serializeSymbol( + symbols[symbols.length - 1], + /*isPrivate*/ false, + !!propertyAsAlias + ); break; } - serializeSymbol(symbol, /*isPrivate*/ false, !!propertyAsAlias); + serializeSymbol( + symbol, + /*isPrivate*/ false, + !!propertyAsAlias + ); } if (!suppressNewPrivateContext) { // deferredPrivates will be filled up by visiting the symbol table // And will continue to iterate as elements are added while visited `deferredPrivates` // (As that's how a map iterator is defined to work) - deferredPrivatesStack[deferredPrivatesStack.length - 1].forEach((symbol: Symbol) => { - serializeSymbol(symbol, /*isPrivate*/ true, !!propertyAsAlias); + deferredPrivatesStack[ + deferredPrivatesStack.length - 1 + ].forEach((symbol: Symbol) => { + serializeSymbol( + symbol, + /*isPrivate*/ true, + !!propertyAsAlias + ); }); deferredPrivatesStack.pop(); } } - function serializeSymbol(symbol: Symbol, isPrivate: boolean, propertyAsAlias: boolean): void { + function serializeSymbol( + symbol: Symbol, + isPrivate: boolean, + propertyAsAlias: boolean + ): void { void getPropertiesOfType(getTypeOfSymbol(symbol)); // resolve symbol's type and properties, which should trigger any required merges // cache visited list based on merged symbol, since we want to use the unmerged top-level symbol, but // still skip reserializing it if we encounter the merged product later on @@ -9488,9 +16556,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { visitedSymbols.add(getSymbolId(visitedSym)); // Only actually serialize symbols within the correct enclosing declaration, otherwise do nothing with the out-of-context symbol const skipMembershipCheck = !isPrivate; // We only call this on exported symbols when we know they're in the correct scope - if (skipMembershipCheck || (!!length(symbol.declarations) && some(symbol.declarations, d => !!findAncestor(d, n => n === enclosingDeclaration)))) { + if ( + skipMembershipCheck || + (!!length(symbol.declarations) && + some( + symbol.declarations, + (d) => + !!findAncestor( + d, + (n) => n === enclosingDeclaration + ) + )) + ) { const scopeCleanup = cloneNodeBuilderContext(context); - context.tracker.pushErrorFallbackNode(find(symbol.declarations, d => getSourceFileOfNode(d) === context.enclosingFile)); + context.tracker.pushErrorFallbackNode( + find( + symbol.declarations, + (d) => + getSourceFileOfNode(d) === context.enclosingFile + ) + ); serializeSymbolWorker(symbol, isPrivate, propertyAsAlias); context.tracker.popErrorFallbackNode(); scopeCleanup(); @@ -9506,31 +16591,79 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If it's a property: emit `export default _default` with a `_default` prop // If it's a class/interface/function: emit a class/interface/function with a `default` modifier // These forms can merge, eg (`export default 12; export default interface A {}`) - function serializeSymbolWorker(symbol: Symbol, isPrivate: boolean, propertyAsAlias: boolean, escapedSymbolName = symbol.escapedName): void { - const symbolName = unescapeLeadingUnderscores(escapedSymbolName); - const isDefault = escapedSymbolName === InternalSymbolName.Default; - if (isPrivate && !(context.flags & NodeBuilderFlags.AllowAnonymousIdentifier) && isStringANonContextualKeyword(symbolName) && !isDefault) { + function serializeSymbolWorker( + symbol: Symbol, + isPrivate: boolean, + propertyAsAlias: boolean, + escapedSymbolName = symbol.escapedName + ): void { + const symbolName = + unescapeLeadingUnderscores(escapedSymbolName); + const isDefault = + escapedSymbolName === InternalSymbolName.Default; + if ( + isPrivate && + !( + context.flags & + NodeBuilderFlags.AllowAnonymousIdentifier + ) && + isStringANonContextualKeyword(symbolName) && + !isDefault + ) { // 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` :( context.encounteredError = true; // TODO: Issue error via symbol tracker? 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 } - let needsPostExportDefault = isDefault && !!( - symbol.flags & SymbolFlags.ExportDoesNotSupportDefaultModifier - || (symbol.flags & SymbolFlags.Function && length(getPropertiesOfType(getTypeOfSymbol(symbol)))) - ) && !(symbol.flags & SymbolFlags.Alias); // An alias symbol should preclude needing to make an alias ourselves - let needsExportDeclaration = !needsPostExportDefault && !isPrivate && isStringANonContextualKeyword(symbolName) && !isDefault; + let needsPostExportDefault = + isDefault && + !!( + symbol.flags & + SymbolFlags.ExportDoesNotSupportDefaultModifier || + (symbol.flags & SymbolFlags.Function && + length( + getPropertiesOfType(getTypeOfSymbol(symbol)) + )) + ) && + !(symbol.flags & SymbolFlags.Alias); // An alias symbol should preclude needing to make an alias ourselves + let needsExportDeclaration = + !needsPostExportDefault && + !isPrivate && + isStringANonContextualKeyword(symbolName) && + !isDefault; // `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 if (needsPostExportDefault || needsExportDeclaration) { isPrivate = true; } - const modifierFlags = (!isPrivate ? ModifierFlags.Export : 0) | (isDefault && !needsPostExportDefault ? ModifierFlags.Default : 0); - const isConstMergedWithNS = symbol.flags & SymbolFlags.Module && - symbol.flags & (SymbolFlags.BlockScopedVariable | SymbolFlags.FunctionScopedVariable | SymbolFlags.Property) && + const modifierFlags = + (!isPrivate ? ModifierFlags.Export : 0) | + (isDefault && !needsPostExportDefault + ? ModifierFlags.Default + : 0); + const isConstMergedWithNS = + symbol.flags & SymbolFlags.Module && + symbol.flags & + (SymbolFlags.BlockScopedVariable | + SymbolFlags.FunctionScopedVariable | + SymbolFlags.Property) && escapedSymbolName !== InternalSymbolName.ExportEquals; - const isConstMergedWithNSPrintableAsSignatureMerge = isConstMergedWithNS && isTypeRepresentableAsFunctionNamespaceMerge(getTypeOfSymbol(symbol), symbol); - if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method) || isConstMergedWithNSPrintableAsSignatureMerge) { - serializeAsFunctionNamespaceMerge(getTypeOfSymbol(symbol), symbol, getInternalSymbolName(symbol, symbolName), modifierFlags); + const isConstMergedWithNSPrintableAsSignatureMerge = + isConstMergedWithNS && + isTypeRepresentableAsFunctionNamespaceMerge( + getTypeOfSymbol(symbol), + symbol + ); + if ( + symbol.flags & + (SymbolFlags.Function | SymbolFlags.Method) || + isConstMergedWithNSPrintableAsSignatureMerge + ) { + serializeAsFunctionNamespaceMerge( + getTypeOfSymbol(symbol), + symbol, + getInternalSymbolName(symbol, symbolName), + modifierFlags + ); } if (symbol.flags & SymbolFlags.TypeAlias) { serializeTypeAlias(symbol, symbolName, modifierFlags); @@ -9538,83 +16671,178 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Need to skip over export= symbols below - json source files get a single `Property` flagged // symbol of name `export=` which needs to be handled like an alias. It's not great, but it is what it is. if ( - symbol.flags & (SymbolFlags.BlockScopedVariable | SymbolFlags.FunctionScopedVariable | SymbolFlags.Property | SymbolFlags.Accessor) - && escapedSymbolName !== InternalSymbolName.ExportEquals - && !(symbol.flags & SymbolFlags.Prototype) - && !(symbol.flags & SymbolFlags.Class) - && !(symbol.flags & SymbolFlags.Method) - && !isConstMergedWithNSPrintableAsSignatureMerge + symbol.flags & + (SymbolFlags.BlockScopedVariable | + SymbolFlags.FunctionScopedVariable | + SymbolFlags.Property | + SymbolFlags.Accessor) && + escapedSymbolName !== InternalSymbolName.ExportEquals && + !(symbol.flags & SymbolFlags.Prototype) && + !(symbol.flags & SymbolFlags.Class) && + !(symbol.flags & SymbolFlags.Method) && + !isConstMergedWithNSPrintableAsSignatureMerge ) { if (propertyAsAlias) { - const createdExport = serializeMaybeAliasAssignment(symbol); + const createdExport = + serializeMaybeAliasAssignment(symbol); if (createdExport) { needsExportDeclaration = false; needsPostExportDefault = false; } - } - else { + } else { const type = getTypeOfSymbol(symbol); - const localName = getInternalSymbolName(symbol, symbolName); - if (type.symbol && type.symbol !== symbol && type.symbol.flags & SymbolFlags.Function && some(type.symbol.declarations, isFunctionExpressionOrArrowFunction) && (type.symbol.members?.size || type.symbol.exports?.size)) { + const localName = getInternalSymbolName( + symbol, + symbolName + ); + if ( + type.symbol && + type.symbol !== symbol && + type.symbol.flags & SymbolFlags.Function && + some( + type.symbol.declarations, + isFunctionExpressionOrArrowFunction + ) && + (type.symbol.members?.size || + type.symbol.exports?.size) + ) { // assignment of a anonymous expando/class-like function, the func/ns/merge branch below won't trigger, // and the assignment form has to reference the unreachable anonymous type so will error. // Instead, serialize the type's symbol, but with the current symbol's name, rather than the anonymous one. if (!context.remappedSymbolReferences) { context.remappedSymbolReferences = new Map(); } - context.remappedSymbolReferences.set(getSymbolId(type.symbol), symbol); // save name remapping as local name for target symbol - serializeSymbolWorker(type.symbol, isPrivate, propertyAsAlias, escapedSymbolName); - context.remappedSymbolReferences.delete(getSymbolId(type.symbol)); - } - else if (!(symbol.flags & SymbolFlags.Function) && isTypeRepresentableAsFunctionNamespaceMerge(type, symbol)) { + context.remappedSymbolReferences.set( + getSymbolId(type.symbol), + symbol + ); // save name remapping as local name for target symbol + serializeSymbolWorker( + type.symbol, + isPrivate, + propertyAsAlias, + escapedSymbolName + ); + context.remappedSymbolReferences.delete( + getSymbolId(type.symbol) + ); + } else if ( + !(symbol.flags & SymbolFlags.Function) && + isTypeRepresentableAsFunctionNamespaceMerge( + type, + symbol + ) + ) { // 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 - serializeAsFunctionNamespaceMerge(type, symbol, localName, modifierFlags); - } - else { + serializeAsFunctionNamespaceMerge( + type, + symbol, + localName, + modifierFlags + ); + } else { // 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!_ // `var` is `FunctionScopedVariable`, `const` and `let` are `BlockScopedVariable`, and `module.exports.thing =` is `Property` - const flags = !(symbol.flags & SymbolFlags.BlockScopedVariable) - ? symbol.parent?.valueDeclaration && isSourceFile(symbol.parent?.valueDeclaration) + const flags = !( + symbol.flags & SymbolFlags.BlockScopedVariable + ) + ? symbol.parent?.valueDeclaration && + isSourceFile(symbol.parent?.valueDeclaration) ? 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) : undefined : isConstantVariable(symbol) ? NodeFlags.Const : NodeFlags.Let; - const name = (needsPostExportDefault || !(symbol.flags & SymbolFlags.Property)) ? localName : getUnusedName(localName, symbol); - let textRange: Node | undefined = symbol.declarations && find(symbol.declarations, d => isVariableDeclaration(d)); - if (textRange && isVariableDeclarationList(textRange.parent) && textRange.parent.declarations.length === 1) { + const name = + needsPostExportDefault || + !(symbol.flags & SymbolFlags.Property) + ? localName + : getUnusedName(localName, symbol); + let textRange: Node | undefined = + symbol.declarations && + find(symbol.declarations, (d) => + isVariableDeclaration(d) + ); + if ( + textRange && + isVariableDeclarationList(textRange.parent) && + textRange.parent.declarations.length === 1 + ) { textRange = textRange.parent.parent; } - const propertyAccessRequire = symbol.declarations?.find(isPropertyAccessExpression); + const propertyAccessRequire = + symbol.declarations?.find( + isPropertyAccessExpression + ); if ( - propertyAccessRequire && isBinaryExpression(propertyAccessRequire.parent) && isIdentifier(propertyAccessRequire.parent.right) - && type.symbol?.valueDeclaration && isSourceFile(type.symbol.valueDeclaration) + propertyAccessRequire && + isBinaryExpression( + propertyAccessRequire.parent + ) && + isIdentifier( + propertyAccessRequire.parent.right + ) && + type.symbol?.valueDeclaration && + isSourceFile(type.symbol.valueDeclaration) ) { - const alias = localName === propertyAccessRequire.parent.right.escapedText ? undefined : propertyAccessRequire.parent.right; - context.approximateLength += 12 + ((alias?.escapedText as string | undefined)?.length ?? 0); // `export { alias };` + const alias = + localName === + propertyAccessRequire.parent.right + .escapedText + ? undefined + : propertyAccessRequire.parent.right; + context.approximateLength += + 12 + + ((alias?.escapedText as string | undefined) + ?.length ?? 0); // `export { alias };` addResult( factory.createExportDeclaration( /*modifiers*/ undefined, /*isTypeOnly*/ false, - factory.createNamedExports([factory.createExportSpecifier(/*isTypeOnly*/ false, alias, localName)]), + factory.createNamedExports([ + factory.createExportSpecifier( + /*isTypeOnly*/ false, + alias, + localName + ), + ]) ), - ModifierFlags.None, + ModifierFlags.None ); - context.tracker.trackSymbol(type.symbol, context.enclosingDeclaration, SymbolFlags.Value); - } - else { + context.tracker.trackSymbol( + type.symbol, + context.enclosingDeclaration, + SymbolFlags.Value + ); + } else { const statement = setTextRange( context, factory.createVariableStatement( /*modifiers*/ undefined, - factory.createVariableDeclarationList([ - factory.createVariableDeclaration(name, /*exclamationToken*/ undefined, serializeTypeForDeclaration(context, /*declaration*/ undefined, type, symbol)), - ], flags), + factory.createVariableDeclarationList( + [ + factory.createVariableDeclaration( + name, + /*exclamationToken*/ undefined, + serializeTypeForDeclaration( + context, + /*declaration*/ undefined, + type, + symbol + ) + ), + ], + flags + ) ), - textRange, + textRange ); context.approximateLength += 7 + name.length; // `var name: ;` - addResult(statement, name !== localName ? modifierFlags & ~ModifierFlags.Export : modifierFlags); + addResult( + statement, + name !== localName + ? modifierFlags & ~ModifierFlags.Export + : modifierFlags + ); if (name !== localName && !isPrivate) { // We rename the variable declaration we generate for Property symbols since they may have a name which // conflicts with a local declaration. For example, given input: @@ -9637,14 +16865,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // export { g_1 as g }; // ``` // To create an export named `g` that does _not_ shadow the local `g` - context.approximateLength += 16 + name.length + localName.length; // `export { name as localName };` + context.approximateLength += + 16 + name.length + localName.length; // `export { name as localName };` addResult( factory.createExportDeclaration( /*modifiers*/ undefined, /*isTypeOnly*/ false, - factory.createNamedExports([factory.createExportSpecifier(/*isTypeOnly*/ false, name, localName)]), + factory.createNamedExports([ + factory.createExportSpecifier( + /*isTypeOnly*/ false, + name, + localName + ), + ]) ), - ModifierFlags.None, + ModifierFlags.None ); needsExportDeclaration = false; needsPostExportDefault = false; @@ -9658,31 +16893,55 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (symbol.flags & SymbolFlags.Class) { if ( - symbol.flags & SymbolFlags.Property - && symbol.valueDeclaration - && isBinaryExpression(symbol.valueDeclaration.parent) - && isClassExpression(symbol.valueDeclaration.parent.right) + symbol.flags & SymbolFlags.Property && + symbol.valueDeclaration && + isBinaryExpression(symbol.valueDeclaration.parent) && + isClassExpression(symbol.valueDeclaration.parent.right) ) { // Looks like a `module.exports.Sub = class {}` - if we serialize `symbol` as a class, the result will have no members, // since the classiness is actually from the target of the effective alias the symbol is. yes. A BlockScopedVariable|Class|Property // _really_ acts like an Alias, and none of a BlockScopedVariable, Class, or Property. This is the travesty of JS binding today. - serializeAsAlias(symbol, getInternalSymbolName(symbol, symbolName), modifierFlags); - } - else { - serializeAsClass(symbol, getInternalSymbolName(symbol, symbolName), modifierFlags); + serializeAsAlias( + symbol, + getInternalSymbolName(symbol, symbolName), + modifierFlags + ); + } else { + serializeAsClass( + symbol, + getInternalSymbolName(symbol, symbolName), + modifierFlags + ); } } - if ((symbol.flags & (SymbolFlags.ValueModule | SymbolFlags.NamespaceModule) && (!isConstMergedWithNS || isTypeOnlyNamespace(symbol))) || isConstMergedWithNSPrintableAsSignatureMerge) { + if ( + (symbol.flags & + (SymbolFlags.ValueModule | + SymbolFlags.NamespaceModule) && + (!isConstMergedWithNS || + isTypeOnlyNamespace(symbol))) || + isConstMergedWithNSPrintableAsSignatureMerge + ) { serializeModule(symbol, symbolName, modifierFlags); } // The class meaning serialization should handle serializing all interface members - if (symbol.flags & SymbolFlags.Interface && !(symbol.flags & SymbolFlags.Class)) { + if ( + symbol.flags & SymbolFlags.Interface && + !(symbol.flags & SymbolFlags.Class) + ) { serializeInterface(symbol, symbolName, modifierFlags); } if (symbol.flags & SymbolFlags.Alias) { - serializeAsAlias(symbol, getInternalSymbolName(symbol, symbolName), modifierFlags); + serializeAsAlias( + symbol, + getInternalSymbolName(symbol, symbolName), + modifierFlags + ); } - if (symbol.flags & SymbolFlags.Property && symbol.escapedName === InternalSymbolName.ExportEquals) { + if ( + symbol.flags & SymbolFlags.Property && + symbol.escapedName === InternalSymbolName.ExportEquals + ) { serializeMaybeAliasAssignment(symbol); } if (symbol.flags & SymbolFlags.ExportStar) { @@ -9690,197 +16949,397 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Straightforward - only one thing to do - make an export declaration if (symbol.declarations) { for (const node of symbol.declarations) { - const resolvedModule = resolveExternalModuleName(node, (node as ExportDeclaration).moduleSpecifier!); + const resolvedModule = resolveExternalModuleName( + node, + (node as ExportDeclaration).moduleSpecifier! + ); if (!resolvedModule) continue; - const isTypeOnly = (node as ExportDeclaration).isTypeOnly; - const specifier = getSpecifierForModuleSymbol(resolvedModule, context); + const isTypeOnly = (node as ExportDeclaration) + .isTypeOnly; + const specifier = getSpecifierForModuleSymbol( + resolvedModule, + context + ); context.approximateLength += 17 + specifier.length; // `export * from "specifier";` - addResult(factory.createExportDeclaration(/*modifiers*/ undefined, isTypeOnly, /*exportClause*/ undefined, factory.createStringLiteral(specifier)), ModifierFlags.None); + addResult( + factory.createExportDeclaration( + /*modifiers*/ undefined, + isTypeOnly, + /*exportClause*/ undefined, + factory.createStringLiteral(specifier) + ), + ModifierFlags.None + ); } } } if (needsPostExportDefault) { - const internalSymbolName = getInternalSymbolName(symbol, symbolName); + const internalSymbolName = getInternalSymbolName( + symbol, + symbolName + ); context.approximateLength += 16 + internalSymbolName.length; // `export default internalName;` - addResult(factory.createExportAssignment(/*modifiers*/ undefined, /*isExportEquals*/ false, factory.createIdentifier(internalSymbolName)), ModifierFlags.None); - } - else if (needsExportDeclaration) { - const internalSymbolName = getInternalSymbolName(symbol, symbolName); - context.approximateLength += 22 + symbolName.length + internalSymbolName.length; // `export { internalName as symbolName };` + addResult( + factory.createExportAssignment( + /*modifiers*/ undefined, + /*isExportEquals*/ false, + factory.createIdentifier(internalSymbolName) + ), + ModifierFlags.None + ); + } else if (needsExportDeclaration) { + const internalSymbolName = getInternalSymbolName( + symbol, + symbolName + ); + context.approximateLength += + 22 + symbolName.length + internalSymbolName.length; // `export { internalName as symbolName };` addResult( factory.createExportDeclaration( /*modifiers*/ undefined, /*isTypeOnly*/ false, - factory.createNamedExports([factory.createExportSpecifier(/*isTypeOnly*/ false, internalSymbolName, symbolName)]), + factory.createNamedExports([ + factory.createExportSpecifier( + /*isTypeOnly*/ false, + internalSymbolName, + symbolName + ), + ]) ), - ModifierFlags.None, + ModifierFlags.None ); } } function includePrivateSymbol(symbol: Symbol) { - if (some(symbol.declarations, isPartOfParameterDeclaration)) return; - Debug.assertIsDefined(deferredPrivatesStack[deferredPrivatesStack.length - 1]); - getUnusedName(unescapeLeadingUnderscores(symbol.escapedName), symbol); // Call to cache unique name for symbol + if (some(symbol.declarations, isPartOfParameterDeclaration)) + return; + Debug.assertIsDefined( + deferredPrivatesStack[deferredPrivatesStack.length - 1] + ); + getUnusedName( + unescapeLeadingUnderscores(symbol.escapedName), + symbol + ); // Call to cache unique name for symbol // Blanket moving (import) aliases into the root private context should work, since imports are not valid within namespaces // (so they must have been in the root to begin with if they were real imports) cjs `require` aliases (an upcoming feature) // will throw a wrench in this, since those may have been nested, but we'll need to synthesize them in the outer scope // 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 // for the moved import; which hopefully the above `getUnusedName` call should produce. - const isExternalImportAlias = !!(symbol.flags & SymbolFlags.Alias) && !some(symbol.declarations, d => - !!findAncestor(d, isExportDeclaration) || - isNamespaceExport(d) || - (isImportEqualsDeclaration(d) && !isExternalModuleReference(d.moduleReference))); - deferredPrivatesStack[isExternalImportAlias ? 0 : (deferredPrivatesStack.length - 1)].set(getSymbolId(symbol), symbol); + const isExternalImportAlias = + !!(symbol.flags & SymbolFlags.Alias) && + !some( + symbol.declarations, + (d) => + !!findAncestor(d, isExportDeclaration) || + isNamespaceExport(d) || + (isImportEqualsDeclaration(d) && + !isExternalModuleReference(d.moduleReference)) + ); + deferredPrivatesStack[ + isExternalImportAlias ? 0 : deferredPrivatesStack.length - 1 + ].set(getSymbolId(symbol), symbol); } function isExportingScope(enclosingDeclaration: Node) { - return ((isSourceFile(enclosingDeclaration) && (isExternalOrCommonJsModule(enclosingDeclaration) || isJsonSourceFile(enclosingDeclaration))) || - (isAmbientModule(enclosingDeclaration) && !isGlobalScopeAugmentation(enclosingDeclaration))); + return ( + (isSourceFile(enclosingDeclaration) && + (isExternalOrCommonJsModule(enclosingDeclaration) || + isJsonSourceFile(enclosingDeclaration))) || + (isAmbientModule(enclosingDeclaration) && + !isGlobalScopeAugmentation(enclosingDeclaration)) + ); } // Prepends a `declare` and/or `export` modifier if the context requires it, and then adds `node` to `result` and returns `node` - function addResult(node: Statement, additionalModifierFlags: ModifierFlags) { + function addResult( + node: Statement, + additionalModifierFlags: ModifierFlags + ) { if (canHaveModifiers(node)) { const oldModifierFlags = getEffectiveModifierFlags(node); let newModifierFlags: ModifierFlags = ModifierFlags.None; - const enclosingDeclaration = context.enclosingDeclaration && - (isJSDocTypeAlias(context.enclosingDeclaration) ? getSourceFileOfNode(context.enclosingDeclaration) : context.enclosingDeclaration); + const enclosingDeclaration = + context.enclosingDeclaration && + (isJSDocTypeAlias(context.enclosingDeclaration) + ? getSourceFileOfNode(context.enclosingDeclaration) + : context.enclosingDeclaration); if ( additionalModifierFlags & ModifierFlags.Export && - enclosingDeclaration && (isExportingScope(enclosingDeclaration) || isModuleDeclaration(enclosingDeclaration)) && + enclosingDeclaration && + (isExportingScope(enclosingDeclaration) || + isModuleDeclaration(enclosingDeclaration)) && canHaveExportModifier(node) ) { // Classes, namespaces, variables, functions, interfaces, and types should all be `export`ed in a module context if not private newModifierFlags |= ModifierFlags.Export; } if ( - addingDeclare && !(newModifierFlags & ModifierFlags.Export) && - (!enclosingDeclaration || !(enclosingDeclaration.flags & NodeFlags.Ambient)) && - (isEnumDeclaration(node) || isVariableStatement(node) || isFunctionDeclaration(node) || isClassDeclaration(node) || isModuleDeclaration(node)) + addingDeclare && + !(newModifierFlags & ModifierFlags.Export) && + (!enclosingDeclaration || + !( + enclosingDeclaration.flags & NodeFlags.Ambient + )) && + (isEnumDeclaration(node) || + isVariableStatement(node) || + isFunctionDeclaration(node) || + isClassDeclaration(node) || + isModuleDeclaration(node)) ) { // Classes, namespaces, variables, enums, and functions all need `declare` modifiers to be valid in a declaration file top-level scope newModifierFlags |= ModifierFlags.Ambient; } - if ((additionalModifierFlags & ModifierFlags.Default) && (isClassDeclaration(node) || isInterfaceDeclaration(node) || isFunctionDeclaration(node))) { + if ( + additionalModifierFlags & ModifierFlags.Default && + (isClassDeclaration(node) || + isInterfaceDeclaration(node) || + isFunctionDeclaration(node)) + ) { newModifierFlags |= ModifierFlags.Default; } if (newModifierFlags) { - node = factory.replaceModifiers(node, newModifierFlags | oldModifierFlags); + node = factory.replaceModifiers( + node, + newModifierFlags | oldModifierFlags + ); } - context.approximateLength += modifiersLength(newModifierFlags | oldModifierFlags); + context.approximateLength += modifiersLength( + newModifierFlags | oldModifierFlags + ); } results.push(node); } - function serializeTypeAlias(symbol: Symbol, symbolName: string, modifierFlags: ModifierFlags) { + function serializeTypeAlias( + symbol: Symbol, + symbolName: string, + modifierFlags: ModifierFlags + ) { const aliasType = getDeclaredTypeOfTypeAlias(symbol); const typeParams = getSymbolLinks(symbol).typeParameters; - const typeParamDecls = map(typeParams, p => typeParameterToDeclaration(p, context)); - const jsdocAliasDecl = symbol.declarations?.find(isJSDocTypeAlias); - const commentText = getTextOfJSDocComment(jsdocAliasDecl ? jsdocAliasDecl.comment || jsdocAliasDecl.parent.comment : undefined); + const typeParamDecls = map(typeParams, (p) => + typeParameterToDeclaration(p, context) + ); + const jsdocAliasDecl = + symbol.declarations?.find(isJSDocTypeAlias); + const commentText = getTextOfJSDocComment( + jsdocAliasDecl + ? jsdocAliasDecl.comment || + jsdocAliasDecl.parent.comment + : undefined + ); const restoreFlags = saveRestoreFlags(context); context.flags |= NodeBuilderFlags.InTypeAlias; const oldEnclosingDecl = context.enclosingDeclaration; context.enclosingDeclaration = jsdocAliasDecl; - const typeNode = jsdocAliasDecl && jsdocAliasDecl.typeExpression - && isJSDocTypeExpression(jsdocAliasDecl.typeExpression) - && syntacticNodeBuilder.tryReuseExistingTypeNode(context, jsdocAliasDecl.typeExpression.type) - || typeToTypeNodeHelper(aliasType, context); - const internalSymbolName = getInternalSymbolName(symbol, symbolName); - context.approximateLength += 8 + (commentText?.length ?? 0) + internalSymbolName.length; // `/* comment */ type name = ...` + const typeNode = + (jsdocAliasDecl && + jsdocAliasDecl.typeExpression && + isJSDocTypeExpression(jsdocAliasDecl.typeExpression) && + syntacticNodeBuilder.tryReuseExistingTypeNode( + context, + jsdocAliasDecl.typeExpression.type + )) || + typeToTypeNodeHelper(aliasType, context); + const internalSymbolName = getInternalSymbolName( + symbol, + symbolName + ); + context.approximateLength += + 8 + (commentText?.length ?? 0) + internalSymbolName.length; // `/* comment */ type name = ...` addResult( setSyntheticLeadingComments( - factory.createTypeAliasDeclaration(/*modifiers*/ undefined, internalSymbolName, typeParamDecls, typeNode), - !commentText ? [] : [{ kind: SyntaxKind.MultiLineCommentTrivia, text: "*\n * " + commentText.replace(/\n/g, "\n * ") + "\n ", pos: -1, end: -1, hasTrailingNewLine: true }], + factory.createTypeAliasDeclaration( + /*modifiers*/ undefined, + internalSymbolName, + typeParamDecls, + typeNode + ), + !commentText + ? [] + : [ + { + kind: SyntaxKind.MultiLineCommentTrivia, + text: + "*\n * " + + commentText.replace(/\n/g, "\n * ") + + "\n ", + pos: -1, + end: -1, + hasTrailingNewLine: true, + }, + ] ), - modifierFlags, + modifierFlags ); restoreFlags(); context.enclosingDeclaration = oldEnclosingDecl; } - function serializeInterface(symbol: Symbol, symbolName: string, modifierFlags: ModifierFlags) { - const internalSymbolName = getInternalSymbolName(symbol, symbolName); + function serializeInterface( + symbol: Symbol, + symbolName: string, + modifierFlags: ModifierFlags + ) { + const internalSymbolName = getInternalSymbolName( + symbol, + symbolName + ); context.approximateLength += 14 + internalSymbolName.length; // `interface name { }` const interfaceType = getDeclaredTypeOfClassOrInterface(symbol); - const localParams = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol); - const typeParamDecls = map(localParams, p => typeParameterToDeclaration(p, context)); + const localParams = + getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol); + const typeParamDecls = map(localParams, (p) => + typeParameterToDeclaration(p, context) + ); const baseTypes = getBaseTypes(interfaceType); - const baseType = length(baseTypes) ? getIntersectionType(baseTypes) : undefined; - const members = serializePropertySymbolsForClassOrInterface(getPropertiesOfType(interfaceType), /*isClass*/ false, baseType); - const callSignatures = serializeSignatures(SignatureKind.Call, interfaceType, baseType, SyntaxKind.CallSignature) as CallSignatureDeclaration[]; - const constructSignatures = serializeSignatures(SignatureKind.Construct, interfaceType, baseType, SyntaxKind.ConstructSignature) as ConstructSignatureDeclaration[]; - const indexSignatures = serializeIndexSignatures(interfaceType, baseType); + const baseType = length(baseTypes) + ? getIntersectionType(baseTypes) + : undefined; + const members = serializePropertySymbolsForClassOrInterface( + getPropertiesOfType(interfaceType), + /*isClass*/ false, + baseType + ); + const callSignatures = serializeSignatures( + SignatureKind.Call, + interfaceType, + baseType, + SyntaxKind.CallSignature + ) as CallSignatureDeclaration[]; + const constructSignatures = serializeSignatures( + SignatureKind.Construct, + interfaceType, + baseType, + SyntaxKind.ConstructSignature + ) as ConstructSignatureDeclaration[]; + const indexSignatures = serializeIndexSignatures( + interfaceType, + baseType + ); - const heritageClauses = !length(baseTypes) ? undefined : [factory.createHeritageClause(SyntaxKind.ExtendsKeyword, mapDefined(baseTypes, b => trySerializeAsTypeReference(b, SymbolFlags.Value)))]; + const heritageClauses = !length(baseTypes) + ? undefined + : [ + factory.createHeritageClause( + SyntaxKind.ExtendsKeyword, + mapDefined(baseTypes, (b) => + trySerializeAsTypeReference( + b, + SymbolFlags.Value + ) + ) + ), + ]; addResult( factory.createInterfaceDeclaration( /*modifiers*/ undefined, internalSymbolName, typeParamDecls, heritageClauses, - [...indexSignatures, ...constructSignatures, ...callSignatures, ...members], + [ + ...indexSignatures, + ...constructSignatures, + ...callSignatures, + ...members, + ] ), - modifierFlags, + modifierFlags ); } - function serializePropertySymbolsForClassOrInterface(props: readonly Symbol[], isClass: false, baseType: Type | undefined): TypeElement[]; - function serializePropertySymbolsForClassOrInterface(props: readonly Symbol[], isClass: true, baseType: Type | undefined, isStatic: boolean): ClassElement[]; - function serializePropertySymbolsForClassOrInterface(props: readonly Symbol[], isClass: boolean, baseType: Type | undefined, isStatic?: boolean): (ClassElement | TypeElement)[] { + function serializePropertySymbolsForClassOrInterface( + props: readonly Symbol[], + isClass: false, + baseType: Type | undefined + ): TypeElement[]; + function serializePropertySymbolsForClassOrInterface( + props: readonly Symbol[], + isClass: true, + baseType: Type | undefined, + isStatic: boolean + ): ClassElement[]; + function serializePropertySymbolsForClassOrInterface( + props: readonly Symbol[], + isClass: boolean, + baseType: Type | undefined, + isStatic?: boolean + ): (ClassElement | TypeElement)[] { const elements: (ClassElement | TypeElement)[] = []; let i = 0; for (const prop of props) { i++; - if (checkTruncationLengthIfExpanding(context) && (i + 2 < props.length - 1)) { + if ( + checkTruncationLengthIfExpanding(context) && + i + 2 < props.length - 1 + ) { context.out.truncated = true; - const placeholder = createTruncationProperty(`... ${props.length - i} more ... `, isClass); + const placeholder = createTruncationProperty( + `... ${props.length - i} more ... `, + isClass + ); elements.push(placeholder); - const result = isClass ? - serializePropertySymbolForClass(props[props.length - 1], isStatic!, baseType) : - serializePropertySymbolForInterface(props[props.length - 1], baseType); + const result = isClass + ? serializePropertySymbolForClass( + props[props.length - 1], + isStatic!, + baseType + ) + : serializePropertySymbolForInterface( + props[props.length - 1], + baseType + ); if (isArray(result)) { elements.push(...result); - } - else { + } else { elements.push(result); } break; } context.approximateLength += 1; // separator - const result = isClass ? - serializePropertySymbolForClass(prop, isStatic!, baseType) : - serializePropertySymbolForInterface(prop, baseType); + const result = isClass + ? serializePropertySymbolForClass( + prop, + isStatic!, + baseType + ) + : serializePropertySymbolForInterface(prop, baseType); if (isArray(result)) { elements.push(...result); - } - else { + } else { elements.push(result); } } return elements; } - function createTruncationProperty(dotDotDotText: string, isClass: boolean): TypeElement | ClassElement { + function createTruncationProperty( + dotDotDotText: string, + isClass: boolean + ): TypeElement | ClassElement { if (context.flags & NodeBuilderFlags.NoTruncation) { - return addSyntheticLeadingComment(factory.createNotEmittedTypeElement(), SyntaxKind.MultiLineCommentTrivia, dotDotDotText); - } - return isClass ? - factory.createPropertyDeclaration( - /*modifiers*/ undefined, - dotDotDotText, - /*questionOrExclamationToken*/ undefined, - /*type*/ undefined, - /*initializer*/ undefined, - ) : - factory.createPropertySignature( - /*modifiers*/ undefined, - dotDotDotText, - /*questionToken*/ undefined, - /*type*/ undefined, + return addSyntheticLeadingComment( + factory.createNotEmittedTypeElement(), + SyntaxKind.MultiLineCommentTrivia, + dotDotDotText ); + } + return isClass + ? factory.createPropertyDeclaration( + /*modifiers*/ undefined, + dotDotDotText, + /*questionOrExclamationToken*/ undefined, + /*type*/ undefined, + /*initializer*/ undefined + ) + : factory.createPropertySignature( + /*modifiers*/ undefined, + dotDotDotText, + /*questionToken*/ undefined, + /*type*/ undefined + ); } function getNamespaceMembersForSerialization(symbol: Symbol) { @@ -9888,25 +17347,52 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const merged = getMergedSymbol(symbol); if (merged !== symbol) { const membersSet = new Set(exports); - for (const exported of getExportsOfSymbol(merged).values()) { - if (!(getSymbolFlags(resolveSymbol(exported)) & SymbolFlags.Value)) { + for (const exported of getExportsOfSymbol( + merged + ).values()) { + if ( + !( + getSymbolFlags(resolveSymbol(exported)) & + SymbolFlags.Value + ) + ) { membersSet.add(exported); } } exports = arrayFrom(membersSet); } - return filter(exports, m => isNamespaceMember(m) && isIdentifierText(m.escapedName as string, ScriptTarget.ESNext)); + return filter( + exports, + (m) => + isNamespaceMember(m) && + isIdentifierText( + m.escapedName as string, + ScriptTarget.ESNext + ) + ); } function isTypeOnlyNamespace(symbol: Symbol) { - return every(getNamespaceMembersForSerialization(symbol), m => !(getSymbolFlags(resolveSymbol(m)) & SymbolFlags.Value)); + return every( + getNamespaceMembersForSerialization(symbol), + (m) => + !(getSymbolFlags(resolveSymbol(m)) & SymbolFlags.Value) + ); } - function serializeModule(symbol: Symbol, symbolName: string, modifierFlags: ModifierFlags) { + function serializeModule( + symbol: Symbol, + symbolName: string, + modifierFlags: ModifierFlags + ) { const members = getNamespaceMembersForSerialization(symbol); const expanding = isExpanding(context); // 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) - const locationMap = arrayToMultiMap(members, m => m.parent && m.parent === symbol || expanding ? "real" : "merged"); + const locationMap = arrayToMultiMap(members, (m) => + (m.parent && m.parent === symbol) || expanding + ? "real" + : "merged" + ); const realMembers = locationMap.get("real") || emptyArray; const mergedMembers = locationMap.get("merged") || emptyArray; // TODO: `suppressNewPrivateContext` is questionable -we need to simply be emitting privates in whatever scope they were declared in, rather @@ -9917,69 +17403,169 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (expanding) { // Use the same name as symbol display. const oldFlags = context.flags; - context.flags |= NodeBuilderFlags.WriteTypeParametersInQualifiedName | SymbolFormatFlags.UseOnlyExternalAliasing; - localName = symbolToNode(symbol, context, /*meaning*/ SymbolFlags.All) as ModuleName; + context.flags |= + NodeBuilderFlags.WriteTypeParametersInQualifiedName | + SymbolFormatFlags.UseOnlyExternalAliasing; + localName = symbolToNode( + symbol, + context, + /*meaning*/ SymbolFlags.All + ) as ModuleName; context.flags = oldFlags; - } - else { - const localText = getInternalSymbolName(symbol, symbolName); + } else { + const localText = getInternalSymbolName( + symbol, + symbolName + ); localName = factory.createIdentifier(localText); context.approximateLength += localText.length; } - serializeAsNamespaceDeclaration(realMembers, localName, modifierFlags, !!(symbol.flags & (SymbolFlags.Function | SymbolFlags.Assignment))); + serializeAsNamespaceDeclaration( + realMembers, + localName, + modifierFlags, + !!( + symbol.flags & + (SymbolFlags.Function | SymbolFlags.Assignment) + ) + ); } if (length(mergedMembers)) { - const containingFile = getSourceFileOfNode(context.enclosingDeclaration); + const containingFile = getSourceFileOfNode( + context.enclosingDeclaration + ); const localName = getInternalSymbolName(symbol, symbolName); - const nsBody = factory.createModuleBlock([factory.createExportDeclaration( - /*modifiers*/ undefined, - /*isTypeOnly*/ false, - factory.createNamedExports(mapDefined(filter(mergedMembers, n => n.escapedName !== InternalSymbolName.ExportEquals), s => { - const name = unescapeLeadingUnderscores(s.escapedName); - const localName = getInternalSymbolName(s, name); - const aliasDecl = s.declarations && getDeclarationOfAliasSymbol(s); - if (containingFile && (aliasDecl ? containingFile !== getSourceFileOfNode(aliasDecl) : !some(s.declarations, d => getSourceFileOfNode(d) === containingFile))) { - context.tracker?.reportNonlocalAugmentation?.(containingFile, symbol, s); - return undefined; - } - const target = aliasDecl && getTargetOfAliasDeclaration(aliasDecl, /*dontRecursivelyResolve*/ true); - includePrivateSymbol(target || s); - const targetName = target ? getInternalSymbolName(target, unescapeLeadingUnderscores(target.escapedName)) : localName; - return factory.createExportSpecifier(/*isTypeOnly*/ false, name === targetName ? undefined : targetName, name); - })), - )]); + const nsBody = factory.createModuleBlock([ + factory.createExportDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + factory.createNamedExports( + mapDefined( + filter( + mergedMembers, + (n) => + n.escapedName !== + InternalSymbolName.ExportEquals + ), + (s) => { + const name = unescapeLeadingUnderscores( + s.escapedName + ); + const localName = getInternalSymbolName( + s, + name + ); + const aliasDecl = + s.declarations && + getDeclarationOfAliasSymbol(s); + if ( + containingFile && + (aliasDecl + ? containingFile !== + getSourceFileOfNode(aliasDecl) + : !some( + s.declarations, + (d) => + getSourceFileOfNode( + d + ) === containingFile + )) + ) { + context.tracker?.reportNonlocalAugmentation?.( + containingFile, + symbol, + s + ); + return undefined; + } + const target = + aliasDecl && + getTargetOfAliasDeclaration( + aliasDecl, + /*dontRecursivelyResolve*/ true + ); + includePrivateSymbol(target || s); + const targetName = target + ? getInternalSymbolName( + target, + unescapeLeadingUnderscores( + target.escapedName + ) + ) + : localName; + return factory.createExportSpecifier( + /*isTypeOnly*/ false, + name === targetName + ? undefined + : targetName, + name + ); + } + ) + ) + ), + ]); addResult( factory.createModuleDeclaration( /*modifiers*/ undefined, factory.createIdentifier(localName), nsBody, - NodeFlags.Namespace, + NodeFlags.Namespace ), - ModifierFlags.None, + ModifierFlags.None ); } } - function serializeEnum(symbol: Symbol, symbolName: string, modifierFlags: ModifierFlags) { - const internalSymbolName = getInternalSymbolName(symbol, symbolName); + function serializeEnum( + symbol: Symbol, + symbolName: string, + modifierFlags: ModifierFlags + ) { + const internalSymbolName = getInternalSymbolName( + symbol, + symbolName + ); context.approximateLength += 9 + internalSymbolName.length; // `enum internalName { }` const members: EnumMember[] = []; - const memberProps = filter(getPropertiesOfType(getTypeOfSymbol(symbol)), p => !!(p.flags & SymbolFlags.EnumMember)); + const memberProps = filter( + getPropertiesOfType(getTypeOfSymbol(symbol)), + (p) => !!(p.flags & SymbolFlags.EnumMember) + ); let i = 0; for (const p of memberProps) { i++; - if (checkTruncationLengthIfExpanding(context) && (i + 2 < memberProps.length - 1)) { + if ( + checkTruncationLengthIfExpanding(context) && + i + 2 < memberProps.length - 1 + ) { context.out.truncated = true; - members.push(factory.createEnumMember(` ... ${memberProps.length - i} more ... `)); + members.push( + factory.createEnumMember( + ` ... ${memberProps.length - i} more ... ` + ) + ); const last = memberProps[memberProps.length - 1]; - const initializedValue = last.declarations && last.declarations[0] && isEnumMember(last.declarations[0]) ? getConstantValue(last.declarations[0]) : undefined; - const initializer = initializedValue === undefined ? undefined : - typeof initializedValue === "string" ? factory.createStringLiteral(initializedValue) : - factory.createNumericLiteral(initializedValue); - const memberName = unescapeLeadingUnderscores(last.escapedName); + const initializedValue = + last.declarations && + last.declarations[0] && + isEnumMember(last.declarations[0]) + ? getConstantValue(last.declarations[0]) + : undefined; + const initializer = + initializedValue === undefined + ? undefined + : typeof initializedValue === "string" + ? factory.createStringLiteral(initializedValue) + : factory.createNumericLiteral( + initializedValue + ); + const memberName = unescapeLeadingUnderscores( + last.escapedName + ); const member = factory.createEnumMember( memberName, - initializer, + initializer ); members.push(member); break; @@ -9988,83 +17574,183 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // I hate that to get the initialized value we need to walk back to the declarations here; but there's no // other way to get the possible const value of an enum member that I'm aware of, as the value is cached // _on the declaration_, not on the declaration's symbol... - const memberDecl = p.declarations && p.declarations[0] && isEnumMember(p.declarations[0]) ? - p.declarations[0] : - undefined; + const memberDecl = + p.declarations && + p.declarations[0] && + isEnumMember(p.declarations[0]) + ? p.declarations[0] + : undefined; let initializer: Expression | undefined; let initializerLength: number; - if (isExpanding(context) && memberDecl && memberDecl.initializer) { - initializer = getSynthesizedDeepClone(memberDecl.initializer); - initializerLength = memberDecl.initializer.end - memberDecl.initializer.pos; - } - else { - const initializedValue = memberDecl && getConstantValue(memberDecl); - initializer = initializedValue === undefined ? undefined : - typeof initializedValue === "string" ? factory.createStringLiteral(initializedValue) : - factory.createNumericLiteral(initializedValue); - initializerLength = (initializer as StringLiteral | NumericLiteral | undefined)?.text.length ?? 0; - } - const memberName = unescapeLeadingUnderscores(p.escapedName); - context.approximateLength += 4 + memberName.length + initializerLength; // `member = initializer,` + if ( + isExpanding(context) && + memberDecl && + memberDecl.initializer + ) { + initializer = getSynthesizedDeepClone( + memberDecl.initializer + ); + initializerLength = + memberDecl.initializer.end - + memberDecl.initializer.pos; + } else { + const initializedValue = + memberDecl && getConstantValue(memberDecl); + initializer = + initializedValue === undefined + ? undefined + : typeof initializedValue === "string" + ? factory.createStringLiteral(initializedValue) + : factory.createNumericLiteral( + initializedValue + ); + initializerLength = + ( + initializer as + | StringLiteral + | NumericLiteral + | undefined + )?.text.length ?? 0; + } + const memberName = unescapeLeadingUnderscores( + p.escapedName + ); + context.approximateLength += + 4 + memberName.length + initializerLength; // `member = initializer,` const member = factory.createEnumMember( memberName, - initializer, + initializer ); members.push(member); } addResult( factory.createEnumDeclaration( - factory.createModifiersFromModifierFlags(isConstEnumSymbol(symbol) ? ModifierFlags.Const : 0), + factory.createModifiersFromModifierFlags( + isConstEnumSymbol(symbol) ? ModifierFlags.Const : 0 + ), internalSymbolName, - members, + members ), - modifierFlags, + modifierFlags ); } - function serializeAsFunctionNamespaceMerge(type: Type, symbol: Symbol, localName: string, modifierFlags: ModifierFlags) { - const signatures = getSignaturesOfType(type, SignatureKind.Call); + function serializeAsFunctionNamespaceMerge( + type: Type, + symbol: Symbol, + localName: string, + modifierFlags: ModifierFlags + ) { + const signatures = getSignaturesOfType( + type, + SignatureKind.Call + ); for (const sig of signatures) { context.approximateLength += 1; // ; // Each overload becomes a separate function declaration, in order - const decl = signatureToSignatureDeclarationHelper(sig, SyntaxKind.FunctionDeclaration, context, { name: factory.createIdentifier(localName) }) as FunctionDeclaration; - addResult(setTextRange(context, decl, getSignatureTextRangeLocation(sig)), modifierFlags); + const decl = signatureToSignatureDeclarationHelper( + sig, + SyntaxKind.FunctionDeclaration, + context, + { name: factory.createIdentifier(localName) } + ) as FunctionDeclaration; + addResult( + setTextRange( + context, + decl, + getSignatureTextRangeLocation(sig) + ), + modifierFlags + ); } // Module symbol emit will take care of module-y members, provided it has exports - if (!(symbol.flags & (SymbolFlags.ValueModule | SymbolFlags.NamespaceModule) && !!symbol.exports && !!symbol.exports.size)) { - const props = filter(getPropertiesOfType(type), isNamespaceMember); + if ( + !( + symbol.flags & + (SymbolFlags.ValueModule | + SymbolFlags.NamespaceModule) && + !!symbol.exports && + !!symbol.exports.size + ) + ) { + const props = filter( + getPropertiesOfType(type), + isNamespaceMember + ); context.approximateLength += localName.length; - serializeAsNamespaceDeclaration(props, factory.createIdentifier(localName), modifierFlags, /*suppressNewPrivateContext*/ true); + serializeAsNamespaceDeclaration( + props, + factory.createIdentifier(localName), + modifierFlags, + /*suppressNewPrivateContext*/ true + ); } } - function createTruncationStatement(dotDotDotText: string): Statement { + function createTruncationStatement( + dotDotDotText: string + ): Statement { if (context.flags & NodeBuilderFlags.NoTruncation) { - return addSyntheticLeadingComment(factory.createEmptyStatement(), SyntaxKind.MultiLineCommentTrivia, dotDotDotText); + return addSyntheticLeadingComment( + factory.createEmptyStatement(), + SyntaxKind.MultiLineCommentTrivia, + dotDotDotText + ); } - return factory.createExpressionStatement(factory.createIdentifier(dotDotDotText)); + return factory.createExpressionStatement( + factory.createIdentifier(dotDotDotText) + ); } function getSignatureTextRangeLocation(signature: Signature) { if (signature.declaration && signature.declaration.parent) { - if (isBinaryExpression(signature.declaration.parent) && getAssignmentDeclarationKind(signature.declaration.parent) === AssignmentDeclarationKind.Property) { + if ( + isBinaryExpression(signature.declaration.parent) && + getAssignmentDeclarationKind( + signature.declaration.parent + ) === AssignmentDeclarationKind.Property + ) { return signature.declaration.parent; } // for expressions assigned to `var`s, use the `var` as the text range - if (isVariableDeclaration(signature.declaration.parent) && signature.declaration.parent.parent) { + if ( + isVariableDeclaration(signature.declaration.parent) && + signature.declaration.parent.parent + ) { return signature.declaration.parent.parent; } } return signature.declaration; } - function serializeAsNamespaceDeclaration(props: readonly Symbol[], localName: ModuleName, modifierFlags: ModifierFlags, suppressNewPrivateContext: boolean) { - const nodeFlags = isIdentifier(localName) ? NodeFlags.Namespace : NodeFlags.None; + function serializeAsNamespaceDeclaration( + props: readonly Symbol[], + localName: ModuleName, + modifierFlags: ModifierFlags, + suppressNewPrivateContext: boolean + ) { + const nodeFlags = isIdentifier(localName) + ? NodeFlags.Namespace + : NodeFlags.None; const expanding = isExpanding(context); if (length(props)) { context.approximateLength += 14; // "namespace { }" - const localVsRemoteMap = arrayToMultiMap(props, p => !length(p.declarations) || some(p.declarations, d => getSourceFileOfNode(d) === getSourceFileOfNode(context.enclosingDeclaration!)) || expanding ? "local" : "remote"); - const localProps = localVsRemoteMap.get("local") || emptyArray; + const localVsRemoteMap = arrayToMultiMap(props, (p) => + !length(p.declarations) || + some( + p.declarations, + (d) => + getSourceFileOfNode(d) === + getSourceFileOfNode( + context.enclosingDeclaration! + ) + ) || + expanding + ? "local" + : "remote" + ); + const localProps = + localVsRemoteMap.get("local") || emptyArray; // handle remote props first - we need to make an `import` declaration that points at the module containing each remote // prop in the outermost scope (TODO: a namespace within a namespace would need to be appropriately handled by this) // Example: @@ -10082,8 +17768,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Add a namespace // Create namespace as non-synthetic so it is usable as an enclosing declaration - let fakespace = parseNodeFactory.createModuleDeclaration(/*modifiers*/ undefined, localName, factory.createModuleBlock([]), nodeFlags); - setParent(fakespace, enclosingDeclaration as SourceFile | NamespaceDeclaration); + let fakespace = parseNodeFactory.createModuleDeclaration( + /*modifiers*/ undefined, + localName, + factory.createModuleBlock([]), + nodeFlags + ); + setParent( + fakespace, + enclosingDeclaration as + | SourceFile + | NamespaceDeclaration + ); fakespace.locals = createSymbolTable(props); fakespace.symbol = props[0].parent!; @@ -10091,52 +17787,96 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { results = []; const oldAddingDeclare = addingDeclare; addingDeclare = false; - const subcontext = { ...context, enclosingDeclaration: fakespace }; + const subcontext = { + ...context, + enclosingDeclaration: fakespace, + }; const oldContext = context; context = subcontext; // 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 - visitSymbolTable(createSymbolTable(localProps), suppressNewPrivateContext, /*propertyAsAlias*/ true); + visitSymbolTable( + createSymbolTable(localProps), + suppressNewPrivateContext, + /*propertyAsAlias*/ true + ); context = oldContext; addingDeclare = oldAddingDeclare; const declarations = results; results = oldResults; // replace namespace with synthetic version - const defaultReplaced = map(declarations, d => - isExportAssignment(d) && !d.isExportEquals && isIdentifier(d.expression) ? factory.createExportDeclaration( - /*modifiers*/ undefined, - /*isTypeOnly*/ false, - factory.createNamedExports([factory.createExportSpecifier(/*isTypeOnly*/ false, d.expression, factory.createIdentifier(InternalSymbolName.Default))]), - ) : d); - const exportModifierStripped = every(defaultReplaced, d => hasSyntacticModifier(d, ModifierFlags.Export)) ? map(defaultReplaced as Extract[], removeExportModifier) : defaultReplaced; + const defaultReplaced = map(declarations, (d) => + isExportAssignment(d) && + !d.isExportEquals && + isIdentifier(d.expression) + ? factory.createExportDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + factory.createNamedExports([ + factory.createExportSpecifier( + /*isTypeOnly*/ false, + d.expression, + factory.createIdentifier( + InternalSymbolName.Default + ) + ), + ]) + ) + : d + ); + const exportModifierStripped = every(defaultReplaced, (d) => + hasSyntacticModifier(d, ModifierFlags.Export) + ) + ? map( + defaultReplaced as Extract< + HasModifiers, + Statement + >[], + removeExportModifier + ) + : defaultReplaced; fakespace = factory.updateModuleDeclaration( fakespace, fakespace.modifiers, fakespace.name, - factory.createModuleBlock(exportModifierStripped), + factory.createModuleBlock(exportModifierStripped) ); addResult(fakespace, modifierFlags); // namespaces can never be default exported - } - else if (expanding) { + } else if (expanding) { context.approximateLength += 14; // "namespace { }" addResult( factory.createModuleDeclaration( /*modifiers*/ undefined, localName, factory.createModuleBlock([]), - nodeFlags, + nodeFlags ), - modifierFlags, + modifierFlags ); } } function isNamespaceMember(p: Symbol) { - return !!(p.flags & (SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias)) || - !(p.flags & SymbolFlags.Prototype || p.escapedName === "prototype" || p.valueDeclaration && isStatic(p.valueDeclaration) && isClassLike(p.valueDeclaration.parent)); + return ( + !!( + p.flags & + (SymbolFlags.Type | + SymbolFlags.Namespace | + SymbolFlags.Alias) + ) || + !( + p.flags & SymbolFlags.Prototype || + p.escapedName === "prototype" || + (p.valueDeclaration && + isStatic(p.valueDeclaration) && + isClassLike(p.valueDeclaration.parent)) + ) + ); } - function sanitizeJSDocImplements(clauses: readonly ExpressionWithTypeArguments[]): ExpressionWithTypeArguments[] | undefined { - const result = mapDefined(clauses, e => { + function sanitizeJSDocImplements( + clauses: readonly ExpressionWithTypeArguments[] + ): ExpressionWithTypeArguments[] | undefined { + const result = mapDefined(clauses, (e) => { const oldEnclosing = context.enclosingDeclaration; context.enclosingDeclaration = e; let expr = e.expression; @@ -10145,17 +17885,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return cleanup(/*result*/ undefined); // Empty heritage clause, should be an error, but prefer emitting no heritage clauses to reemitting the empty one } let introducesError: boolean; - ({ introducesError, node: expr } = trackExistingEntityName(expr, context)); + ({ introducesError, node: expr } = + trackExistingEntityName(expr, context)); if (introducesError) { return cleanup(/*result*/ undefined); } } - return cleanup(factory.createExpressionWithTypeArguments( - expr, - map(e.typeArguments, a => - syntacticNodeBuilder.tryReuseExistingTypeNode(context, a) - || typeToTypeNodeHelper(getTypeFromTypeNode(context, a), context)), - )); + return cleanup( + factory.createExpressionWithTypeArguments( + expr, + map( + e.typeArguments, + (a) => + syntacticNodeBuilder.tryReuseExistingTypeNode( + context, + a + ) || + typeToTypeNodeHelper( + getTypeFromTypeNode(context, a), + context + ) + ) + ) + ); function cleanup(result: T): T { context.enclosingDeclaration = oldEnclosing; @@ -10168,67 +17920,160 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - function serializeAsClass(symbol: Symbol, localName: string, modifierFlags: ModifierFlags) { + function serializeAsClass( + symbol: Symbol, + localName: string, + modifierFlags: ModifierFlags + ) { context.approximateLength += 9 + localName.length; // `class localName { }` const originalDecl = symbol.declarations?.find(isClassLike); const oldEnclosing = context.enclosingDeclaration; context.enclosingDeclaration = originalDecl || oldEnclosing; - const localParams = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol); - const typeParamDecls = map(localParams, p => typeParameterToDeclaration(p, context)); - forEach(localParams, p => context.approximateLength += symbolName(p.symbol).length); - const classType = getTypeWithThisArgument(getDeclaredTypeOfClassOrInterface(symbol)) as InterfaceType; + const localParams = + getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol); + const typeParamDecls = map(localParams, (p) => + typeParameterToDeclaration(p, context) + ); + forEach( + localParams, + (p) => + (context.approximateLength += symbolName( + p.symbol + ).length) + ); + const classType = getTypeWithThisArgument( + getDeclaredTypeOfClassOrInterface(symbol) + ) as InterfaceType; const baseTypes = getBaseTypes(classType); - const originalImplements = originalDecl && getEffectiveImplementsTypeNodes(originalDecl); - const implementsExpressions = originalImplements && sanitizeJSDocImplements(originalImplements) - || mapDefined(getImplementsTypes(classType), serializeImplementedType); + const originalImplements = + originalDecl && + getEffectiveImplementsTypeNodes(originalDecl); + const implementsExpressions = + (originalImplements && + sanitizeJSDocImplements(originalImplements)) || + mapDefined( + getImplementsTypes(classType), + serializeImplementedType + ); const staticType = getTypeOfSymbol(symbol); - const isClass = !!staticType.symbol?.valueDeclaration && isClassLike(staticType.symbol.valueDeclaration); + const isClass = + !!staticType.symbol?.valueDeclaration && + isClassLike(staticType.symbol.valueDeclaration); const staticBaseType = isClass ? getBaseConstructorTypeOfClass(staticType as InterfaceType) : anyType; - context.approximateLength += (length(baseTypes) ? 8 : 0) + (length(implementsExpressions) ? 11 : 0); // `extends ` and `implements ` + context.approximateLength += + (length(baseTypes) ? 8 : 0) + + (length(implementsExpressions) ? 11 : 0); // `extends ` and `implements ` const heritageClauses = [ - ...!length(baseTypes) ? [] : [factory.createHeritageClause(SyntaxKind.ExtendsKeyword, map(baseTypes, b => serializeBaseType(b, staticBaseType, localName)))], - ...!length(implementsExpressions) ? [] : [factory.createHeritageClause(SyntaxKind.ImplementsKeyword, implementsExpressions)], + ...(!length(baseTypes) + ? [] + : [ + factory.createHeritageClause( + SyntaxKind.ExtendsKeyword, + map(baseTypes, (b) => + serializeBaseType( + b, + staticBaseType, + localName + ) + ) + ), + ]), + ...(!length(implementsExpressions) + ? [] + : [ + factory.createHeritageClause( + SyntaxKind.ImplementsKeyword, + implementsExpressions + ), + ]), ]; - const symbolProps = getNonInheritedProperties(classType, baseTypes, getPropertiesOfType(classType)); - const publicSymbolProps = filter(symbolProps, s => !isHashPrivate(s)); + const symbolProps = getNonInheritedProperties( + classType, + baseTypes, + getPropertiesOfType(classType) + ); + const publicSymbolProps = filter( + symbolProps, + (s) => !isHashPrivate(s) + ); const hasPrivateIdentifier = some(symbolProps, isHashPrivate); // Boil down all private properties into a single one. - const privateProperties = hasPrivateIdentifier ? - isExpanding(context) ? - serializePropertySymbolsForClassOrInterface(filter(symbolProps, isHashPrivate), /*isClass*/ true, baseTypes[0], /*isStatic*/ false) : - [factory.createPropertyDeclaration( - /*modifiers*/ undefined, - factory.createPrivateIdentifier("#private"), - /*questionOrExclamationToken*/ undefined, - /*type*/ undefined, - /*initializer*/ undefined, - )] : - emptyArray; + const privateProperties = hasPrivateIdentifier + ? isExpanding(context) + ? serializePropertySymbolsForClassOrInterface( + filter(symbolProps, isHashPrivate), + /*isClass*/ true, + baseTypes[0], + /*isStatic*/ false + ) + : [ + factory.createPropertyDeclaration( + /*modifiers*/ undefined, + factory.createPrivateIdentifier("#private"), + /*questionOrExclamationToken*/ undefined, + /*type*/ undefined, + /*initializer*/ undefined + ), + ] + : emptyArray; if (hasPrivateIdentifier && !isExpanding(context)) { context.approximateLength += 9; // `#private;` } - const publicProperties = serializePropertySymbolsForClassOrInterface(publicSymbolProps, /*isClass*/ true, baseTypes[0], /*isStatic*/ false); + const publicProperties = + serializePropertySymbolsForClassOrInterface( + publicSymbolProps, + /*isClass*/ true, + baseTypes[0], + /*isStatic*/ false + ); // Consider static members empty if symbol also has function or module meaning - function namespacey emit will handle statics - const staticMembers = serializePropertySymbolsForClassOrInterface( - filter(getPropertiesOfType(staticType), p => !(p.flags & SymbolFlags.Prototype) && p.escapedName !== "prototype" && !isNamespaceMember(p)), - /*isClass*/ true, - staticBaseType, - /*isStatic*/ true, - ); + const staticMembers = + serializePropertySymbolsForClassOrInterface( + filter( + getPropertiesOfType(staticType), + (p) => + !(p.flags & SymbolFlags.Prototype) && + p.escapedName !== "prototype" && + !isNamespaceMember(p) + ), + /*isClass*/ true, + staticBaseType, + /*isStatic*/ true + ); // When we encounter an `X.prototype.y` assignment in a JS file, we bind `X` as a class regardless as to whether // the value is ever initialized with a class or function-like value. For cases where `X` could never be // created via `new`, we will inject a `private constructor()` declaration to indicate it is not createable. - const isNonConstructableClassLikeInJsFile = !isClass && + const isNonConstructableClassLikeInJsFile = + !isClass && !!symbol.valueDeclaration && isInJSFile(symbol.valueDeclaration) && - !some(getSignaturesOfType(staticType, SignatureKind.Construct)); - if (isNonConstructableClassLikeInJsFile) context.approximateLength += 21; // `private constructor()` - const constructors = isNonConstructableClassLikeInJsFile ? - [factory.createConstructorDeclaration(factory.createModifiersFromModifierFlags(ModifierFlags.Private), [], /*body*/ undefined)] : - serializeSignatures(SignatureKind.Construct, staticType, staticBaseType, SyntaxKind.Constructor) as ConstructorDeclaration[]; - const indexSignatures = serializeIndexSignatures(classType, baseTypes[0]); + !some( + getSignaturesOfType(staticType, SignatureKind.Construct) + ); + if (isNonConstructableClassLikeInJsFile) + context.approximateLength += 21; // `private constructor()` + const constructors = isNonConstructableClassLikeInJsFile + ? [ + factory.createConstructorDeclaration( + factory.createModifiersFromModifierFlags( + ModifierFlags.Private + ), + [], + /*body*/ undefined + ), + ] + : (serializeSignatures( + SignatureKind.Construct, + staticType, + staticBaseType, + SyntaxKind.Constructor + ) as ConstructorDeclaration[]); + const indexSignatures = serializeIndexSignatures( + classType, + baseTypes[0] + ); context.enclosingDeclaration = oldEnclosing; addResult( setTextRange( @@ -10238,21 +18083,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { localName, typeParamDecls, heritageClauses, - [...indexSignatures, ...staticMembers, ...constructors, ...publicProperties, ...privateProperties], + [ + ...indexSignatures, + ...staticMembers, + ...constructors, + ...publicProperties, + ...privateProperties, + ] ), - symbol.declarations && filter(symbol.declarations, d => isClassDeclaration(d) || isClassExpression(d))[0], + symbol.declarations && + filter( + symbol.declarations, + (d) => + isClassDeclaration(d) || + isClassExpression(d) + )[0] ), - modifierFlags, + modifierFlags ); } - function getSomeTargetNameFromDeclarations(declarations: Declaration[] | undefined) { - return firstDefined(declarations, d => { + function getSomeTargetNameFromDeclarations( + declarations: Declaration[] | undefined + ) { + return firstDefined(declarations, (d) => { if (isImportSpecifier(d) || isExportSpecifier(d)) { - return moduleExportNameTextUnescaped(d.propertyName || d.name); + return moduleExportNameTextUnescaped( + d.propertyName || d.name + ); } if (isBinaryExpression(d) || isExportAssignment(d)) { - const expression = isExportAssignment(d) ? d.expression : d.right; + const expression = isExportAssignment(d) + ? d.expression + : d.right; if (isPropertyAccessExpression(expression)) { return idText(expression.name); } @@ -10268,163 +18131,288 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { }); } - function serializeAsAlias(symbol: Symbol, localName: string, modifierFlags: ModifierFlags) { + function serializeAsAlias( + symbol: Symbol, + localName: string, + modifierFlags: ModifierFlags + ) { // synthesize an alias, eg `export { symbolName as Name }` // need to mark the alias `symbol` points at // as something we need to serialize as a private declaration as well const node = getDeclarationOfAliasSymbol(symbol); if (!node) return Debug.fail(); - const target = getMergedSymbol(getTargetOfAliasDeclaration(node, /*dontRecursivelyResolve*/ true)); + const target = getMergedSymbol( + getTargetOfAliasDeclaration( + node, + /*dontRecursivelyResolve*/ true + ) + ); if (!target) { return; } // If `target` refers to a shorthand module symbol, the name we're trying to pull out isn;t recoverable from the target symbol // In such a scenario, we must fall back to looking for an alias declaration on `symbol` and pulling the target name from that - let verbatimTargetName = isShorthandAmbientModuleSymbol(target) && getSomeTargetNameFromDeclarations(symbol.declarations) || unescapeLeadingUnderscores(target.escapedName); - if (verbatimTargetName === InternalSymbolName.ExportEquals && allowSyntheticDefaultImports) { + let verbatimTargetName = + (isShorthandAmbientModuleSymbol(target) && + getSomeTargetNameFromDeclarations( + symbol.declarations + )) || + unescapeLeadingUnderscores(target.escapedName); + if ( + verbatimTargetName === InternalSymbolName.ExportEquals && + allowSyntheticDefaultImports + ) { // target refers to an `export=` symbol that was hoisted into a synthetic default - rename here to match verbatimTargetName = InternalSymbolName.Default; } - const targetName = getInternalSymbolName(target, verbatimTargetName); + const targetName = getInternalSymbolName( + target, + verbatimTargetName + ); includePrivateSymbol(target); // the target may be within the same scope - attempt to serialize it first switch (node.kind) { case SyntaxKind.BindingElement: - if (node.parent?.parent?.kind === SyntaxKind.VariableDeclaration) { + if ( + node.parent?.parent?.kind === + SyntaxKind.VariableDeclaration + ) { // const { SomeClass } = require('./lib'); - const specifier = getSpecifierForModuleSymbol(target.parent || target, context); // './lib' + const specifier = getSpecifierForModuleSymbol( + target.parent || target, + context + ); // './lib' const { propertyName } = node as BindingElement; - const propertyNameText = propertyName && isIdentifier(propertyName) ? idText(propertyName) : undefined; - context.approximateLength += 24 + localName.length + specifier.length + (propertyNameText?.length ?? 0); // `import { propertyName as name } from "specifier";` + const propertyNameText = + propertyName && isIdentifier(propertyName) + ? idText(propertyName) + : undefined; + context.approximateLength += + 24 + + localName.length + + specifier.length + + (propertyNameText?.length ?? 0); // `import { propertyName as name } from "specifier";` addResult( factory.createImportDeclaration( /*modifiers*/ undefined, factory.createImportClause( /*phaseModifier*/ undefined, /*name*/ undefined, - factory.createNamedImports([factory.createImportSpecifier( - /*isTypeOnly*/ false, - propertyNameText ? factory.createIdentifier(propertyNameText) : undefined, - factory.createIdentifier(localName), - )]), + factory.createNamedImports([ + factory.createImportSpecifier( + /*isTypeOnly*/ false, + propertyNameText + ? factory.createIdentifier( + propertyNameText + ) + : undefined, + factory.createIdentifier( + localName + ) + ), + ]) ), factory.createStringLiteral(specifier), - /*attributes*/ undefined, + /*attributes*/ undefined ), - ModifierFlags.None, + ModifierFlags.None ); break; } // We don't know how to serialize this (nested?) binding element - Debug.failBadSyntaxKind(node.parent?.parent || node, "Unhandled binding element grandparent kind in declaration serialization"); + Debug.failBadSyntaxKind( + node.parent?.parent || node, + "Unhandled binding element grandparent kind in declaration serialization" + ); break; case SyntaxKind.ShorthandPropertyAssignment: - if (node.parent?.parent?.kind === SyntaxKind.BinaryExpression) { + if ( + node.parent?.parent?.kind === + SyntaxKind.BinaryExpression + ) { // module.exports = { SomeClass } serializeExportSpecifier( unescapeLeadingUnderscores(symbol.escapedName), - targetName, + targetName ); } break; case SyntaxKind.VariableDeclaration: // commonjs require: const x = require('y') - if (isPropertyAccessExpression((node as VariableDeclaration).initializer!)) { + if ( + isPropertyAccessExpression( + (node as VariableDeclaration).initializer! + ) + ) { // const x = require('y').z - const initializer = (node as VariableDeclaration).initializer! as PropertyAccessExpression; // require('y').z - const uniqueName = factory.createUniqueName(localName); // _x - const specifier = getSpecifierForModuleSymbol(target.parent || target, context); // 'y' + const initializer = (node as VariableDeclaration) + .initializer! as PropertyAccessExpression; // require('y').z + const uniqueName = + factory.createUniqueName(localName); // _x + const specifier = getSpecifierForModuleSymbol( + target.parent || target, + context + ); // 'y' // import _x = require('y'); - context.approximateLength += 22 + specifier.length + idText(uniqueName).length; // `import uniqueName = require("specifier");` + context.approximateLength += + 22 + + specifier.length + + idText(uniqueName).length; // `import uniqueName = require("specifier");` addResult( factory.createImportEqualsDeclaration( /*modifiers*/ undefined, /*isTypeOnly*/ false, uniqueName, - factory.createExternalModuleReference(factory.createStringLiteral(specifier)), + factory.createExternalModuleReference( + factory.createStringLiteral(specifier) + ) ), - ModifierFlags.None, + ModifierFlags.None ); // import x = _x.z - context.approximateLength += 12 + localName.length + idText(uniqueName).length + idText(initializer.name).length; // `import localName = uniqueName.initializerName;` + context.approximateLength += + 12 + + localName.length + + idText(uniqueName).length + + idText(initializer.name).length; // `import localName = uniqueName.initializerName;` addResult( factory.createImportEqualsDeclaration( /*modifiers*/ undefined, /*isTypeOnly*/ false, factory.createIdentifier(localName), - factory.createQualifiedName(uniqueName, initializer.name as Identifier), + factory.createQualifiedName( + uniqueName, + initializer.name as Identifier + ) ), - modifierFlags, + modifierFlags ); break; } - // else fall through and treat commonjs require just like import= + // else fall through and treat commonjs require just like import= case SyntaxKind.ImportEqualsDeclaration: // This _specifically_ only exists to handle json declarations - where we make aliases, but since // we emit no declarations for the json document, must not refer to it in the declarations - if (target.escapedName === InternalSymbolName.ExportEquals && some(target.declarations, d => isSourceFile(d) && isJsonSourceFile(d))) { + if ( + target.escapedName === + InternalSymbolName.ExportEquals && + some( + target.declarations, + (d) => isSourceFile(d) && isJsonSourceFile(d) + ) + ) { serializeMaybeAliasAssignment(symbol); break; } // Could be a local `import localName = ns.member` or // an external `import localName = require("whatever")` - const isLocalImport = !(target.flags & SymbolFlags.ValueModule) && !isVariableDeclaration(node); - context.approximateLength += 11 + localName.length + unescapeLeadingUnderscores(target.escapedName).length; // `import localName = target;` + const isLocalImport = + !(target.flags & SymbolFlags.ValueModule) && + !isVariableDeclaration(node); + context.approximateLength += + 11 + + localName.length + + unescapeLeadingUnderscores(target.escapedName) + .length; // `import localName = target;` addResult( factory.createImportEqualsDeclaration( /*modifiers*/ undefined, /*isTypeOnly*/ false, factory.createIdentifier(localName), isLocalImport - ? symbolToName(target, context, SymbolFlags.All, /*expectsIdentifier*/ false) - : factory.createExternalModuleReference(factory.createStringLiteral(getSpecifierForModuleSymbol(target, context))), + ? symbolToName( + target, + context, + SymbolFlags.All, + /*expectsIdentifier*/ false + ) + : factory.createExternalModuleReference( + factory.createStringLiteral( + getSpecifierForModuleSymbol( + target, + context + ) + ) + ) ), - isLocalImport ? modifierFlags : ModifierFlags.None, + isLocalImport ? modifierFlags : ModifierFlags.None ); break; case SyntaxKind.NamespaceExportDeclaration: // export as namespace foo // TODO: Not part of a file's local or export symbol tables // Is bound into file.symbol.globalExports instead, which we don't currently traverse - addResult(factory.createNamespaceExportDeclaration(idText((node as NamespaceExportDeclaration).name)), ModifierFlags.None); + addResult( + factory.createNamespaceExportDeclaration( + idText( + (node as NamespaceExportDeclaration).name + ) + ), + ModifierFlags.None + ); break; case SyntaxKind.ImportClause: { - const generatedSpecifier = getSpecifierForModuleSymbol(target.parent || target, context); // generate specifier (even though we're reusing and existing one) for ambient module reference include side effects - const specifier = context.bundled ? factory.createStringLiteral(generatedSpecifier) : (node as ImportClause).parent.moduleSpecifier; - const attributes = isImportDeclaration(node.parent) ? node.parent.attributes : undefined; - const isTypeOnly = isJSDocImportTag((node as ImportClause).parent); - context.approximateLength += 14 + localName.length + 3 + (isTypeOnly ? 4 : 0); // `import localName from specifier;`, approximate specifier + const generatedSpecifier = getSpecifierForModuleSymbol( + target.parent || target, + context + ); // generate specifier (even though we're reusing and existing one) for ambient module reference include side effects + const specifier = context.bundled + ? factory.createStringLiteral(generatedSpecifier) + : (node as ImportClause).parent.moduleSpecifier; + const attributes = isImportDeclaration(node.parent) + ? node.parent.attributes + : undefined; + const isTypeOnly = isJSDocImportTag( + (node as ImportClause).parent + ); + context.approximateLength += + 14 + localName.length + 3 + (isTypeOnly ? 4 : 0); // `import localName from specifier;`, approximate specifier addResult( factory.createImportDeclaration( /*modifiers*/ undefined, factory.createImportClause( - /* phaseModifier */ isTypeOnly ? SyntaxKind.TypeKeyword : undefined, + /* phaseModifier */ isTypeOnly + ? SyntaxKind.TypeKeyword + : undefined, factory.createIdentifier(localName), - /*namedBindings*/ undefined, + /*namedBindings*/ undefined ), specifier, - attributes, + attributes ), - ModifierFlags.None, + ModifierFlags.None ); break; } case SyntaxKind.NamespaceImport: { - const generatedSpecifier = getSpecifierForModuleSymbol(target.parent || target, context); // generate specifier (even though we're reusing and existing one) for ambient module reference include side effects - const specifier = context.bundled ? factory.createStringLiteral(generatedSpecifier) : (node as NamespaceImport).parent.parent.moduleSpecifier; - const isTypeOnly = isJSDocImportTag((node as NamespaceImport).parent.parent); - context.approximateLength += 19 + localName.length + 3 + (isTypeOnly ? 4 : 0); // `import * as localName from specifier;`, approximate specifier + const generatedSpecifier = getSpecifierForModuleSymbol( + target.parent || target, + context + ); // generate specifier (even though we're reusing and existing one) for ambient module reference include side effects + const specifier = context.bundled + ? factory.createStringLiteral(generatedSpecifier) + : (node as NamespaceImport).parent.parent + .moduleSpecifier; + const isTypeOnly = isJSDocImportTag( + (node as NamespaceImport).parent.parent + ); + context.approximateLength += + 19 + localName.length + 3 + (isTypeOnly ? 4 : 0); // `import * as localName from specifier;`, approximate specifier addResult( factory.createImportDeclaration( /*modifiers*/ undefined, factory.createImportClause( - /* phaseModifier */ isTypeOnly ? SyntaxKind.TypeKeyword : undefined, + /* phaseModifier */ isTypeOnly + ? SyntaxKind.TypeKeyword + : undefined, /*name*/ undefined, - factory.createNamespaceImport(factory.createIdentifier(localName)), + factory.createNamespaceImport( + factory.createIdentifier(localName) + ) ), specifier, - (node as ImportClause).parent.attributes, + (node as ImportClause).parent.attributes ), - ModifierFlags.None, + ModifierFlags.None ); break; } @@ -10434,45 +18422,71 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { factory.createExportDeclaration( /*modifiers*/ undefined, /*isTypeOnly*/ false, - factory.createNamespaceExport(factory.createIdentifier(localName)), - factory.createStringLiteral(getSpecifierForModuleSymbol(target, context)), + factory.createNamespaceExport( + factory.createIdentifier(localName) + ), + factory.createStringLiteral( + getSpecifierForModuleSymbol(target, context) + ) ), - ModifierFlags.None, + ModifierFlags.None ); break; case SyntaxKind.ImportSpecifier: { - const generatedSpecifier = getSpecifierForModuleSymbol(target.parent || target, context); // generate specifier (even though we're reusing and existing one) for ambient module reference include side effects - const specifier = context.bundled ? factory.createStringLiteral(generatedSpecifier) : (node as ImportSpecifier).parent.parent.parent.moduleSpecifier; - const isTypeOnly = isJSDocImportTag((node as ImportSpecifier).parent.parent.parent); - context.approximateLength += 19 + localName.length + 3 + (isTypeOnly ? 4 : 0); // `import { localName } from specifier;`, approximate specifier + const generatedSpecifier = getSpecifierForModuleSymbol( + target.parent || target, + context + ); // generate specifier (even though we're reusing and existing one) for ambient module reference include side effects + const specifier = context.bundled + ? factory.createStringLiteral(generatedSpecifier) + : (node as ImportSpecifier).parent.parent.parent + .moduleSpecifier; + const isTypeOnly = isJSDocImportTag( + (node as ImportSpecifier).parent.parent.parent + ); + context.approximateLength += + 19 + localName.length + 3 + (isTypeOnly ? 4 : 0); // `import { localName } from specifier;`, approximate specifier addResult( factory.createImportDeclaration( /*modifiers*/ undefined, factory.createImportClause( - /* phaseModifier */ isTypeOnly ? SyntaxKind.TypeKeyword : undefined, + /* phaseModifier */ isTypeOnly + ? SyntaxKind.TypeKeyword + : undefined, /*name*/ undefined, factory.createNamedImports([ factory.createImportSpecifier( /*isTypeOnly*/ false, - localName !== verbatimTargetName ? factory.createIdentifier(verbatimTargetName) : undefined, - factory.createIdentifier(localName), + localName !== verbatimTargetName + ? factory.createIdentifier( + verbatimTargetName + ) + : undefined, + factory.createIdentifier(localName) ), - ]), + ]) ), specifier, - (node as ImportSpecifier).parent.parent.parent.attributes, + (node as ImportSpecifier).parent.parent.parent + .attributes ), - ModifierFlags.None, + ModifierFlags.None ); break; } case SyntaxKind.ExportSpecifier: // does not use localName because the symbol name in this case refers to the name in the exports table, // which we must exactly preserve - const specifier = (node.parent.parent as ExportDeclaration).moduleSpecifier; + const specifier = ( + node.parent.parent as ExportDeclaration + ).moduleSpecifier; if (specifier) { - const propertyName = (node as ExportSpecifier).propertyName; - if (propertyName && moduleExportNameIsDefault(propertyName)) { + const propertyName = (node as ExportSpecifier) + .propertyName; + if ( + propertyName && + moduleExportNameIsDefault(propertyName) + ) { verbatimTargetName = InternalSymbolName.Default; } } @@ -10481,7 +18495,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { serializeExportSpecifier( unescapeLeadingUnderscores(symbol.escapedName), specifier ? verbatimTargetName : targetName, - specifier && isStringLiteralLike(specifier) ? factory.createStringLiteral(specifier.text) : undefined, + specifier && isStringLiteralLike(specifier) + ? factory.createStringLiteral(specifier.text) + : undefined ); break; case SyntaxKind.ExportAssignment: @@ -10493,28 +18509,49 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Could be best encoded as though an export specifier or as though an export assignment // If name is default or export=, do an export assignment // Otherwise do an export specifier - if (symbol.escapedName === InternalSymbolName.Default || symbol.escapedName === InternalSymbolName.ExportEquals) { + if ( + symbol.escapedName === InternalSymbolName.Default || + symbol.escapedName === + InternalSymbolName.ExportEquals + ) { serializeMaybeAliasAssignment(symbol); - } - else { + } else { serializeExportSpecifier(localName, targetName); } break; default: - return Debug.failBadSyntaxKind(node, "Unhandled alias declaration kind in symbol serializer!"); + return Debug.failBadSyntaxKind( + node, + "Unhandled alias declaration kind in symbol serializer!" + ); } } - function serializeExportSpecifier(localName: string, targetName: string, specifier?: Expression) { - context.approximateLength += 16 + localName.length + (localName !== targetName ? targetName.length : 0); // `export { targetName as localName };` + function serializeExportSpecifier( + localName: string, + targetName: string, + specifier?: Expression + ) { + context.approximateLength += + 16 + + localName.length + + (localName !== targetName ? targetName.length : 0); // `export { targetName as localName };` addResult( factory.createExportDeclaration( /*modifiers*/ undefined, /*isTypeOnly*/ false, - factory.createNamedExports([factory.createExportSpecifier(/*isTypeOnly*/ false, localName !== targetName ? targetName : undefined, localName)]), - specifier, + factory.createNamedExports([ + factory.createExportSpecifier( + /*isTypeOnly*/ false, + localName !== targetName + ? targetName + : undefined, + localName + ), + ]), + specifier ), - ModifierFlags.None, + ModifierFlags.None ); } @@ -10528,21 +18565,58 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const name = unescapeLeadingUnderscores(symbol.escapedName); const isExportEquals = name === InternalSymbolName.ExportEquals; const isDefault = name === InternalSymbolName.Default; - const isExportAssignmentCompatibleSymbolName = isExportEquals || isDefault; + const isExportAssignmentCompatibleSymbolName = + isExportEquals || isDefault; // synthesize export = ref // ref should refer to either be a locally scoped symbol which we need to emit, or // a reference to another namespace/module which we may need to emit an `import` statement for - const aliasDecl = symbol.declarations && getDeclarationOfAliasSymbol(symbol); + const aliasDecl = + symbol.declarations && getDeclarationOfAliasSymbol(symbol); // serialize what the alias points to, preserve the declaration's initializer - const target = aliasDecl && getTargetOfAliasDeclaration(aliasDecl, /*dontRecursivelyResolve*/ true); + const target = + aliasDecl && + getTargetOfAliasDeclaration( + aliasDecl, + /*dontRecursivelyResolve*/ true + ); // If the target resolves and resolves to a thing defined in this file, emit as an alias, otherwise emit as a const - if (target && length(target.declarations) && some(target.declarations, d => getSourceFileOfNode(d) === getSourceFileOfNode(enclosingDeclaration))) { + if ( + target && + length(target.declarations) && + some( + target.declarations, + (d) => + getSourceFileOfNode(d) === + getSourceFileOfNode(enclosingDeclaration) + ) + ) { // In case `target` refers to a namespace member, look at the declaration and serialize the leftmost symbol in it // eg, `namespace A { export class B {} }; exports = A.B;` // Technically, this is all that's required in the case where the assignment is an entity name expression - const expr = aliasDecl && ((isExportAssignment(aliasDecl) || isBinaryExpression(aliasDecl)) ? getExportAssignmentExpression(aliasDecl) : getPropertyAssignmentAliasLikeExpression(aliasDecl as ShorthandPropertyAssignment | PropertyAssignment | PropertyAccessExpression)); - const first = expr && isEntityNameExpression(expr) ? getFirstNonModuleExportsIdentifier(expr) : undefined; - const referenced = first && resolveEntityName(first, SymbolFlags.All, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, enclosingDeclaration); + const expr = + aliasDecl && + (isExportAssignment(aliasDecl) || + isBinaryExpression(aliasDecl) + ? getExportAssignmentExpression(aliasDecl) + : getPropertyAssignmentAliasLikeExpression( + aliasDecl as + | ShorthandPropertyAssignment + | PropertyAssignment + | PropertyAccessExpression + )); + const first = + expr && isEntityNameExpression(expr) + ? getFirstNonModuleExportsIdentifier(expr) + : undefined; + const referenced = + first && + resolveEntityName( + first, + SymbolFlags.All, + /*ignoreErrors*/ true, + /*dontResolveAlias*/ true, + enclosingDeclaration + ); if (referenced || target) { includePrivateSymbol(referenced || target); } @@ -10552,25 +18626,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // issue a visibility error on it. Only anonymous classes that an alias points at _would_ issue // a visibility error here (as they're not visible within any scope), but we want to hoist them // into the containing scope anyway, so we want to skip the visibility checks. - const prevDisableTrackSymbol = context.tracker.disableTrackSymbol; + const prevDisableTrackSymbol = + context.tracker.disableTrackSymbol; context.tracker.disableTrackSymbol = true; if (isExportAssignmentCompatibleSymbolName) { context.approximateLength += 10; // `export = ;` - results.push(factory.createExportAssignment( - /*modifiers*/ undefined, - isExportEquals, - symbolToExpression(target, context, SymbolFlags.All), - )); - } - else { + results.push( + factory.createExportAssignment( + /*modifiers*/ undefined, + isExportEquals, + symbolToExpression( + target, + context, + SymbolFlags.All + ) + ) + ); + } else { if (first === expr && first) { // serialize as `export {target as name}` serializeExportSpecifier(name, idText(first)); - } - else if (expr && isClassExpression(expr)) { - serializeExportSpecifier(name, getInternalSymbolName(target, symbolName(target))); - } - else { + } else if (expr && isClassExpression(expr)) { + serializeExportSpecifier( + name, + getInternalSymbolName( + target, + symbolName(target) + ) + ); + } else { // serialize as `import _Ref = t.arg.et; export { _Ref as name }` const varName = getUnusedName(name, symbol); context.approximateLength += varName.length + 10; // `import name = ;` @@ -10579,54 +18663,95 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /*modifiers*/ undefined, /*isTypeOnly*/ false, factory.createIdentifier(varName), - symbolToName(target, context, SymbolFlags.All, /*expectsIdentifier*/ false), + symbolToName( + target, + context, + SymbolFlags.All, + /*expectsIdentifier*/ false + ) ), - ModifierFlags.None, + ModifierFlags.None ); serializeExportSpecifier(name, varName); } } context.tracker.disableTrackSymbol = prevDisableTrackSymbol; return true; - } - else { + } else { // serialize as an anonymous property declaration const varName = getUnusedName(name, symbol); // We have to use `getWidenedType` here since the object within a json file is unwidened within the file // (Unwidened types can only exist in expression contexts and should never be serialized) - const typeToSerialize = getWidenedType(getTypeOfSymbol(getMergedSymbol(symbol))); - if (isTypeRepresentableAsFunctionNamespaceMerge(typeToSerialize, symbol)) { + const typeToSerialize = getWidenedType( + getTypeOfSymbol(getMergedSymbol(symbol)) + ); + if ( + isTypeRepresentableAsFunctionNamespaceMerge( + typeToSerialize, + symbol + ) + ) { // If there are no index signatures and `typeToSerialize` is an object type, emit as a namespace instead of a const - serializeAsFunctionNamespaceMerge(typeToSerialize, symbol, varName, isExportAssignmentCompatibleSymbolName ? ModifierFlags.None : ModifierFlags.Export); - } - else { - const flags = context.enclosingDeclaration?.kind === SyntaxKind.ModuleDeclaration && (!(symbol.flags & SymbolFlags.Accessor) || symbol.flags & SymbolFlags.SetAccessor) ? NodeFlags.Let : NodeFlags.Const; + serializeAsFunctionNamespaceMerge( + typeToSerialize, + symbol, + varName, + isExportAssignmentCompatibleSymbolName + ? ModifierFlags.None + : ModifierFlags.Export + ); + } else { + const flags = + context.enclosingDeclaration?.kind === + SyntaxKind.ModuleDeclaration && + (!(symbol.flags & SymbolFlags.Accessor) || + symbol.flags & SymbolFlags.SetAccessor) + ? NodeFlags.Let + : NodeFlags.Const; context.approximateLength += varName.length + 5; // `var name: ;` const statement = factory.createVariableStatement( /*modifiers*/ undefined, - factory.createVariableDeclarationList([ - factory.createVariableDeclaration(varName, /*exclamationToken*/ undefined, serializeTypeForDeclaration(context, /*declaration*/ undefined, typeToSerialize, symbol)), - ], flags), + factory.createVariableDeclarationList( + [ + factory.createVariableDeclaration( + varName, + /*exclamationToken*/ undefined, + serializeTypeForDeclaration( + context, + /*declaration*/ undefined, + typeToSerialize, + symbol + ) + ), + ], + flags + ) ); // Inlined JSON types exported with [module.]exports= will already emit an export=, so should use `declare`. // Otherwise, the type itself should be exported. addResult( statement, - target && target.flags & SymbolFlags.Property && target.escapedName === InternalSymbolName.ExportEquals ? ModifierFlags.Ambient - : name === varName ? ModifierFlags.Export - : ModifierFlags.None, + target && + target.flags & SymbolFlags.Property && + target.escapedName === + InternalSymbolName.ExportEquals + ? ModifierFlags.Ambient + : name === varName + ? ModifierFlags.Export + : ModifierFlags.None ); } if (isExportAssignmentCompatibleSymbolName) { context.approximateLength += varName.length + 10; // `export = name;` - results.push(factory.createExportAssignment( - /*modifiers*/ undefined, - isExportEquals, - factory.createIdentifier(varName), - )); + results.push( + factory.createExportAssignment( + /*modifiers*/ undefined, + isExportEquals, + factory.createIdentifier(varName) + ) + ); return true; - } - else if (name !== varName) { + } else if (name !== varName) { serializeExportSpecifier(name, varName); return true; } @@ -10634,30 +18759,75 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function isTypeRepresentableAsFunctionNamespaceMerge(typeToSerialize: Type, hostSymbol: Symbol) { + function isTypeRepresentableAsFunctionNamespaceMerge( + typeToSerialize: Type, + hostSymbol: Symbol + ) { // Only object types which are not constructable, or indexable, whose members all come from the // context source file, and whose property names are all valid identifiers and not late-bound, _and_ // whose input is not type annotated (if the input symbol has an annotation we can reuse, we should prefer it) - const ctxSrc = getSourceFileOfNode(context.enclosingDeclaration); - return getObjectFlags(typeToSerialize) & (ObjectFlags.Anonymous | ObjectFlags.Mapped) && + const ctxSrc = getSourceFileOfNode( + context.enclosingDeclaration + ); + return ( + getObjectFlags(typeToSerialize) & + (ObjectFlags.Anonymous | ObjectFlags.Mapped) && !some(typeToSerialize.symbol?.declarations, isTypeNode) && // If the type comes straight from a type node, we shouldn't try to break it up !length(getIndexInfosOfType(typeToSerialize)) && !isClassInstanceSide(typeToSerialize) && // While a class instance is potentially representable as a NS, prefer printing a reference to the instance type and serializing the class - !!(length(filter(getPropertiesOfType(typeToSerialize), isNamespaceMember)) || length(getSignaturesOfType(typeToSerialize, SignatureKind.Call))) && - !length(getSignaturesOfType(typeToSerialize, SignatureKind.Construct)) && // TODO: could probably serialize as function + ns + class, now that that's OK - !getDeclarationWithTypeAnnotation(hostSymbol, enclosingDeclaration) && - !(typeToSerialize.symbol && some(typeToSerialize.symbol.declarations, d => getSourceFileOfNode(d) !== ctxSrc)) && - !some(getPropertiesOfType(typeToSerialize), p => isLateBoundName(p.escapedName)) && - !some(getPropertiesOfType(typeToSerialize), p => some(p.declarations, d => getSourceFileOfNode(d) !== ctxSrc)) && - every(getPropertiesOfType(typeToSerialize), p => { + !!( + length( + filter( + getPropertiesOfType(typeToSerialize), + isNamespaceMember + ) + ) || + length( + getSignaturesOfType( + typeToSerialize, + SignatureKind.Call + ) + ) + ) && + !length( + getSignaturesOfType( + typeToSerialize, + SignatureKind.Construct + ) + ) && // TODO: could probably serialize as function + ns + class, now that that's OK + !getDeclarationWithTypeAnnotation( + hostSymbol, + enclosingDeclaration + ) && + !( + typeToSerialize.symbol && + some( + typeToSerialize.symbol.declarations, + (d) => getSourceFileOfNode(d) !== ctxSrc + ) + ) && + !some(getPropertiesOfType(typeToSerialize), (p) => + isLateBoundName(p.escapedName) + ) && + !some(getPropertiesOfType(typeToSerialize), (p) => + some( + p.declarations, + (d) => getSourceFileOfNode(d) !== ctxSrc + ) + ) && + every(getPropertiesOfType(typeToSerialize), (p) => { if (!isIdentifierText(symbolName(p), languageVersion)) { return false; } if (!(p.flags & SymbolFlags.Accessor)) { return true; } - return getNonMissingTypeOfSymbol(p) === getWriteTypeOfSymbol(p); - }); + return ( + getNonMissingTypeOfSymbol(p) === + getWriteTypeOfSymbol(p) + ); + }) + ); } function makeSerializePropertySymbol( @@ -10666,143 +18836,300 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { name: string | PropertyName, questionOrExclamationToken: QuestionToken | undefined, type: TypeNode | undefined, - initializer: Expression | undefined, + initializer: Expression | undefined ) => T, methodKind: SignatureDeclaration["kind"], - useAccessors: true, - ): (p: Symbol, isStatic: boolean, baseType: Type | undefined) => T | AccessorDeclaration | (T | AccessorDeclaration)[]; + useAccessors: true + ): ( + p: Symbol, + isStatic: boolean, + baseType: Type | undefined + ) => T | AccessorDeclaration | (T | AccessorDeclaration)[]; function makeSerializePropertySymbol( createProperty: ( modifiers: readonly Modifier[] | undefined, name: string | PropertyName, questionOrExclamationToken: QuestionToken | undefined, type: TypeNode | undefined, - initializer: Expression | undefined, + initializer: Expression | undefined ) => T, methodKind: SignatureDeclaration["kind"], - useAccessors: false, - ): (p: Symbol, isStatic: boolean, baseType: Type | undefined) => T | T[]; + useAccessors: false + ): ( + p: Symbol, + isStatic: boolean, + baseType: Type | undefined + ) => T | T[]; function makeSerializePropertySymbol( createProperty: ( modifiers: readonly Modifier[] | undefined, name: string | PropertyName, questionOrExclamationToken: QuestionToken | undefined, type: TypeNode | undefined, - initializer: Expression | undefined, + initializer: Expression | undefined ) => T, methodKind: SignatureDeclaration["kind"], - useAccessors: boolean, - ): (p: Symbol, isStatic: boolean, baseType: Type | undefined) => T | AccessorDeclaration | (T | AccessorDeclaration)[] { - return function serializePropertySymbol(p: Symbol, isStatic: boolean, baseType: Type | undefined): T | AccessorDeclaration | (T | AccessorDeclaration)[] { - const modifierFlags = getDeclarationModifierFlagsFromSymbol(p); - const omitType = !!(modifierFlags & ModifierFlags.Private) && !isExpanding(context); - if (isStatic && (p.flags & (SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias))) { + useAccessors: boolean + ): ( + p: Symbol, + isStatic: boolean, + baseType: Type | undefined + ) => T | AccessorDeclaration | (T | AccessorDeclaration)[] { + return function serializePropertySymbol( + p: Symbol, + isStatic: boolean, + baseType: Type | undefined + ): T | AccessorDeclaration | (T | AccessorDeclaration)[] { + const modifierFlags = + getDeclarationModifierFlagsFromSymbol(p); + const omitType = + !!(modifierFlags & ModifierFlags.Private) && + !isExpanding(context); + if ( + isStatic && + p.flags & + (SymbolFlags.Type | + SymbolFlags.Namespace | + SymbolFlags.Alias) + ) { // Only value-only-meaning symbols can be correctly encoded as class statics, type/namespace/alias meaning symbols // need to be merged namespace members return []; } if ( - p.flags & SymbolFlags.Prototype || p.escapedName === "constructor" || - (baseType && getPropertyOfType(baseType, p.escapedName) - && isReadonlySymbol(getPropertyOfType(baseType, p.escapedName)!) === isReadonlySymbol(p) - && (p.flags & SymbolFlags.Optional) === (getPropertyOfType(baseType, p.escapedName)!.flags & SymbolFlags.Optional) - && isTypeIdenticalTo(getTypeOfSymbol(p), getTypeOfPropertyOfType(baseType, p.escapedName)!)) + p.flags & SymbolFlags.Prototype || + p.escapedName === "constructor" || + (baseType && + getPropertyOfType(baseType, p.escapedName) && + isReadonlySymbol( + getPropertyOfType(baseType, p.escapedName)! + ) === isReadonlySymbol(p) && + (p.flags & SymbolFlags.Optional) === + (getPropertyOfType(baseType, p.escapedName)! + .flags & + SymbolFlags.Optional) && + isTypeIdenticalTo( + getTypeOfSymbol(p), + getTypeOfPropertyOfType( + baseType, + p.escapedName + )! + )) ) { return []; } - const flag = (modifierFlags & ~ModifierFlags.Async) | (isStatic ? ModifierFlags.Static : 0); + const flag = + (modifierFlags & ~ModifierFlags.Async) | + (isStatic ? ModifierFlags.Static : 0); const name = getPropertyNameNodeForSymbol(p, context); - const firstPropertyLikeDecl = p.declarations?.find(or(isPropertyDeclaration, isAccessor, isVariableDeclaration, isPropertySignature, isBinaryExpression, isPropertyAccessExpression)); + const firstPropertyLikeDecl = p.declarations?.find( + or( + isPropertyDeclaration, + isAccessor, + isVariableDeclaration, + isPropertySignature, + isBinaryExpression, + isPropertyAccessExpression + ) + ); if (p.flags & SymbolFlags.Accessor && useAccessors) { const result: AccessorDeclaration[] = []; if (p.flags & SymbolFlags.SetAccessor) { - const setter = p.declarations && forEach(p.declarations, d => { - if (d.kind === SyntaxKind.SetAccessor) { - return d as SetAccessorDeclaration; - } - if (isCallExpression(d) && isBindableObjectDefinePropertyCall(d)) { - return forEach(d.arguments[2].properties, propDecl => { - const id = getNameOfDeclaration(propDecl); - if (!!id && isIdentifier(id) && idText(id) === "set") { - return propDecl; - } - }); - } - }); + const setter = + p.declarations && + forEach(p.declarations, (d) => { + if (d.kind === SyntaxKind.SetAccessor) { + return d as SetAccessorDeclaration; + } + if ( + isCallExpression(d) && + isBindableObjectDefinePropertyCall(d) + ) { + return forEach( + d.arguments[2].properties, + (propDecl) => { + const id = + getNameOfDeclaration( + propDecl + ); + if ( + !!id && + isIdentifier(id) && + idText(id) === "set" + ) { + return propDecl; + } + } + ); + } + }); Debug.assert(!!setter); - const paramSymbol = isFunctionLikeDeclaration(setter) ? getSignatureFromDeclaration(setter).parameters[0] : undefined; - const setterDeclaration = p.declarations?.find(isSetAccessor); - context.approximateLength += modifiersLength(flag) + 7 + (paramSymbol ? symbolName(paramSymbol).length : 5) + (omitType ? 0 : 2); // `modifiers set name(param);`, approximate name - result.push(setTextRange( - context, - factory.createSetAccessorDeclaration( - factory.createModifiersFromModifierFlags(flag), - name, - [factory.createParameterDeclaration( - /*modifiers*/ undefined, - /*dotDotDotToken*/ undefined, - paramSymbol ? parameterToParameterDeclarationName(paramSymbol, getEffectiveParameterDeclaration(paramSymbol), context) : "value", - /*questionToken*/ undefined, - omitType ? undefined : serializeTypeForDeclaration(context, setterDeclaration, getWriteTypeOfSymbol(p), p), - )], - /*body*/ undefined, - ), - setterDeclaration ?? firstPropertyLikeDecl, - )); + const paramSymbol = isFunctionLikeDeclaration( + setter + ) + ? getSignatureFromDeclaration(setter) + .parameters[0] + : undefined; + const setterDeclaration = + p.declarations?.find(isSetAccessor); + context.approximateLength += + modifiersLength(flag) + + 7 + + (paramSymbol + ? symbolName(paramSymbol).length + : 5) + + (omitType ? 0 : 2); // `modifiers set name(param);`, approximate name + result.push( + setTextRange( + context, + factory.createSetAccessorDeclaration( + factory.createModifiersFromModifierFlags( + flag + ), + name, + [ + factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + paramSymbol + ? parameterToParameterDeclarationName( + paramSymbol, + getEffectiveParameterDeclaration( + paramSymbol + ), + context + ) + : "value", + /*questionToken*/ undefined, + omitType + ? undefined + : serializeTypeForDeclaration( + context, + setterDeclaration, + getWriteTypeOfSymbol( + p + ), + p + ) + ), + ], + /*body*/ undefined + ), + setterDeclaration ?? firstPropertyLikeDecl + ) + ); } if (p.flags & SymbolFlags.GetAccessor) { - const getterDeclaration = p.declarations?.find(isGetAccessor); - context.approximateLength += modifiersLength(flag) + 8 + (omitType ? 0 : 2); // `modifiers get name(): ;`, approximate name - result.push(setTextRange( - context, - factory.createGetAccessorDeclaration( - factory.createModifiersFromModifierFlags(flag), - name, - [], - omitType ? undefined : serializeTypeForDeclaration(context, getterDeclaration, getTypeOfSymbol(p), p), - /*body*/ undefined, - ), - getterDeclaration ?? firstPropertyLikeDecl, - )); + const getterDeclaration = + p.declarations?.find(isGetAccessor); + context.approximateLength += + modifiersLength(flag) + 8 + (omitType ? 0 : 2); // `modifiers get name(): ;`, approximate name + result.push( + setTextRange( + context, + factory.createGetAccessorDeclaration( + factory.createModifiersFromModifierFlags( + flag + ), + name, + [], + omitType + ? undefined + : serializeTypeForDeclaration( + context, + getterDeclaration, + getTypeOfSymbol(p), + p + ), + /*body*/ undefined + ), + getterDeclaration ?? firstPropertyLikeDecl + ) + ); } return result; } // This is an else/if as accessors and properties can't merge in TS, but might in JS // If this happens, we assume the accessor takes priority, as it imposes more constraints - else if (p.flags & (SymbolFlags.Property | SymbolFlags.Variable | SymbolFlags.Accessor)) { - const modifierFlags = (isReadonlySymbol(p) ? ModifierFlags.Readonly : 0) | flag; - context.approximateLength += 2 + (omitType ? 0 : 2) + modifiersLength(modifierFlags); // `modifiers name: ;`, approximate name + else if ( + p.flags & + (SymbolFlags.Property | + SymbolFlags.Variable | + SymbolFlags.Accessor) + ) { + const modifierFlags = + (isReadonlySymbol(p) ? ModifierFlags.Readonly : 0) | + flag; + context.approximateLength += + 2 + + (omitType ? 0 : 2) + + modifiersLength(modifierFlags); // `modifiers name: ;`, approximate name return setTextRange( context, createProperty( - factory.createModifiersFromModifierFlags(modifierFlags), + factory.createModifiersFromModifierFlags( + modifierFlags + ), name, - p.flags & SymbolFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined, - omitType ? undefined : serializeTypeForDeclaration(context, p.declarations?.find(isSetAccessorDeclaration), getWriteTypeOfSymbol(p), p), + p.flags & SymbolFlags.Optional + ? factory.createToken( + SyntaxKind.QuestionToken + ) + : undefined, + omitType + ? undefined + : serializeTypeForDeclaration( + context, + p.declarations?.find( + isSetAccessorDeclaration + ), + getWriteTypeOfSymbol(p), + p + ), // TODO: https://github.com/microsoft/TypeScript/pull/32372#discussion_r328386357 // interface members can't have initializers, however class members _can_ - /*initializer*/ undefined, + /*initializer*/ undefined ), - p.declarations?.find(or(isPropertyDeclaration, isVariableDeclaration)) || firstPropertyLikeDecl, + p.declarations?.find( + or(isPropertyDeclaration, isVariableDeclaration) + ) || firstPropertyLikeDecl ); } if (p.flags & (SymbolFlags.Method | SymbolFlags.Function)) { const type = getTypeOfSymbol(p); - const signatures = getSignaturesOfType(type, SignatureKind.Call); + const signatures = getSignaturesOfType( + type, + SignatureKind.Call + ); if (omitType) { - const modifierFlags = (isReadonlySymbol(p) ? ModifierFlags.Readonly : 0) | flag; - context.approximateLength += 1 + modifiersLength(modifierFlags); // `modifiers name;`, approximate name + const modifierFlags = + (isReadonlySymbol(p) + ? ModifierFlags.Readonly + : 0) | flag; + context.approximateLength += + 1 + modifiersLength(modifierFlags); // `modifiers name;`, approximate name return setTextRange( context, createProperty( - factory.createModifiersFromModifierFlags(modifierFlags), + factory.createModifiersFromModifierFlags( + modifierFlags + ), name, - p.flags & SymbolFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined, + p.flags & SymbolFlags.Optional + ? factory.createToken( + SyntaxKind.QuestionToken + ) + : undefined, /*type*/ undefined, - /*initializer*/ undefined, + /*initializer*/ undefined ), - p.declarations?.find(isFunctionLikeDeclaration) || signatures[0] && signatures[0].declaration || p.declarations && p.declarations[0], + p.declarations?.find( + isFunctionLikeDeclaration + ) || + (signatures[0] && + signatures[0].declaration) || + (p.declarations && p.declarations[0]) ); } @@ -10816,17 +19143,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { context, { name, - questionToken: p.flags & SymbolFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined, - modifiers: flag ? factory.createModifiersFromModifierFlags(flag) : undefined, - }, + questionToken: + p.flags & SymbolFlags.Optional + ? factory.createToken( + SyntaxKind.QuestionToken + ) + : undefined, + modifiers: flag + ? factory.createModifiersFromModifierFlags( + flag + ) + : undefined, + } ); - const location = sig.declaration && isPrototypePropertyAssignment(sig.declaration.parent) ? sig.declaration.parent : sig.declaration; + const location = + sig.declaration && + isPrototypePropertyAssignment( + sig.declaration.parent + ) + ? sig.declaration.parent + : sig.declaration; results.push(setTextRange(context, decl, location)); } return results as unknown as T[]; } // The `Constructor`'s symbol isn't in the class's properties lists, obviously, since it's a signature on the static - return Debug.fail(`Unhandled class member kind! ${(p as any).__debugFlags || p.flags}`); + return Debug.fail( + `Unhandled class member kind! ${ + (p as any).__debugFlags || p.flags + }` + ); }; } @@ -10851,26 +19197,56 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function serializePropertySymbolForInterface(p: Symbol, baseType: Type | undefined) { - return serializePropertySymbolForInterfaceWorker(p, /*isStatic*/ false, baseType); + function serializePropertySymbolForInterface( + p: Symbol, + baseType: Type | undefined + ) { + return serializePropertySymbolForInterfaceWorker( + p, + /*isStatic*/ false, + baseType + ); } - function serializeSignatures(kind: SignatureKind, input: Type, baseType: Type | undefined, outputKind: SignatureDeclaration["kind"]) { + function serializeSignatures( + kind: SignatureKind, + input: Type, + baseType: Type | undefined, + outputKind: SignatureDeclaration["kind"] + ) { const signatures = getSignaturesOfType(input, kind); if (kind === SignatureKind.Construct) { - if (!baseType && every(signatures, s => length(s.parameters) === 0)) { + if ( + !baseType && + every(signatures, (s) => length(s.parameters) === 0) + ) { return []; // No base type, every constructor is empty - elide the extraneous `constructor()` } if (baseType) { // If there is a base type, if every signature in the class is identical to a signature in the baseType, elide all the declarations - const baseSigs = getSignaturesOfType(baseType, SignatureKind.Construct); - if (!length(baseSigs) && every(signatures, s => length(s.parameters) === 0)) { + const baseSigs = getSignaturesOfType( + baseType, + SignatureKind.Construct + ); + if ( + !length(baseSigs) && + every(signatures, (s) => length(s.parameters) === 0) + ) { return []; // Base had no explicit signatures, if all our signatures are also implicit, return an empty list } if (baseSigs.length === signatures.length) { let failed = false; for (let i = 0; i < baseSigs.length; i++) { - if (!compareSignaturesIdentical(signatures[i], baseSigs[i], /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ true, compareTypesIdentical)) { + if ( + !compareSignaturesIdentical( + signatures[i], + baseSigs[i], + /*partialMatch*/ false, + /*ignoreThisTypes*/ false, + /*ignoreReturnTypes*/ true, + compareTypesIdentical + ) + ) { failed = true; break; } @@ -10883,19 +19259,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let privateProtected: ModifierFlags = 0; for (const s of signatures) { if (s.declaration) { - privateProtected |= getSelectedEffectiveModifierFlags(s.declaration, ModifierFlags.Private | ModifierFlags.Protected); + privateProtected |= + getSelectedEffectiveModifierFlags( + s.declaration, + ModifierFlags.Private | + ModifierFlags.Protected + ); } } if (privateProtected) { - return [setTextRange( - context, - factory.createConstructorDeclaration( - factory.createModifiersFromModifierFlags(privateProtected), - /*parameters*/ [], - /*body*/ undefined, + return [ + setTextRange( + context, + factory.createConstructorDeclaration( + factory.createModifiersFromModifierFlags( + privateProtected + ), + /*parameters*/ [], + /*body*/ undefined + ), + signatures[0].declaration ), - signatures[0].declaration, - )]; + ]; } } @@ -10903,29 +19288,49 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (const sig of signatures) { context.approximateLength += 1; // ; // Each overload becomes a separate constructor declaration, in order - const decl = signatureToSignatureDeclarationHelper(sig, outputKind, context); + const decl = signatureToSignatureDeclarationHelper( + sig, + outputKind, + context + ); results.push(setTextRange(context, decl, sig.declaration)); } return results; } - function serializeIndexSignatures(input: Type, baseType: Type | undefined) { + function serializeIndexSignatures( + input: Type, + baseType: Type | undefined + ) { const results: IndexSignatureDeclaration[] = []; for (const info of getIndexInfosOfType(input)) { if (baseType) { - const baseInfo = getIndexInfoOfType(baseType, info.keyType); + const baseInfo = getIndexInfoOfType( + baseType, + info.keyType + ); if (baseInfo) { if (isTypeIdenticalTo(info.type, baseInfo.type)) { continue; // elide identical index signatures } } } - results.push(indexInfoToIndexSignatureDeclarationHelper(info, context, /*typeNode*/ undefined)); + results.push( + indexInfoToIndexSignatureDeclarationHelper( + info, + context, + /*typeNode*/ undefined + ) + ); } return results; } - function serializeBaseType(t: Type, staticType: Type, rootName: string) { + function serializeBaseType( + t: Type, + staticType: Type, + rootName: string + ) { const ref = trySerializeAsTypeReference(t, SymbolFlags.Value); if (ref) { return ref; @@ -10933,12 +19338,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const tempName = getUnusedName(`${rootName}_base`); const statement = factory.createVariableStatement( /*modifiers*/ undefined, - factory.createVariableDeclarationList([ - factory.createVariableDeclaration(tempName, /*exclamationToken*/ undefined, typeToTypeNodeHelper(staticType, context)), - ], NodeFlags.Const), + factory.createVariableDeclarationList( + [ + factory.createVariableDeclaration( + tempName, + /*exclamationToken*/ undefined, + typeToTypeNodeHelper(staticType, context) + ), + ], + NodeFlags.Const + ) ); addResult(statement, ModifierFlags.None); - return factory.createExpressionWithTypeArguments(factory.createIdentifier(tempName), /*typeArguments*/ undefined); + return factory.createExpressionWithTypeArguments( + factory.createIdentifier(tempName), + /*typeArguments*/ undefined + ); } function trySerializeAsTypeReference(t: Type, flags: SymbolFlags) { @@ -10947,15 +19362,41 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We don't use `isValueSymbolAccessible` below. since that considers alternative containers (like modules) // which we can't write out in a syntactically valid way as an expression - if ((t as TypeReference).target && isSymbolAccessibleByFlags((t as TypeReference).target.symbol, enclosingDeclaration, flags)) { - typeArgs = map(getTypeArguments(t as TypeReference), t => typeToTypeNodeHelper(t, context)); - reference = symbolToExpression((t as TypeReference).target.symbol, context, SymbolFlags.Type); - } - else if (t.symbol && isSymbolAccessibleByFlags(t.symbol, enclosingDeclaration, flags)) { - reference = symbolToExpression(t.symbol, context, SymbolFlags.Type); + if ( + (t as TypeReference).target && + isSymbolAccessibleByFlags( + (t as TypeReference).target.symbol, + enclosingDeclaration, + flags + ) + ) { + typeArgs = map(getTypeArguments(t as TypeReference), (t) => + typeToTypeNodeHelper(t, context) + ); + reference = symbolToExpression( + (t as TypeReference).target.symbol, + context, + SymbolFlags.Type + ); + } else if ( + t.symbol && + isSymbolAccessibleByFlags( + t.symbol, + enclosingDeclaration, + flags + ) + ) { + reference = symbolToExpression( + t.symbol, + context, + SymbolFlags.Type + ); } if (reference) { - return factory.createExpressionWithTypeArguments(reference, typeArgs); + return factory.createExpressionWithTypeArguments( + reference, + typeArgs + ); } } @@ -10965,7 +19406,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return ref; } if (t.symbol) { - return factory.createExpressionWithTypeArguments(symbolToExpression(t.symbol, context, SymbolFlags.Type), /*typeArguments*/ undefined); + return factory.createExpressionWithTypeArguments( + symbolToExpression(t.symbol, context, SymbolFlags.Type), + /*typeArguments*/ undefined + ); } } @@ -10993,20 +19437,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getNameCandidateWorker(symbol: Symbol, localName: string) { - if (localName === InternalSymbolName.Default || localName === InternalSymbolName.Class || localName === InternalSymbolName.Function) { + if ( + localName === InternalSymbolName.Default || + localName === InternalSymbolName.Class || + localName === InternalSymbolName.Function + ) { const restoreFlags = saveRestoreFlags(context); context.flags |= NodeBuilderFlags.InInitialEntityName; - const nameCandidate = getNameOfSymbolAsWritten(symbol, context); + const nameCandidate = getNameOfSymbolAsWritten( + symbol, + context + ); restoreFlags(); - localName = nameCandidate.length > 0 && isSingleOrDoubleQuote(nameCandidate.charCodeAt(0)) ? stripQuotes(nameCandidate) : nameCandidate; + localName = + nameCandidate.length > 0 && + isSingleOrDoubleQuote(nameCandidate.charCodeAt(0)) + ? stripQuotes(nameCandidate) + : nameCandidate; } if (localName === InternalSymbolName.Default) { localName = "_default"; - } - else if (localName === InternalSymbolName.ExportEquals) { + } else if (localName === InternalSymbolName.ExportEquals) { localName = "_exports"; } - localName = isIdentifierText(localName, languageVersion) && !isStringANonContextualKeyword(localName) ? localName : "_" + localName.replace(/[^a-z0-9]/gi, "_"); + localName = + isIdentifierText(localName, languageVersion) && + !isStringANonContextualKeyword(localName) + ? localName + : "_" + localName.replace(/[^a-z0-9]/gi, "_"); return localName; } @@ -11030,11 +19488,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // `valueDeclaration` could be undefined if inherited from // a union/intersection base type, but inherited properties // don't matter here. - return !!s.valueDeclaration && isNamedDeclaration(s.valueDeclaration) && isPrivateIdentifier(s.valueDeclaration.name); + return ( + !!s.valueDeclaration && + isNamedDeclaration(s.valueDeclaration) && + isPrivateIdentifier(s.valueDeclaration.name) + ); } - function getClonedHashPrivateName(s: Symbol): PrivateIdentifier | undefined { - if (s.valueDeclaration && isNamedDeclaration(s.valueDeclaration) && isPrivateIdentifier(s.valueDeclaration.name)) { + function getClonedHashPrivateName( + s: Symbol + ): PrivateIdentifier | undefined { + if ( + s.valueDeclaration && + isNamedDeclaration(s.valueDeclaration) && + isPrivateIdentifier(s.valueDeclaration.name) + ) { return factory.cloneNode(s.valueDeclaration.name); } return undefined; @@ -11044,35 +19512,81 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** Returns true if a type is declared in a lib file. */ // Don't expand types like `Array` or `Promise`, instead treating them as opaque. function isLibType(type: Type): boolean { - const symbol = (getObjectFlags(type) & ObjectFlags.Reference) !== 0 ? (type as TypeReference).target.symbol : type.symbol; - return isTupleType(type) || !!(symbol?.declarations?.some(decl => host.isSourceFileDefaultLibrary(getSourceFileOfNode(decl)))); + const symbol = + (getObjectFlags(type) & ObjectFlags.Reference) !== 0 + ? (type as TypeReference).target.symbol + : type.symbol; + return ( + isTupleType(type) || + !!symbol?.declarations?.some((decl) => + host.isSourceFileDefaultLibrary(getSourceFileOfNode(decl)) + ) + ); } - function typePredicateToString(typePredicate: TypePredicate, enclosingDeclaration?: Node, flags: TypeFormatFlags = TypeFormatFlags.UseAliasDefinedOutsideCurrentScope, writer?: EmitTextWriter): string { - return writer ? typePredicateToStringWorker(writer).getText() : usingSingleLineStringWriter(typePredicateToStringWorker); + function typePredicateToString( + typePredicate: TypePredicate, + enclosingDeclaration?: Node, + flags: TypeFormatFlags = TypeFormatFlags.UseAliasDefinedOutsideCurrentScope, + writer?: EmitTextWriter + ): string { + return writer + ? typePredicateToStringWorker(writer).getText() + : usingSingleLineStringWriter(typePredicateToStringWorker); function typePredicateToStringWorker(writer: EmitTextWriter) { - const nodeBuilderFlags = toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName; - const predicate = nodeBuilder.typePredicateToTypePredicateNode(typePredicate, enclosingDeclaration, nodeBuilderFlags)!; // TODO: GH#18217 + const nodeBuilderFlags = + toNodeBuilderFlags(flags) | + NodeBuilderFlags.IgnoreErrors | + NodeBuilderFlags.WriteTypeParametersInQualifiedName; + const predicate = nodeBuilder.typePredicateToTypePredicateNode( + typePredicate, + enclosingDeclaration, + nodeBuilderFlags + )!; // TODO: GH#18217 const printer = createPrinterWithRemoveComments(); - const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); - printer.writeNode(EmitHint.Unspecified, predicate, /*sourceFile*/ sourceFile, writer); + const sourceFile = + enclosingDeclaration && + getSourceFileOfNode(enclosingDeclaration); + printer.writeNode( + EmitHint.Unspecified, + predicate, + /*sourceFile*/ sourceFile, + writer + ); return writer; } } - function formatUnionTypes(types: readonly Type[], expandingEnum: boolean): Type[] { + function formatUnionTypes( + types: readonly Type[], + expandingEnum: boolean + ): Type[] { const result: Type[] = []; let flags = 0 as TypeFlags; for (let i = 0; i < types.length; i++) { const t = types[i]; flags |= t.flags; if (!(t.flags & TypeFlags.Nullable)) { - if (t.flags & (TypeFlags.BooleanLiteral) || !expandingEnum && (t.flags | TypeFlags.EnumLike)) { - const baseType = t.flags & TypeFlags.BooleanLiteral ? booleanType : getBaseTypeOfEnumLikeType(t as LiteralType); + if ( + t.flags & TypeFlags.BooleanLiteral || + (!expandingEnum && t.flags | TypeFlags.EnumLike) + ) { + const baseType = + t.flags & TypeFlags.BooleanLiteral + ? booleanType + : getBaseTypeOfEnumLikeType(t as LiteralType); if (baseType.flags & TypeFlags.Union) { const count = (baseType as UnionType).types.length; - if (i + count <= types.length && getRegularTypeOfLiteralType(types[i + count - 1]) === getRegularTypeOfLiteralType((baseType as UnionType).types[count - 1])) { + if ( + i + count <= types.length && + getRegularTypeOfLiteralType( + types[i + count - 1] + ) === + getRegularTypeOfLiteralType( + (baseType as UnionType).types[count - 1] + ) + ) { result.push(baseType); i += count - 1; continue; @@ -11098,8 +19612,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getTypeAliasForTypeLiteral(type: Type): Symbol | undefined { - if (type.symbol && type.symbol.flags & SymbolFlags.TypeLiteral && type.symbol.declarations) { - const node = walkUpParenthesizedTypes(type.symbol.declarations[0].parent); + if ( + type.symbol && + type.symbol.flags & SymbolFlags.TypeLiteral && + type.symbol.declarations + ) { + const node = walkUpParenthesizedTypes( + type.symbol.declarations[0].parent + ); if (isTypeAliasDeclaration(node)) { return getSymbolOfDeclaration(node); } @@ -11108,22 +19628,41 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isTopLevelInExternalModuleAugmentation(node: Node): boolean { - return node && node.parent && + return ( + node && + node.parent && node.parent.kind === SyntaxKind.ModuleBlock && - isExternalModuleAugmentation(node.parent.parent); + isExternalModuleAugmentation(node.parent.parent) + ); } function isDefaultBindingContext(location: Node) { - return location.kind === SyntaxKind.SourceFile || isAmbientModule(location); + return ( + location.kind === SyntaxKind.SourceFile || isAmbientModule(location) + ); } - function getNameOfSymbolFromNameType(symbol: Symbol, context?: NodeBuilderContext) { + function getNameOfSymbolFromNameType( + symbol: Symbol, + context?: NodeBuilderContext + ) { const nameType = getSymbolLinks(symbol).nameType; if (nameType) { if (nameType.flags & TypeFlags.StringOrNumberLiteral) { - const name = "" + (nameType as StringLiteralType | NumberLiteralType).value; - if (!isIdentifierText(name, getEmitScriptTarget(compilerOptions)) && !isNumericLiteralName(name)) { - return `"${escapeString(name, CharacterCodes.doubleQuote)}"`; + const name = + "" + + (nameType as StringLiteralType | NumberLiteralType).value; + if ( + !isIdentifierText( + name, + getEmitScriptTarget(compilerOptions) + ) && + !isNumericLiteralName(name) + ) { + return `"${escapeString( + name, + CharacterCodes.doubleQuote + )}"`; } if (isNumericLiteralName(name) && startsWith(name, "-")) { return `[${name}]`; @@ -11131,7 +19670,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return name; } if (nameType.flags & TypeFlags.UniqueESSymbol) { - return `[${getNameOfSymbolAsWritten((nameType as UniqueESSymbolType).symbol, context)}]`; + return `[${getNameOfSymbolAsWritten( + (nameType as UniqueESSymbolType).symbol, + context + )}]`; } } } @@ -11143,33 +19685,63 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Unlike `symbolName(symbol)`, this will include quotes if the name is from a string literal. * It will also use a representation of a number as written instead of a decimal form, e.g. `0o11` instead of `9`. */ - function getNameOfSymbolAsWritten(symbol: Symbol, context?: NodeBuilderContext): string { + function getNameOfSymbolAsWritten( + symbol: Symbol, + context?: NodeBuilderContext + ): string { if (context?.remappedSymbolReferences?.has(getSymbolId(symbol))) { symbol = context.remappedSymbolReferences.get(getSymbolId(symbol))!; } if ( - context && symbol.escapedName === InternalSymbolName.Default && !(context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope) && + context && + symbol.escapedName === InternalSymbolName.Default && + !( + context.flags & + NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope + ) && // If it's not the first part of an entity name, it must print as `default` (!(context.flags & NodeBuilderFlags.InInitialEntityName) || // if the symbol is synthesized, it will only be referenced externally it must print as `default` !symbol.declarations || // if not in the same binding context (source file, module declaration), it must print as `default` - (context.enclosingDeclaration && findAncestor(symbol.declarations[0], isDefaultBindingContext) !== findAncestor(context.enclosingDeclaration, isDefaultBindingContext))) + (context.enclosingDeclaration && + findAncestor( + symbol.declarations[0], + isDefaultBindingContext + ) !== + findAncestor( + context.enclosingDeclaration, + isDefaultBindingContext + ))) ) { return "default"; } if (symbol.declarations && symbol.declarations.length) { - let declaration = firstDefined(symbol.declarations, d => getNameOfDeclaration(d) ? d : undefined); // Try using a declaration with a name, first + let declaration = firstDefined(symbol.declarations, (d) => + getNameOfDeclaration(d) ? d : undefined + ); // Try using a declaration with a name, first const name = declaration && getNameOfDeclaration(declaration); if (declaration && name) { - if (isCallExpression(declaration) && isBindableObjectDefinePropertyCall(declaration)) { + if ( + isCallExpression(declaration) && + isBindableObjectDefinePropertyCall(declaration) + ) { return symbolName(symbol); } - if (isComputedPropertyName(name) && !(getCheckFlags(symbol) & CheckFlags.Late)) { + if ( + isComputedPropertyName(name) && + !(getCheckFlags(symbol) & CheckFlags.Late) + ) { const nameType = getSymbolLinks(symbol).nameType; - if (nameType && nameType.flags & TypeFlags.StringOrNumberLiteral) { + if ( + nameType && + nameType.flags & TypeFlags.StringOrNumberLiteral + ) { // Computed property name isn't late bound, but has a well-known name type - use name type to generate a symbol name - const result = getNameOfSymbolFromNameType(symbol, context); + const result = getNameOfSymbolFromNameType( + symbol, + context + ); if (result !== undefined) { return result; } @@ -11180,17 +19752,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!declaration) { declaration = symbol.declarations[0]; // Declaration may be nameless, but we'll try anyway } - if (declaration.parent && declaration.parent.kind === SyntaxKind.VariableDeclaration) { - return declarationNameToString((declaration.parent as VariableDeclaration).name); + if ( + declaration.parent && + declaration.parent.kind === SyntaxKind.VariableDeclaration + ) { + return declarationNameToString( + (declaration.parent as VariableDeclaration).name + ); } switch (declaration.kind) { case SyntaxKind.ClassExpression: case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: - if (context && !context.encounteredError && !(context.flags & NodeBuilderFlags.AllowAnonymousIdentifier)) { + if ( + context && + !context.encounteredError && + !( + context.flags & + NodeBuilderFlags.AllowAnonymousIdentifier + ) + ) { context.encounteredError = true; } - return declaration.kind === SyntaxKind.ClassExpression ? "(Anonymous class)" : "(Anonymous function)"; + return declaration.kind === SyntaxKind.ClassExpression + ? "(Anonymous class)" + : "(Anonymous function)"; } } const name = getNameOfSymbolFromNameType(symbol, context); @@ -11215,18 +19801,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.JSDocEnumTag: // Top-level jsdoc type aliases are considered exported // 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 - return !!(node.parent && node.parent.parent && node.parent.parent.parent && isSourceFile(node.parent.parent.parent)); + return !!( + node.parent && + node.parent.parent && + node.parent.parent.parent && + isSourceFile(node.parent.parent.parent) + ); case SyntaxKind.BindingElement: return isDeclarationVisible(node.parent.parent); case SyntaxKind.VariableDeclaration: if ( isBindingPattern((node as VariableDeclaration).name) && - !((node as VariableDeclaration).name as BindingPattern).elements.length + !((node as VariableDeclaration).name as BindingPattern) + .elements.length ) { // If the binding pattern is empty, this variable declaration is not visible return false; } - // falls through + // falls through case SyntaxKind.ModuleDeclaration: case SyntaxKind.ClassDeclaration: case SyntaxKind.InterfaceDeclaration: @@ -11241,8 +19833,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const parent = getDeclarationContainer(node); // If the node is not exported or it is not ambient module element (except import declaration) if ( - !(getCombinedModifierFlagsCached(node as Declaration) & ModifierFlags.Export) && - !(node.kind !== SyntaxKind.ImportEqualsDeclaration && parent.kind !== SyntaxKind.SourceFile && parent.flags & NodeFlags.Ambient) + !( + getCombinedModifierFlagsCached( + node as Declaration + ) & ModifierFlags.Export + ) && + !( + node.kind !== SyntaxKind.ImportEqualsDeclaration && + parent.kind !== SyntaxKind.SourceFile && + parent.flags & NodeFlags.Ambient + ) ) { return isGlobalSourceFile(parent); } @@ -11255,12 +19855,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.SetAccessor: case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: - if (hasEffectiveModifier(node, ModifierFlags.Private | ModifierFlags.Protected)) { + if ( + hasEffectiveModifier( + node, + ModifierFlags.Private | ModifierFlags.Protected + ) + ) { // Private/protected properties/methods are not visible return false; } - // Public properties/methods are visible if its parents are visible, so: - // falls through + // Public properties/methods are visible if its parents are visible, so: + // falls through case SyntaxKind.Constructor: case SyntaxKind.ConstructSignature: @@ -11306,13 +19911,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function collectLinkedAliases(node: ModuleExportName, setVisibility?: boolean): Node[] | undefined { + function collectLinkedAliases( + node: ModuleExportName, + setVisibility?: boolean + ): Node[] | undefined { let exportSymbol: Symbol | undefined; - if (node.kind !== SyntaxKind.StringLiteral && node.parent && node.parent.kind === SyntaxKind.ExportAssignment) { - exportSymbol = resolveName(node, node, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, /*nameNotFoundMessage*/ undefined, /*isUse*/ false); - } - else if (node.parent.kind === SyntaxKind.ExportSpecifier) { - exportSymbol = getTargetOfExportSpecifier(node.parent as ExportSpecifier, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias); + if ( + node.kind !== SyntaxKind.StringLiteral && + node.parent && + node.parent.kind === SyntaxKind.ExportAssignment + ) { + exportSymbol = resolveName( + node, + node, + SymbolFlags.Value | + SymbolFlags.Type | + SymbolFlags.Namespace | + SymbolFlags.Alias, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ false + ); + } else if (node.parent.kind === SyntaxKind.ExportSpecifier) { + exportSymbol = getTargetOfExportSpecifier( + node.parent as ExportSpecifier, + SymbolFlags.Value | + SymbolFlags.Type | + SymbolFlags.Namespace | + SymbolFlags.Alias + ); } let result: Node[] | undefined; let visited: Set | undefined; @@ -11324,21 +19950,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; function buildVisibleNodeList(declarations: Declaration[] | undefined) { - forEach(declarations, declaration => { - const resultNode = getAnyImportSyntax(declaration) || declaration; + forEach(declarations, (declaration) => { + const resultNode = + getAnyImportSyntax(declaration) || declaration; if (setVisibility) { getNodeLinks(declaration).isVisible = true; - } - else { + } else { result = result || []; pushIfUnique(result, resultNode); } if (isInternalModuleImportEqualsDeclaration(declaration)) { // Add the referenced top container visible - const internalModuleReference = declaration.moduleReference as Identifier | QualifiedName; - const firstIdentifier = getFirstIdentifier(internalModuleReference); - const importSymbol = resolveName(declaration, firstIdentifier.escapedText, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, /*nameNotFoundMessage*/ undefined, /*isUse*/ false); + const internalModuleReference = + declaration.moduleReference as + | Identifier + | QualifiedName; + const firstIdentifier = getFirstIdentifier( + internalModuleReference + ); + const importSymbol = resolveName( + declaration, + firstIdentifier.escapedText, + SymbolFlags.Value | + SymbolFlags.Type | + SymbolFlags.Namespace, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ false + ); if (importSymbol && visited) { if (tryAddToSet(visited, getSymbolId(importSymbol))) { buildVisibleNodeList(importSymbol.declarations); @@ -11360,8 +19999,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param target The symbol, type, or signature whose type is being queried * @param propertyName The property name that should be used to query the target for its type */ - function pushTypeResolution(target: TypeSystemEntity, propertyName: TypeSystemPropertyName): boolean { - const resolutionCycleStartIndex = findResolutionCycleStartIndex(target, propertyName); + function pushTypeResolution( + target: TypeSystemEntity, + propertyName: TypeSystemPropertyName + ): boolean { + const resolutionCycleStartIndex = findResolutionCycleStartIndex( + target, + propertyName + ); if (resolutionCycleStartIndex >= 0) { // A cycle was found const { length } = resolutionTargets; @@ -11376,19 +20021,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; } - function findResolutionCycleStartIndex(target: TypeSystemEntity, propertyName: TypeSystemPropertyName): number { + function findResolutionCycleStartIndex( + target: TypeSystemEntity, + propertyName: TypeSystemPropertyName + ): number { for (let i = resolutionTargets.length - 1; i >= resolutionStart; i--) { - if (resolutionTargetHasProperty(resolutionTargets[i], resolutionPropertyNames[i])) { + if ( + resolutionTargetHasProperty( + resolutionTargets[i], + resolutionPropertyNames[i] + ) + ) { return -1; } - if (resolutionTargets[i] === target && resolutionPropertyNames[i] === propertyName) { + if ( + resolutionTargets[i] === target && + resolutionPropertyNames[i] === propertyName + ) { return i; } } return -1; } - function resolutionTargetHasProperty(target: TypeSystemEntity, propertyName: TypeSystemPropertyName): boolean { + function resolutionTargetHasProperty( + target: TypeSystemEntity, + propertyName: TypeSystemPropertyName + ): boolean { switch (propertyName) { case TypeSystemPropertyName.Type: return !!getSymbolLinks(target as Symbol).type; @@ -11407,7 +20066,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case TypeSystemPropertyName.WriteType: return !!getSymbolLinks(target as Symbol).writeType; case TypeSystemPropertyName.ParameterInitializerContainsUndefined: - return getNodeLinks(target as ParameterDeclaration).parameterInitializerContainsUndefined !== undefined; + return ( + getNodeLinks(target as ParameterDeclaration) + .parameterInitializerContainsUndefined !== undefined + ); } return Debug.assertNever(propertyName); } @@ -11423,7 +20085,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getDeclarationContainer(node: Node): Node { - return findAncestor(getRootDeclaration(node), node => { + return findAncestor(getRootDeclaration(node), (node) => { switch (node.kind) { case SyntaxKind.VariableDeclaration: case SyntaxKind.VariableDeclarationList: @@ -11443,12 +20105,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Every class automatically contains a static property member named 'prototype', // the type of which is an instantiation of the class type with type Any supplied as a type argument for each type parameter. // It is an error to explicitly declare a static property member with the name 'prototype'. - const classType = getDeclaredTypeOfSymbol(getParentOfSymbol(prototype)!) as InterfaceType; - return classType.typeParameters ? createTypeReference(classType as GenericType, map(classType.typeParameters, _ => anyType)) : classType; + const classType = getDeclaredTypeOfSymbol( + getParentOfSymbol(prototype)! + ) as InterfaceType; + return classType.typeParameters + ? createTypeReference( + classType as GenericType, + map(classType.typeParameters, (_) => anyType) + ) + : classType; } // Return the type of the given property in the given type, or undefined if no such property exists - function getTypeOfPropertyOfType(type: Type, name: __String): Type | undefined { + function getTypeOfPropertyOfType( + type: Type, + name: __String + ): Type | undefined { const prop = getPropertyOfType(type, name); return prop ? getTypeOfSymbol(prop) : undefined; } @@ -11457,11 +20129,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Return the type of the matching property or index signature in the given type, or undefined * if no matching property or index signature exists. Add optionality to index signature types. */ - function getTypeOfPropertyOrIndexSignatureOfType(type: Type, name: __String): Type | undefined { + function getTypeOfPropertyOrIndexSignatureOfType( + type: Type, + name: __String + ): Type | undefined { let propType; - return getTypeOfPropertyOfType(type, name) || - (propType = getApplicableIndexInfoForName(type, name)?.type) && - addOptionality(propType, /*isProperty*/ true, /*isOptional*/ true); + return ( + getTypeOfPropertyOfType(type, name) || + ((propType = getApplicableIndexInfoForName(type, name)?.type) && + addOptionality( + propType, + /*isProperty*/ true, + /*isOptional*/ true + )) + ); } function isTypeAny(type: Type | undefined) { @@ -11471,43 +20152,71 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isErrorType(type: Type) { // The only 'any' types that have alias symbols are those manufactured by getTypeFromTypeAliasReference for // a reference to an unresolved symbol. We want those to behave like the errorType. - return type === errorType || !!(type.flags & TypeFlags.Any && type.aliasSymbol); + return ( + type === errorType || + !!(type.flags & TypeFlags.Any && type.aliasSymbol) + ); } // Return the type of a binding element parent. We check SymbolLinks first to see if a type has been // assigned by contextual typing. - function getTypeForBindingElementParent(node: BindingElementGrandparent, checkMode: CheckMode) { + function getTypeForBindingElementParent( + node: BindingElementGrandparent, + checkMode: CheckMode + ) { if (checkMode !== CheckMode.Normal) { - return getTypeForVariableLikeDeclaration(node, /*includeOptionality*/ false, checkMode); + return getTypeForVariableLikeDeclaration( + node, + /*includeOptionality*/ false, + checkMode + ); } const symbol = getSymbolOfDeclaration(node); - return symbol && getSymbolLinks(symbol).type || getTypeForVariableLikeDeclaration(node, /*includeOptionality*/ false, checkMode); + return ( + (symbol && getSymbolLinks(symbol).type) || + getTypeForVariableLikeDeclaration( + node, + /*includeOptionality*/ false, + checkMode + ) + ); } - function getRestType(source: Type, properties: PropertyName[], symbol: Symbol | undefined): Type { - source = filterType(source, t => !(t.flags & TypeFlags.Nullable)); + function getRestType( + source: Type, + properties: PropertyName[], + symbol: Symbol | undefined + ): Type { + source = filterType(source, (t) => !(t.flags & TypeFlags.Nullable)); if (source.flags & TypeFlags.Never) { return emptyObjectType; } if (source.flags & TypeFlags.Union) { - return mapType(source, t => getRestType(t, properties, symbol)); + return mapType(source, (t) => getRestType(t, properties, symbol)); } - let omitKeyType = getUnionType(map(properties, getLiteralTypeFromPropertyName)); + let omitKeyType = getUnionType( + map(properties, getLiteralTypeFromPropertyName) + ); const spreadableProperties: Symbol[] = []; const unspreadableToRestKeys: Type[] = []; for (const prop of getPropertiesOfType(source)) { - const literalTypeFromProperty = getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique); + const literalTypeFromProperty = getLiteralTypeFromProperty( + prop, + TypeFlags.StringOrNumberLiteralOrUnique + ); if ( - !isTypeAssignableTo(literalTypeFromProperty, omitKeyType) - && !(getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected)) - && isSpreadableProperty(prop) + !isTypeAssignableTo(literalTypeFromProperty, omitKeyType) && + !( + getDeclarationModifierFlagsFromSymbol(prop) & + (ModifierFlags.Private | ModifierFlags.Protected) + ) && + isSpreadableProperty(prop) ) { spreadableProperties.push(prop); - } - else { + } else { unspreadableToRestKeys.push(literalTypeFromProperty); } } @@ -11517,7 +20226,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If the type we're spreading from has properties that cannot // be spread into the rest type (e.g. getters, methods), ensure // they are explicitly omitted, as they would in the non-generic case. - omitKeyType = getUnionType([omitKeyType, ...unspreadableToRestKeys]); + omitKeyType = getUnionType([ + omitKeyType, + ...unspreadableToRestKeys, + ]); } if (omitKeyType.flags & TypeFlags.Never) { @@ -11528,23 +20240,50 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!omitTypeAlias) { return errorType; } - return getTypeAliasInstantiation(omitTypeAlias, [source, omitKeyType]); + return getTypeAliasInstantiation(omitTypeAlias, [ + source, + omitKeyType, + ]); } const members = createSymbolTable(); for (const prop of spreadableProperties) { - members.set(prop.escapedName, getSpreadSymbol(prop, /*readonly*/ false)); + members.set( + prop.escapedName, + getSpreadSymbol(prop, /*readonly*/ false) + ); } - const result = createAnonymousType(symbol, members, emptyArray, emptyArray, getIndexInfosOfType(source)); + const result = createAnonymousType( + symbol, + members, + emptyArray, + emptyArray, + getIndexInfosOfType(source) + ); result.objectFlags |= ObjectFlags.ObjectRestType; return result; } function isGenericTypeWithUndefinedConstraint(type: Type) { - return !!(type.flags & TypeFlags.Instantiable) && maybeTypeOfKind(getBaseConstraintOfType(type) || unknownType, TypeFlags.Undefined); + return ( + !!(type.flags & TypeFlags.Instantiable) && + maybeTypeOfKind( + getBaseConstraintOfType(type) || unknownType, + TypeFlags.Undefined + ) + ); } function getNonUndefinedType(type: Type) { - const typeOrConstraint = someType(type, isGenericTypeWithUndefinedConstraint) ? mapType(type, t => t.flags & TypeFlags.Instantiable ? getBaseConstraintOrType(t) : t) : type; + const typeOrConstraint = someType( + type, + isGenericTypeWithUndefinedConstraint + ) + ? mapType(type, (t) => + t.flags & TypeFlags.Instantiable + ? getBaseConstraintOrType(t) + : t + ) + : type; return getTypeWithFacts(typeOrConstraint, TypeFacts.NEUndefined); } @@ -11557,19 +20296,51 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // [ x ] = obj; // Expression // We construct a synthetic element access expression corresponding to 'obj.x' such that the control // flow analyzer doesn't have to handle all the different syntactic forms. - function getFlowTypeOfDestructuring(node: BindingElement | PropertyAssignment | ShorthandPropertyAssignment | Expression, declaredType: Type) { + function getFlowTypeOfDestructuring( + node: + | BindingElement + | PropertyAssignment + | ShorthandPropertyAssignment + | Expression, + declaredType: Type + ) { const reference = getSyntheticElementAccess(node); - return reference ? getFlowTypeOfReference(reference, declaredType) : declaredType; - } - - function getSyntheticElementAccess(node: BindingElement | PropertyAssignment | ShorthandPropertyAssignment | Expression): ElementAccessExpression | undefined { + return reference + ? getFlowTypeOfReference(reference, declaredType) + : declaredType; + } + + function getSyntheticElementAccess( + node: + | BindingElement + | PropertyAssignment + | ShorthandPropertyAssignment + | Expression + ): ElementAccessExpression | undefined { const parentAccess = getParentElementAccess(node); - if (parentAccess && canHaveFlowNode(parentAccess) && parentAccess.flowNode) { + if ( + parentAccess && + canHaveFlowNode(parentAccess) && + parentAccess.flowNode + ) { const propName = getDestructuringPropertyName(node); if (propName) { - const literal = setTextRangeWorker(parseNodeFactory.createStringLiteral(propName), node); - const lhsExpr = isLeftHandSideExpression(parentAccess) ? parentAccess : parseNodeFactory.createParenthesizedExpression(parentAccess); - const result = setTextRangeWorker(parseNodeFactory.createElementAccessExpression(lhsExpr, literal), node); + const literal = setTextRangeWorker( + parseNodeFactory.createStringLiteral(propName), + node + ); + const lhsExpr = isLeftHandSideExpression(parentAccess) + ? parentAccess + : parseNodeFactory.createParenthesizedExpression( + parentAccess + ); + const result = setTextRangeWorker( + parseNodeFactory.createElementAccessExpression( + lhsExpr, + literal + ), + node + ); setParent(literal, result); setParent(result, node); if (lhsExpr !== parentAccess) { @@ -11581,12 +20352,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getParentElementAccess(node: BindingElement | PropertyAssignment | ShorthandPropertyAssignment | Expression) { + function getParentElementAccess( + node: + | BindingElement + | PropertyAssignment + | ShorthandPropertyAssignment + | Expression + ) { const ancestor = node.parent.parent; switch (ancestor.kind) { case SyntaxKind.BindingElement: case SyntaxKind.PropertyAssignment: - return getSyntheticElementAccess(ancestor as BindingElement | PropertyAssignment); + return getSyntheticElementAccess( + ancestor as BindingElement | PropertyAssignment + ); case SyntaxKind.ArrayLiteralExpression: return getSyntheticElementAccess(node.parent as Expression); case SyntaxKind.VariableDeclaration: @@ -11596,102 +20375,214 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getDestructuringPropertyName(node: BindingElement | PropertyAssignment | ShorthandPropertyAssignment | Expression) { + function getDestructuringPropertyName( + node: + | BindingElement + | PropertyAssignment + | ShorthandPropertyAssignment + | Expression + ) { const parent = node.parent; - if (node.kind === SyntaxKind.BindingElement && parent.kind === SyntaxKind.ObjectBindingPattern) { - return getLiteralPropertyNameText((node as BindingElement).propertyName || (node as BindingElement).name as Identifier); + if ( + node.kind === SyntaxKind.BindingElement && + parent.kind === SyntaxKind.ObjectBindingPattern + ) { + return getLiteralPropertyNameText( + (node as BindingElement).propertyName || + ((node as BindingElement).name as Identifier) + ); } - if (node.kind === SyntaxKind.PropertyAssignment || node.kind === SyntaxKind.ShorthandPropertyAssignment) { - return getLiteralPropertyNameText((node as PropertyAssignment | ShorthandPropertyAssignment).name); + if ( + node.kind === SyntaxKind.PropertyAssignment || + node.kind === SyntaxKind.ShorthandPropertyAssignment + ) { + return getLiteralPropertyNameText( + (node as PropertyAssignment | ShorthandPropertyAssignment).name + ); } - return "" + ((parent as BindingPattern | ArrayLiteralExpression).elements as NodeArray).indexOf(node); + return ( + "" + + ( + (parent as BindingPattern | ArrayLiteralExpression) + .elements as NodeArray + ).indexOf(node) + ); } function getLiteralPropertyNameText(name: PropertyName) { const type = getLiteralTypeFromPropertyName(name); - return type.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral) ? "" + (type as StringLiteralType | NumberLiteralType).value : undefined; + return type.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral) + ? "" + (type as StringLiteralType | NumberLiteralType).value + : undefined; } /** Return the inferred type for a binding element */ - function getTypeForBindingElement(declaration: BindingElement): Type | undefined { - const checkMode = declaration.dotDotDotToken ? CheckMode.RestBindingElement : CheckMode.Normal; - const parentType = getTypeForBindingElementParent(declaration.parent.parent, checkMode); - return parentType && getBindingElementTypeFromParentType(declaration, parentType, /*noTupleBoundsCheck*/ false); + function getTypeForBindingElement( + declaration: BindingElement + ): Type | undefined { + const checkMode = declaration.dotDotDotToken + ? CheckMode.RestBindingElement + : CheckMode.Normal; + const parentType = getTypeForBindingElementParent( + declaration.parent.parent, + checkMode + ); + return ( + parentType && + getBindingElementTypeFromParentType( + declaration, + parentType, + /*noTupleBoundsCheck*/ false + ) + ); } - function getBindingElementTypeFromParentType(declaration: BindingElement, parentType: Type, noTupleBoundsCheck: boolean): Type { + function getBindingElementTypeFromParentType( + declaration: BindingElement, + parentType: Type, + noTupleBoundsCheck: boolean + ): Type { // If an any type was inferred for parent, infer that for the binding element if (isTypeAny(parentType)) { return parentType; } const pattern = declaration.parent; // Relax null check on ambient destructuring parameters, since the parameters have no implementation and are just documentation - if (strictNullChecks && declaration.flags & NodeFlags.Ambient && isPartOfParameterDeclaration(declaration)) { + if ( + strictNullChecks && + declaration.flags & NodeFlags.Ambient && + isPartOfParameterDeclaration(declaration) + ) { parentType = getNonNullableType(parentType); } // Filter `undefined` from the type we check against if the parent has an initializer and that initializer is not possibly `undefined` - else if (strictNullChecks && pattern.parent.initializer && !(hasTypeFacts(getTypeOfInitializer(pattern.parent.initializer), TypeFacts.EQUndefined))) { + else if ( + strictNullChecks && + pattern.parent.initializer && + !hasTypeFacts( + getTypeOfInitializer(pattern.parent.initializer), + TypeFacts.EQUndefined + ) + ) { parentType = getTypeWithFacts(parentType, TypeFacts.NEUndefined); } - const accessFlags = AccessFlags.ExpressionPosition | (noTupleBoundsCheck || hasDefaultValue(declaration) ? AccessFlags.AllowMissing : 0); + const accessFlags = + AccessFlags.ExpressionPosition | + (noTupleBoundsCheck || hasDefaultValue(declaration) + ? AccessFlags.AllowMissing + : 0); let type: Type | undefined; if (pattern.kind === SyntaxKind.ObjectBindingPattern) { if (declaration.dotDotDotToken) { parentType = getReducedType(parentType); - if (parentType.flags & TypeFlags.Unknown || !isValidSpreadType(parentType)) { - error(declaration, Diagnostics.Rest_types_may_only_be_created_from_object_types); + if ( + parentType.flags & TypeFlags.Unknown || + !isValidSpreadType(parentType) + ) { + error( + declaration, + Diagnostics.Rest_types_may_only_be_created_from_object_types + ); return errorType; } const literalMembers: PropertyName[] = []; for (const element of pattern.elements) { if (!element.dotDotDotToken) { - literalMembers.push(element.propertyName || element.name as Identifier); + literalMembers.push( + element.propertyName || (element.name as Identifier) + ); } } - type = getRestType(parentType, literalMembers, declaration.symbol); - } - else { + type = getRestType( + parentType, + literalMembers, + declaration.symbol + ); + } else { // Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form) - const name = declaration.propertyName || declaration.name as Identifier; + const name = + declaration.propertyName || + (declaration.name as Identifier); const indexType = getLiteralTypeFromPropertyName(name); - const declaredType = getIndexedAccessType(parentType, indexType, accessFlags, name); + const declaredType = getIndexedAccessType( + parentType, + indexType, + accessFlags, + name + ); type = getFlowTypeOfDestructuring(declaration, declaredType); } - } - else { + } else { // This elementType will be used if the specific property corresponding to this index is not // present (aka the tuple element property). This call also checks that the parentType is in // fact an iterable or array (depending on target language). - const elementType = checkIteratedTypeOrElementType(IterationUse.Destructuring | (declaration.dotDotDotToken ? 0 : IterationUse.PossiblyOutOfBounds), parentType, undefinedType, pattern); + const elementType = checkIteratedTypeOrElementType( + IterationUse.Destructuring | + (declaration.dotDotDotToken + ? 0 + : IterationUse.PossiblyOutOfBounds), + parentType, + undefinedType, + pattern + ); const index = pattern.elements.indexOf(declaration); if (declaration.dotDotDotToken) { // If the parent is a tuple type, the rest element has a tuple type of the // remaining tuple element types. Otherwise, the rest element has an array type with same // element type as the parent type. - const baseConstraint = mapType(parentType, t => t.flags & TypeFlags.InstantiableNonPrimitive ? getBaseConstraintOrType(t) : t); - type = everyType(baseConstraint, isTupleType) ? - mapType(baseConstraint, t => sliceTupleType(t as TupleTypeReference, index)) : - createArrayType(elementType); - } - else if (isArrayLikeType(parentType)) { + const baseConstraint = mapType(parentType, (t) => + t.flags & TypeFlags.InstantiableNonPrimitive + ? getBaseConstraintOrType(t) + : t + ); + type = everyType(baseConstraint, isTupleType) + ? mapType(baseConstraint, (t) => + sliceTupleType(t as TupleTypeReference, index) + ) + : createArrayType(elementType); + } else if (isArrayLikeType(parentType)) { const indexType = getNumberLiteralType(index); - const declaredType = getIndexedAccessTypeOrUndefined(parentType, indexType, accessFlags, declaration.name) || errorType; + const declaredType = + getIndexedAccessTypeOrUndefined( + parentType, + indexType, + accessFlags, + declaration.name + ) || errorType; type = getFlowTypeOfDestructuring(declaration, declaredType); - } - else { + } else { type = elementType; } } if (!declaration.initializer) { return type; } - if (getEffectiveTypeAnnotationNode(walkUpBindingElementsAndPatterns(declaration))) { + if ( + getEffectiveTypeAnnotationNode( + walkUpBindingElementsAndPatterns(declaration) + ) + ) { // In strict null checking mode, if a default value of a non-undefined type is specified, remove // undefined from the final type. - return strictNullChecks && !(hasTypeFacts(checkDeclarationInitializer(declaration, CheckMode.Normal), TypeFacts.IsUndefined)) ? getNonUndefinedType(type) : type; + return strictNullChecks && + !hasTypeFacts( + checkDeclarationInitializer(declaration, CheckMode.Normal), + TypeFacts.IsUndefined + ) + ? getNonUndefinedType(type) + : type; } - return widenTypeInferredFromInitializer(declaration, getUnionType([getNonUndefinedType(type), checkDeclarationInitializer(declaration, CheckMode.Normal)], UnionReduction.Subtype)); + return widenTypeInferredFromInitializer( + declaration, + getUnionType( + [ + getNonUndefinedType(type), + checkDeclarationInitializer(declaration, CheckMode.Normal), + ], + UnionReduction.Subtype + ) + ); } function getTypeForDeclarationFromJSDocComment(declaration: Node) { @@ -11704,32 +20595,66 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isNullOrUndefined(node: Expression) { const expr = skipParentheses(node, /*excludeJSDocTypeAssertions*/ true); - return expr.kind === SyntaxKind.NullKeyword || expr.kind === SyntaxKind.Identifier && getResolvedSymbol(expr as Identifier) === undefinedSymbol; + return ( + expr.kind === SyntaxKind.NullKeyword || + (expr.kind === SyntaxKind.Identifier && + getResolvedSymbol(expr as Identifier) === undefinedSymbol) + ); } function isEmptyArrayLiteral(node: Expression) { const expr = skipParentheses(node, /*excludeJSDocTypeAssertions*/ true); - return expr.kind === SyntaxKind.ArrayLiteralExpression && (expr as ArrayLiteralExpression).elements.length === 0; + return ( + expr.kind === SyntaxKind.ArrayLiteralExpression && + (expr as ArrayLiteralExpression).elements.length === 0 + ); } - function addOptionality(type: Type, isProperty = false, isOptional = true): Type { - return strictNullChecks && isOptional ? getOptionalType(type, isProperty) : type; + function addOptionality( + type: Type, + isProperty = false, + isOptional = true + ): Type { + return strictNullChecks && isOptional + ? getOptionalType(type, isProperty) + : type; } // Return the inferred type for a variable, parameter, or property declaration function getTypeForVariableLikeDeclaration( - declaration: ParameterDeclaration | PropertyDeclaration | PropertySignature | VariableDeclaration | BindingElement | JSDocPropertyLikeTag, + declaration: + | ParameterDeclaration + | PropertyDeclaration + | PropertySignature + | VariableDeclaration + | BindingElement + | JSDocPropertyLikeTag, includeOptionality: boolean, - checkMode: CheckMode, + checkMode: CheckMode ): Type | undefined { // A variable declared in a for..in statement is of type string, or of type keyof T when the // right hand expression is of a type parameter type. - if (isVariableDeclaration(declaration) && declaration.parent.parent.kind === SyntaxKind.ForInStatement) { - const indexType = getIndexType(getNonNullableTypeIfNeeded(checkExpression(declaration.parent.parent.expression, /*checkMode*/ checkMode))); - return indexType.flags & (TypeFlags.TypeParameter | TypeFlags.Index) ? getExtractStringType(indexType) : stringType; + if ( + isVariableDeclaration(declaration) && + declaration.parent.parent.kind === SyntaxKind.ForInStatement + ) { + const indexType = getIndexType( + getNonNullableTypeIfNeeded( + checkExpression( + declaration.parent.parent.expression, + /*checkMode*/ checkMode + ) + ) + ); + return indexType.flags & (TypeFlags.TypeParameter | TypeFlags.Index) + ? getExtractStringType(indexType) + : stringType; } - if (isVariableDeclaration(declaration) && declaration.parent.parent.kind === SyntaxKind.ForOfStatement) { + if ( + isVariableDeclaration(declaration) && + declaration.parent.parent.kind === SyntaxKind.ForOfStatement + ) { // checkRightHandSideOfForOf will return undefined if the for-of expression type was // missing properties/signatures required to get its iteratedType (like // [Symbol.iterator] or next). This may be because we accessed properties from anyType, @@ -11742,15 +20667,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getTypeForBindingElement(declaration as BindingElement); } - const isProperty = (isPropertyDeclaration(declaration) && !hasAccessorModifier(declaration)) || isPropertySignature(declaration) || isJSDocPropertyTag(declaration); - const isOptional = includeOptionality && isOptionalDeclaration(declaration); + const isProperty = + (isPropertyDeclaration(declaration) && + !hasAccessorModifier(declaration)) || + isPropertySignature(declaration) || + isJSDocPropertyTag(declaration); + const isOptional = + includeOptionality && isOptionalDeclaration(declaration); // Use type from type annotation if one is present const declaredType = tryGetTypeFromEffectiveTypeNode(declaration); if (isCatchClauseVariableDeclarationOrBindingElement(declaration)) { if (declaredType) { // If the catch clause is explicitly annotated with any or unknown, accept it, otherwise error. - return isTypeAny(declaredType) || declaredType === unknownType ? declaredType : errorType; + return isTypeAny(declaredType) || declaredType === unknownType + ? declaredType + : errorType; } // If the catch clause is not explicitly annotated, treat it as though it were explicitly // annotated with unknown or any, depending on useUnknownInCatchVariables. @@ -11762,18 +20694,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if ( (noImplicitAny || isInJSFile(declaration)) && - isVariableDeclaration(declaration) && !isBindingPattern(declaration.name) && - !(getCombinedModifierFlagsCached(declaration) & ModifierFlags.Export) && !(declaration.flags & NodeFlags.Ambient) + isVariableDeclaration(declaration) && + !isBindingPattern(declaration.name) && + !( + getCombinedModifierFlagsCached(declaration) & + ModifierFlags.Export + ) && + !(declaration.flags & NodeFlags.Ambient) ) { // If --noImplicitAny is on or the declaration is in a Javascript file, // use control flow tracked 'any' type for non-ambient, non-exported var or let variables with no // initializer or a 'null' or 'undefined' initializer. - if (!(getCombinedNodeFlagsCached(declaration) & NodeFlags.Constant) && (!declaration.initializer || isNullOrUndefined(declaration.initializer))) { + if ( + !( + getCombinedNodeFlagsCached(declaration) & NodeFlags.Constant + ) && + (!declaration.initializer || + isNullOrUndefined(declaration.initializer)) + ) { return autoType; } // Use control flow tracked 'any[]' type for non-ambient, non-exported variables with an empty array // literal initializer. - if (declaration.initializer && isEmptyArrayLiteral(declaration.initializer)) { + if ( + declaration.initializer && + isEmptyArrayLiteral(declaration.initializer) + ) { return autoArrayType; } } @@ -11786,10 +20732,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const func = declaration.parent as FunctionLikeDeclaration; // For a parameter of a set accessor, use the type of the get accessor if one is present if (func.kind === SyntaxKind.SetAccessor && hasBindableName(func)) { - const getter = getDeclarationOfKind(getSymbolOfDeclaration(declaration.parent), SyntaxKind.GetAccessor); + const getter = getDeclarationOfKind( + getSymbolOfDeclaration(declaration.parent), + SyntaxKind.GetAccessor + ); if (getter) { const getterSignature = getSignatureFromDeclaration(getter); - const thisParameter = getAccessorThisParameter(func as AccessorDeclaration); + const thisParameter = getAccessorThisParameter( + func as AccessorDeclaration + ); if (thisParameter && declaration === thisParameter) { // Use the type from the *getter* Debug.assert(!thisParameter.type); @@ -11798,10 +20749,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getReturnTypeOfSignature(getterSignature); } } - const parameterTypeOfTypeTag = getParameterTypeOfTypeTag(func, declaration); + const parameterTypeOfTypeTag = getParameterTypeOfTypeTag( + func, + declaration + ); if (parameterTypeOfTypeTag) return parameterTypeOfTypeTag; // Use contextual parameter type if one is available - const type = declaration.symbol.escapedName === InternalSymbolName.This ? getContextualThisParameterType(func) : getContextuallyTypedParameterType(declaration); + const type = + declaration.symbol.escapedName === InternalSymbolName.This + ? getContextualThisParameterType(func) + : getContextuallyTypedParameterType(declaration); if (type) { return addOptionality(type, /*isProperty*/ false, isOptional); } @@ -11809,33 +20766,65 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Use the type of the initializer expression if one is present and the declaration is // not a parameter of a contextually typed function - if (hasOnlyExpressionInitializer(declaration) && !!declaration.initializer) { + if ( + hasOnlyExpressionInitializer(declaration) && + !!declaration.initializer + ) { if (isInJSFile(declaration) && !isParameter(declaration)) { - const containerObjectType = getJSContainerObjectType(declaration, getSymbolOfDeclaration(declaration), getDeclaredExpandoInitializer(declaration)); + const containerObjectType = getJSContainerObjectType( + declaration, + getSymbolOfDeclaration(declaration), + getDeclaredExpandoInitializer(declaration) + ); if (containerObjectType) { return containerObjectType; } } - const type = widenTypeInferredFromInitializer(declaration, checkDeclarationInitializer(declaration, checkMode)); + const type = widenTypeInferredFromInitializer( + declaration, + checkDeclarationInitializer(declaration, checkMode) + ); return addOptionality(type, isProperty, isOptional); } - if (isPropertyDeclaration(declaration) && (noImplicitAny || isInJSFile(declaration))) { + if ( + isPropertyDeclaration(declaration) && + (noImplicitAny || isInJSFile(declaration)) + ) { // We have a property declaration with no type annotation or initializer, in noImplicitAny mode or a .js file. // Use control flow analysis of this.xxx assignments in the constructor or static block to determine the type of the property. if (!hasStaticModifier(declaration)) { - const constructor = findConstructorDeclaration(declaration.parent); - const type = constructor ? getFlowTypeInConstructor(declaration.symbol, constructor) : - getEffectiveModifierFlags(declaration) & ModifierFlags.Ambient ? getTypeOfPropertyInBaseClass(declaration.symbol) : - undefined; - return type && addOptionality(type, /*isProperty*/ true, isOptional); - } - else { - const staticBlocks = filter(declaration.parent.members, isClassStaticBlockDeclaration); - const type = staticBlocks.length ? getFlowTypeInStaticBlocks(declaration.symbol, staticBlocks) : - getEffectiveModifierFlags(declaration) & ModifierFlags.Ambient ? getTypeOfPropertyInBaseClass(declaration.symbol) : - undefined; - return type && addOptionality(type, /*isProperty*/ true, isOptional); + const constructor = findConstructorDeclaration( + declaration.parent + ); + const type = constructor + ? getFlowTypeInConstructor(declaration.symbol, constructor) + : getEffectiveModifierFlags(declaration) & + ModifierFlags.Ambient + ? getTypeOfPropertyInBaseClass(declaration.symbol) + : undefined; + return ( + type && + addOptionality(type, /*isProperty*/ true, isOptional) + ); + } else { + const staticBlocks = filter( + declaration.parent.members, + isClassStaticBlockDeclaration + ); + const type = staticBlocks.length + ? getFlowTypeInStaticBlocks( + declaration.symbol, + staticBlocks + ) + : getEffectiveModifierFlags(declaration) & + ModifierFlags.Ambient + ? getTypeOfPropertyInBaseClass(declaration.symbol) + : undefined; + return ( + type && + addOptionality(type, /*isProperty*/ true, isOptional) + ); } } @@ -11848,7 +20837,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If the declaration specifies a binding pattern and is not a parameter of a contextually // typed function, use the type implied by the binding pattern if (isBindingPattern(declaration.name)) { - return getTypeFromBindingPattern(declaration.name, /*includePatternInType*/ false, /*reportErrors*/ true); + return getTypeFromBindingPattern( + declaration.name, + /*includePatternInType*/ false, + /*reportErrors*/ true + ); } // No type specified and nothing can be inferred @@ -11859,15 +20852,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // A property is considered a constructor declared property when all declaration sites are this.xxx assignments, // when no declaration sites have JSDoc type annotations, and when at least one declaration site is in the body of // a class constructor. - if (symbol.valueDeclaration && isBinaryExpression(symbol.valueDeclaration)) { + if ( + symbol.valueDeclaration && + isBinaryExpression(symbol.valueDeclaration) + ) { const links = getSymbolLinks(symbol); if (links.isConstructorDeclaredProperty === undefined) { links.isConstructorDeclaredProperty = false; - links.isConstructorDeclaredProperty = !!getDeclaringConstructor(symbol) && every(symbol.declarations, declaration => - isBinaryExpression(declaration) && - isPossiblyAliasedThisProperty(declaration) && - (declaration.left.kind !== SyntaxKind.ElementAccessExpression || isStringOrNumericLiteralLike((declaration.left as ElementAccessExpression).argumentExpression)) && - !getAnnotatedTypeForAssignmentDeclaration(/*declaredType*/ undefined, declaration, symbol, declaration)); + links.isConstructorDeclaredProperty = + !!getDeclaringConstructor(symbol) && + every( + symbol.declarations, + (declaration) => + isBinaryExpression(declaration) && + isPossiblyAliasedThisProperty(declaration) && + (declaration.left.kind !== + SyntaxKind.ElementAccessExpression || + isStringOrNumericLiteralLike( + ( + declaration.left as ElementAccessExpression + ).argumentExpression + )) && + !getAnnotatedTypeForAssignmentDeclaration( + /*declaredType*/ undefined, + declaration, + symbol, + declaration + ) + ); } return links.isConstructorDeclaredProperty; } @@ -11878,8 +20890,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // A property is auto-typed when its declaration has no type annotation or initializer and we're in // noImplicitAny mode or a .js file. const declaration = symbol.valueDeclaration; - return declaration && isPropertyDeclaration(declaration) && !getEffectiveTypeAnnotationNode(declaration) && - !declaration.initializer && (noImplicitAny || isInJSFile(declaration)); + return ( + declaration && + isPropertyDeclaration(declaration) && + !getEffectiveTypeAnnotationNode(declaration) && + !declaration.initializer && + (noImplicitAny || isInJSFile(declaration)) + ); } function getDeclaringConstructor(symbol: Symbol) { @@ -11887,8 +20904,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return; } for (const declaration of symbol.declarations) { - const container = getThisContainer(declaration, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); - if (container && (container.kind === SyntaxKind.Constructor || isJSConstructor(container))) { + const container = getThisContainer( + declaration, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false + ); + if ( + container && + (container.kind === SyntaxKind.Constructor || + isJSConstructor(container)) + ) { return container as ConstructorDeclaration; } } @@ -11898,12 +20923,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getFlowTypeFromCommonJSExport(symbol: Symbol) { const file = getSourceFileOfNode(symbol.declarations![0]); const accessName = unescapeLeadingUnderscores(symbol.escapedName); - const areAllModuleExports = symbol.declarations!.every(d => isInJSFile(d) && isAccessExpression(d) && isModuleExportsAccessExpression(d.expression)); + const areAllModuleExports = symbol.declarations!.every( + (d) => + isInJSFile(d) && + isAccessExpression(d) && + isModuleExportsAccessExpression(d.expression) + ); const reference = areAllModuleExports - ? factory.createPropertyAccessExpression(factory.createPropertyAccessExpression(factory.createIdentifier("module"), factory.createIdentifier("exports")), accessName) - : factory.createPropertyAccessExpression(factory.createIdentifier("exports"), accessName); + ? factory.createPropertyAccessExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("module"), + factory.createIdentifier("exports") + ), + accessName + ) + : factory.createPropertyAccessExpression( + factory.createIdentifier("exports"), + accessName + ); if (areAllModuleExports) { - setParent((reference.expression as PropertyAccessExpression).expression, reference.expression); + setParent( + (reference.expression as PropertyAccessExpression).expression, + reference.expression + ); } setParent(reference.expression, reference); setParent(reference, file); @@ -11911,18 +20953,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getFlowTypeOfReference(reference, autoType, undefinedType); } - function getFlowTypeInStaticBlocks(symbol: Symbol, staticBlocks: readonly ClassStaticBlockDeclaration[]) { + function getFlowTypeInStaticBlocks( + symbol: Symbol, + staticBlocks: readonly ClassStaticBlockDeclaration[] + ) { const accessName = startsWith(symbol.escapedName as string, "__#") - ? factory.createPrivateIdentifier((symbol.escapedName as string).split("@")[1]) + ? factory.createPrivateIdentifier( + (symbol.escapedName as string).split("@")[1] + ) : unescapeLeadingUnderscores(symbol.escapedName); for (const staticBlock of staticBlocks) { - const reference = factory.createPropertyAccessExpression(factory.createThis(), accessName); + const reference = factory.createPropertyAccessExpression( + factory.createThis(), + accessName + ); setParent(reference.expression, reference); setParent(reference, staticBlock); reference.flowNode = staticBlock.returnFlowNode; const flowType = getFlowTypeOfProperty(reference, symbol); - if (noImplicitAny && (flowType === autoType || flowType === autoArrayType)) { - error(symbol.valueDeclaration, Diagnostics.Member_0_implicitly_has_an_1_type, symbolToString(symbol), typeToString(flowType)); + if ( + noImplicitAny && + (flowType === autoType || flowType === autoArrayType) + ) { + error( + symbol.valueDeclaration, + Diagnostics.Member_0_implicitly_has_an_1_type, + symbolToString(symbol), + typeToString(flowType) + ); } // We don't infer a type if assignments are only null or undefined. if (everyType(flowType, isNullableType)) { @@ -11932,40 +20990,77 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getFlowTypeInConstructor(symbol: Symbol, constructor: ConstructorDeclaration) { + function getFlowTypeInConstructor( + symbol: Symbol, + constructor: ConstructorDeclaration + ) { const accessName = startsWith(symbol.escapedName as string, "__#") - ? factory.createPrivateIdentifier((symbol.escapedName as string).split("@")[1]) + ? factory.createPrivateIdentifier( + (symbol.escapedName as string).split("@")[1] + ) : unescapeLeadingUnderscores(symbol.escapedName); - const reference = factory.createPropertyAccessExpression(factory.createThis(), accessName); + const reference = factory.createPropertyAccessExpression( + factory.createThis(), + accessName + ); setParent(reference.expression, reference); setParent(reference, constructor); reference.flowNode = constructor.returnFlowNode; const flowType = getFlowTypeOfProperty(reference, symbol); - if (noImplicitAny && (flowType === autoType || flowType === autoArrayType)) { - error(symbol.valueDeclaration, Diagnostics.Member_0_implicitly_has_an_1_type, symbolToString(symbol), typeToString(flowType)); + if ( + noImplicitAny && + (flowType === autoType || flowType === autoArrayType) + ) { + error( + symbol.valueDeclaration, + Diagnostics.Member_0_implicitly_has_an_1_type, + symbolToString(symbol), + typeToString(flowType) + ); } // We don't infer a type if assignments are only null or undefined. - return everyType(flowType, isNullableType) ? undefined : convertAutoToAny(flowType); + return everyType(flowType, isNullableType) + ? undefined + : convertAutoToAny(flowType); } function getFlowTypeOfProperty(reference: Node, prop: Symbol | undefined) { - const initialType = prop?.valueDeclaration - && (!isAutoTypedProperty(prop) || getEffectiveModifierFlags(prop.valueDeclaration) & ModifierFlags.Ambient) - && getTypeOfPropertyInBaseClass(prop) - || undefinedType; + const initialType = + (prop?.valueDeclaration && + (!isAutoTypedProperty(prop) || + getEffectiveModifierFlags(prop.valueDeclaration) & + ModifierFlags.Ambient) && + getTypeOfPropertyInBaseClass(prop)) || + undefinedType; return getFlowTypeOfReference(reference, autoType, initialType); } - function getWidenedTypeForAssignmentDeclaration(symbol: Symbol, resolvedSymbol?: Symbol) { + function getWidenedTypeForAssignmentDeclaration( + symbol: Symbol, + resolvedSymbol?: Symbol + ) { // function/class/{} initializers are themselves containers, so they won't merge in the same way as other initializers - const container = getAssignedExpandoInitializer(symbol.valueDeclaration); + const container = getAssignedExpandoInitializer( + symbol.valueDeclaration + ); if (container) { - const tag = isInJSFile(container) ? getJSDocTypeTag(container) : undefined; + const tag = isInJSFile(container) + ? getJSDocTypeTag(container) + : undefined; if (tag && tag.typeExpression) { return getTypeFromTypeNode(tag.typeExpression); } - const containerObjectType = symbol.valueDeclaration && getJSContainerObjectType(symbol.valueDeclaration, symbol, container); - return containerObjectType || getWidenedLiteralType(checkExpressionCached(container)); + const containerObjectType = + symbol.valueDeclaration && + getJSContainerObjectType( + symbol.valueDeclaration, + symbol, + container + ); + return ( + containerObjectType || + getWidenedLiteralType(checkExpressionCached(container)) + ); } let type; let definedInConstructor = false; @@ -11973,16 +21068,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We use control flow analysis to determine the type of the property if the property qualifies as a constructor // declared property and the resulting control flow type isn't just undefined or null. if (isConstructorDeclaredProperty(symbol)) { - type = getFlowTypeInConstructor(symbol, getDeclaringConstructor(symbol)!); + type = getFlowTypeInConstructor( + symbol, + getDeclaringConstructor(symbol)! + ); } if (!type) { let types: Type[] | undefined; if (symbol.declarations) { let jsdocType: Type | undefined; for (const declaration of symbol.declarations) { - const expression = (isBinaryExpression(declaration) || isCallExpression(declaration)) ? declaration : - isAccessExpression(declaration) ? isBinaryExpression(declaration.parent) ? declaration.parent : declaration : - undefined; + const expression = + isBinaryExpression(declaration) || + isCallExpression(declaration) + ? declaration + : isAccessExpression(declaration) + ? isBinaryExpression(declaration.parent) + ? declaration.parent + : declaration + : undefined; if (!expression) { 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 } @@ -11990,19 +21094,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const kind = isAccessExpression(expression) ? getAssignmentDeclarationPropertyAccessKind(expression) : getAssignmentDeclarationKind(expression); - if (kind === AssignmentDeclarationKind.ThisProperty || isBinaryExpression(expression) && isPossiblyAliasedThisProperty(expression, kind)) { + if ( + kind === AssignmentDeclarationKind.ThisProperty || + (isBinaryExpression(expression) && + isPossiblyAliasedThisProperty(expression, kind)) + ) { if (isDeclarationInConstructor(expression)) { definedInConstructor = true; - } - else { + } else { definedInMethod = true; } } if (!isCallExpression(expression)) { - jsdocType = getAnnotatedTypeForAssignmentDeclaration(jsdocType, expression, symbol, declaration); + jsdocType = getAnnotatedTypeForAssignmentDeclaration( + jsdocType, + expression, + symbol, + declaration + ); } if (!jsdocType) { - (types || (types = [])).push((isBinaryExpression(expression) || isCallExpression(expression)) ? getInitializerTypeFromAssignmentDeclaration(symbol, resolvedSymbol, expression, kind) : neverType); + (types || (types = [])).push( + isBinaryExpression(expression) || + isCallExpression(expression) + ? getInitializerTypeFromAssignmentDeclaration( + symbol, + resolvedSymbol, + expression, + kind + ) + : neverType + ); } } type = jsdocType; @@ -12011,29 +21133,62 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!length(types)) { return errorType; // No types from any declarations :( } - let constructorTypes = definedInConstructor && symbol.declarations ? getConstructorDefinedThisAssignmentTypes(types!, symbol.declarations) : undefined; + let constructorTypes = + definedInConstructor && symbol.declarations + ? getConstructorDefinedThisAssignmentTypes( + types!, + symbol.declarations + ) + : undefined; // use only the constructor types unless they were only assigned null | undefined (including widening variants) if (definedInMethod) { const propType = getTypeOfPropertyInBaseClass(symbol); if (propType) { - (constructorTypes || (constructorTypes = [])).push(propType); + (constructorTypes || (constructorTypes = [])).push( + propType + ); definedInConstructor = true; } } - const sourceTypes = some(constructorTypes, t => !!(t.flags & ~TypeFlags.Nullable)) ? constructorTypes : types; // TODO: GH#18217 + const sourceTypes = some( + constructorTypes, + (t) => !!(t.flags & ~TypeFlags.Nullable) + ) + ? constructorTypes + : types; // TODO: GH#18217 type = getUnionType(sourceTypes!); } } - const widened = getWidenedType(addOptionality(type, /*isProperty*/ false, definedInMethod && !definedInConstructor)); - if (symbol.valueDeclaration && isInJSFile(symbol.valueDeclaration) && filterType(widened, t => !!(t.flags & ~TypeFlags.Nullable)) === neverType) { + const widened = getWidenedType( + addOptionality( + type, + /*isProperty*/ false, + definedInMethod && !definedInConstructor + ) + ); + if ( + symbol.valueDeclaration && + isInJSFile(symbol.valueDeclaration) && + filterType(widened, (t) => !!(t.flags & ~TypeFlags.Nullable)) === + neverType + ) { reportImplicitAny(symbol.valueDeclaration, anyType); return anyType; } return widened; } - function getJSContainerObjectType(decl: Node, symbol: Symbol, init: Expression | undefined): Type | undefined { - if (!isInJSFile(decl) || !init || !isObjectLiteralExpression(init) || init.properties.length) { + function getJSContainerObjectType( + decl: Node, + symbol: Symbol, + init: Expression | undefined + ): Type | undefined { + if ( + !isInJSFile(decl) || + !init || + !isObjectLiteralExpression(init) || + init.properties.length + ) { return undefined; } const exports = createSymbolTable(); @@ -12048,28 +21203,53 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (s?.exports?.size) { mergeSymbolTable(exports, s.exports); } - const type = createAnonymousType(symbol, exports, emptyArray, emptyArray, emptyArray); + const type = createAnonymousType( + symbol, + exports, + emptyArray, + emptyArray, + emptyArray + ); type.objectFlags |= ObjectFlags.JSLiteral; return type; } - function getAnnotatedTypeForAssignmentDeclaration(declaredType: Type | undefined, expression: Expression, symbol: Symbol, declaration: Declaration) { + function getAnnotatedTypeForAssignmentDeclaration( + declaredType: Type | undefined, + expression: Expression, + symbol: Symbol, + declaration: Declaration + ) { const typeNode = getEffectiveTypeAnnotationNode(expression.parent); if (typeNode) { const type = getWidenedType(getTypeFromTypeNode(typeNode)); if (!declaredType) { return type; - } - else if (!isErrorType(declaredType) && !isErrorType(type) && !isTypeIdenticalTo(declaredType, type)) { - errorNextVariableOrPropertyDeclarationMustHaveSameType(/*firstDeclaration*/ undefined, declaredType, declaration, type); + } else if ( + !isErrorType(declaredType) && + !isErrorType(type) && + !isTypeIdenticalTo(declaredType, type) + ) { + errorNextVariableOrPropertyDeclarationMustHaveSameType( + /*firstDeclaration*/ undefined, + declaredType, + declaration, + type + ); } } if (symbol.parent?.valueDeclaration) { - const possiblyAnnotatedSymbol = getFunctionExpressionParentSymbolOrSymbol(symbol.parent); + const possiblyAnnotatedSymbol = + getFunctionExpressionParentSymbolOrSymbol(symbol.parent); if (possiblyAnnotatedSymbol.valueDeclaration) { - const typeNode = getEffectiveTypeAnnotationNode(possiblyAnnotatedSymbol.valueDeclaration); + const typeNode = getEffectiveTypeAnnotationNode( + possiblyAnnotatedSymbol.valueDeclaration + ); if (typeNode) { - const annotationSymbol = getPropertyOfType(getTypeFromTypeNode(typeNode), symbol.escapedName); + const annotationSymbol = getPropertyOfType( + getTypeFromTypeNode(typeNode), + symbol.escapedName + ); if (annotationSymbol) { return getNonMissingTypeOfSymbol(annotationSymbol); } @@ -12081,24 +21261,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } /** If we don't have an explicit JSDoc type, get the type from the initializer. */ - function getInitializerTypeFromAssignmentDeclaration(symbol: Symbol, resolvedSymbol: Symbol | undefined, expression: BinaryExpression | CallExpression, kind: AssignmentDeclarationKind) { + function getInitializerTypeFromAssignmentDeclaration( + symbol: Symbol, + resolvedSymbol: Symbol | undefined, + expression: BinaryExpression | CallExpression, + kind: AssignmentDeclarationKind + ) { if (isCallExpression(expression)) { if (resolvedSymbol) { return getTypeOfSymbol(resolvedSymbol); // This shouldn't happen except under some hopefully forbidden merges of export assignments and object define assignments } - const objectLitType = checkExpressionCached((expression as BindableObjectDefinePropertyCall).arguments[2]); - const valueType = getTypeOfPropertyOfType(objectLitType, "value" as __String); + const objectLitType = checkExpressionCached( + (expression as BindableObjectDefinePropertyCall).arguments[2] + ); + const valueType = getTypeOfPropertyOfType( + objectLitType, + "value" as __String + ); if (valueType) { return valueType; } - const getFunc = getTypeOfPropertyOfType(objectLitType, "get" as __String); + const getFunc = getTypeOfPropertyOfType( + objectLitType, + "get" as __String + ); if (getFunc) { const getSig = getSingleCallSignature(getFunc); if (getSig) { return getReturnTypeOfSignature(getSig); } } - const setFunc = getTypeOfPropertyOfType(objectLitType, "set" as __String); + const setFunc = getTypeOfPropertyOfType( + objectLitType, + "set" as __String + ); if (setFunc) { const setSig = getSingleCallSignature(setFunc); if (setSig) { @@ -12110,16 +21306,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (containsSameNamedThisProperty(expression.left, expression.right)) { return anyType; } - const isDirectExport = kind === AssignmentDeclarationKind.ExportsProperty && (isPropertyAccessExpression(expression.left) || isElementAccessExpression(expression.left)) && (isModuleExportsAccessExpression(expression.left.expression) || (isIdentifier(expression.left.expression) && isExportsIdentifier(expression.left.expression))); - const type = resolvedSymbol ? getTypeOfSymbol(resolvedSymbol) - : isDirectExport ? getRegularTypeOfLiteralType(checkExpressionCached(expression.right)) + const isDirectExport = + kind === AssignmentDeclarationKind.ExportsProperty && + (isPropertyAccessExpression(expression.left) || + isElementAccessExpression(expression.left)) && + (isModuleExportsAccessExpression(expression.left.expression) || + (isIdentifier(expression.left.expression) && + isExportsIdentifier(expression.left.expression))); + const type = resolvedSymbol + ? getTypeOfSymbol(resolvedSymbol) + : isDirectExport + ? getRegularTypeOfLiteralType( + checkExpressionCached(expression.right) + ) : getWidenedLiteralType(checkExpressionCached(expression.right)); if ( type.flags & TypeFlags.Object && kind === AssignmentDeclarationKind.ModuleExports && symbol.escapedName === InternalSymbolName.ExportEquals ) { - const exportedType = resolveStructuredTypeMembers(type as ObjectType); + const exportedType = resolveStructuredTypeMembers( + type as ObjectType + ); const members = createSymbolTable(); copyEntries(exportedType.members, members); const initialSize = members.size; @@ -12128,8 +21336,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } (resolvedSymbol || symbol).exports!.forEach((s, name) => { const exportedMember = members.get(name)!; - if (exportedMember && exportedMember !== s && !(s.flags & SymbolFlags.Alias)) { - if (s.flags & SymbolFlags.Value && exportedMember.flags & SymbolFlags.Value) { + if ( + exportedMember && + exportedMember !== s && + !(s.flags & SymbolFlags.Alias) + ) { + if ( + s.flags & SymbolFlags.Value && + exportedMember.flags & SymbolFlags.Value + ) { // If the member has an additional value-like declaration, union the types from the two declarations, // but issue an error if they occurred in two different files. The purpose is to support a JS file with // a pattern like: @@ -12140,29 +21355,66 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // but we may have a JS file with `module.exports = { a: true }` along with a TypeScript module augmentation // declaring an `export const a: number`. In that case, we issue a duplicate identifier error, because // it's unclear what that's supposed to mean, so it's probably a mistake. - if (s.valueDeclaration && exportedMember.valueDeclaration && getSourceFileOfNode(s.valueDeclaration) !== getSourceFileOfNode(exportedMember.valueDeclaration)) { - const unescapedName = unescapeLeadingUnderscores(s.escapedName); - const exportedMemberName = tryCast(exportedMember.valueDeclaration, isNamedDeclaration)?.name || exportedMember.valueDeclaration; + if ( + s.valueDeclaration && + exportedMember.valueDeclaration && + getSourceFileOfNode(s.valueDeclaration) !== + getSourceFileOfNode( + exportedMember.valueDeclaration + ) + ) { + const unescapedName = unescapeLeadingUnderscores( + s.escapedName + ); + const exportedMemberName = + tryCast( + exportedMember.valueDeclaration, + isNamedDeclaration + )?.name || exportedMember.valueDeclaration; addRelatedInfo( - error(s.valueDeclaration, Diagnostics.Duplicate_identifier_0, unescapedName), - createDiagnosticForNode(exportedMemberName, Diagnostics._0_was_also_declared_here, unescapedName), + error( + s.valueDeclaration, + Diagnostics.Duplicate_identifier_0, + unescapedName + ), + createDiagnosticForNode( + exportedMemberName, + Diagnostics._0_was_also_declared_here, + unescapedName + ) ); addRelatedInfo( - error(exportedMemberName, Diagnostics.Duplicate_identifier_0, unescapedName), - createDiagnosticForNode(s.valueDeclaration, Diagnostics._0_was_also_declared_here, unescapedName), + error( + exportedMemberName, + Diagnostics.Duplicate_identifier_0, + unescapedName + ), + createDiagnosticForNode( + s.valueDeclaration, + Diagnostics._0_was_also_declared_here, + unescapedName + ) ); } - const union = createSymbol(s.flags | exportedMember.flags, name); - union.links.type = getUnionType([getTypeOfSymbol(s), getTypeOfSymbol(exportedMember)]); - union.valueDeclaration = exportedMember.valueDeclaration; - union.declarations = concatenate(exportedMember.declarations, s.declarations); + const union = createSymbol( + s.flags | exportedMember.flags, + name + ); + union.links.type = getUnionType([ + getTypeOfSymbol(s), + getTypeOfSymbol(exportedMember), + ]); + union.valueDeclaration = + exportedMember.valueDeclaration; + union.declarations = concatenate( + exportedMember.declarations, + s.declarations + ); members.set(name, union); - } - else { + } else { members.set(name, mergeSymbol(s, exportedMember)); } - } - else { + } else { members.set(name, s); } }); @@ -12171,7 +21423,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { members, exportedType.callSignatures, exportedType.constructSignatures, - exportedType.indexInfos, + exportedType.indexInfos ); if (initialSize === members.size) { if (type.aliasSymbol) { @@ -12184,8 +21436,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { result.aliasTypeArguments = length(args) ? args : undefined; } } - result.objectFlags |= getPropagatingFlagsOfTypes([type]) | getObjectFlags(type) & (ObjectFlags.JSLiteral | ObjectFlags.ArrayLiteral | ObjectFlags.ObjectLiteral); - if (result.symbol && result.symbol.flags & SymbolFlags.Class && type === getDeclaredTypeOfClassOrInterface(result.symbol)) { + result.objectFlags |= + getPropagatingFlagsOfTypes([type]) | + (getObjectFlags(type) & + (ObjectFlags.JSLiteral | + ObjectFlags.ArrayLiteral | + ObjectFlags.ObjectLiteral)); + if ( + result.symbol && + result.symbol.flags & SymbolFlags.Class && + type === getDeclaredTypeOfClassOrInterface(result.symbol) + ) { result.objectFlags |= ObjectFlags.IsClassInstanceClone; // Propagate the knowledge that this type is equivalent to the symbol's class instance type } return result; @@ -12197,27 +21458,47 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return type; } - function containsSameNamedThisProperty(thisProperty: Expression, expression: Expression) { - return isPropertyAccessExpression(thisProperty) - && thisProperty.expression.kind === SyntaxKind.ThisKeyword - && forEachChildRecursively(expression, n => isMatchingReference(thisProperty, n)); + function containsSameNamedThisProperty( + thisProperty: Expression, + expression: Expression + ) { + return ( + isPropertyAccessExpression(thisProperty) && + thisProperty.expression.kind === SyntaxKind.ThisKeyword && + forEachChildRecursively(expression, (n) => + isMatchingReference(thisProperty, n) + ) + ); } function isDeclarationInConstructor(expression: Expression) { - const thisContainer = getThisContainer(expression, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); + const thisContainer = getThisContainer( + expression, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false + ); // Properties defined in a constructor (or base constructor, or javascript constructor function) don't get undefined added. // Function expressions that are assigned to the prototype count as methods. - return thisContainer.kind === SyntaxKind.Constructor || + return ( + thisContainer.kind === SyntaxKind.Constructor || thisContainer.kind === SyntaxKind.FunctionDeclaration || - (thisContainer.kind === SyntaxKind.FunctionExpression && !isPrototypePropertyAssignment(thisContainer.parent)); + (thisContainer.kind === SyntaxKind.FunctionExpression && + !isPrototypePropertyAssignment(thisContainer.parent)) + ); } - function getConstructorDefinedThisAssignmentTypes(types: Type[], declarations: Declaration[]): Type[] | undefined { + function getConstructorDefinedThisAssignmentTypes( + types: Type[], + declarations: Declaration[] + ): Type[] | undefined { Debug.assert(types.length === declarations.length); return types.filter((_, i) => { const declaration = declarations[i]; - const expression = isBinaryExpression(declaration) ? declaration : - isBinaryExpression(declaration.parent) ? declaration.parent : undefined; + const expression = isBinaryExpression(declaration) + ? declaration + : isBinaryExpression(declaration.parent) + ? declaration.parent + : undefined; return expression && isDeclarationInConstructor(expression); }); } @@ -12225,18 +21506,44 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Return the type implied by a binding pattern element. This is the type of the initializer of the element if // one is present. Otherwise, if the element is itself a binding pattern, it is the type implied by the binding // pattern. Otherwise, it is the type any. - function getTypeFromBindingElement(element: BindingElement, includePatternInType?: boolean, reportErrors?: boolean): Type { + function getTypeFromBindingElement( + element: BindingElement, + includePatternInType?: boolean, + reportErrors?: boolean + ): Type { if (element.initializer) { // The type implied by a binding pattern is independent of context, so we check the initializer with no // contextual type or, if the element itself is a binding pattern, with the type implied by that binding // pattern. - const contextualType = isBindingPattern(element.name) ? getTypeFromBindingPattern(element.name, /*includePatternInType*/ true, /*reportErrors*/ false) : unknownType; - return addOptionality(getWidenedLiteralTypeForInitializer(element, checkDeclarationInitializer(element, CheckMode.Normal, contextualType))); + const contextualType = isBindingPattern(element.name) + ? getTypeFromBindingPattern( + element.name, + /*includePatternInType*/ true, + /*reportErrors*/ false + ) + : unknownType; + return addOptionality( + getWidenedLiteralTypeForInitializer( + element, + checkDeclarationInitializer( + element, + CheckMode.Normal, + contextualType + ) + ) + ); } if (isBindingPattern(element.name)) { - return getTypeFromBindingPattern(element.name, includePatternInType, reportErrors); + return getTypeFromBindingPattern( + element.name, + includePatternInType, + reportErrors + ); } - if (reportErrors && !declarationBelongsToPrivateAmbientMember(element)) { + if ( + reportErrors && + !declarationBelongsToPrivateAmbientMember(element) + ) { reportImplicitAny(element, anyType); } // When we're including the pattern in the type (an indication we're obtaining a contextual type), we @@ -12247,30 +21554,53 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Return the type implied by an object binding pattern - function getTypeFromObjectBindingPattern(pattern: ObjectBindingPattern, includePatternInType: boolean, reportErrors: boolean): Type { + function getTypeFromObjectBindingPattern( + pattern: ObjectBindingPattern, + includePatternInType: boolean, + reportErrors: boolean + ): Type { const members = createSymbolTable(); let stringIndexInfo: IndexInfo | undefined; - let objectFlags = ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral; - forEach(pattern.elements, e => { - const name = e.propertyName || e.name as Identifier; + let objectFlags = + ObjectFlags.ObjectLiteral | + ObjectFlags.ContainsObjectOrArrayLiteral; + forEach(pattern.elements, (e) => { + const name = e.propertyName || (e.name as Identifier); if (e.dotDotDotToken) { - stringIndexInfo = createIndexInfo(stringType, anyType, /*isReadonly*/ false); + stringIndexInfo = createIndexInfo( + stringType, + anyType, + /*isReadonly*/ false + ); return; } const exprType = getLiteralTypeFromPropertyName(name); if (!isTypeUsableAsPropertyName(exprType)) { // do not include computed properties in the implied type - objectFlags |= ObjectFlags.ObjectLiteralPatternWithComputedProperties; + objectFlags |= + ObjectFlags.ObjectLiteralPatternWithComputedProperties; return; } const text = getPropertyNameFromType(exprType); - const flags = SymbolFlags.Property | (e.initializer ? SymbolFlags.Optional : 0); + const flags = + SymbolFlags.Property | + (e.initializer ? SymbolFlags.Optional : 0); const symbol = createSymbol(flags, text); - symbol.links.type = getTypeFromBindingElement(e, includePatternInType, reportErrors); + symbol.links.type = getTypeFromBindingElement( + e, + includePatternInType, + reportErrors + ); members.set(symbol.escapedName, symbol); }); - const result = createAnonymousType(/*symbol*/ undefined, members, emptyArray, emptyArray, stringIndexInfo ? [stringIndexInfo] : emptyArray); + const result = createAnonymousType( + /*symbol*/ undefined, + members, + emptyArray, + emptyArray, + stringIndexInfo ? [stringIndexInfo] : emptyArray + ); result.objectFlags |= objectFlags; if (includePatternInType) { result.pattern = pattern; @@ -12280,17 +21610,55 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Return the type implied by an array binding pattern - function getTypeFromArrayBindingPattern(pattern: BindingPattern, includePatternInType: boolean, reportErrors: boolean): Type { + function getTypeFromArrayBindingPattern( + pattern: BindingPattern, + includePatternInType: boolean, + reportErrors: boolean + ): Type { const elements = pattern.elements; const lastElement = lastOrUndefined(elements); - const restElement = lastElement && lastElement.kind === SyntaxKind.BindingElement && lastElement.dotDotDotToken ? lastElement : undefined; - if (elements.length === 0 || elements.length === 1 && restElement) { - return languageVersion >= ScriptTarget.ES2015 ? createIterableType(anyType) : anyArrayType; - } - const elementTypes = map(elements, e => isOmittedExpression(e) ? anyType : getTypeFromBindingElement(e, includePatternInType, reportErrors)); - const minLength = findLastIndex(elements, e => !(e === restElement || isOmittedExpression(e) || hasDefaultValue(e)), elements.length - 1) + 1; - const elementFlags = map(elements, (e, i) => e === restElement ? ElementFlags.Rest : i >= minLength ? ElementFlags.Optional : ElementFlags.Required); - let result = createTupleType(elementTypes, elementFlags) as TypeReference; + const restElement = + lastElement && + lastElement.kind === SyntaxKind.BindingElement && + lastElement.dotDotDotToken + ? lastElement + : undefined; + if (elements.length === 0 || (elements.length === 1 && restElement)) { + return languageVersion >= ScriptTarget.ES2015 + ? createIterableType(anyType) + : anyArrayType; + } + const elementTypes = map(elements, (e) => + isOmittedExpression(e) + ? anyType + : getTypeFromBindingElement( + e, + includePatternInType, + reportErrors + ) + ); + const minLength = + findLastIndex( + elements, + (e) => + !( + e === restElement || + isOmittedExpression(e) || + hasDefaultValue(e) + ), + elements.length - 1 + ) + 1; + const elementFlags = map(elements, (e, i) => + e === restElement + ? ElementFlags.Rest + : i >= minLength + ? ElementFlags.Optional + : ElementFlags.Required + ); + let result = createTupleType( + elementTypes, + elementFlags + ) as TypeReference; if (includePatternInType) { result = cloneTypeReference(result); result.pattern = pattern; @@ -12306,11 +21674,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // used as the contextual type of an initializer associated with the binding pattern. Also, for a destructuring // parameter with no type annotation or initializer, the type implied by the binding pattern becomes the type of // the parameter. - function getTypeFromBindingPattern(pattern: BindingPattern, includePatternInType = false, reportErrors = false): Type { + function getTypeFromBindingPattern( + pattern: BindingPattern, + includePatternInType = false, + reportErrors = false + ): Type { if (includePatternInType) contextualBindingPatterns.push(pattern); - const result = pattern.kind === SyntaxKind.ObjectBindingPattern - ? getTypeFromObjectBindingPattern(pattern, includePatternInType, reportErrors) - : getTypeFromArrayBindingPattern(pattern, includePatternInType, reportErrors); + const result = + pattern.kind === SyntaxKind.ObjectBindingPattern + ? getTypeFromObjectBindingPattern( + pattern, + includePatternInType, + reportErrors + ) + : getTypeFromArrayBindingPattern( + pattern, + includePatternInType, + reportErrors + ); if (includePatternInType) contextualBindingPatterns.pop(); return result; } @@ -12324,24 +21705,54 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Here, the array literal [1, "one"] is contextually typed by the type [any, string], which is the implied type of the // binding pattern [x, s = ""]. Because the contextual type is a tuple type, the resulting type of [1, "one"] is the // tuple type [number, string]. Thus, the type inferred for 'x' is number and the type inferred for 's' is string. - function getWidenedTypeForVariableLikeDeclaration(declaration: ParameterDeclaration | PropertyDeclaration | PropertySignature | VariableDeclaration | BindingElement | JSDocPropertyLikeTag, reportErrors?: boolean): Type { - return widenTypeForVariableLikeDeclaration(getTypeForVariableLikeDeclaration(declaration, /*includeOptionality*/ true, CheckMode.Normal), declaration, reportErrors); + function getWidenedTypeForVariableLikeDeclaration( + declaration: + | ParameterDeclaration + | PropertyDeclaration + | PropertySignature + | VariableDeclaration + | BindingElement + | JSDocPropertyLikeTag, + reportErrors?: boolean + ): Type { + return widenTypeForVariableLikeDeclaration( + getTypeForVariableLikeDeclaration( + declaration, + /*includeOptionality*/ true, + CheckMode.Normal + ), + declaration, + reportErrors + ); } function getTypeFromImportAttributes(node: ImportAttributes): Type { const links = getNodeLinks(node); if (!links.resolvedType) { - const symbol = createSymbol(SymbolFlags.ObjectLiteral, InternalSymbolName.ImportAttributes); + const symbol = createSymbol( + SymbolFlags.ObjectLiteral, + InternalSymbolName.ImportAttributes + ); const members = createSymbolTable(); - forEach(node.elements, attr => { - const member = createSymbol(SymbolFlags.Property, getNameFromImportAttribute(attr)); + forEach(node.elements, (attr) => { + const member = createSymbol( + SymbolFlags.Property, + getNameFromImportAttribute(attr) + ); member.parent = symbol; member.links.type = checkImportAttribute(attr); member.links.target = member; members.set(member.escapedName, member); }); - const type = createAnonymousType(symbol, members, emptyArray, emptyArray, emptyArray); - type.objectFlags |= ObjectFlags.ObjectLiteral | ObjectFlags.NonInferrableType; + const type = createAnonymousType( + symbol, + members, + emptyArray, + emptyArray, + emptyArray + ); + type.objectFlags |= + ObjectFlags.ObjectLiteral | ObjectFlags.NonInferrableType; links.resolvedType = type; } return links.resolvedType; @@ -12349,14 +21760,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isGlobalSymbolConstructor(node: Node) { const symbol = getSymbolOfNode(node); - const globalSymbol = getGlobalESSymbolConstructorTypeSymbol(/*reportErrors*/ false); + const globalSymbol = getGlobalESSymbolConstructorTypeSymbol( + /*reportErrors*/ false + ); return globalSymbol && symbol && symbol === globalSymbol; } - function widenTypeForVariableLikeDeclaration(type: Type | undefined, declaration: any, reportErrors?: boolean) { + function widenTypeForVariableLikeDeclaration( + type: Type | undefined, + declaration: any, + reportErrors?: boolean + ) { if (type) { // 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` - if (type.flags & TypeFlags.ESSymbol && isGlobalSymbolConstructor(declaration.parent)) { + if ( + type.flags & TypeFlags.ESSymbol && + isGlobalSymbolConstructor(declaration.parent) + ) { type = getESSymbolLikeTypeForNode(declaration); } if (reportErrors) { @@ -12364,7 +21784,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // always widen a 'unique symbol' type if the type was created for a different declaration. - if (type.flags & TypeFlags.UniqueESSymbol && (isBindingElement(declaration) || !tryGetTypeFromEffectiveTypeNode(declaration)) && type.symbol !== getSymbolOfDeclaration(declaration)) { + if ( + type.flags & TypeFlags.UniqueESSymbol && + (isBindingElement(declaration) || + !tryGetTypeFromEffectiveTypeNode(declaration)) && + type.symbol !== getSymbolOfDeclaration(declaration) + ) { type = esSymbolType; } @@ -12372,7 +21797,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Rest parameters default to type any[], other parameters default to type any - type = isParameter(declaration) && declaration.dotDotDotToken ? anyArrayType : anyType; + type = + isParameter(declaration) && declaration.dotDotDotToken + ? anyArrayType + : anyType; // Report implicit any errors unless this is a private property within an ambient declaration if (reportErrors) { @@ -12383,9 +21811,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return type; } - function declarationBelongsToPrivateAmbientMember(declaration: VariableLikeDeclaration) { + function declarationBelongsToPrivateAmbientMember( + declaration: VariableLikeDeclaration + ) { const root = getRootDeclaration(declaration); - const memberDeclaration = root.kind === SyntaxKind.Parameter ? root.parent : root; + const memberDeclaration = + root.kind === SyntaxKind.Parameter ? root.parent : root; return isPrivateWithinAmbient(memberDeclaration); } @@ -12419,7 +21850,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // to preserve this type. In fact, we need to _prefer_ that type, but it won't // be assigned until contextual typing is complete, so we need to defer in // cases where contextual typing may take place. - if (!links.type && !isParameterOfContextSensitiveSignature(symbol)) { + if ( + !links.type && + !isParameterOfContextSensitiveSignature(symbol) + ) { links.type = type; } return type; @@ -12427,7 +21861,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return links.type; } - function getTypeOfVariableOrParameterOrPropertyWorker(symbol: Symbol): Type { + function getTypeOfVariableOrParameterOrPropertyWorker( + symbol: Symbol + ): Type { // Handle prototype property if (symbol.flags & SymbolFlags.Prototype) { return getTypeOfPrototypeProperty(symbol); @@ -12436,18 +21872,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (symbol === requireSymbol) { return anyType; } - if (symbol.flags & SymbolFlags.ModuleExports && symbol.valueDeclaration) { - const fileSymbol = getSymbolOfDeclaration(getSourceFileOfNode(symbol.valueDeclaration)); - const result = createSymbol(fileSymbol.flags, "exports" as __String); - result.declarations = fileSymbol.declarations ? fileSymbol.declarations.slice() : []; + if ( + symbol.flags & SymbolFlags.ModuleExports && + symbol.valueDeclaration + ) { + const fileSymbol = getSymbolOfDeclaration( + getSourceFileOfNode(symbol.valueDeclaration) + ); + const result = createSymbol( + fileSymbol.flags, + "exports" as __String + ); + result.declarations = fileSymbol.declarations + ? fileSymbol.declarations.slice() + : []; result.parent = symbol; result.links.target = fileSymbol; - if (fileSymbol.valueDeclaration) result.valueDeclaration = fileSymbol.valueDeclaration; - if (fileSymbol.members) result.members = new Map(fileSymbol.members); - if (fileSymbol.exports) result.exports = new Map(fileSymbol.exports); + if (fileSymbol.valueDeclaration) + result.valueDeclaration = fileSymbol.valueDeclaration; + if (fileSymbol.members) + result.members = new Map(fileSymbol.members); + if (fileSymbol.exports) + result.exports = new Map(fileSymbol.exports); const members = createSymbolTable(); members.set("exports" as __String, result); - return createAnonymousType(symbol, members, emptyArray, emptyArray, emptyArray); + return createAnonymousType( + symbol, + members, + emptyArray, + emptyArray, + emptyArray + ); } Debug.assertIsDefined(symbol.valueDeclaration); const declaration = symbol.valueDeclaration; @@ -12456,7 +21911,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!declaration.statements.length) { return emptyObjectType; } - return getWidenedType(getWidenedLiteralType(checkExpression(declaration.statements[0].expression))); + return getWidenedType( + getWidenedLiteralType( + checkExpression(declaration.statements[0].expression) + ) + ); } if (isAccessor(declaration)) { // Binding of certain patterns in JS code will occasionally mark symbols as both properties @@ -12467,79 +21926,112 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Handle variable, parameter or property if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) { // Symbol is property of some kind that is merged with something - should use `getTypeOfFuncClassEnumModule` and not `getTypeOfVariableOrParameterOrProperty` - if (symbol.flags & SymbolFlags.ValueModule && !(symbol.flags & SymbolFlags.Assignment)) { + if ( + symbol.flags & SymbolFlags.ValueModule && + !(symbol.flags & SymbolFlags.Assignment) + ) { return getTypeOfFuncClassEnumModule(symbol); } return reportCircularityError(symbol); } let type: Type; if (declaration.kind === SyntaxKind.ExportAssignment) { - type = widenTypeForVariableLikeDeclaration(tryGetTypeFromEffectiveTypeNode(declaration) || checkExpressionCached((declaration as ExportAssignment).expression), declaration); - } - else if ( + type = widenTypeForVariableLikeDeclaration( + tryGetTypeFromEffectiveTypeNode(declaration) || + checkExpressionCached( + (declaration as ExportAssignment).expression + ), + declaration + ); + } else if ( isBinaryExpression(declaration) || (isInJSFile(declaration) && - (isCallExpression(declaration) || (isPropertyAccessExpression(declaration) || isBindableStaticElementAccessExpression(declaration)) && isBinaryExpression(declaration.parent))) + (isCallExpression(declaration) || + ((isPropertyAccessExpression(declaration) || + isBindableStaticElementAccessExpression(declaration)) && + isBinaryExpression(declaration.parent)))) ) { type = getWidenedTypeForAssignmentDeclaration(symbol); - } - else if ( - isPropertyAccessExpression(declaration) - || isElementAccessExpression(declaration) - || isIdentifier(declaration) - || isStringLiteralLike(declaration) - || isNumericLiteral(declaration) - || isClassDeclaration(declaration) - || isFunctionDeclaration(declaration) - || (isMethodDeclaration(declaration) && !isObjectLiteralMethod(declaration)) - || isMethodSignature(declaration) - || isSourceFile(declaration) + } else if ( + isPropertyAccessExpression(declaration) || + isElementAccessExpression(declaration) || + isIdentifier(declaration) || + isStringLiteralLike(declaration) || + isNumericLiteral(declaration) || + isClassDeclaration(declaration) || + isFunctionDeclaration(declaration) || + (isMethodDeclaration(declaration) && + !isObjectLiteralMethod(declaration)) || + isMethodSignature(declaration) || + isSourceFile(declaration) ) { // Symbol is property of some kind that is merged with something - should use `getTypeOfFuncClassEnumModule` and not `getTypeOfVariableOrParameterOrProperty` - if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) { + if ( + symbol.flags & + (SymbolFlags.Function | + SymbolFlags.Method | + SymbolFlags.Class | + SymbolFlags.Enum | + SymbolFlags.ValueModule) + ) { return getTypeOfFuncClassEnumModule(symbol); } - type = isBinaryExpression(declaration.parent) ? - getWidenedTypeForAssignmentDeclaration(symbol) : - tryGetTypeFromEffectiveTypeNode(declaration) || anyType; - } - else if (isPropertyAssignment(declaration)) { - type = tryGetTypeFromEffectiveTypeNode(declaration) || checkPropertyAssignment(declaration); - } - else if (isJsxAttribute(declaration)) { - type = tryGetTypeFromEffectiveTypeNode(declaration) || checkJsxAttribute(declaration); - } - else if (isShorthandPropertyAssignment(declaration)) { - type = tryGetTypeFromEffectiveTypeNode(declaration) || checkExpressionForMutableLocation(declaration.name, CheckMode.Normal); - } - else if (isObjectLiteralMethod(declaration)) { - type = tryGetTypeFromEffectiveTypeNode(declaration) || checkObjectLiteralMethod(declaration, CheckMode.Normal); - } - else if ( - isParameter(declaration) - || isPropertyDeclaration(declaration) - || isPropertySignature(declaration) - || isVariableDeclaration(declaration) - || isBindingElement(declaration) - || isJSDocPropertyLikeTag(declaration) + type = isBinaryExpression(declaration.parent) + ? getWidenedTypeForAssignmentDeclaration(symbol) + : tryGetTypeFromEffectiveTypeNode(declaration) || anyType; + } else if (isPropertyAssignment(declaration)) { + type = + tryGetTypeFromEffectiveTypeNode(declaration) || + checkPropertyAssignment(declaration); + } else if (isJsxAttribute(declaration)) { + type = + tryGetTypeFromEffectiveTypeNode(declaration) || + checkJsxAttribute(declaration); + } else if (isShorthandPropertyAssignment(declaration)) { + type = + tryGetTypeFromEffectiveTypeNode(declaration) || + checkExpressionForMutableLocation( + declaration.name, + CheckMode.Normal + ); + } else if (isObjectLiteralMethod(declaration)) { + type = + tryGetTypeFromEffectiveTypeNode(declaration) || + checkObjectLiteralMethod(declaration, CheckMode.Normal); + } else if ( + isParameter(declaration) || + isPropertyDeclaration(declaration) || + isPropertySignature(declaration) || + isVariableDeclaration(declaration) || + isBindingElement(declaration) || + isJSDocPropertyLikeTag(declaration) ) { - type = getWidenedTypeForVariableLikeDeclaration(declaration, /*reportErrors*/ true); + type = getWidenedTypeForVariableLikeDeclaration( + declaration, + /*reportErrors*/ true + ); } // getTypeOfSymbol dispatches some JS merges incorrectly because their symbol flags are not mutually exclusive. // Re-dispatch based on valueDeclaration.kind instead. else if (isEnumDeclaration(declaration)) { type = getTypeOfFuncClassEnumModule(symbol); - } - else if (isEnumMember(declaration)) { + } else if (isEnumMember(declaration)) { type = getTypeOfEnumMember(symbol); - } - else { - return Debug.fail("Unhandled declaration kind! " + Debug.formatSyntaxKind(declaration.kind) + " for " + Debug.formatSymbol(symbol)); + } else { + return Debug.fail( + "Unhandled declaration kind! " + + Debug.formatSyntaxKind(declaration.kind) + + " for " + + Debug.formatSymbol(symbol) + ); } if (!popTypeResolution()) { // Symbol is property of some kind that is merged with something - should use `getTypeOfFuncClassEnumModule` and not `getTypeOfVariableOrParameterOrProperty` - if (symbol.flags & SymbolFlags.ValueModule && !(symbol.flags & SymbolFlags.Assignment)) { + if ( + symbol.flags & SymbolFlags.ValueModule && + !(symbol.flags & SymbolFlags.Assignment) + ) { return getTypeOfFuncClassEnumModule(symbol); } return reportCircularityError(symbol); @@ -12547,35 +22039,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return type; } - function getAnnotatedAccessorTypeNode(accessor: AccessorDeclaration | PropertyDeclaration | undefined): TypeNode | undefined { + function getAnnotatedAccessorTypeNode( + accessor: AccessorDeclaration | PropertyDeclaration | undefined + ): TypeNode | undefined { if (accessor) { switch (accessor.kind) { case SyntaxKind.GetAccessor: - const getterTypeAnnotation = getEffectiveReturnTypeNode(accessor); + const getterTypeAnnotation = + getEffectiveReturnTypeNode(accessor); return getterTypeAnnotation; case SyntaxKind.SetAccessor: - const setterTypeAnnotation = getEffectiveSetAccessorTypeAnnotationNode(accessor); + const setterTypeAnnotation = + getEffectiveSetAccessorTypeAnnotationNode(accessor); return setterTypeAnnotation; case SyntaxKind.PropertyDeclaration: Debug.assert(hasAccessorModifier(accessor)); - const accessorTypeAnnotation = getEffectiveTypeAnnotationNode(accessor); + const accessorTypeAnnotation = + getEffectiveTypeAnnotationNode(accessor); return accessorTypeAnnotation; } } return undefined; } - function getAnnotatedAccessorType(accessor: AccessorDeclaration | PropertyDeclaration | undefined): Type | undefined { + function getAnnotatedAccessorType( + accessor: AccessorDeclaration | PropertyDeclaration | undefined + ): Type | undefined { const node = getAnnotatedAccessorTypeNode(accessor); return node && getTypeFromTypeNode(node); } - function getAnnotatedAccessorThisParameter(accessor: AccessorDeclaration): Symbol | undefined { + function getAnnotatedAccessorThisParameter( + accessor: AccessorDeclaration + ): Symbol | undefined { const parameter = getAccessorThisParameter(accessor); return parameter && parameter.symbol; } - function getThisTypeOfDeclaration(declaration: SignatureDeclaration): Type | undefined { + function getThisTypeOfDeclaration( + declaration: SignatureDeclaration + ): Type | undefined { return getThisTypeOfSignature(getSignatureFromDeclaration(declaration)); } @@ -12585,42 +22088,88 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) { return errorType; } - const getter = getDeclarationOfKind(symbol, SyntaxKind.GetAccessor); - const setter = getDeclarationOfKind(symbol, SyntaxKind.SetAccessor); - const accessor = tryCast(getDeclarationOfKind(symbol, SyntaxKind.PropertyDeclaration), isAutoAccessorPropertyDeclaration); + const getter = getDeclarationOfKind( + symbol, + SyntaxKind.GetAccessor + ); + const setter = getDeclarationOfKind( + symbol, + SyntaxKind.SetAccessor + ); + const accessor = tryCast( + getDeclarationOfKind( + symbol, + SyntaxKind.PropertyDeclaration + ), + isAutoAccessorPropertyDeclaration + ); // We try to resolve a getter type annotation, a setter type annotation, or a getter function // body return type inference, in that order. - let type = getter && isInJSFile(getter) && getTypeForDeclarationFromJSDocComment(getter) || + let type = + (getter && + isInJSFile(getter) && + getTypeForDeclarationFromJSDocComment(getter)) || getAnnotatedAccessorType(getter) || getAnnotatedAccessorType(setter) || getAnnotatedAccessorType(accessor) || - getter && getter.body && getReturnTypeFromBody(getter) || - accessor && getWidenedTypeForVariableLikeDeclaration(accessor, /*reportErrors*/ true); + (getter && getter.body && getReturnTypeFromBody(getter)) || + (accessor && + getWidenedTypeForVariableLikeDeclaration( + accessor, + /*reportErrors*/ true + )); if (!type) { if (setter && !isPrivateWithinAmbient(setter)) { - errorOrSuggestion(noImplicitAny, setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation, symbolToString(symbol)); - } - else if (getter && !isPrivateWithinAmbient(getter)) { - errorOrSuggestion(noImplicitAny, getter, Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation, symbolToString(symbol)); - } - else if (accessor && !isPrivateWithinAmbient(accessor)) { - errorOrSuggestion(noImplicitAny, accessor, Diagnostics.Member_0_implicitly_has_an_1_type, symbolToString(symbol), "any"); + errorOrSuggestion( + noImplicitAny, + setter, + Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation, + symbolToString(symbol) + ); + } else if (getter && !isPrivateWithinAmbient(getter)) { + errorOrSuggestion( + noImplicitAny, + getter, + Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation, + symbolToString(symbol) + ); + } else if (accessor && !isPrivateWithinAmbient(accessor)) { + errorOrSuggestion( + noImplicitAny, + accessor, + Diagnostics.Member_0_implicitly_has_an_1_type, + symbolToString(symbol), + "any" + ); } type = anyType; } if (!popTypeResolution()) { if (getAnnotatedAccessorTypeNode(getter)) { - error(getter, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol)); - } - else if (getAnnotatedAccessorTypeNode(setter)) { - error(setter, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol)); - } - else if (getAnnotatedAccessorTypeNode(accessor)) { - error(setter, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol)); - } - else if (getter && noImplicitAny) { - 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)); + error( + getter, + Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, + symbolToString(symbol) + ); + } else if (getAnnotatedAccessorTypeNode(setter)) { + error( + setter, + Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, + symbolToString(symbol) + ); + } else if (getAnnotatedAccessorTypeNode(accessor)) { + error( + setter, + Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, + symbolToString(symbol) + ); + } else if (getter && noImplicitAny) { + 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) + ); } type = anyType; } @@ -12636,12 +22185,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return errorType; } - const setter = getDeclarationOfKind(symbol, SyntaxKind.SetAccessor) - ?? tryCast(getDeclarationOfKind(symbol, SyntaxKind.PropertyDeclaration), isAutoAccessorPropertyDeclaration); + const setter = + getDeclarationOfKind( + symbol, + SyntaxKind.SetAccessor + ) ?? + tryCast( + getDeclarationOfKind( + symbol, + SyntaxKind.PropertyDeclaration + ), + isAutoAccessorPropertyDeclaration + ); let writeType = getAnnotatedAccessorType(setter); if (!popTypeResolution()) { if (getAnnotatedAccessorTypeNode(setter)) { - error(setter, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol)); + error( + setter, + Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, + symbolToString(symbol) + ); } writeType = anyType; } @@ -12652,17 +22215,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getBaseTypeVariableOfClass(symbol: Symbol) { - const baseConstructorType = getBaseConstructorTypeOfClass(getDeclaredTypeOfClassOrInterface(symbol)); - return baseConstructorType.flags & TypeFlags.TypeVariable ? baseConstructorType : - baseConstructorType.flags & TypeFlags.Intersection ? find((baseConstructorType as IntersectionType).types, t => !!(t.flags & TypeFlags.TypeVariable)) : - undefined; + const baseConstructorType = getBaseConstructorTypeOfClass( + getDeclaredTypeOfClassOrInterface(symbol) + ); + return baseConstructorType.flags & TypeFlags.TypeVariable + ? baseConstructorType + : baseConstructorType.flags & TypeFlags.Intersection + ? find( + (baseConstructorType as IntersectionType).types, + (t) => !!(t.flags & TypeFlags.TypeVariable) + ) + : undefined; } function getTypeOfFuncClassEnumModule(symbol: Symbol): Type { let links = getSymbolLinks(symbol); const originalLinks = links; if (!links.type) { - const expando = symbol.valueDeclaration && getSymbolOfExpando(symbol.valueDeclaration, /*allowDeclaration*/ false); + const expando = + symbol.valueDeclaration && + getSymbolOfExpando( + symbol.valueDeclaration, + /*allowDeclaration*/ false + ); if (expando) { const merged = mergeJSSymbols(symbol, expando); if (merged) { @@ -12671,31 +22246,44 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { links = merged.links; } } - originalLinks.type = links.type = getTypeOfFuncClassEnumModuleWorker(symbol); + originalLinks.type = links.type = + getTypeOfFuncClassEnumModuleWorker(symbol); } return links.type; } function getTypeOfFuncClassEnumModuleWorker(symbol: Symbol): Type { const declaration = symbol.valueDeclaration; - if (symbol.flags & SymbolFlags.Module && isShorthandAmbientModuleSymbol(symbol)) { + if ( + symbol.flags & SymbolFlags.Module && + isShorthandAmbientModuleSymbol(symbol) + ) { return anyType; - } - else if ( - declaration && (declaration.kind === SyntaxKind.BinaryExpression || - isAccessExpression(declaration) && - declaration.parent.kind === SyntaxKind.BinaryExpression) + } else if ( + declaration && + (declaration.kind === SyntaxKind.BinaryExpression || + (isAccessExpression(declaration) && + declaration.parent.kind === SyntaxKind.BinaryExpression)) ) { return getWidenedTypeForAssignmentDeclaration(symbol); - } - else if (symbol.flags & SymbolFlags.ValueModule && declaration && isSourceFile(declaration) && declaration.commonJsModuleIndicator) { + } else if ( + symbol.flags & SymbolFlags.ValueModule && + declaration && + isSourceFile(declaration) && + declaration.commonJsModuleIndicator + ) { const resolvedModule = resolveExternalModuleSymbol(symbol); if (resolvedModule !== symbol) { if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) { return errorType; } - const exportEquals = getMergedSymbol(symbol.exports!.get(InternalSymbolName.ExportEquals)!); - const type = getWidenedTypeForAssignmentDeclaration(exportEquals, exportEquals === resolvedModule ? undefined : resolvedModule); + const exportEquals = getMergedSymbol( + symbol.exports!.get(InternalSymbolName.ExportEquals)! + ); + const type = getWidenedTypeForAssignmentDeclaration( + exportEquals, + exportEquals === resolvedModule ? undefined : resolvedModule + ); if (!popTypeResolution()) { return reportCircularityError(symbol); } @@ -12705,10 +22293,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const type = createObjectType(ObjectFlags.Anonymous, symbol); if (symbol.flags & SymbolFlags.Class) { const baseTypeVariable = getBaseTypeVariableOfClass(symbol); - return baseTypeVariable ? getIntersectionType([type, baseTypeVariable]) : type; - } - else { - return strictNullChecks && symbol.flags & SymbolFlags.Optional ? getOptionalType(type, /*isProperty*/ true) : type; + return baseTypeVariable + ? getIntersectionType([type, baseTypeVariable]) + : type; + } else { + return strictNullChecks && symbol.flags & SymbolFlags.Optional + ? getOptionalType(type, /*isProperty*/ true) + : type; } } @@ -12724,23 +22315,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return errorType; } const targetSymbol = resolveAlias(symbol); - const exportSymbol = symbol.declarations && getTargetOfAliasDeclaration(getDeclarationOfAliasSymbol(symbol)!, /*dontRecursivelyResolve*/ true); - const declaredType = firstDefined(exportSymbol?.declarations, d => isExportAssignment(d) ? tryGetTypeFromEffectiveTypeNode(d) : undefined); + const exportSymbol = + symbol.declarations && + getTargetOfAliasDeclaration( + getDeclarationOfAliasSymbol(symbol)!, + /*dontRecursivelyResolve*/ true + ); + const declaredType = firstDefined(exportSymbol?.declarations, (d) => + isExportAssignment(d) + ? tryGetTypeFromEffectiveTypeNode(d) + : undefined + ); // It only makes sense to get the type of a value symbol. If the result of resolving // the alias is not a value, then it has no type. To get the type associated with a // type symbol, call getDeclaredTypeOfSymbol. // This check is important because without it, a call to getTypeOfSymbol could end // up recursively calling getTypeOfAlias, causing a stack overflow. - links.type ??= exportSymbol?.declarations && isDuplicatedCommonJSExport(exportSymbol.declarations) && symbol.declarations!.length ? getFlowTypeFromCommonJSExport(exportSymbol) - : isDuplicatedCommonJSExport(symbol.declarations) ? autoType - : declaredType ? declaredType - : getSymbolFlags(targetSymbol) & SymbolFlags.Value ? getTypeOfSymbol(targetSymbol) - : errorType; + links.type ??= + exportSymbol?.declarations && + isDuplicatedCommonJSExport(exportSymbol.declarations) && + symbol.declarations!.length + ? getFlowTypeFromCommonJSExport(exportSymbol) + : isDuplicatedCommonJSExport(symbol.declarations) + ? autoType + : declaredType + ? declaredType + : getSymbolFlags(targetSymbol) & SymbolFlags.Value + ? getTypeOfSymbol(targetSymbol) + : errorType; if (!popTypeResolution()) { reportCircularityError(exportSymbol ?? symbol); - return links.type ??= errorType; + return (links.type ??= errorType); } } return links.type; @@ -12748,12 +22355,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getTypeOfInstantiatedSymbol(symbol: Symbol): Type { const links = getSymbolLinks(symbol); - return links.type || (links.type = instantiateType(getTypeOfSymbol(links.target!), links.mapper)); + return ( + links.type || + (links.type = instantiateType( + getTypeOfSymbol(links.target!), + links.mapper + )) + ); } function getWriteTypeOfInstantiatedSymbol(symbol: Symbol): Type { const links = getSymbolLinks(symbol); - return links.writeType || (links.writeType = instantiateType(getWriteTypeOfSymbol(links.target!), links.mapper)); + return ( + links.writeType || + (links.writeType = instantiateType( + getWriteTypeOfSymbol(links.target!), + links.mapper + )) + ); } function reportCircularityError(symbol: Symbol) { @@ -12761,18 +22380,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Check if variable has type annotation that circularly references the variable itself if (declaration) { if (getEffectiveTypeAnnotationNode(declaration)) { - error(symbol.valueDeclaration, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol)); + error( + symbol.valueDeclaration, + Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, + symbolToString(symbol) + ); return errorType; } // Check if variable has initializer that circularly references the variable itself - if (noImplicitAny && (declaration.kind !== SyntaxKind.Parameter || (declaration as HasInitializer).initializer)) { - 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, symbolToString(symbol)); + if ( + noImplicitAny && + (declaration.kind !== SyntaxKind.Parameter || + (declaration as HasInitializer).initializer) + ) { + 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, + symbolToString(symbol) + ); } - } - else if (symbol.flags & SymbolFlags.Alias) { + } else if (symbol.flags & SymbolFlags.Alias) { const node = getDeclarationOfAliasSymbol(symbol); if (node) { - error(node, Diagnostics.Circular_definition_of_import_alias_0, symbolToString(symbol)); + error( + node, + Diagnostics.Circular_definition_of_import_alias_0, + symbolToString(symbol) + ); } } // Circularities could also result from parameters in function expressions that end up @@ -12786,17 +22420,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!links.type) { Debug.assertIsDefined(links.deferralParent); Debug.assertIsDefined(links.deferralConstituents); - links.type = links.deferralParent.flags & TypeFlags.Union ? getUnionType(links.deferralConstituents) : getIntersectionType(links.deferralConstituents); + links.type = + links.deferralParent.flags & TypeFlags.Union + ? getUnionType(links.deferralConstituents) + : getIntersectionType(links.deferralConstituents); } return links.type; } - function getWriteTypeOfSymbolWithDeferredType(symbol: Symbol): Type | undefined { + function getWriteTypeOfSymbolWithDeferredType( + symbol: Symbol + ): Type | undefined { const links = getSymbolLinks(symbol); if (!links.writeType && links.deferralWriteConstituents) { Debug.assertIsDefined(links.deferralParent); Debug.assertIsDefined(links.deferralConstituents); - links.writeType = links.deferralParent.flags & TypeFlags.Union ? getUnionType(links.deferralWriteConstituents) : getIntersectionType(links.deferralWriteConstituents); + links.writeType = + links.deferralParent.flags & TypeFlags.Union + ? getUnionType(links.deferralWriteConstituents) + : getIntersectionType(links.deferralWriteConstituents); } return links.writeType; } @@ -12809,17 +22451,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getWriteTypeOfSymbol(symbol: Symbol): Type { const checkFlags = getCheckFlags(symbol); if (symbol.flags & SymbolFlags.Property) { - return checkFlags & CheckFlags.SyntheticProperty ? - checkFlags & CheckFlags.DeferredType ? - getWriteTypeOfSymbolWithDeferredType(symbol) || getTypeOfSymbolWithDeferredType(symbol) : - // NOTE: cast to TransientSymbol should be safe because only TransientSymbols can have CheckFlags.SyntheticProperty - (symbol as TransientSymbol).links.writeType || (symbol as TransientSymbol).links.type! : - removeMissingType(getTypeOfSymbol(symbol), !!(symbol.flags & SymbolFlags.Optional)); + return checkFlags & CheckFlags.SyntheticProperty + ? checkFlags & CheckFlags.DeferredType + ? getWriteTypeOfSymbolWithDeferredType(symbol) || + getTypeOfSymbolWithDeferredType(symbol) + : // NOTE: cast to TransientSymbol should be safe because only TransientSymbols can have CheckFlags.SyntheticProperty + (symbol as TransientSymbol).links.writeType || + (symbol as TransientSymbol).links.type! + : removeMissingType( + getTypeOfSymbol(symbol), + !!(symbol.flags & SymbolFlags.Optional) + ); } if (symbol.flags & SymbolFlags.Accessor) { - return checkFlags & CheckFlags.Instantiated ? - getWriteTypeOfInstantiatedSymbol(symbol) : - getWriteTypeOfAccessors(symbol); + return checkFlags & CheckFlags.Instantiated + ? getWriteTypeOfInstantiatedSymbol(symbol) + : getWriteTypeOfAccessors(symbol); } return getTypeOfSymbol(symbol); } @@ -12841,7 +22488,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property)) { return getTypeOfVariableOrParameterOrProperty(symbol); } - if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) { + if ( + symbol.flags & + (SymbolFlags.Function | + SymbolFlags.Method | + SymbolFlags.Class | + SymbolFlags.Enum | + SymbolFlags.ValueModule) + ) { return getTypeOfFuncClassEnumModule(symbol); } if (symbol.flags & SymbolFlags.EnumMember) { @@ -12857,11 +22511,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getNonMissingTypeOfSymbol(symbol: Symbol) { - return removeMissingType(getTypeOfSymbol(symbol), !!(symbol.flags & SymbolFlags.Optional)); + return removeMissingType( + getTypeOfSymbol(symbol), + !!(symbol.flags & SymbolFlags.Optional) + ); } function isReferenceToSomeType(type: Type, targets: readonly Type[]) { - if (type === undefined || (getObjectFlags(type) & ObjectFlags.Reference) === 0) { + if ( + type === undefined || + (getObjectFlags(type) & ObjectFlags.Reference) === 0 + ) { return false; } for (const target of targets) { @@ -12873,25 +22533,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isReferenceToType(type: Type, target: Type) { - return type !== undefined - && target !== undefined - && (getObjectFlags(type) & ObjectFlags.Reference) !== 0 - && (type as TypeReference).target === target; + return ( + type !== undefined && + target !== undefined && + (getObjectFlags(type) & ObjectFlags.Reference) !== 0 && + (type as TypeReference).target === target + ); } function getTargetType(type: Type): Type { - return getObjectFlags(type) & ObjectFlags.Reference ? (type as TypeReference).target : type; + return getObjectFlags(type) & ObjectFlags.Reference + ? (type as TypeReference).target + : type; } // TODO: GH#18217 If `checkBase` is undefined, we should not call this because this will always return false. function hasBaseType(type: Type, checkBase: Type | undefined) { return check(type); function check(type: Type): boolean { - if (getObjectFlags(type) & (ObjectFlags.ClassOrInterface | ObjectFlags.Reference)) { + if ( + getObjectFlags(type) & + (ObjectFlags.ClassOrInterface | ObjectFlags.Reference) + ) { const target = getTargetType(type) as InterfaceType; - return target === checkBase || some(getBaseTypes(target), check); - } - else if (type.flags & TypeFlags.Intersection) { + return ( + target === checkBase || some(getBaseTypes(target), check) + ); + } else if (type.flags & TypeFlags.Intersection) { return some((type as IntersectionType).types, check); } return false; @@ -12901,23 +22569,49 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Appends the type parameters given by a list of declarations to a set of type parameters and returns the resulting set. // The function allocates a new array if the input type parameter set is undefined, but otherwise it modifies the set // in-place and returns the same array. - function appendTypeParameters(typeParameters: TypeParameter[] | undefined, declarations: readonly TypeParameterDeclaration[]): TypeParameter[] | undefined { + function appendTypeParameters( + typeParameters: TypeParameter[] | undefined, + declarations: readonly TypeParameterDeclaration[] + ): TypeParameter[] | undefined { for (const declaration of declarations) { - typeParameters = appendIfUnique(typeParameters, getDeclaredTypeOfTypeParameter(getSymbolOfDeclaration(declaration))); + typeParameters = appendIfUnique( + typeParameters, + getDeclaredTypeOfTypeParameter( + getSymbolOfDeclaration(declaration) + ) + ); } return typeParameters; } // Return the outer type parameters of a node or undefined if the node has no outer type parameters. - function getOuterTypeParameters(node: Node, includeThisTypes?: boolean): TypeParameter[] | undefined { + function getOuterTypeParameters( + node: Node, + includeThisTypes?: boolean + ): TypeParameter[] | undefined { while (true) { node = node.parent; // TODO: GH#18217 Use SourceFile kind check instead if (node && isBinaryExpression(node)) { // prototype assignments get the outer type parameters of their constructor function const assignmentKind = getAssignmentDeclarationKind(node); - if (assignmentKind === AssignmentDeclarationKind.Prototype || assignmentKind === AssignmentDeclarationKind.PrototypeProperty) { - const symbol = getSymbolOfDeclaration(node.left as BindableStaticNameExpression | PropertyAssignment); - if (symbol && symbol.parent && !findAncestor(symbol.parent.valueDeclaration, d => node === d)) { + if ( + assignmentKind === AssignmentDeclarationKind.Prototype || + assignmentKind === + AssignmentDeclarationKind.PrototypeProperty + ) { + const symbol = getSymbolOfDeclaration( + node.left as + | BindableStaticNameExpression + | PropertyAssignment + ); + if ( + symbol && + symbol.parent && + !findAncestor( + symbol.parent.valueDeclaration, + (d) => node === d + ) + ) { node = symbol.parent.valueDeclaration!; } } @@ -12947,35 +22641,95 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.JSDocCallbackTag: case SyntaxKind.MappedType: case SyntaxKind.ConditionalType: { - const outerTypeParameters = getOuterTypeParameters(node, includeThisTypes); - if ((kind === SyntaxKind.FunctionExpression || kind === SyntaxKind.ArrowFunction || isObjectLiteralMethod(node)) && isContextSensitive(node as Expression | MethodDeclaration)) { - const signature = firstOrUndefined(getSignaturesOfType(getTypeOfSymbol(getSymbolOfDeclaration(node as FunctionLikeDeclaration)), SignatureKind.Call)); + const outerTypeParameters = getOuterTypeParameters( + node, + includeThisTypes + ); + if ( + (kind === SyntaxKind.FunctionExpression || + kind === SyntaxKind.ArrowFunction || + isObjectLiteralMethod(node)) && + isContextSensitive( + node as Expression | MethodDeclaration + ) + ) { + const signature = firstOrUndefined( + getSignaturesOfType( + getTypeOfSymbol( + getSymbolOfDeclaration( + node as FunctionLikeDeclaration + ) + ), + SignatureKind.Call + ) + ); if (signature && signature.typeParameters) { - return [...(outerTypeParameters || emptyArray), ...signature.typeParameters]; + return [ + ...(outerTypeParameters || emptyArray), + ...signature.typeParameters, + ]; } } if (kind === SyntaxKind.MappedType) { - return append(outerTypeParameters, getDeclaredTypeOfTypeParameter(getSymbolOfDeclaration((node as MappedTypeNode).typeParameter))); - } - else if (kind === SyntaxKind.ConditionalType) { - return concatenate(outerTypeParameters, getInferTypeParameters(node as ConditionalTypeNode)); + return append( + outerTypeParameters, + getDeclaredTypeOfTypeParameter( + getSymbolOfDeclaration( + (node as MappedTypeNode).typeParameter + ) + ) + ); + } else if (kind === SyntaxKind.ConditionalType) { + return concatenate( + outerTypeParameters, + getInferTypeParameters(node as ConditionalTypeNode) + ); } - const outerAndOwnTypeParameters = appendTypeParameters(outerTypeParameters, getEffectiveTypeParameterDeclarations(node as DeclarationWithTypeParameters)); - const thisType = includeThisTypes && - (kind === SyntaxKind.ClassDeclaration || kind === SyntaxKind.ClassExpression || kind === SyntaxKind.InterfaceDeclaration || isJSConstructor(node)) && - getDeclaredTypeOfClassOrInterface(getSymbolOfDeclaration(node as ClassLikeDeclaration | InterfaceDeclaration)).thisType; - return thisType ? append(outerAndOwnTypeParameters, thisType) : outerAndOwnTypeParameters; + const outerAndOwnTypeParameters = appendTypeParameters( + outerTypeParameters, + getEffectiveTypeParameterDeclarations( + node as DeclarationWithTypeParameters + ) + ); + const thisType = + includeThisTypes && + (kind === SyntaxKind.ClassDeclaration || + kind === SyntaxKind.ClassExpression || + kind === SyntaxKind.InterfaceDeclaration || + isJSConstructor(node)) && + getDeclaredTypeOfClassOrInterface( + getSymbolOfDeclaration( + node as + | ClassLikeDeclaration + | InterfaceDeclaration + ) + ).thisType; + return thisType + ? append(outerAndOwnTypeParameters, thisType) + : outerAndOwnTypeParameters; } case SyntaxKind.JSDocParameterTag: - const paramSymbol = getParameterSymbolFromJSDoc(node as JSDocParameterTag); + const paramSymbol = getParameterSymbolFromJSDoc( + node as JSDocParameterTag + ); if (paramSymbol) { node = paramSymbol.valueDeclaration!; } break; case SyntaxKind.JSDoc: { - const outerTypeParameters = getOuterTypeParameters(node, includeThisTypes); + const outerTypeParameters = getOuterTypeParameters( + node, + includeThisTypes + ); return (node as JSDoc).tags - ? appendTypeParameters(outerTypeParameters, flatMap((node as JSDoc).tags, t => isJSDocTemplateTag(t) ? t.typeParameters : undefined)) + ? appendTypeParameters( + outerTypeParameters, + flatMap((node as JSDoc).tags, (t) => + isJSDocTemplateTag(t) + ? t.typeParameters + : undefined + ) + ) : outerTypeParameters; } } @@ -12983,26 +22737,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // The outer type parameters are those defined by enclosing generic classes, methods, or functions. - function getOuterTypeParametersOfClassOrInterface(symbol: Symbol): TypeParameter[] | undefined { - const declaration = (symbol.flags & SymbolFlags.Class || symbol.flags & SymbolFlags.Function) - ? symbol.valueDeclaration - : symbol.declarations?.find(decl => { - if (decl.kind === SyntaxKind.InterfaceDeclaration) { - return true; - } - if (decl.kind !== SyntaxKind.VariableDeclaration) { - return false; - } - const initializer = (decl as VariableDeclaration).initializer; - return !!initializer && (initializer.kind === SyntaxKind.FunctionExpression || initializer.kind === SyntaxKind.ArrowFunction); - })!; - Debug.assert(!!declaration, "Class was missing valueDeclaration -OR- non-class had no interface declarations"); + function getOuterTypeParametersOfClassOrInterface( + symbol: Symbol + ): TypeParameter[] | undefined { + const declaration = + symbol.flags & SymbolFlags.Class || + symbol.flags & SymbolFlags.Function + ? symbol.valueDeclaration + : symbol.declarations?.find((decl) => { + if (decl.kind === SyntaxKind.InterfaceDeclaration) { + return true; + } + if (decl.kind !== SyntaxKind.VariableDeclaration) { + return false; + } + const initializer = (decl as VariableDeclaration) + .initializer; + return ( + !!initializer && + (initializer.kind === SyntaxKind.FunctionExpression || + initializer.kind === SyntaxKind.ArrowFunction) + ); + })!; + Debug.assert( + !!declaration, + "Class was missing valueDeclaration -OR- non-class had no interface declarations" + ); return getOuterTypeParameters(declaration); } // The local type parameters are the combined set of type parameters from all declarations of the class, // interface, or type alias. - function getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol: Symbol): TypeParameter[] | undefined { + function getLocalTypeParametersOfClassOrInterfaceOrTypeAlias( + symbol: Symbol + ): TypeParameter[] | undefined { if (!symbol.declarations) { return; } @@ -13015,8 +22783,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { isJSConstructor(node) || isTypeAlias(node) ) { - const declaration = node as InterfaceDeclaration | TypeAliasDeclaration | JSDocTypedefTag | JSDocCallbackTag; - result = appendTypeParameters(result, getEffectiveTypeParameterDeclarations(declaration)); + const declaration = node as + | InterfaceDeclaration + | TypeAliasDeclaration + | JSDocTypedefTag + | JSDocCallbackTag; + result = appendTypeParameters( + result, + getEffectiveTypeParameterDeclarations(declaration) + ); } } return result; @@ -13024,8 +22799,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // The full set of type parameters for a generic class or interface type consists of its outer type parameters plus // its locally declared type parameters. - function getTypeParametersOfClassOrInterface(symbol: Symbol): TypeParameter[] | undefined { - return concatenate(getOuterTypeParametersOfClassOrInterface(symbol), getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol)); + function getTypeParametersOfClassOrInterface( + symbol: Symbol + ): TypeParameter[] | undefined { + return concatenate( + getOuterTypeParametersOfClassOrInterface(symbol), + getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol) + ); } // A type is a mixin constructor if it has a single construct signature taking no type parameters and a single @@ -13034,9 +22814,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const signatures = getSignaturesOfType(type, SignatureKind.Construct); if (signatures.length === 1) { const s = signatures[0]; - if (!s.typeParameters && s.parameters.length === 1 && signatureHasRestParameter(s)) { + if ( + !s.typeParameters && + s.parameters.length === 1 && + signatureHasRestParameter(s) + ) { const paramType = getTypeOfParameter(s.parameters[0]); - return isTypeAny(paramType) || getElementTypeOfArrayType(paramType) === anyType; + return ( + isTypeAny(paramType) || + getElementTypeOfArrayType(paramType) === anyType + ); } } return false; @@ -13053,21 +22840,50 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function getBaseTypeNodeOfClass(type: InterfaceType): ExpressionWithTypeArguments | undefined { + function getBaseTypeNodeOfClass( + type: InterfaceType + ): ExpressionWithTypeArguments | undefined { const decl = getClassLikeDeclarationOfSymbol(type.symbol); return decl && getEffectiveBaseTypeNode(decl); } - function getConstructorsForTypeArguments(type: Type, typeArgumentNodes: readonly TypeNode[] | undefined, location: Node): readonly Signature[] { + function getConstructorsForTypeArguments( + type: Type, + typeArgumentNodes: readonly TypeNode[] | undefined, + location: Node + ): readonly Signature[] { const typeArgCount = length(typeArgumentNodes); const isJavascript = isInJSFile(location); - return filter(getSignaturesOfType(type, SignatureKind.Construct), sig => (isJavascript || typeArgCount >= getMinTypeArgumentCount(sig.typeParameters)) && typeArgCount <= length(sig.typeParameters)); + return filter( + getSignaturesOfType(type, SignatureKind.Construct), + (sig) => + (isJavascript || + typeArgCount >= + getMinTypeArgumentCount(sig.typeParameters)) && + typeArgCount <= length(sig.typeParameters) + ); } - function getInstantiatedConstructorsForTypeArguments(type: Type, typeArgumentNodes: readonly TypeNode[] | undefined, location: Node): readonly Signature[] { - const signatures = getConstructorsForTypeArguments(type, typeArgumentNodes, location); + function getInstantiatedConstructorsForTypeArguments( + type: Type, + typeArgumentNodes: readonly TypeNode[] | undefined, + location: Node + ): readonly Signature[] { + const signatures = getConstructorsForTypeArguments( + type, + typeArgumentNodes, + location + ); const typeArguments = map(typeArgumentNodes, getTypeFromTypeNode); - return sameMap(signatures, sig => some(sig.typeParameters) ? getSignatureInstantiation(sig, typeArguments, isInJSFile(location)) : sig); + return sameMap(signatures, (sig) => + some(sig.typeParameters) + ? getSignatureInstantiation( + sig, + typeArguments, + isInJSFile(location) + ) + : sig + ); } /** @@ -13084,41 +22900,75 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const extended = decl && getEffectiveBaseTypeNode(decl); const baseTypeNode = getBaseTypeNodeOfClass(type); if (!baseTypeNode) { - return type.resolvedBaseConstructorType = undefinedType; + return (type.resolvedBaseConstructorType = undefinedType); } - if (!pushTypeResolution(type, TypeSystemPropertyName.ResolvedBaseConstructorType)) { + if ( + !pushTypeResolution( + type, + TypeSystemPropertyName.ResolvedBaseConstructorType + ) + ) { return errorType; } - const baseConstructorType = checkExpression(baseTypeNode.expression); + const baseConstructorType = checkExpression( + baseTypeNode.expression + ); if (extended && baseTypeNode !== extended) { Debug.assert(!extended.typeArguments); // Because this is in a JS file, and baseTypeNode is in an @extends tag checkExpression(extended.expression); } - if (baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection)) { + if ( + baseConstructorType.flags & + (TypeFlags.Object | TypeFlags.Intersection) + ) { // Resolving the members of a class requires us to resolve the base class of that class. // We force resolution here such that we catch circularities now. resolveStructuredTypeMembers(baseConstructorType as ObjectType); } if (!popTypeResolution()) { - error(type.symbol.valueDeclaration, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_base_expression, symbolToString(type.symbol)); - return type.resolvedBaseConstructorType ??= errorType; + error( + type.symbol.valueDeclaration, + Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_base_expression, + symbolToString(type.symbol) + ); + return (type.resolvedBaseConstructorType ??= errorType); } - if (!(baseConstructorType.flags & TypeFlags.Any) && baseConstructorType !== nullWideningType && !isConstructorType(baseConstructorType)) { - const err = error(baseTypeNode.expression, Diagnostics.Type_0_is_not_a_constructor_function_type, typeToString(baseConstructorType)); + if ( + !(baseConstructorType.flags & TypeFlags.Any) && + baseConstructorType !== nullWideningType && + !isConstructorType(baseConstructorType) + ) { + const err = error( + baseTypeNode.expression, + Diagnostics.Type_0_is_not_a_constructor_function_type, + typeToString(baseConstructorType) + ); if (baseConstructorType.flags & TypeFlags.TypeParameter) { - const constraint = getConstraintFromTypeParameter(baseConstructorType); + const constraint = + getConstraintFromTypeParameter(baseConstructorType); let ctorReturn: Type = unknownType; if (constraint) { - const ctorSig = getSignaturesOfType(constraint, SignatureKind.Construct); + const ctorSig = getSignaturesOfType( + constraint, + SignatureKind.Construct + ); if (ctorSig[0]) { ctorReturn = getReturnTypeOfSignature(ctorSig[0]); } } if (baseConstructorType.symbol.declarations) { - 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))); + 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) + ) + ); } } - return type.resolvedBaseConstructorType ??= errorType; + return (type.resolvedBaseConstructorType ??= errorType); } type.resolvedBaseConstructorType ??= baseConstructorType; } @@ -13129,15 +22979,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let resolvedImplementsTypes: BaseType[] = emptyArray; if (type.symbol.declarations) { for (const declaration of type.symbol.declarations) { - const implementsTypeNodes = getEffectiveImplementsTypeNodes(declaration as ClassLikeDeclaration); + const implementsTypeNodes = getEffectiveImplementsTypeNodes( + declaration as ClassLikeDeclaration + ); if (!implementsTypeNodes) continue; for (const node of implementsTypeNodes) { const implementsType = getTypeFromTypeNode(node); if (!isErrorType(implementsType)) { if (resolvedImplementsTypes === emptyArray) { - resolvedImplementsTypes = [implementsType as ObjectType]; - } - else { + resolvedImplementsTypes = [ + implementsType as ObjectType, + ]; + } else { resolvedImplementsTypes.push(implementsType); } } @@ -13148,29 +23001,48 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function reportCircularBaseType(node: Node, type: Type) { - error(node, Diagnostics.Type_0_recursively_references_itself_as_a_base_type, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType)); + error( + node, + Diagnostics.Type_0_recursively_references_itself_as_a_base_type, + typeToString( + type, + /*enclosingDeclaration*/ undefined, + TypeFormatFlags.WriteArrayAsGenericType + ) + ); } function getBaseTypes(type: InterfaceType): BaseType[] { if (!type.baseTypesResolved) { - if (pushTypeResolution(type, TypeSystemPropertyName.ResolvedBaseTypes)) { + if ( + pushTypeResolution( + type, + TypeSystemPropertyName.ResolvedBaseTypes + ) + ) { if (type.objectFlags & ObjectFlags.Tuple) { - type.resolvedBaseTypes = [getTupleBaseType(type as TupleType)]; - } - else if (type.symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { + type.resolvedBaseTypes = [ + getTupleBaseType(type as TupleType), + ]; + } else if ( + type.symbol.flags & + (SymbolFlags.Class | SymbolFlags.Interface) + ) { if (type.symbol.flags & SymbolFlags.Class) { resolveBaseTypesOfClass(type); } if (type.symbol.flags & SymbolFlags.Interface) { resolveBaseTypesOfInterface(type); } - } - else { + } else { Debug.fail("type must be class or interface"); } if (!popTypeResolution() && type.symbol.declarations) { for (const declaration of type.symbol.declarations) { - if (declaration.kind === SyntaxKind.ClassDeclaration || declaration.kind === SyntaxKind.InterfaceDeclaration) { + if ( + declaration.kind === SyntaxKind.ClassDeclaration || + declaration.kind === SyntaxKind.InterfaceDeclaration + ) { reportCircularBaseType(declaration, type); } } @@ -13182,56 +23054,102 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getTupleBaseType(type: TupleType) { - const elementTypes = sameMap(type.typeParameters, (t, i) => type.elementFlags[i] & ElementFlags.Variadic ? getIndexedAccessType(t, numberType) : t); - return createArrayType(getUnionType(elementTypes || emptyArray), type.readonly); + const elementTypes = sameMap(type.typeParameters, (t, i) => + type.elementFlags[i] & ElementFlags.Variadic + ? getIndexedAccessType(t, numberType) + : t + ); + return createArrayType( + getUnionType(elementTypes || emptyArray), + type.readonly + ); } function resolveBaseTypesOfClass(type: InterfaceType) { type.resolvedBaseTypes = resolvingEmptyArray; - const baseConstructorType = getApparentType(getBaseConstructorTypeOfClass(type)); - if (!(baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.Any))) { - return type.resolvedBaseTypes = emptyArray; + const baseConstructorType = getApparentType( + getBaseConstructorTypeOfClass(type) + ); + if ( + !( + baseConstructorType.flags & + (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.Any) + ) + ) { + return (type.resolvedBaseTypes = emptyArray); } const baseTypeNode = getBaseTypeNodeOfClass(type)!; let baseType: Type; - const originalBaseType = baseConstructorType.symbol ? getDeclaredTypeOfSymbol(baseConstructorType.symbol) : undefined; + const originalBaseType = baseConstructorType.symbol + ? getDeclaredTypeOfSymbol(baseConstructorType.symbol) + : undefined; if ( - baseConstructorType.symbol && baseConstructorType.symbol.flags & SymbolFlags.Class && + baseConstructorType.symbol && + baseConstructorType.symbol.flags & SymbolFlags.Class && areAllOuterTypeParametersApplied(originalBaseType!) ) { // 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 // class and all return the instance type of the class. There is no need for further checks and we can apply the // type arguments in the same manner as a type reference to get the same error reporting experience. - baseType = getTypeFromClassOrInterfaceReference(baseTypeNode, baseConstructorType.symbol); - } - else if (baseConstructorType.flags & TypeFlags.Any) { + baseType = getTypeFromClassOrInterfaceReference( + baseTypeNode, + baseConstructorType.symbol + ); + } else if (baseConstructorType.flags & TypeFlags.Any) { baseType = baseConstructorType; - } - else { + } else { // The class derives from a "class-like" constructor function, check that we have at least one construct signature // with a matching number of type parameters and use the return type of the first instantiated signature. Elsewhere // we check that all instantiated signatures return the same type. - const constructors = getInstantiatedConstructorsForTypeArguments(baseConstructorType, baseTypeNode.typeArguments, baseTypeNode); + const constructors = getInstantiatedConstructorsForTypeArguments( + baseConstructorType, + baseTypeNode.typeArguments, + baseTypeNode + ); if (!constructors.length) { - error(baseTypeNode.expression, Diagnostics.No_base_constructor_has_the_specified_number_of_type_arguments); - return type.resolvedBaseTypes = emptyArray; + error( + baseTypeNode.expression, + Diagnostics.No_base_constructor_has_the_specified_number_of_type_arguments + ); + return (type.resolvedBaseTypes = emptyArray); } baseType = getReturnTypeOfSignature(constructors[0]); } if (isErrorType(baseType)) { - return type.resolvedBaseTypes = emptyArray; + return (type.resolvedBaseTypes = emptyArray); } const reducedBaseType = getReducedType(baseType); if (!isValidBaseType(reducedBaseType)) { - const elaboration = elaborateNeverIntersection(/*errorInfo*/ undefined, baseType); - 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)); - diagnostics.add(createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(baseTypeNode.expression), baseTypeNode.expression, diagnostic)); - return type.resolvedBaseTypes = emptyArray; + const elaboration = elaborateNeverIntersection( + /*errorInfo*/ undefined, + baseType + ); + 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) + ); + diagnostics.add( + createDiagnosticForNodeFromMessageChain( + getSourceFileOfNode(baseTypeNode.expression), + baseTypeNode.expression, + diagnostic + ) + ); + return (type.resolvedBaseTypes = emptyArray); } if (type === reducedBaseType || hasBaseType(reducedBaseType, type)) { - error(type.symbol.valueDeclaration, Diagnostics.Type_0_recursively_references_itself_as_a_base_type, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType)); - return type.resolvedBaseTypes = emptyArray; + error( + type.symbol.valueDeclaration, + Diagnostics.Type_0_recursively_references_itself_as_a_base_type, + typeToString( + type, + /*enclosingDeclaration*/ undefined, + TypeFormatFlags.WriteArrayAsGenericType + ) + ); + return (type.resolvedBaseTypes = emptyArray); } if (type.resolvedBaseTypes === resolvingEmptyArray) { // Circular reference, likely through instantiation of default parameters @@ -13240,17 +23158,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // partial instantiation of the members without the base types fully resolved type.members = undefined; } - return type.resolvedBaseTypes = [reducedBaseType]; + return (type.resolvedBaseTypes = [reducedBaseType]); } - function areAllOuterTypeParametersApplied(type: Type): boolean { // TODO: GH#18217 Shouldn't this take an InterfaceType? + function areAllOuterTypeParametersApplied(type: Type): boolean { + // TODO: GH#18217 Shouldn't this take an InterfaceType? // An unapplied type parameter has its symbol still the same as the matching argument symbol. // Since parameters are applied outer-to-inner, only the last outer parameter needs to be checked. const outerTypeParameters = (type as InterfaceType).outerTypeParameters; if (outerTypeParameters) { const last = outerTypeParameters.length - 1; const typeArguments = getTypeArguments(type as TypeReference); - return outerTypeParameters[last].symbol !== typeArguments[last].symbol; + return ( + outerTypeParameters[last].symbol !== typeArguments[last].symbol + ); } return true; } @@ -13265,33 +23186,52 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // TODO: Given that we allow type parmeters here now, is this `!isGenericMappedType(type)` check really needed? // There's no reason a `T` should be allowed while a `Readonly` should not. - return !!(type.flags & (TypeFlags.Object | TypeFlags.NonPrimitive | TypeFlags.Any) && !isGenericMappedType(type) || - type.flags & TypeFlags.Intersection && every((type as IntersectionType).types, isValidBaseType)); + return !!( + (type.flags & + (TypeFlags.Object | TypeFlags.NonPrimitive | TypeFlags.Any) && + !isGenericMappedType(type)) || + (type.flags & TypeFlags.Intersection && + every((type as IntersectionType).types, isValidBaseType)) + ); } function resolveBaseTypesOfInterface(type: InterfaceType): void { type.resolvedBaseTypes = type.resolvedBaseTypes || emptyArray; if (type.symbol.declarations) { for (const declaration of type.symbol.declarations) { - if (declaration.kind === SyntaxKind.InterfaceDeclaration && getInterfaceBaseTypeNodes(declaration as InterfaceDeclaration)) { - for (const node of getInterfaceBaseTypeNodes(declaration as InterfaceDeclaration)!) { - const baseType = getReducedType(getTypeFromTypeNode(node)); + if ( + declaration.kind === SyntaxKind.InterfaceDeclaration && + getInterfaceBaseTypeNodes( + declaration as InterfaceDeclaration + ) + ) { + for (const node of getInterfaceBaseTypeNodes( + declaration as InterfaceDeclaration + )!) { + const baseType = getReducedType( + getTypeFromTypeNode(node) + ); if (!isErrorType(baseType)) { if (isValidBaseType(baseType)) { - if (type !== baseType && !hasBaseType(baseType, type)) { + if ( + type !== baseType && + !hasBaseType(baseType, type) + ) { if (type.resolvedBaseTypes === emptyArray) { - type.resolvedBaseTypes = [baseType as ObjectType]; - } - else { + type.resolvedBaseTypes = [ + baseType as ObjectType, + ]; + } else { type.resolvedBaseTypes.push(baseType); } - } - else { + } else { reportCircularBaseType(declaration, type); } - } - else { - error(node, Diagnostics.An_interface_can_only_extend_an_object_type_or_intersection_of_object_types_with_statically_known_members); + } else { + error( + node, + Diagnostics.An_interface_can_only_extend_an_object_type_or_intersection_of_object_types_with_statically_known_members + ); } } } @@ -13316,12 +23256,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (declaration.flags & NodeFlags.ContainsThis) { return false; } - const baseTypeNodes = getInterfaceBaseTypeNodes(declaration as InterfaceDeclaration); + const baseTypeNodes = getInterfaceBaseTypeNodes( + declaration as InterfaceDeclaration + ); if (baseTypeNodes) { for (const node of baseTypeNodes) { if (isEntityNameExpression(node.expression)) { - const baseSymbol = resolveEntityName(node.expression, SymbolFlags.Type, /*ignoreErrors*/ true); - if (!baseSymbol || !(baseSymbol.flags & SymbolFlags.Interface) || getDeclaredTypeOfClassOrInterface(baseSymbol).thisType) { + const baseSymbol = resolveEntityName( + node.expression, + SymbolFlags.Type, + /*ignoreErrors*/ true + ); + if ( + !baseSymbol || + !(baseSymbol.flags & SymbolFlags.Interface) || + getDeclaredTypeOfClassOrInterface(baseSymbol) + .thisType + ) { return false; } } @@ -13336,31 +23287,58 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let links = getSymbolLinks(symbol); const originalLinks = links; if (!links.declaredType) { - const kind = symbol.flags & SymbolFlags.Class ? ObjectFlags.Class : ObjectFlags.Interface; - const merged = mergeJSSymbols(symbol, symbol.valueDeclaration && getAssignedClassSymbol(symbol.valueDeclaration)); + const kind = + symbol.flags & SymbolFlags.Class + ? ObjectFlags.Class + : ObjectFlags.Interface; + const merged = mergeJSSymbols( + symbol, + symbol.valueDeclaration && + getAssignedClassSymbol(symbol.valueDeclaration) + ); if (merged) { // note:we overwrite links because we just cloned the symbol symbol = merged; links = merged.links; } - const type = originalLinks.declaredType = links.declaredType = createObjectType(kind, symbol) as InterfaceType; - const outerTypeParameters = getOuterTypeParametersOfClassOrInterface(symbol); - const localTypeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol); + const type = + (originalLinks.declaredType = + links.declaredType = + createObjectType(kind, symbol) as InterfaceType); + const outerTypeParameters = + getOuterTypeParametersOfClassOrInterface(symbol); + const localTypeParameters = + getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol); // A class or interface is generic if it has type parameters or a "this" type. We always give classes a "this" type // because it is not feasible to analyze all members to determine if the "this" type escapes the class (in particular, // property types inferred from initializers and method return types inferred from return statements are very hard // to exhaustively analyze). We give interfaces a "this" type if we can't definitely determine that they are free of // "this" references. - if (outerTypeParameters || localTypeParameters || kind === ObjectFlags.Class || !isThislessInterface(symbol)) { + if ( + outerTypeParameters || + localTypeParameters || + kind === ObjectFlags.Class || + !isThislessInterface(symbol) + ) { type.objectFlags |= ObjectFlags.Reference; - type.typeParameters = concatenate(outerTypeParameters, localTypeParameters); + type.typeParameters = concatenate( + outerTypeParameters, + localTypeParameters + ); type.outerTypeParameters = outerTypeParameters; type.localTypeParameters = localTypeParameters; - (type as GenericType).instantiations = new Map(); - (type as GenericType).instantiations.set(getTypeListId(type.typeParameters), type as GenericType); + (type as GenericType).instantiations = new Map< + string, + TypeReference + >(); + (type as GenericType).instantiations.set( + getTypeListId(type.typeParameters), + type as GenericType + ); (type as GenericType).target = type as GenericType; - (type as GenericType).resolvedTypeArguments = type.typeParameters; + (type as GenericType).resolvedTypeArguments = + type.typeParameters; type.thisType = createTypeParameter(symbol); type.thisType.isThisType = true; type.thisType.constraint = type; @@ -13374,34 +23352,56 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!links.declaredType) { // Note that we use the links object as the target here because the symbol object is used as the unique // identity for resolution of the 'type' property in SymbolLinks. - if (!pushTypeResolution(symbol, TypeSystemPropertyName.DeclaredType)) { + if ( + !pushTypeResolution(symbol, TypeSystemPropertyName.DeclaredType) + ) { return errorType; } - const declaration = Debug.checkDefined(symbol.declarations?.find(isTypeAlias), "Type alias symbol with no valid declaration found"); - const typeNode = isJSDocTypeAlias(declaration) ? declaration.typeExpression : declaration.type; + const declaration = Debug.checkDefined( + symbol.declarations?.find(isTypeAlias), + "Type alias symbol with no valid declaration found" + ); + const typeNode = isJSDocTypeAlias(declaration) + ? declaration.typeExpression + : declaration.type; // If typeNode is missing, we will error in checkJSDocTypedefTag. let type = typeNode ? getTypeFromTypeNode(typeNode) : errorType; if (popTypeResolution()) { - const typeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol); + const typeParameters = + getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol); if (typeParameters) { // Initialize the instantiation cache for generic type aliases. The declared type corresponds to // an instantiation of the type alias with the type parameters supplied as type arguments. links.typeParameters = typeParameters; links.instantiations = new Map(); - links.instantiations.set(getTypeListId(typeParameters), type); + links.instantiations.set( + getTypeListId(typeParameters), + type + ); } - if (type === intrinsicMarkerType && symbol.escapedName === "BuiltinIteratorReturn") { + if ( + type === intrinsicMarkerType && + symbol.escapedName === "BuiltinIteratorReturn" + ) { type = getBuiltinIteratorReturnType(); } - } - else { + } else { type = errorType; if (declaration.kind === SyntaxKind.JSDocEnumTag) { - error(declaration.typeExpression.type, Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol)); - } - else { - error(isNamedDeclaration(declaration) ? declaration.name || declaration : declaration, Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol)); + error( + declaration.typeExpression.type, + Diagnostics.Type_alias_0_circularly_references_itself, + symbolToString(symbol) + ); + } else { + error( + isNamedDeclaration(declaration) + ? declaration.name || declaration + : declaration, + Diagnostics.Type_alias_0_circularly_references_itself, + symbolToString(symbol) + ); } } links.declaredType ??= type; @@ -13410,7 +23410,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getBaseTypeOfEnumLikeType(type: Type) { - return type.flags & TypeFlags.EnumLike && type.symbol.flags & SymbolFlags.EnumMember ? getDeclaredTypeOfSymbol(getParentOfSymbol(type.symbol)!) : type; + return type.flags & TypeFlags.EnumLike && + type.symbol.flags & SymbolFlags.EnumMember + ? getDeclaredTypeOfSymbol(getParentOfSymbol(type.symbol)!) + : type; } function getDeclaredTypeOfEnum(symbol: Symbol): Type { @@ -13420,25 +23423,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (symbol.declarations) { for (const declaration of symbol.declarations) { if (declaration.kind === SyntaxKind.EnumDeclaration) { - for (const member of (declaration as EnumDeclaration).members) { + for (const member of (declaration as EnumDeclaration) + .members) { if (hasBindableName(member)) { - const memberSymbol = getSymbolOfDeclaration(member); + const memberSymbol = + getSymbolOfDeclaration(member); const value = getEnumMemberValue(member).value; const memberType = getFreshTypeOfLiteralType( - value !== undefined ? - getEnumLiteralType(value, getSymbolId(symbol), memberSymbol) : - createComputedEnumType(memberSymbol), + value !== undefined + ? getEnumLiteralType( + value, + getSymbolId(symbol), + memberSymbol + ) + : createComputedEnumType(memberSymbol) + ); + getSymbolLinks(memberSymbol).declaredType = + memberType; + memberTypeList.push( + getRegularTypeOfLiteralType(memberType) ); - getSymbolLinks(memberSymbol).declaredType = memberType; - memberTypeList.push(getRegularTypeOfLiteralType(memberType)); } } } } } - const enumType = memberTypeList.length ? - getUnionType(memberTypeList, UnionReduction.Literal, symbol, /*aliasTypeArguments*/ undefined) : - createComputedEnumType(symbol); + const enumType = memberTypeList.length + ? getUnionType( + memberTypeList, + UnionReduction.Literal, + symbol, + /*aliasTypeArguments*/ undefined + ) + : createComputedEnumType(symbol); if (enumType.flags & TypeFlags.Union) { enumType.flags |= TypeFlags.EnumLiteral; enumType.symbol = symbol; @@ -13449,8 +23466,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function createComputedEnumType(symbol: Symbol) { - const regularType = createTypeWithSymbol(TypeFlags.Enum, symbol) as EnumType; - const freshType = createTypeWithSymbol(TypeFlags.Enum, symbol) as EnumType; + const regularType = createTypeWithSymbol( + TypeFlags.Enum, + symbol + ) as EnumType; + const freshType = createTypeWithSymbol( + TypeFlags.Enum, + symbol + ) as EnumType; regularType.regularType = regularType; regularType.freshType = freshType; freshType.regularType = regularType; @@ -13471,12 +23494,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getDeclaredTypeOfTypeParameter(symbol: Symbol): TypeParameter { const links = getSymbolLinks(symbol); - return links.declaredType || (links.declaredType = createTypeParameter(symbol)); + return ( + links.declaredType || + (links.declaredType = createTypeParameter(symbol)) + ); } function getDeclaredTypeOfAlias(symbol: Symbol): Type { const links = getSymbolLinks(symbol); - return links.declaredType || (links.declaredType = getDeclaredTypeOfSymbol(resolveAlias(symbol))); + return ( + links.declaredType || + (links.declaredType = getDeclaredTypeOfSymbol(resolveAlias(symbol))) + ); } function getDeclaredTypeOfSymbol(symbol: Symbol): Type { @@ -13528,7 +23557,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ArrayType: return isThislessType((node as ArrayTypeNode).elementType); case SyntaxKind.TypeReference: - return !(node as TypeReferenceNode).typeArguments || (node as TypeReferenceNode).typeArguments!.every(isThislessType); + return ( + !(node as TypeReferenceNode).typeArguments || + (node as TypeReferenceNode).typeArguments!.every( + isThislessType + ) + ); } return false; } @@ -13543,7 +23577,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * A variable-like declaration is free of this references if it has a type annotation * that is thisless, or if it has no type annotation and no initializer (and is thus of type any). */ - function isThislessVariableLikeDeclaration(node: VariableLikeDeclaration): boolean { + function isThislessVariableLikeDeclaration( + node: VariableLikeDeclaration + ): boolean { const typeNode = getEffectiveTypeAnnotationNode(node); return typeNode ? isThislessType(typeNode) : !hasInitializer(node); } @@ -13553,12 +23589,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * annotation that is free of this references and if each parameter is thisless and if * each type parameter (if present) is thisless. */ - function isThislessFunctionLikeDeclaration(node: FunctionLikeDeclaration): boolean { + function isThislessFunctionLikeDeclaration( + node: FunctionLikeDeclaration + ): boolean { const returnType = getEffectiveReturnTypeNode(node); const typeParameters = getEffectiveTypeParameterDeclarations(node); - return (node.kind === SyntaxKind.Constructor || (!!returnType && isThislessType(returnType))) && + return ( + (node.kind === SyntaxKind.Constructor || + (!!returnType && isThislessType(returnType))) && node.parameters.every(isThislessVariableLikeDeclaration) && - typeParameters.every(isThislessTypeParameter); + typeParameters.every(isThislessTypeParameter) + ); } /** @@ -13575,13 +23616,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { switch (declaration.kind) { case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: - return isThislessVariableLikeDeclaration(declaration as VariableLikeDeclaration); + return isThislessVariableLikeDeclaration( + declaration as VariableLikeDeclaration + ); case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: case SyntaxKind.Constructor: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: - return isThislessFunctionLikeDeclaration(declaration as FunctionLikeDeclaration | AccessorDeclaration); + return isThislessFunctionLikeDeclaration( + declaration as + | FunctionLikeDeclaration + | AccessorDeclaration + ); } } } @@ -13590,10 +23637,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // The mappingThisOnly flag indicates that the only type parameter being mapped is "this". When the flag is true, // we check symbols to see if we can quickly conclude they are free of "this" references, thus needing no instantiation. - function createInstantiatedSymbolTable(symbols: Symbol[], mapper: TypeMapper, mappingThisOnly: boolean): SymbolTable { + function createInstantiatedSymbolTable( + symbols: Symbol[], + mapper: TypeMapper, + mappingThisOnly: boolean + ): SymbolTable { const result = createSymbolTable(); for (const symbol of symbols) { - result.set(symbol.escapedName, mappingThisOnly && isThisless(symbol) ? symbol : instantiateSymbol(symbol, mapper)); + result.set( + symbol.escapedName, + mappingThisOnly && isThisless(symbol) + ? symbol + : instantiateSymbol(symbol, mapper) + ); } return result; } @@ -13605,12 +23661,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const derived = symbols.get(base.escapedName); if ( - !derived + !derived || // non-constructor/static-block assignment declarations are ignored here; they're not treated as overrides - || derived.valueDeclaration - && isBinaryExpression(derived.valueDeclaration) - && !isConstructorDeclaredProperty(derived) - && !getContainingClassStaticBlock(derived.valueDeclaration) + (derived.valueDeclaration && + isBinaryExpression(derived.valueDeclaration) && + !isConstructorDeclaredProperty(derived) && + !getContainingClassStaticBlock(derived.valueDeclaration)) ) { symbols.set(base.escapedName, base); symbols.set(base.escapedName, base); @@ -13619,22 +23675,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isStaticPrivateIdentifierProperty(s: Symbol): boolean { - return !!s.valueDeclaration && isPrivateIdentifierClassElementDeclaration(s.valueDeclaration) && isStatic(s.valueDeclaration); + return ( + !!s.valueDeclaration && + isPrivateIdentifierClassElementDeclaration(s.valueDeclaration) && + isStatic(s.valueDeclaration) + ); } - function resolveDeclaredMembers(type: InterfaceType): InterfaceTypeWithDeclaredMembers { + function resolveDeclaredMembers( + type: InterfaceType + ): InterfaceTypeWithDeclaredMembers { if (!(type as InterfaceTypeWithDeclaredMembers).declaredProperties) { const symbol = type.symbol; const members = getMembersOfSymbol(symbol); - (type as InterfaceTypeWithDeclaredMembers).declaredProperties = getNamedMembers(members); + (type as InterfaceTypeWithDeclaredMembers).declaredProperties = + getNamedMembers(members); // Start with signatures at empty array in case of recursive types - (type as InterfaceTypeWithDeclaredMembers).declaredCallSignatures = emptyArray; - (type as InterfaceTypeWithDeclaredMembers).declaredConstructSignatures = emptyArray; - (type as InterfaceTypeWithDeclaredMembers).declaredIndexInfos = emptyArray; - - (type as InterfaceTypeWithDeclaredMembers).declaredCallSignatures = getSignaturesOfSymbol(members.get(InternalSymbolName.Call)); - (type as InterfaceTypeWithDeclaredMembers).declaredConstructSignatures = getSignaturesOfSymbol(members.get(InternalSymbolName.New)); - (type as InterfaceTypeWithDeclaredMembers).declaredIndexInfos = getIndexInfosOfSymbol(symbol); + (type as InterfaceTypeWithDeclaredMembers).declaredCallSignatures = + emptyArray; + ( + type as InterfaceTypeWithDeclaredMembers + ).declaredConstructSignatures = emptyArray; + (type as InterfaceTypeWithDeclaredMembers).declaredIndexInfos = + emptyArray; + + (type as InterfaceTypeWithDeclaredMembers).declaredCallSignatures = + getSignaturesOfSymbol(members.get(InternalSymbolName.Call)); + ( + type as InterfaceTypeWithDeclaredMembers + ).declaredConstructSignatures = getSignaturesOfSymbol( + members.get(InternalSymbolName.New) + ); + (type as InterfaceTypeWithDeclaredMembers).declaredIndexInfos = + getIndexInfosOfSymbol(symbol); } return type as InterfaceTypeWithDeclaredMembers; } @@ -13648,20 +23721,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * - The type of its expression is a string or numeric literal type, or is a `unique symbol` type. */ function isLateBindableName(node: DeclarationName): node is LateBoundName { - return isLateBindableAST(node) - && isTypeUsableAsPropertyName(isComputedPropertyName(node) ? checkComputedPropertyName(node) : checkExpressionCached((node as ElementAccessExpression).argumentExpression)); + return ( + isLateBindableAST(node) && + isTypeUsableAsPropertyName( + isComputedPropertyName(node) + ? checkComputedPropertyName(node) + : checkExpressionCached( + (node as ElementAccessExpression).argumentExpression + ) + ) + ); } - function isLateBindableIndexSignature(node: DeclarationName): node is LateBoundName { - return isLateBindableAST(node) - && isTypeUsableAsIndexSignature(isComputedPropertyName(node) ? checkComputedPropertyName(node) : checkExpressionCached((node as ElementAccessExpression).argumentExpression)); + function isLateBindableIndexSignature( + node: DeclarationName + ): node is LateBoundName { + return ( + isLateBindableAST(node) && + isTypeUsableAsIndexSignature( + isComputedPropertyName(node) + ? checkComputedPropertyName(node) + : checkExpressionCached( + (node as ElementAccessExpression).argumentExpression + ) + ) + ); } function isLateBindableAST(node: DeclarationName) { if (!isComputedPropertyName(node) && !isElementAccessExpression(node)) { return false; } - const expr = isComputedPropertyName(node) ? node.expression : node.argumentExpression; + const expr = isComputedPropertyName(node) + ? node.expression + : node.argumentExpression; return isEntityNameExpression(expr); } @@ -13670,15 +23763,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isLateBoundName(name: __String): boolean { - return (name as string).charCodeAt(0) === CharacterCodes._ && + return ( + (name as string).charCodeAt(0) === CharacterCodes._ && (name as string).charCodeAt(1) === CharacterCodes._ && - (name as string).charCodeAt(2) === CharacterCodes.at; + (name as string).charCodeAt(2) === CharacterCodes.at + ); } /** * Indicates whether a declaration has a late-bindable dynamic name. */ - function hasLateBindableName(node: Declaration): node is LateBoundDeclaration | LateBoundBinaryExpressionDeclaration { + function hasLateBindableName( + node: Declaration + ): node is LateBoundDeclaration | LateBoundBinaryExpressionDeclaration { const name = getNameOfDeclaration(node); return !!name && isLateBindableName(name); } @@ -13707,14 +23804,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * late-bound members that `addDeclarationToSymbol` in binder.ts performs for early-bound * members. */ - function addDeclarationToLateBoundSymbol(symbol: Symbol, member: LateBoundDeclaration | BinaryExpression, symbolFlags: SymbolFlags) { - Debug.assert(!!(getCheckFlags(symbol) & CheckFlags.Late), "Expected a late-bound symbol."); + function addDeclarationToLateBoundSymbol( + symbol: Symbol, + member: LateBoundDeclaration | BinaryExpression, + symbolFlags: SymbolFlags + ) { + Debug.assert( + !!(getCheckFlags(symbol) & CheckFlags.Late), + "Expected a late-bound symbol." + ); symbol.flags |= symbolFlags; getSymbolLinks(member.symbol).lateSymbol = symbol; if (!symbol.declarations) { symbol.declarations = [member]; - } - else if (!member.symbol.isReplaceableByMethod) { + } else if (!member.symbol.isReplaceableByMethod) { symbol.declarations.push(member); } if (symbolFlags & SymbolFlags.Value) { @@ -13750,7 +23853,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param lateSymbols The late-bound symbols of the parent. * @param decl The member to bind. */ - function lateBindMember(parent: Symbol, earlySymbols: SymbolTable | undefined, lateSymbols: Map<__String, TransientSymbol>, decl: LateBoundDeclaration | LateBoundBinaryExpressionDeclaration) { + function lateBindMember( + parent: Symbol, + earlySymbols: SymbolTable | undefined, + lateSymbols: Map<__String, TransientSymbol>, + decl: LateBoundDeclaration | LateBoundBinaryExpressionDeclaration + ) { Debug.assert(!!decl.symbol, "The member is expected to have a symbol."); const links = getNodeLinks(decl); if (!links.resolvedSymbol) { @@ -13758,50 +23866,96 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // fall back to the early-bound name of this member. links.resolvedSymbol = decl.symbol; const declName = isBinaryExpression(decl) ? decl.left : decl.name; - const type = isElementAccessExpression(declName) ? checkExpressionCached(declName.argumentExpression) : checkComputedPropertyName(declName); + const type = isElementAccessExpression(declName) + ? checkExpressionCached(declName.argumentExpression) + : checkComputedPropertyName(declName); if (isTypeUsableAsPropertyName(type)) { const memberName = getPropertyNameFromType(type); const symbolFlags = decl.symbol.flags; // Get or add a late-bound symbol for the member. This allows us to merge late-bound accessor declarations. let lateSymbol = lateSymbols.get(memberName); - if (!lateSymbol) lateSymbols.set(memberName, lateSymbol = createSymbol(SymbolFlags.None, memberName, CheckFlags.Late)); + if (!lateSymbol) + lateSymbols.set( + memberName, + (lateSymbol = createSymbol( + SymbolFlags.None, + memberName, + CheckFlags.Late + )) + ); // Report an error if there's a symbol declaration with the same name and conflicting flags. - const earlySymbol = earlySymbols && earlySymbols.get(memberName); + const earlySymbol = + earlySymbols && earlySymbols.get(memberName); // Duplicate property declarations of classes are checked in checkClassForDuplicateDeclarations. - if (!(parent.flags & SymbolFlags.Class) && lateSymbol.flags & getExcludedSymbolFlags(symbolFlags)) { + if ( + !(parent.flags & SymbolFlags.Class) && + lateSymbol.flags & getExcludedSymbolFlags(symbolFlags) + ) { // If we have an existing early-bound member, combine its declarations so that we can // report an error at each declaration. - const declarations = earlySymbol ? concatenate(earlySymbol.declarations, lateSymbol.declarations) : lateSymbol.declarations; - const name = !(type.flags & TypeFlags.UniqueESSymbol) && unescapeLeadingUnderscores(memberName) || declarationNameToString(declName); - forEach(declarations, declaration => error(getNameOfDeclaration(declaration) || declaration, Diagnostics.Property_0_was_also_declared_here, name)); - error(declName || decl, Diagnostics.Duplicate_property_0, name); - lateSymbol = createSymbol(SymbolFlags.None, memberName, CheckFlags.Late); + const declarations = earlySymbol + ? concatenate( + earlySymbol.declarations, + lateSymbol.declarations + ) + : lateSymbol.declarations; + const name = + (!(type.flags & TypeFlags.UniqueESSymbol) && + unescapeLeadingUnderscores(memberName)) || + declarationNameToString(declName); + forEach(declarations, (declaration) => + error( + getNameOfDeclaration(declaration) || declaration, + Diagnostics.Property_0_was_also_declared_here, + name + ) + ); + error( + declName || decl, + Diagnostics.Duplicate_property_0, + name + ); + lateSymbol = createSymbol( + SymbolFlags.None, + memberName, + CheckFlags.Late + ); } lateSymbol.links.nameType = type; addDeclarationToLateBoundSymbol(lateSymbol, decl, symbolFlags); if (lateSymbol.parent) { - Debug.assert(lateSymbol.parent === parent, "Existing symbol parent should match new one"); - } - else { + Debug.assert( + lateSymbol.parent === parent, + "Existing symbol parent should match new one" + ); + } else { lateSymbol.parent = parent; } - return links.resolvedSymbol = lateSymbol; + return (links.resolvedSymbol = lateSymbol); } } return links.resolvedSymbol; } - function lateBindIndexSignature(parent: Symbol, earlySymbols: SymbolTable | undefined, lateSymbols: Map<__String, TransientSymbol>, decl: LateBoundDeclaration | LateBoundBinaryExpressionDeclaration) { + function lateBindIndexSignature( + parent: Symbol, + earlySymbols: SymbolTable | undefined, + lateSymbols: Map<__String, TransientSymbol>, + decl: LateBoundDeclaration | LateBoundBinaryExpressionDeclaration + ) { // First, late bind the index symbol itself, if needed let indexSymbol = lateSymbols.get(InternalSymbolName.Index); if (!indexSymbol) { const early = earlySymbols?.get(InternalSymbolName.Index); if (!early) { - indexSymbol = createSymbol(SymbolFlags.None, InternalSymbolName.Index, CheckFlags.Late); - } - else { + indexSymbol = createSymbol( + SymbolFlags.None, + InternalSymbolName.Index, + CheckFlags.Late + ); + } else { indexSymbol = cloneSymbol(early); indexSymbol.links.checkFlags |= CheckFlags.Late; } @@ -13812,19 +23966,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // since that would point at an index symbol and not a single property symbol, like most consumers would expect) if (!indexSymbol.declarations) { indexSymbol.declarations = [decl]; - } - else if (!decl.symbol.isReplaceableByMethod) { + } else if (!decl.symbol.isReplaceableByMethod) { indexSymbol.declarations.push(decl); } } - function getResolvedMembersOrExportsOfSymbol(symbol: Symbol, resolutionKind: MembersOrExportsResolutionKind): Map<__String, Symbol> { + function getResolvedMembersOrExportsOfSymbol( + symbol: Symbol, + resolutionKind: MembersOrExportsResolutionKind + ): Map<__String, Symbol> { const links = getSymbolLinks(symbol); if (!links[resolutionKind]) { - const isStatic = resolutionKind === MembersOrExportsResolutionKind.resolvedExports; - const earlySymbols = !isStatic ? symbol.members : - symbol.flags & SymbolFlags.Module ? getExportsOfModuleWorker(symbol).exports : - symbol.exports; + const isStatic = + resolutionKind === + MembersOrExportsResolutionKind.resolvedExports; + const earlySymbols = !isStatic + ? symbol.members + : symbol.flags & SymbolFlags.Module + ? getExportsOfModuleWorker(symbol).exports + : symbol.exports; // In the event we recursively resolve the members/exports of the symbol, we // set the initial value of resolvedMembers/resolvedExports to the early-bound @@ -13832,44 +23992,81 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { links[resolutionKind] = earlySymbols || emptySymbols; // fill in any as-yet-unresolved late-bound members. - const lateSymbols = createSymbolTable() as Map<__String, TransientSymbol>; + const lateSymbols = createSymbolTable() as Map< + __String, + TransientSymbol + >; for (const decl of symbol.declarations || emptyArray) { const members = getMembersOfDeclaration(decl); if (members) { for (const member of members) { if (isStatic === hasStaticModifier(member)) { if (hasLateBindableName(member)) { - lateBindMember(symbol, earlySymbols, lateSymbols, member); - } - else if (hasLateBindableIndexSignature(member)) { - lateBindIndexSignature(symbol, earlySymbols, lateSymbols, member as Node as LateBoundDeclaration | LateBoundBinaryExpressionDeclaration); + lateBindMember( + symbol, + earlySymbols, + lateSymbols, + member + ); + } else if (hasLateBindableIndexSignature(member)) { + lateBindIndexSignature( + symbol, + earlySymbols, + lateSymbols, + member as Node as + | LateBoundDeclaration + | LateBoundBinaryExpressionDeclaration + ); } } } } } - const assignments = getFunctionExpressionParentSymbolOrSymbol(symbol).assignmentDeclarationMembers; + const assignments = + getFunctionExpressionParentSymbolOrSymbol( + symbol + ).assignmentDeclarationMembers; if (assignments) { const decls = arrayFrom(assignments.values()); for (const member of decls) { - const assignmentKind = getAssignmentDeclarationKind(member as BinaryExpression | CallExpression); - const isInstanceMember = assignmentKind === AssignmentDeclarationKind.PrototypeProperty - || isBinaryExpression(member) && isPossiblyAliasedThisProperty(member, assignmentKind) - || assignmentKind === AssignmentDeclarationKind.ObjectDefinePrototypeProperty - || assignmentKind === AssignmentDeclarationKind.Prototype; // A straight `Prototype` assignment probably can never have a computed name + const assignmentKind = getAssignmentDeclarationKind( + member as BinaryExpression | CallExpression + ); + const isInstanceMember = + assignmentKind === + AssignmentDeclarationKind.PrototypeProperty || + (isBinaryExpression(member) && + isPossiblyAliasedThisProperty( + member, + assignmentKind + )) || + assignmentKind === + AssignmentDeclarationKind.ObjectDefinePrototypeProperty || + assignmentKind === AssignmentDeclarationKind.Prototype; // A straight `Prototype` assignment probably can never have a computed name if (isStatic === !isInstanceMember) { if (hasLateBindableName(member)) { - lateBindMember(symbol, earlySymbols, lateSymbols, member); + lateBindMember( + symbol, + earlySymbols, + lateSymbols, + member + ); } } } } let resolved = combineSymbolTables(earlySymbols, lateSymbols); - if (symbol.flags & SymbolFlags.Transient && links.cjsExportMerged && symbol.declarations) { + if ( + symbol.flags & SymbolFlags.Transient && + links.cjsExportMerged && + symbol.declarations + ) { for (const decl of symbol.declarations) { - const original = getSymbolLinks(decl.symbol)[resolutionKind]; + const original = getSymbolLinks(decl.symbol)[ + resolutionKind + ]; if (!resolved) { resolved = original; continue; @@ -13896,7 +24093,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { */ function getMembersOfSymbol(symbol: Symbol) { return symbol.flags & SymbolFlags.LateBindingContainer - ? getResolvedMembersOrExportsOfSymbol(symbol, MembersOrExportsResolutionKind.resolvedMembers) + ? getResolvedMembersOrExportsOfSymbol( + symbol, + MembersOrExportsResolutionKind.resolvedMembers + ) : symbol.members || emptySymbols; } @@ -13907,15 +24107,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * For a description of late-binding, see `lateBindMember`. */ function getLateBoundSymbol(symbol: Symbol): Symbol { - if (symbol.flags & SymbolFlags.ClassMember && symbol.escapedName === InternalSymbolName.Computed) { + if ( + symbol.flags & SymbolFlags.ClassMember && + symbol.escapedName === InternalSymbolName.Computed + ) { const links = getSymbolLinks(symbol); - if (!links.lateSymbol && some(symbol.declarations, hasLateBindableName)) { + if ( + !links.lateSymbol && + some(symbol.declarations, hasLateBindableName) + ) { // force late binding of members/exports. This will set the late-bound symbol const parent = getMergedSymbol(symbol.parent)!; if (some(symbol.declarations, hasStaticModifier)) { getExportsOfSymbol(parent); - } - else { + } else { getMembersOfSymbol(parent); } } @@ -13924,42 +24129,82 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return symbol; } - function getTypeWithThisArgument(type: Type, thisArgument?: Type, needApparentType?: boolean): Type { + function getTypeWithThisArgument( + type: Type, + thisArgument?: Type, + needApparentType?: boolean + ): Type { if (getObjectFlags(type) & ObjectFlags.Reference) { const target = (type as TypeReference).target; const typeArguments = getTypeArguments(type as TypeReference); - return length(target.typeParameters) === length(typeArguments) ? createTypeReference(target, concatenate(typeArguments, [thisArgument || target.thisType!])) : type; - } - else if (type.flags & TypeFlags.Intersection) { - const types = sameMap((type as IntersectionType).types, t => getTypeWithThisArgument(t, thisArgument, needApparentType)); - return types !== (type as IntersectionType).types ? getIntersectionType(types) : type; + return length(target.typeParameters) === length(typeArguments) + ? createTypeReference( + target, + concatenate(typeArguments, [ + thisArgument || target.thisType!, + ]) + ) + : type; + } else if (type.flags & TypeFlags.Intersection) { + const types = sameMap((type as IntersectionType).types, (t) => + getTypeWithThisArgument(t, thisArgument, needApparentType) + ); + return types !== (type as IntersectionType).types + ? getIntersectionType(types) + : type; } return needApparentType ? getApparentType(type) : type; } - function resolveObjectTypeMembers(type: ObjectType, source: InterfaceTypeWithDeclaredMembers, typeParameters: readonly TypeParameter[], typeArguments: readonly Type[]) { + function resolveObjectTypeMembers( + type: ObjectType, + source: InterfaceTypeWithDeclaredMembers, + typeParameters: readonly TypeParameter[], + typeArguments: readonly Type[] + ) { let mapper: TypeMapper | undefined; let members: SymbolTable; let callSignatures: readonly Signature[]; let constructSignatures: readonly Signature[]; let indexInfos: readonly IndexInfo[]; - if (rangeEquals(typeParameters, typeArguments, 0, typeParameters.length)) { - members = source.symbol ? getMembersOfSymbol(source.symbol) : createSymbolTable(source.declaredProperties); + if ( + rangeEquals(typeParameters, typeArguments, 0, typeParameters.length) + ) { + members = source.symbol + ? getMembersOfSymbol(source.symbol) + : createSymbolTable(source.declaredProperties); callSignatures = source.declaredCallSignatures; constructSignatures = source.declaredConstructSignatures; indexInfos = source.declaredIndexInfos; - } - else { + } else { mapper = createTypeMapper(typeParameters, typeArguments); - members = createInstantiatedSymbolTable(source.declaredProperties, mapper, /*mappingThisOnly*/ typeParameters.length === 1); - callSignatures = instantiateSignatures(source.declaredCallSignatures, mapper); - constructSignatures = instantiateSignatures(source.declaredConstructSignatures, mapper); - indexInfos = instantiateIndexInfos(source.declaredIndexInfos, mapper); + members = createInstantiatedSymbolTable( + source.declaredProperties, + mapper, + /*mappingThisOnly*/ typeParameters.length === 1 + ); + callSignatures = instantiateSignatures( + source.declaredCallSignatures, + mapper + ); + constructSignatures = instantiateSignatures( + source.declaredConstructSignatures, + mapper + ); + indexInfos = instantiateIndexInfos( + source.declaredIndexInfos, + mapper + ); } const baseTypes = getBaseTypes(source); if (baseTypes.length) { - if (source.symbol && members === getMembersOfSymbol(source.symbol)) { - const symbolTable = createSymbolTable(source.declaredProperties); + if ( + source.symbol && + members === getMembersOfSymbol(source.symbol) + ) { + const symbolTable = createSymbolTable( + source.declaredProperties + ); // copy index signature symbol as well (for quickinfo) const sourceIndex = getIndexSymbol(source.symbol); if (sourceIndex) { @@ -13967,30 +24212,86 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } members = symbolTable; } - setStructuredTypeMembers(type, members, callSignatures, constructSignatures, indexInfos); + setStructuredTypeMembers( + type, + members, + callSignatures, + constructSignatures, + indexInfos + ); const thisArgument = lastOrUndefined(typeArguments); for (const baseType of baseTypes) { - const instantiatedBaseType = thisArgument ? getTypeWithThisArgument(instantiateType(baseType, mapper), thisArgument) : baseType; - addInheritedMembers(members, getPropertiesOfType(instantiatedBaseType)); - callSignatures = concatenate(callSignatures, getSignaturesOfType(instantiatedBaseType, SignatureKind.Call)); - constructSignatures = concatenate(constructSignatures, getSignaturesOfType(instantiatedBaseType, SignatureKind.Construct)); - const inheritedIndexInfos = instantiatedBaseType !== anyType ? getIndexInfosOfType(instantiatedBaseType) : [anyBaseTypeIndexInfo]; - indexInfos = concatenate(indexInfos, filter(inheritedIndexInfos, info => !findIndexInfo(indexInfos, info.keyType))); + const instantiatedBaseType = thisArgument + ? getTypeWithThisArgument( + instantiateType(baseType, mapper), + thisArgument + ) + : baseType; + addInheritedMembers( + members, + getPropertiesOfType(instantiatedBaseType) + ); + callSignatures = concatenate( + callSignatures, + getSignaturesOfType( + instantiatedBaseType, + SignatureKind.Call + ) + ); + constructSignatures = concatenate( + constructSignatures, + getSignaturesOfType( + instantiatedBaseType, + SignatureKind.Construct + ) + ); + const inheritedIndexInfos = + instantiatedBaseType !== anyType + ? getIndexInfosOfType(instantiatedBaseType) + : [anyBaseTypeIndexInfo]; + indexInfos = concatenate( + indexInfos, + filter( + inheritedIndexInfos, + (info) => !findIndexInfo(indexInfos, info.keyType) + ) + ); } } - setStructuredTypeMembers(type, members, callSignatures, constructSignatures, indexInfos); + setStructuredTypeMembers( + type, + members, + callSignatures, + constructSignatures, + indexInfos + ); } function resolveClassOrInterfaceMembers(type: InterfaceType): void { - resolveObjectTypeMembers(type, resolveDeclaredMembers(type), emptyArray, emptyArray); + resolveObjectTypeMembers( + type, + resolveDeclaredMembers(type), + emptyArray, + emptyArray + ); } function resolveTypeReferenceMembers(type: TypeReference): void { const source = resolveDeclaredMembers(type.target); - const typeParameters = concatenate(source.typeParameters!, [source.thisType!]); + const typeParameters = concatenate(source.typeParameters!, [ + source.thisType!, + ]); const typeArguments = getTypeArguments(type); - const paddedTypeArguments = typeArguments.length === typeParameters.length ? typeArguments : concatenate(typeArguments, [type]); - resolveObjectTypeMembers(type, source, typeParameters, paddedTypeArguments); + const paddedTypeArguments = + typeArguments.length === typeParameters.length + ? typeArguments + : concatenate(typeArguments, [type]); + resolveObjectTypeMembers( + type, + source, + typeParameters, + paddedTypeArguments + ); } function createSignature( @@ -14001,7 +24302,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { resolvedReturnType: Type | undefined, resolvedTypePredicate: TypePredicate | undefined, minArgumentCount: number, - flags: SignatureFlags, + flags: SignatureFlags ): Signature { const sig = new Signature(checker, flags); sig.declaration = declaration; @@ -14020,7 +24321,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function cloneSignature(sig: Signature): Signature { - const result = createSignature(sig.declaration, sig.typeParameters, sig.thisParameter, sig.parameters, /*resolvedReturnType*/ undefined, /*resolvedTypePredicate*/ undefined, sig.minArgumentCount, sig.flags & SignatureFlags.PropagatingFlags); + const result = createSignature( + sig.declaration, + sig.typeParameters, + sig.thisParameter, + sig.parameters, + /*resolvedReturnType*/ undefined, + /*resolvedTypePredicate*/ undefined, + sig.minArgumentCount, + sig.flags & SignatureFlags.PropagatingFlags + ); result.target = sig.target; result.mapper = sig.mapper; result.compositeSignatures = sig.compositeSignatures; @@ -14028,7 +24338,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function createUnionSignature(signature: Signature, unionSignatures: Signature[]) { + function createUnionSignature( + signature: Signature, + unionSignatures: Signature[] + ) { const result = cloneSignature(signature); result.compositeSignatures = unionSignatures; result.compositeKind = TypeFlags.Union; @@ -14037,58 +24350,129 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function getOptionalCallSignature(signature: Signature, callChainFlags: SignatureFlags): Signature { - if ((signature.flags & SignatureFlags.CallChainFlags) === callChainFlags) { + function getOptionalCallSignature( + signature: Signature, + callChainFlags: SignatureFlags + ): Signature { + if ( + (signature.flags & SignatureFlags.CallChainFlags) === + callChainFlags + ) { return signature; } if (!signature.optionalCallSignatureCache) { signature.optionalCallSignatureCache = {}; } - const key = callChainFlags === SignatureFlags.IsInnerCallChain ? "inner" : "outer"; - return signature.optionalCallSignatureCache[key] - || (signature.optionalCallSignatureCache[key] = createOptionalCallSignature(signature, callChainFlags)); + const key = + callChainFlags === SignatureFlags.IsInnerCallChain + ? "inner" + : "outer"; + return ( + signature.optionalCallSignatureCache[key] || + (signature.optionalCallSignatureCache[key] = + createOptionalCallSignature(signature, callChainFlags)) + ); } - function createOptionalCallSignature(signature: Signature, callChainFlags: SignatureFlags) { - Debug.assert(callChainFlags === SignatureFlags.IsInnerCallChain || callChainFlags === SignatureFlags.IsOuterCallChain, "An optional call signature can either be for an inner call chain or an outer call chain, but not both."); + function createOptionalCallSignature( + signature: Signature, + callChainFlags: SignatureFlags + ) { + Debug.assert( + callChainFlags === SignatureFlags.IsInnerCallChain || + callChainFlags === SignatureFlags.IsOuterCallChain, + "An optional call signature can either be for an inner call chain or an outer call chain, but not both." + ); const result = cloneSignature(signature); result.flags |= callChainFlags; return result; } - function getExpandedParameters(sig: Signature, skipUnionExpanding?: boolean): readonly (readonly Symbol[])[] { + function getExpandedParameters( + sig: Signature, + skipUnionExpanding?: boolean + ): readonly (readonly Symbol[])[] { if (signatureHasRestParameter(sig)) { const restIndex = sig.parameters.length - 1; const restSymbol = sig.parameters[restIndex]; const restType = getTypeOfSymbol(restSymbol); if (isTupleType(restType)) { - return [expandSignatureParametersWithTupleMembers(restType, restIndex, restSymbol)]; - } - else if (!skipUnionExpanding && restType.flags & TypeFlags.Union && every((restType as UnionType).types, isTupleType)) { - return map((restType as UnionType).types, t => expandSignatureParametersWithTupleMembers(t as TupleTypeReference, restIndex, restSymbol)); + return [ + expandSignatureParametersWithTupleMembers( + restType, + restIndex, + restSymbol + ), + ]; + } else if ( + !skipUnionExpanding && + restType.flags & TypeFlags.Union && + every((restType as UnionType).types, isTupleType) + ) { + return map((restType as UnionType).types, (t) => + expandSignatureParametersWithTupleMembers( + t as TupleTypeReference, + restIndex, + restSymbol + ) + ); } } return [sig.parameters]; - function expandSignatureParametersWithTupleMembers(restType: TupleTypeReference, restIndex: number, restSymbol: Symbol) { + function expandSignatureParametersWithTupleMembers( + restType: TupleTypeReference, + restIndex: number, + restSymbol: Symbol + ) { const elementTypes = getTypeArguments(restType); - const associatedNames = getUniqAssociatedNamesFromTupleType(restType, restSymbol); + const associatedNames = getUniqAssociatedNamesFromTupleType( + restType, + restSymbol + ); const restParams = map(elementTypes, (t, i) => { // Lookup the label from the individual tuple passed in before falling back to the signature `rest` parameter name - const name = associatedNames && associatedNames[i] ? associatedNames[i] : - getParameterNameAtPosition(sig, restIndex + i, restType); + const name = + associatedNames && associatedNames[i] + ? associatedNames[i] + : getParameterNameAtPosition( + sig, + restIndex + i, + restType + ); const flags = restType.target.elementFlags[i]; - const checkFlags = flags & ElementFlags.Variable ? CheckFlags.RestParameter : - flags & ElementFlags.Optional ? CheckFlags.OptionalParameter : 0; - const symbol = createSymbol(SymbolFlags.FunctionScopedVariable, name, checkFlags); - symbol.links.type = flags & ElementFlags.Rest ? createArrayType(t) : t; + const checkFlags = + flags & ElementFlags.Variable + ? CheckFlags.RestParameter + : flags & ElementFlags.Optional + ? CheckFlags.OptionalParameter + : 0; + const symbol = createSymbol( + SymbolFlags.FunctionScopedVariable, + name, + checkFlags + ); + symbol.links.type = + flags & ElementFlags.Rest ? createArrayType(t) : t; return symbol; }); return concatenate(sig.parameters.slice(0, restIndex), restParams); } - function getUniqAssociatedNamesFromTupleType(type: TupleTypeReference, restSymbol: Symbol) { - const names = map(type.target.labeledElementDeclarations, (labeledElement, i) => getTupleElementLabel(labeledElement, i, type.target.elementFlags[i], restSymbol)); + function getUniqAssociatedNamesFromTupleType( + type: TupleTypeReference, + restSymbol: Symbol + ) { + const names = map( + type.target.labeledElementDeclarations, + (labeledElement, i) => + getTupleElementLabel( + labeledElement, + i, + type.target.elementFlags[i], + restSymbol + ) + ); if (names) { const duplicates: number[] = []; const uniqueNames = new Set<__String>(); @@ -14102,7 +24486,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (const i of duplicates) { let counter = counters.get(names[i]) ?? 1; let name: __String; - while (!tryAddToSet(uniqueNames, name = `${names[i]}_${counter}` as __String)) { + while ( + !tryAddToSet( + uniqueNames, + (name = `${names[i]}_${counter}` as __String) + ) + ) { counter++; } names[i] = name; @@ -14113,13 +24502,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getDefaultConstructSignatures(classType: InterfaceType): Signature[] { + function getDefaultConstructSignatures( + classType: InterfaceType + ): Signature[] { const baseConstructorType = getBaseConstructorTypeOfClass(classType); - const baseSignatures = getSignaturesOfType(baseConstructorType, SignatureKind.Construct); + const baseSignatures = getSignaturesOfType( + baseConstructorType, + SignatureKind.Construct + ); const declaration = getClassLikeDeclarationOfSymbol(classType.symbol); - const isAbstract = !!declaration && hasSyntacticModifier(declaration, ModifierFlags.Abstract); + const isAbstract = + !!declaration && + hasSyntacticModifier(declaration, ModifierFlags.Abstract); if (baseSignatures.length === 0) { - return [createSignature(/*declaration*/ undefined, classType.localTypeParameters, /*thisParameter*/ undefined, emptyArray, classType, /*resolvedTypePredicate*/ undefined, 0, isAbstract ? SignatureFlags.Abstract : SignatureFlags.None)]; + return [ + createSignature( + /*declaration*/ undefined, + classType.localTypeParameters, + /*thisParameter*/ undefined, + emptyArray, + classType, + /*resolvedTypePredicate*/ undefined, + 0, + isAbstract ? SignatureFlags.Abstract : SignatureFlags.None + ), + ]; } const baseTypeNode = getBaseTypeNodeOfClass(classType)!; const isJavaScript = isInJSFile(baseTypeNode); @@ -14127,28 +24534,65 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const typeArgCount = length(typeArguments); const result: Signature[] = []; for (const baseSig of baseSignatures) { - const minTypeArgumentCount = getMinTypeArgumentCount(baseSig.typeParameters); + const minTypeArgumentCount = getMinTypeArgumentCount( + baseSig.typeParameters + ); const typeParamCount = length(baseSig.typeParameters); - if (isJavaScript || typeArgCount >= minTypeArgumentCount && typeArgCount <= typeParamCount) { - const sig = typeParamCount ? createSignatureInstantiation(baseSig, fillMissingTypeArguments(typeArguments, baseSig.typeParameters, minTypeArgumentCount, isJavaScript)) : cloneSignature(baseSig); + if ( + isJavaScript || + (typeArgCount >= minTypeArgumentCount && + typeArgCount <= typeParamCount) + ) { + const sig = typeParamCount + ? createSignatureInstantiation( + baseSig, + fillMissingTypeArguments( + typeArguments, + baseSig.typeParameters, + minTypeArgumentCount, + isJavaScript + ) + ) + : cloneSignature(baseSig); sig.typeParameters = classType.localTypeParameters; sig.resolvedReturnType = classType; - sig.flags = isAbstract ? sig.flags | SignatureFlags.Abstract : sig.flags & ~SignatureFlags.Abstract; + sig.flags = isAbstract + ? sig.flags | SignatureFlags.Abstract + : sig.flags & ~SignatureFlags.Abstract; result.push(sig); } } return result; } - function findMatchingSignature(signatureList: readonly Signature[], signature: Signature, partialMatch: boolean, ignoreThisTypes: boolean, ignoreReturnTypes: boolean): Signature | undefined { + function findMatchingSignature( + signatureList: readonly Signature[], + signature: Signature, + partialMatch: boolean, + ignoreThisTypes: boolean, + ignoreReturnTypes: boolean + ): Signature | undefined { for (const s of signatureList) { - if (compareSignaturesIdentical(s, signature, partialMatch, ignoreThisTypes, ignoreReturnTypes, partialMatch ? compareTypesSubtypeOf : compareTypesIdentical)) { + if ( + compareSignaturesIdentical( + s, + signature, + partialMatch, + ignoreThisTypes, + ignoreReturnTypes, + partialMatch ? compareTypesSubtypeOf : compareTypesIdentical + ) + ) { return s; } } } - function findMatchingSignatures(signatureLists: readonly (readonly Signature[])[], signature: Signature, listIndex: number): Signature[] | undefined { + function findMatchingSignatures( + signatureLists: readonly (readonly Signature[])[], + signature: Signature, + listIndex: number + ): Signature[] | undefined { if (signature.typeParameters) { // We require an exact match for generic signatures, so we only return signatures from the first // signature list and only if they have exact matches in the other signature lists. @@ -14156,7 +24600,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } for (let i = 1; i < signatureLists.length; i++) { - if (!findMatchingSignature(signatureLists[i], signature, /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ false)) { + if ( + !findMatchingSignature( + signatureLists[i], + signature, + /*partialMatch*/ false, + /*ignoreThisTypes*/ false, + /*ignoreReturnTypes*/ false + ) + ) { return undefined; } } @@ -14166,10 +24618,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (let i = 0; i < signatureLists.length; i++) { // Allow matching non-generic signatures to have excess parameters (as a fallback if exact parameter match is not found) and different return types. // Prefer matching this types if possible. - const match = i === listIndex - ? signature - : findMatchingSignature(signatureLists[i], signature, /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ true) - || findMatchingSignature(signatureLists[i], signature, /*partialMatch*/ true, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ true); + const match = + i === listIndex + ? signature + : findMatchingSignature( + signatureLists[i], + signature, + /*partialMatch*/ false, + /*ignoreThisTypes*/ false, + /*ignoreReturnTypes*/ true + ) || + findMatchingSignature( + signatureLists[i], + signature, + /*partialMatch*/ true, + /*ignoreThisTypes*/ false, + /*ignoreReturnTypes*/ true + ); if (!match) { return undefined; } @@ -14182,29 +24647,61 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Generic signatures must match exactly, but non-generic signatures are allowed to have extra optional // parameters and may differ in return types. When signatures differ in return types, the resulting return // type is the union of the constituent return types. - function getUnionSignatures(signatureLists: readonly (readonly Signature[])[]): Signature[] { + function getUnionSignatures( + signatureLists: readonly (readonly Signature[])[] + ): Signature[] { let result: Signature[] | undefined; let indexWithLengthOverOne: number | undefined; for (let i = 0; i < signatureLists.length; i++) { if (signatureLists[i].length === 0) return emptyArray; if (signatureLists[i].length > 1) { - indexWithLengthOverOne = indexWithLengthOverOne === undefined ? i : -1; // -1 is a signal there are multiple overload sets + indexWithLengthOverOne = + indexWithLengthOverOne === undefined ? i : -1; // -1 is a signal there are multiple overload sets } for (const signature of signatureLists[i]) { // Only process signatures with parameter lists that aren't already in the result list - if (!result || !findMatchingSignature(result, signature, /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ true)) { - const unionSignatures = findMatchingSignatures(signatureLists, signature, i); + if ( + !result || + !findMatchingSignature( + result, + signature, + /*partialMatch*/ false, + /*ignoreThisTypes*/ false, + /*ignoreReturnTypes*/ true + ) + ) { + const unionSignatures = findMatchingSignatures( + signatureLists, + signature, + i + ); if (unionSignatures) { let s = signature; // Union the result types when more than one signature matches if (unionSignatures.length > 1) { let thisParameter = signature.thisParameter; - const firstThisParameterOfUnionSignatures = forEach(unionSignatures, sig => sig.thisParameter); + const firstThisParameterOfUnionSignatures = forEach( + unionSignatures, + (sig) => sig.thisParameter + ); if (firstThisParameterOfUnionSignatures) { - const thisType = getIntersectionType(mapDefined(unionSignatures, sig => sig.thisParameter && getTypeOfSymbol(sig.thisParameter))); - thisParameter = createSymbolWithType(firstThisParameterOfUnionSignatures, thisType); + const thisType = getIntersectionType( + mapDefined( + unionSignatures, + (sig) => + sig.thisParameter && + getTypeOfSymbol(sig.thisParameter) + ) + ); + thisParameter = createSymbolWithType( + firstThisParameterOfUnionSignatures, + thisType + ); } - s = createUnionSignature(signature, unionSignatures); + s = createUnionSignature( + signature, + unionSignatures + ); s.thisParameter = thisParameter; } (result || (result = [])).push(s); @@ -14217,13 +24714,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // signature that handles all over them. We only do this when there are overloads in only one constituent. // (Overloads are conditional in nature and having overloads in multiple constituents would necessitate making a power set of // signatures from the type, whose ordering would be non-obvious) - const masterList = signatureLists[indexWithLengthOverOne !== undefined ? indexWithLengthOverOne : 0]; + const masterList = + signatureLists[ + indexWithLengthOverOne !== undefined + ? indexWithLengthOverOne + : 0 + ]; let results: Signature[] | undefined = masterList.slice(); for (const signatures of signatureLists) { if (signatures !== masterList) { const signature = signatures[0]; - Debug.assert(!!signature, "getUnionSignatures bails early on empty signature lists and should not have empty lists on second pass"); - results = !!signature.typeParameters && some(results, s => !!s.typeParameters && !compareTypeParametersIdentical(signature.typeParameters, s.typeParameters)) ? undefined : map(results, sig => combineSignaturesOfUnionMembers(sig, signature)); + Debug.assert( + !!signature, + "getUnionSignatures bails early on empty signature lists and should not have empty lists on second pass" + ); + results = + !!signature.typeParameters && + some( + results, + (s) => + !!s.typeParameters && + !compareTypeParametersIdentical( + signature.typeParameters, + s.typeParameters + ) + ) + ? undefined + : map(results, (sig) => + combineSignaturesOfUnionMembers( + sig, + signature + ) + ); if (!results) { break; } @@ -14234,7 +24756,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result || emptyArray; } - function compareTypeParametersIdentical(sourceParams: readonly TypeParameter[] | undefined, targetParams: readonly TypeParameter[] | undefined): boolean { + function compareTypeParametersIdentical( + sourceParams: readonly TypeParameter[] | undefined, + targetParams: readonly TypeParameter[] | undefined + ): boolean { if (length(sourceParams) !== length(targetParams)) { return false; } @@ -14248,7 +24773,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const target = targetParams[i]; if (source === target) continue; // We instantiate the target type parameter constraints into the source types so we can recognize `` as the same as `` - if (!isTypeIdenticalTo(getConstraintFromTypeParameter(source) || unknownType, instantiateType(getConstraintFromTypeParameter(target) || unknownType, mapper))) return false; + if ( + !isTypeIdenticalTo( + getConstraintFromTypeParameter(source) || unknownType, + instantiateType( + getConstraintFromTypeParameter(target) || unknownType, + mapper + ) + ) + ) + return false; // We don't compare defaults - we just use the type parameter defaults from the first signature that seems to match. // It might make sense to combine these defaults in the future, but doing so intelligently requires knowing // 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) @@ -14258,80 +24792,146 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; } - function combineUnionThisParam(left: Symbol | undefined, right: Symbol | undefined, mapper: TypeMapper | undefined): Symbol | undefined { + function combineUnionThisParam( + left: Symbol | undefined, + right: Symbol | undefined, + mapper: TypeMapper | undefined + ): Symbol | undefined { if (!left || !right) { return left || right; } // A signature `this` type might be a read or a write position... It's very possible that it should be invariant // and we should refuse to merge signatures if there are `this` types and they do not match. However, so as to be // permissive when calling, for now, we'll intersect the `this` types just like we do for param types in union signatures. - const thisType = getIntersectionType([getTypeOfSymbol(left), instantiateType(getTypeOfSymbol(right), mapper)]); + const thisType = getIntersectionType([ + getTypeOfSymbol(left), + instantiateType(getTypeOfSymbol(right), mapper), + ]); return createSymbolWithType(left, thisType); } - function combineUnionParameters(left: Signature, right: Signature, mapper: TypeMapper | undefined) { + function combineUnionParameters( + left: Signature, + right: Signature, + mapper: TypeMapper | undefined + ) { const leftCount = getParameterCount(left); const rightCount = getParameterCount(right); const longest = leftCount >= rightCount ? left : right; const shorter = longest === left ? right : left; const longestCount = longest === left ? leftCount : rightCount; - const eitherHasEffectiveRest = hasEffectiveRestParameter(left) || hasEffectiveRestParameter(right); - const needsExtraRestElement = eitherHasEffectiveRest && !hasEffectiveRestParameter(longest); - const params = new Array(longestCount + (needsExtraRestElement ? 1 : 0)); + const eitherHasEffectiveRest = + hasEffectiveRestParameter(left) || hasEffectiveRestParameter(right); + const needsExtraRestElement = + eitherHasEffectiveRest && !hasEffectiveRestParameter(longest); + const params = new Array( + longestCount + (needsExtraRestElement ? 1 : 0) + ); for (let i = 0; i < longestCount; i++) { let longestParamType = tryGetTypeAtPosition(longest, i)!; if (longest === right) { longestParamType = instantiateType(longestParamType, mapper); } - let shorterParamType = tryGetTypeAtPosition(shorter, i) || unknownType; + let shorterParamType = + tryGetTypeAtPosition(shorter, i) || unknownType; if (shorter === right) { shorterParamType = instantiateType(shorterParamType, mapper); } - const unionParamType = getIntersectionType([longestParamType, shorterParamType]); - const isRestParam = eitherHasEffectiveRest && !needsExtraRestElement && i === (longestCount - 1); - const isOptional = i >= getMinArgumentCount(longest) && i >= getMinArgumentCount(shorter); - const leftName = i >= leftCount ? undefined : getParameterNameAtPosition(left, i); - const rightName = i >= rightCount ? undefined : getParameterNameAtPosition(right, i); - - const paramName = leftName === rightName ? leftName : - !leftName ? rightName : - !rightName ? leftName : - undefined; + const unionParamType = getIntersectionType([ + longestParamType, + shorterParamType, + ]); + const isRestParam = + eitherHasEffectiveRest && + !needsExtraRestElement && + i === longestCount - 1; + const isOptional = + i >= getMinArgumentCount(longest) && + i >= getMinArgumentCount(shorter); + const leftName = + i >= leftCount + ? undefined + : getParameterNameAtPosition(left, i); + const rightName = + i >= rightCount + ? undefined + : getParameterNameAtPosition(right, i); + + const paramName = + leftName === rightName + ? leftName + : !leftName + ? rightName + : !rightName + ? leftName + : undefined; const paramSymbol = createSymbol( - SymbolFlags.FunctionScopedVariable | (isOptional && !isRestParam ? SymbolFlags.Optional : 0), - paramName || `arg${i}` as __String, - isRestParam ? CheckFlags.RestParameter : isOptional ? CheckFlags.OptionalParameter : 0, + SymbolFlags.FunctionScopedVariable | + (isOptional && !isRestParam ? SymbolFlags.Optional : 0), + paramName || (`arg${i}` as __String), + isRestParam + ? CheckFlags.RestParameter + : isOptional + ? CheckFlags.OptionalParameter + : 0 ); - paramSymbol.links.type = isRestParam ? createArrayType(unionParamType) : unionParamType; + paramSymbol.links.type = isRestParam + ? createArrayType(unionParamType) + : unionParamType; params[i] = paramSymbol; } if (needsExtraRestElement) { - const restParamSymbol = createSymbol(SymbolFlags.FunctionScopedVariable, "args" as __String, CheckFlags.RestParameter); - restParamSymbol.links.type = createArrayType(getTypeAtPosition(shorter, longestCount)); + const restParamSymbol = createSymbol( + SymbolFlags.FunctionScopedVariable, + "args" as __String, + CheckFlags.RestParameter + ); + restParamSymbol.links.type = createArrayType( + getTypeAtPosition(shorter, longestCount) + ); if (shorter === right) { - restParamSymbol.links.type = instantiateType(restParamSymbol.links.type, mapper); + restParamSymbol.links.type = instantiateType( + restParamSymbol.links.type, + mapper + ); } params[longestCount] = restParamSymbol; } return params; } - function combineSignaturesOfUnionMembers(left: Signature, right: Signature): Signature { + function combineSignaturesOfUnionMembers( + left: Signature, + right: Signature + ): Signature { const typeParams = left.typeParameters || right.typeParameters; let paramMapper: TypeMapper | undefined; if (left.typeParameters && right.typeParameters) { - paramMapper = createTypeMapper(right.typeParameters, left.typeParameters); + paramMapper = createTypeMapper( + right.typeParameters, + left.typeParameters + ); // We just use the type parameter defaults from the first signature } - let flags = (left.flags | right.flags) & (SignatureFlags.PropagatingFlags & ~SignatureFlags.HasRestParameter); + let flags = + (left.flags | right.flags) & + (SignatureFlags.PropagatingFlags & + ~SignatureFlags.HasRestParameter); const declaration = left.declaration; const params = combineUnionParameters(left, right, paramMapper); const lastParam = lastOrUndefined(params); if (lastParam && getCheckFlags(lastParam) & CheckFlags.RestParameter) { flags |= SignatureFlags.HasRestParameter; } - const thisParam = combineUnionThisParam(left.thisParameter, right.thisParameter, paramMapper); - const minArgCount = Math.max(left.minArgumentCount, right.minArgumentCount); + const thisParam = combineUnionThisParam( + left.thisParameter, + right.thisParameter, + paramMapper + ); + const minArgCount = Math.max( + left.minArgumentCount, + right.minArgumentCount + ); const result = createSignature( declaration, typeParams, @@ -14340,14 +24940,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /*resolvedReturnType*/ undefined, /*resolvedTypePredicate*/ undefined, minArgCount, - flags, + flags ); result.compositeKind = TypeFlags.Union; - result.compositeSignatures = concatenate(left.compositeKind !== TypeFlags.Intersection && left.compositeSignatures || [left], [right]); + result.compositeSignatures = concatenate( + (left.compositeKind !== TypeFlags.Intersection && + left.compositeSignatures) || [left], + [right] + ); if (paramMapper) { - result.mapper = left.compositeKind !== TypeFlags.Intersection && left.mapper && left.compositeSignatures ? combineTypeMappers(left.mapper, paramMapper) : paramMapper; - } - else if (left.compositeKind !== TypeFlags.Intersection && left.mapper && left.compositeSignatures) { + result.mapper = + left.compositeKind !== TypeFlags.Intersection && + left.mapper && + left.compositeSignatures + ? combineTypeMappers(left.mapper, paramMapper) + : paramMapper; + } else if ( + left.compositeKind !== TypeFlags.Intersection && + left.mapper && + left.compositeSignatures + ) { result.mapper = left.mapper; } return result; @@ -14359,8 +24971,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const result = []; for (const info of sourceInfos) { const indexType = info.keyType; - if (every(types, t => !!getIndexInfoOfType(t, indexType))) { - result.push(createIndexInfo(indexType, getUnionType(map(types, t => getIndexTypeOfType(t, indexType)!)), some(types, t => getIndexInfoOfType(t, indexType)!.isReadonly))); + if (every(types, (t) => !!getIndexInfoOfType(t, indexType))) { + result.push( + createIndexInfo( + indexType, + getUnionType( + map( + types, + (t) => getIndexTypeOfType(t, indexType)! + ) + ), + some( + types, + (t) => + getIndexInfoOfType(t, indexType)!.isReadonly + ) + ) + ); } } return result; @@ -14371,36 +24998,79 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function resolveUnionTypeMembers(type: UnionType) { // The members and properties collections are empty for union types. To get all properties of a union // type use getPropertiesOfType (only the language service uses this). - const callSignatures = getUnionSignatures(map(type.types, t => t === globalFunctionType ? [unknownSignature] : getSignaturesOfType(t, SignatureKind.Call))); - const constructSignatures = getUnionSignatures(map(type.types, t => getSignaturesOfType(t, SignatureKind.Construct))); + const callSignatures = getUnionSignatures( + map(type.types, (t) => + t === globalFunctionType + ? [unknownSignature] + : getSignaturesOfType(t, SignatureKind.Call) + ) + ); + const constructSignatures = getUnionSignatures( + map(type.types, (t) => + getSignaturesOfType(t, SignatureKind.Construct) + ) + ); const indexInfos = getUnionIndexInfos(type.types); - setStructuredTypeMembers(type, emptySymbols, callSignatures, constructSignatures, indexInfos); + setStructuredTypeMembers( + type, + emptySymbols, + callSignatures, + constructSignatures, + indexInfos + ); } function intersectTypes(type1: Type, type2: Type): Type; - function intersectTypes(type1: Type | undefined, type2: Type | undefined): Type | undefined; - function intersectTypes(type1: Type | undefined, type2: Type | undefined): Type | undefined { - return !type1 ? type2 : !type2 ? type1 : getIntersectionType([type1, type2]); + function intersectTypes( + type1: Type | undefined, + type2: Type | undefined + ): Type | undefined; + function intersectTypes( + type1: Type | undefined, + type2: Type | undefined + ): Type | undefined { + return !type1 + ? type2 + : !type2 + ? type1 + : getIntersectionType([type1, type2]); } function findMixins(types: readonly Type[]): readonly boolean[] { - const constructorTypeCount = countWhere(types, t => getSignaturesOfType(t, SignatureKind.Construct).length > 0); + const constructorTypeCount = countWhere( + types, + (t) => getSignaturesOfType(t, SignatureKind.Construct).length > 0 + ); const mixinFlags = map(types, isMixinConstructorType); - if (constructorTypeCount > 0 && constructorTypeCount === countWhere(mixinFlags, b => b)) { + if ( + constructorTypeCount > 0 && + constructorTypeCount === countWhere(mixinFlags, (b) => b) + ) { const firstMixinIndex = mixinFlags.indexOf(/*searchElement*/ true); mixinFlags[firstMixinIndex] = false; } return mixinFlags; } - function includeMixinType(type: Type, types: readonly Type[], mixinFlags: readonly boolean[], index: number): Type { + function includeMixinType( + type: Type, + types: readonly Type[], + mixinFlags: readonly boolean[], + index: number + ): Type { const mixedTypes: Type[] = []; for (let i = 0; i < types.length; i++) { if (i === index) { mixedTypes.push(type); - } - else if (mixinFlags[i]) { - mixedTypes.push(getReturnTypeOfSignature(getSignaturesOfType(types[i], SignatureKind.Construct)[0])); + } else if (mixinFlags[i]) { + mixedTypes.push( + getReturnTypeOfSignature( + getSignaturesOfType( + types[i], + SignatureKind.Construct + )[0] + ) + ); } } return getIntersectionType(mixedTypes); @@ -14414,7 +25084,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let indexInfos: IndexInfo[] | undefined; const types = type.types; const mixinFlags = findMixins(types); - const mixinCount = countWhere(mixinFlags, b => b); + const mixinCount = countWhere(mixinFlags, (b) => b); for (let i = 0; i < types.length; i++) { const t = type.types[i]; // When an intersection type contains mixin constructor types, the construct signatures from @@ -14423,37 +25093,91 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // '{ new(...args: any[]) => A } & { new(s: string) => B }' has a single construct signature // 'new(s: string) => A & B'. if (!mixinFlags[i]) { - let signatures = getSignaturesOfType(t, SignatureKind.Construct); + let signatures = getSignaturesOfType( + t, + SignatureKind.Construct + ); if (signatures.length && mixinCount > 0) { - signatures = map(signatures, s => { + signatures = map(signatures, (s) => { const clone = cloneSignature(s); - clone.resolvedReturnType = includeMixinType(getReturnTypeOfSignature(s), types, mixinFlags, i); + clone.resolvedReturnType = includeMixinType( + getReturnTypeOfSignature(s), + types, + mixinFlags, + i + ); return clone; }); } - constructSignatures = appendSignatures(constructSignatures, signatures); + constructSignatures = appendSignatures( + constructSignatures, + signatures + ); } - callSignatures = appendSignatures(callSignatures, getSignaturesOfType(t, SignatureKind.Call)); - indexInfos = reduceLeft(getIndexInfosOfType(t), (infos, newInfo) => appendIndexInfo(infos, newInfo, /*union*/ false), indexInfos); + callSignatures = appendSignatures( + callSignatures, + getSignaturesOfType(t, SignatureKind.Call) + ); + indexInfos = reduceLeft( + getIndexInfosOfType(t), + (infos, newInfo) => + appendIndexInfo(infos, newInfo, /*union*/ false), + indexInfos + ); } - setStructuredTypeMembers(type, emptySymbols, callSignatures || emptyArray, constructSignatures || emptyArray, indexInfos || emptyArray); + setStructuredTypeMembers( + type, + emptySymbols, + callSignatures || emptyArray, + constructSignatures || emptyArray, + indexInfos || emptyArray + ); } - function appendSignatures(signatures: Signature[] | undefined, newSignatures: readonly Signature[]) { + function appendSignatures( + signatures: Signature[] | undefined, + newSignatures: readonly Signature[] + ) { for (const sig of newSignatures) { - if (!signatures || every(signatures, s => !compareSignaturesIdentical(s, sig, /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ false, compareTypesIdentical))) { + if ( + !signatures || + every( + signatures, + (s) => + !compareSignaturesIdentical( + s, + sig, + /*partialMatch*/ false, + /*ignoreThisTypes*/ false, + /*ignoreReturnTypes*/ false, + compareTypesIdentical + ) + ) + ) { signatures = append(signatures, sig); } } return signatures; } - function appendIndexInfo(indexInfos: IndexInfo[] | undefined, newInfo: IndexInfo, union: boolean) { + function appendIndexInfo( + indexInfos: IndexInfo[] | undefined, + newInfo: IndexInfo, + union: boolean + ) { if (indexInfos) { for (let i = 0; i < indexInfos.length; i++) { const info = indexInfos[i]; if (info.keyType === newInfo.keyType) { - indexInfos[i] = createIndexInfo(info.keyType, union ? getUnionType([info.type, newInfo.type]) : getIntersectionType([info.type, newInfo.type]), union ? info.isReadonly || newInfo.isReadonly : info.isReadonly && newInfo.isReadonly); + indexInfos[i] = createIndexInfo( + info.keyType, + union + ? getUnionType([info.type, newInfo.type]) + : getIntersectionType([info.type, newInfo.type]), + union + ? info.isReadonly || newInfo.isReadonly + : info.isReadonly && newInfo.isReadonly + ); return indexInfos; } } @@ -14466,22 +25190,63 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { */ function resolveAnonymousTypeMembers(type: AnonymousType) { if (type.target) { - setStructuredTypeMembers(type, emptySymbols, emptyArray, emptyArray, emptyArray); - const members = createInstantiatedSymbolTable(getPropertiesOfObjectType(type.target), type.mapper!, /*mappingThisOnly*/ false); - const callSignatures = instantiateSignatures(getSignaturesOfType(type.target, SignatureKind.Call), type.mapper!); - const constructSignatures = instantiateSignatures(getSignaturesOfType(type.target, SignatureKind.Construct), type.mapper!); - const indexInfos = instantiateIndexInfos(getIndexInfosOfType(type.target), type.mapper!); - setStructuredTypeMembers(type, members, callSignatures, constructSignatures, indexInfos); + setStructuredTypeMembers( + type, + emptySymbols, + emptyArray, + emptyArray, + emptyArray + ); + const members = createInstantiatedSymbolTable( + getPropertiesOfObjectType(type.target), + type.mapper!, + /*mappingThisOnly*/ false + ); + const callSignatures = instantiateSignatures( + getSignaturesOfType(type.target, SignatureKind.Call), + type.mapper! + ); + const constructSignatures = instantiateSignatures( + getSignaturesOfType(type.target, SignatureKind.Construct), + type.mapper! + ); + const indexInfos = instantiateIndexInfos( + getIndexInfosOfType(type.target), + type.mapper! + ); + setStructuredTypeMembers( + type, + members, + callSignatures, + constructSignatures, + indexInfos + ); return; } const symbol = getMergedSymbol(type.symbol); if (symbol.flags & SymbolFlags.TypeLiteral) { - setStructuredTypeMembers(type, emptySymbols, emptyArray, emptyArray, emptyArray); + setStructuredTypeMembers( + type, + emptySymbols, + emptyArray, + emptyArray, + emptyArray + ); const members = getMembersOfSymbol(symbol); - const callSignatures = getSignaturesOfSymbol(members.get(InternalSymbolName.Call)); - const constructSignatures = getSignaturesOfSymbol(members.get(InternalSymbolName.New)); + const callSignatures = getSignaturesOfSymbol( + members.get(InternalSymbolName.Call) + ); + const constructSignatures = getSignaturesOfSymbol( + members.get(InternalSymbolName.New) + ); const indexInfos = getIndexInfosOfSymbol(symbol); - setStructuredTypeMembers(type, members, callSignatures, constructSignatures, indexInfos); + setStructuredTypeMembers( + type, + members, + callSignatures, + constructSignatures, + indexInfos + ); return; } // Combinations of function, class, enum and module @@ -14489,43 +25254,82 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let indexInfos: IndexInfo[] | undefined; if (symbol === globalThisSymbol) { const varsOnly = new Map<__String, Symbol>(); - members.forEach(p => { - if (!(p.flags & SymbolFlags.BlockScoped) && !(p.flags & SymbolFlags.ValueModule && p.declarations?.length && every(p.declarations, isAmbientModule))) { + members.forEach((p) => { + if ( + !(p.flags & SymbolFlags.BlockScoped) && + !( + p.flags & SymbolFlags.ValueModule && + p.declarations?.length && + every(p.declarations, isAmbientModule) + ) + ) { varsOnly.set(p.escapedName, p); } }); members = varsOnly; } let baseConstructorIndexInfo: IndexInfo | undefined; - setStructuredTypeMembers(type, members, emptyArray, emptyArray, emptyArray); + setStructuredTypeMembers( + type, + members, + emptyArray, + emptyArray, + emptyArray + ); if (symbol.flags & SymbolFlags.Class) { const classType = getDeclaredTypeOfClassOrInterface(symbol); - const baseConstructorType = getBaseConstructorTypeOfClass(classType); - if (baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.TypeVariable)) { - members = createSymbolTable(getNamedOrIndexSignatureMembers(members)); - addInheritedMembers(members, getPropertiesOfType(baseConstructorType)); - } - else if (baseConstructorType === anyType) { + const baseConstructorType = + getBaseConstructorTypeOfClass(classType); + if ( + baseConstructorType.flags & + (TypeFlags.Object | + TypeFlags.Intersection | + TypeFlags.TypeVariable) + ) { + members = createSymbolTable( + getNamedOrIndexSignatureMembers(members) + ); + addInheritedMembers( + members, + getPropertiesOfType(baseConstructorType) + ); + } else if (baseConstructorType === anyType) { baseConstructorIndexInfo = anyBaseTypeIndexInfo; } } const indexSymbol = getIndexSymbolFromSymbolTable(members); if (indexSymbol) { - indexInfos = getIndexInfosOfIndexSymbol(indexSymbol, arrayFrom(members.values())); - } - else { + indexInfos = getIndexInfosOfIndexSymbol( + indexSymbol, + arrayFrom(members.values()) + ); + } else { if (baseConstructorIndexInfo) { indexInfos = append(indexInfos, baseConstructorIndexInfo); } if ( - symbol.flags & SymbolFlags.Enum && (getDeclaredTypeOfSymbol(symbol).flags & TypeFlags.Enum || - some(type.properties, prop => !!(getTypeOfSymbol(prop).flags & TypeFlags.NumberLike))) + symbol.flags & SymbolFlags.Enum && + (getDeclaredTypeOfSymbol(symbol).flags & TypeFlags.Enum || + some( + type.properties, + (prop) => + !!( + getTypeOfSymbol(prop).flags & + TypeFlags.NumberLike + ) + )) ) { indexInfos = append(indexInfos, enumNumberIndexInfo); } } - setStructuredTypeMembers(type, members, emptyArray, emptyArray, indexInfos || emptyArray); + setStructuredTypeMembers( + type, + members, + emptyArray, + emptyArray, + indexInfos || emptyArray + ); // We resolve the members before computing the signatures because a signature may use // typeof with a qualified name expression that circularly references the type we are // in the process of resolving (see issue #6072). The temporarily empty signature list @@ -14536,17 +25340,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // And likewise for construct signatures for classes if (symbol.flags & SymbolFlags.Class) { const classType = getDeclaredTypeOfClassOrInterface(symbol); - let constructSignatures = symbol.members ? getSignaturesOfSymbol(symbol.members.get(InternalSymbolName.Constructor)) : emptyArray; + let constructSignatures = symbol.members + ? getSignaturesOfSymbol( + symbol.members.get(InternalSymbolName.Constructor) + ) + : emptyArray; if (symbol.flags & SymbolFlags.Function) { constructSignatures = addRange( constructSignatures.slice(), - mapDefined( - type.callSignatures, - sig => - isJSConstructor(sig.declaration) ? - createSignature(sig.declaration, sig.typeParameters, sig.thisParameter, sig.parameters, classType, /*resolvedTypePredicate*/ undefined, sig.minArgumentCount, sig.flags & SignatureFlags.PropagatingFlags) : - undefined, - ), + mapDefined(type.callSignatures, (sig) => + isJSConstructor(sig.declaration) + ? createSignature( + sig.declaration, + sig.typeParameters, + sig.thisParameter, + sig.parameters, + classType, + /*resolvedTypePredicate*/ undefined, + sig.minArgumentCount, + sig.flags & SignatureFlags.PropagatingFlags + ) + : undefined + ) ); } if (!constructSignatures.length) { @@ -14556,12 +25371,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - type ReplaceableIndexedAccessType = IndexedAccessType & { objectType: TypeParameter; indexType: TypeParameter; }; - function replaceIndexedAccess(instantiable: Type, type: ReplaceableIndexedAccessType, replacement: Type) { + type ReplaceableIndexedAccessType = IndexedAccessType & { + objectType: TypeParameter; + indexType: TypeParameter; + }; + function replaceIndexedAccess( + instantiable: Type, + type: ReplaceableIndexedAccessType, + replacement: Type + ) { // map type.indexType to 0 // map type.objectType to `[TReplacement]` // thus making the indexed access `[TReplacement][0]` or `TReplacement` - return instantiateType(instantiable, createTypeMapper([type.indexType, type.objectType], [getNumberLiteralType(0), createTupleType([replacement])])); + return instantiateType( + instantiable, + createTypeMapper( + [type.indexType, type.objectType], + [getNumberLiteralType(0), createTupleType([replacement])] + ) + ); } // If the original mapped type had an intersection constraint we extract its components, @@ -14570,23 +25398,51 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // e.g. { [K in keyof U & ("a" | "b") ] } -> "a" | "b" function getLimitedConstraint(type: ReverseMappedType) { const constraint = getConstraintTypeFromMappedType(type.mappedType); - if (!(constraint.flags & TypeFlags.Union || constraint.flags & TypeFlags.Intersection)) { + if ( + !( + constraint.flags & TypeFlags.Union || + constraint.flags & TypeFlags.Intersection + ) + ) { return; } - const origin = (constraint.flags & TypeFlags.Union) ? (constraint as UnionType).origin : (constraint as IntersectionType); + const origin = + constraint.flags & TypeFlags.Union + ? (constraint as UnionType).origin + : (constraint as IntersectionType); if (!origin || !(origin.flags & TypeFlags.Intersection)) { return; } - const limitedConstraint = getIntersectionType((origin as IntersectionType).types.filter(t => t !== type.constraintType)); + const limitedConstraint = getIntersectionType( + (origin as IntersectionType).types.filter( + (t) => t !== type.constraintType + ) + ); return limitedConstraint !== neverType ? limitedConstraint : undefined; } function resolveReverseMappedTypeMembers(type: ReverseMappedType) { const indexInfo = getIndexInfoOfType(type.source, stringType); const modifiers = getMappedTypeModifiers(type.mappedType); - const readonlyMask = modifiers & MappedTypeModifiers.IncludeReadonly ? false : true; - const optionalMask = modifiers & MappedTypeModifiers.IncludeOptional ? 0 : SymbolFlags.Optional; - const indexInfos = indexInfo ? [createIndexInfo(stringType, inferReverseMappedType(indexInfo.type, type.mappedType, type.constraintType) || unknownType, readonlyMask && indexInfo.isReadonly)] : emptyArray; + const readonlyMask = + modifiers & MappedTypeModifiers.IncludeReadonly ? false : true; + const optionalMask = + modifiers & MappedTypeModifiers.IncludeOptional + ? 0 + : SymbolFlags.Optional; + const indexInfos = indexInfo + ? [ + createIndexInfo( + stringType, + inferReverseMappedType( + indexInfo.type, + type.mappedType, + type.constraintType + ) || unknownType, + readonlyMask && indexInfo.isReadonly + ), + ] + : emptyArray; const members = createSymbolTable(); const limitedConstraint = getLimitedConstraint(type); for (const prop of getPropertiesOfType(type.source)) { @@ -14594,36 +25450,62 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // extract the filtering type literals we skip those properties that are not assignable to them, // because the extra properties wouldn't get through the application of the mapped type anyway if (limitedConstraint) { - const propertyNameType = getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique); + const propertyNameType = getLiteralTypeFromProperty( + prop, + TypeFlags.StringOrNumberLiteralOrUnique + ); if (!isTypeAssignableTo(propertyNameType, limitedConstraint)) { continue; } } - const checkFlags = CheckFlags.ReverseMapped | (readonlyMask && isReadonlySymbol(prop) ? CheckFlags.Readonly : 0); - const inferredProp = createSymbol(SymbolFlags.Property | prop.flags & optionalMask, prop.escapedName, checkFlags) as ReverseMappedSymbol; + const checkFlags = + CheckFlags.ReverseMapped | + (readonlyMask && isReadonlySymbol(prop) + ? CheckFlags.Readonly + : 0); + const inferredProp = createSymbol( + SymbolFlags.Property | (prop.flags & optionalMask), + prop.escapedName, + checkFlags + ) as ReverseMappedSymbol; inferredProp.declarations = prop.declarations; inferredProp.links.nameType = getSymbolLinks(prop).nameType; inferredProp.links.propertyType = getTypeOfSymbol(prop); if ( - type.constraintType.type.flags & TypeFlags.IndexedAccess - && (type.constraintType.type as IndexedAccessType).objectType.flags & TypeFlags.TypeParameter - && (type.constraintType.type as IndexedAccessType).indexType.flags & TypeFlags.TypeParameter + type.constraintType.type.flags & TypeFlags.IndexedAccess && + (type.constraintType.type as IndexedAccessType).objectType + .flags & TypeFlags.TypeParameter && + (type.constraintType.type as IndexedAccessType).indexType + .flags & TypeFlags.TypeParameter ) { // 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 // inferring to the "type parameter" (or indexed access) shared by the constraint and template. So, to reduce the number of // type identities produced, we simplify such indexed access occurences - const newTypeParam = (type.constraintType.type as IndexedAccessType).objectType; - const newMappedType = replaceIndexedAccess(type.mappedType, type.constraintType.type as ReplaceableIndexedAccessType, newTypeParam); + const newTypeParam = ( + type.constraintType.type as IndexedAccessType + ).objectType; + const newMappedType = replaceIndexedAccess( + type.mappedType, + type.constraintType.type as ReplaceableIndexedAccessType, + newTypeParam + ); inferredProp.links.mappedType = newMappedType as MappedType; - inferredProp.links.constraintType = getIndexType(newTypeParam) as IndexType; - } - else { + inferredProp.links.constraintType = getIndexType( + newTypeParam + ) as IndexType; + } else { inferredProp.links.mappedType = type.mappedType; inferredProp.links.constraintType = type.constraintType; } members.set(prop.escapedName, inferredProp); } - setStructuredTypeMembers(type, members, emptyArray, emptyArray, indexInfos); + setStructuredTypeMembers( + type, + members, + emptyArray, + emptyArray, + indexInfos + ); } // Return the lower bound of the key type in a mapped type. Intuitively, the lower @@ -14632,29 +25514,52 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getLowerBoundOfKeyType(type: Type): Type { if (type.flags & TypeFlags.Index) { const t = getApparentType((type as IndexType).type); - return isGenericTupleType(t) ? getKnownKeysOfTupleType(t) : getIndexType(t); + return isGenericTupleType(t) + ? getKnownKeysOfTupleType(t) + : getIndexType(t); } if (type.flags & TypeFlags.Conditional) { if ((type as ConditionalType).root.isDistributive) { const checkType = (type as ConditionalType).checkType; const constraint = getLowerBoundOfKeyType(checkType); if (constraint !== checkType) { - return getConditionalTypeInstantiation(type as ConditionalType, prependTypeMapping((type as ConditionalType).root.checkType, constraint, (type as ConditionalType).mapper), /*forConstraint*/ false); + return getConditionalTypeInstantiation( + type as ConditionalType, + prependTypeMapping( + (type as ConditionalType).root.checkType, + constraint, + (type as ConditionalType).mapper + ), + /*forConstraint*/ false + ); } } return type; } if (type.flags & TypeFlags.Union) { - return mapType(type as UnionType, getLowerBoundOfKeyType, /*noReductions*/ true); + return mapType( + type as UnionType, + getLowerBoundOfKeyType, + /*noReductions*/ true + ); } if (type.flags & TypeFlags.Intersection) { // Similarly to getTypeFromIntersectionTypeNode, we preserve the special string & {}, number & {}, // and bigint & {} intersections that are used to prevent subtype reduction in union types. const types = (type as IntersectionType).types; - if (types.length === 2 && !!(types[0].flags & (TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt)) && types[1] === emptyTypeLiteralType) { + if ( + types.length === 2 && + !!( + types[0].flags & + (TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt) + ) && + types[1] === emptyTypeLiteralType + ) { return type; } - return getIntersectionType(sameMap((type as UnionType).types, getLowerBoundOfKeyType)); + return getIntersectionType( + sameMap((type as UnionType).types, getLowerBoundOfKeyType) + ); } return type; } @@ -14663,16 +25568,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getCheckFlags(s) & CheckFlags.Late; } - function forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType(type: Type, include: TypeFlags, stringsOnly: boolean, cb: (keyType: Type) => void) { + function forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType( + type: Type, + include: TypeFlags, + stringsOnly: boolean, + cb: (keyType: Type) => void + ) { for (const prop of getPropertiesOfType(type)) { cb(getLiteralTypeFromProperty(prop, include)); } if (type.flags & TypeFlags.Any) { cb(stringType); - } - else { + } else { for (const info of getIndexInfosOfType(type)) { - if (!stringsOnly || info.keyType.flags & (TypeFlags.String | TypeFlags.TemplateLiteral)) { + if ( + !stringsOnly || + info.keyType.flags & + (TypeFlags.String | TypeFlags.TemplateLiteral) + ) { cb(info.keyType); } } @@ -14684,30 +25597,60 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const members: SymbolTable = createSymbolTable(); let indexInfos: IndexInfo[] | undefined; // Resolve upfront such that recursive references see an empty object type. - setStructuredTypeMembers(type, emptySymbols, emptyArray, emptyArray, emptyArray); + setStructuredTypeMembers( + type, + emptySymbols, + emptyArray, + emptyArray, + emptyArray + ); // In { [P in K]: T }, we refer to P as the type parameter type, K as the constraint type, // and T as the template type. const typeParameter = getTypeParameterFromMappedType(type); const constraintType = getConstraintTypeFromMappedType(type); const mappedType = (type.target as MappedType) || type; const nameType = getNameTypeFromMappedType(mappedType); - const shouldLinkPropDeclarations = getMappedTypeNameTypeKind(mappedType) !== MappedTypeNameTypeKind.Remapping; + const shouldLinkPropDeclarations = + getMappedTypeNameTypeKind(mappedType) !== + MappedTypeNameTypeKind.Remapping; const templateType = getTemplateTypeFromMappedType(mappedType); - const modifiersType = getApparentType(getModifiersTypeFromMappedType(type)); // The 'T' in 'keyof T' + const modifiersType = getApparentType( + getModifiersTypeFromMappedType(type) + ); // The 'T' in 'keyof T' const templateModifiers = getMappedTypeModifiers(type); const include = TypeFlags.StringOrNumberLiteralOrUnique; if (isMappedTypeWithKeyofConstraintDeclaration(type)) { // We have a { [P in keyof T]: X } - forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType(modifiersType, include, /*stringsOnly*/ false, addMemberForKeyType); - } - else { - forEachType(getLowerBoundOfKeyType(constraintType), addMemberForKeyType); + forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType( + modifiersType, + include, + /*stringsOnly*/ false, + addMemberForKeyType + ); + } else { + forEachType( + getLowerBoundOfKeyType(constraintType), + addMemberForKeyType + ); } - setStructuredTypeMembers(type, members, emptyArray, emptyArray, indexInfos || emptyArray); + setStructuredTypeMembers( + type, + members, + emptyArray, + emptyArray, + indexInfos || emptyArray + ); function addMemberForKeyType(keyType: Type) { - const propNameType = nameType ? instantiateType(nameType, appendTypeMapping(type.mapper, typeParameter, keyType)) : keyType; - forEachType(propNameType, t => addMemberForKeyTypeWorker(keyType, t)); + const propNameType = nameType + ? instantiateType( + nameType, + appendTypeMapping(type.mapper, typeParameter, keyType) + ) + : keyType; + forEachType(propNameType, (t) => + addMemberForKeyTypeWorker(keyType, t) + ); } function addMemberForKeyTypeWorker(keyType: Type, propNameType: Type) { @@ -14718,40 +25661,109 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // String enum members from separate enums with identical values // are distinct types with the same property name. Make the resulting // property symbol's name type be the union of those enum member types. - const existingProp = members.get(propName) as MappedSymbol | undefined; + const existingProp = members.get(propName) as + | MappedSymbol + | undefined; if (existingProp) { - existingProp.links.nameType = getUnionType([existingProp.links.nameType!, propNameType]); - existingProp.links.keyType = getUnionType([existingProp.links.keyType, keyType]); - } - else { - const modifiersProp = isTypeUsableAsPropertyName(keyType) ? getPropertyOfType(modifiersType, getPropertyNameFromType(keyType)) : undefined; - const isOptional = !!(templateModifiers & MappedTypeModifiers.IncludeOptional || - !(templateModifiers & MappedTypeModifiers.ExcludeOptional) && modifiersProp && modifiersProp.flags & SymbolFlags.Optional); - const isReadonly = !!(templateModifiers & MappedTypeModifiers.IncludeReadonly || - !(templateModifiers & MappedTypeModifiers.ExcludeReadonly) && modifiersProp && isReadonlySymbol(modifiersProp)); - const stripOptional = strictNullChecks && !isOptional && modifiersProp && modifiersProp.flags & SymbolFlags.Optional; - const lateFlag: CheckFlags = modifiersProp ? getIsLateCheckFlag(modifiersProp) : 0; - const prop = createSymbol(SymbolFlags.Property | (isOptional ? SymbolFlags.Optional : 0), propName, lateFlag | CheckFlags.Mapped | (isReadonly ? CheckFlags.Readonly : 0) | (stripOptional ? CheckFlags.StripOptional : 0)) as MappedSymbol; + existingProp.links.nameType = getUnionType([ + existingProp.links.nameType!, + propNameType, + ]); + existingProp.links.keyType = getUnionType([ + existingProp.links.keyType, + keyType, + ]); + } else { + const modifiersProp = isTypeUsableAsPropertyName(keyType) + ? getPropertyOfType( + modifiersType, + getPropertyNameFromType(keyType) + ) + : undefined; + const isOptional = !!( + templateModifiers & + MappedTypeModifiers.IncludeOptional || + (!( + templateModifiers & + MappedTypeModifiers.ExcludeOptional + ) && + modifiersProp && + modifiersProp.flags & SymbolFlags.Optional) + ); + const isReadonly = !!( + templateModifiers & + MappedTypeModifiers.IncludeReadonly || + (!( + templateModifiers & + MappedTypeModifiers.ExcludeReadonly + ) && + modifiersProp && + isReadonlySymbol(modifiersProp)) + ); + const stripOptional = + strictNullChecks && + !isOptional && + modifiersProp && + modifiersProp.flags & SymbolFlags.Optional; + const lateFlag: CheckFlags = modifiersProp + ? getIsLateCheckFlag(modifiersProp) + : 0; + const prop = createSymbol( + SymbolFlags.Property | + (isOptional ? SymbolFlags.Optional : 0), + propName, + lateFlag | + CheckFlags.Mapped | + (isReadonly ? CheckFlags.Readonly : 0) | + (stripOptional ? CheckFlags.StripOptional : 0) + ) as MappedSymbol; prop.links.mappedType = type; prop.links.nameType = propNameType; prop.links.keyType = keyType; if (modifiersProp) { prop.links.syntheticOrigin = modifiersProp; - prop.declarations = shouldLinkPropDeclarations ? modifiersProp.declarations : undefined; + prop.declarations = shouldLinkPropDeclarations + ? modifiersProp.declarations + : undefined; } members.set(propName, prop); } - } - else if (isValidIndexKeyType(propNameType) || propNameType.flags & (TypeFlags.Any | TypeFlags.Enum)) { - const indexKeyType = propNameType.flags & (TypeFlags.Any | TypeFlags.String) ? stringType : - propNameType.flags & (TypeFlags.Number | TypeFlags.Enum) ? numberType : - propNameType; - const propType = instantiateType(templateType, appendTypeMapping(type.mapper, typeParameter, keyType)); - const modifiersIndexInfo = getApplicableIndexInfo(modifiersType, propNameType); - const isReadonly = !!(templateModifiers & MappedTypeModifiers.IncludeReadonly || - !(templateModifiers & MappedTypeModifiers.ExcludeReadonly) && modifiersIndexInfo?.isReadonly); - const indexInfo = createIndexInfo(indexKeyType, propType, isReadonly); - indexInfos = appendIndexInfo(indexInfos, indexInfo, /*union*/ true); + } else if ( + isValidIndexKeyType(propNameType) || + propNameType.flags & (TypeFlags.Any | TypeFlags.Enum) + ) { + const indexKeyType = + propNameType.flags & (TypeFlags.Any | TypeFlags.String) + ? stringType + : propNameType.flags & + (TypeFlags.Number | TypeFlags.Enum) + ? numberType + : propNameType; + const propType = instantiateType( + templateType, + appendTypeMapping(type.mapper, typeParameter, keyType) + ); + const modifiersIndexInfo = getApplicableIndexInfo( + modifiersType, + propNameType + ); + const isReadonly = !!( + templateModifiers & MappedTypeModifiers.IncludeReadonly || + (!( + templateModifiers & MappedTypeModifiers.ExcludeReadonly + ) && + modifiersIndexInfo?.isReadonly) + ); + const indexInfo = createIndexInfo( + indexKeyType, + propType, + isReadonly + ); + indexInfos = appendIndexInfo( + indexInfos, + indexInfo, + /*union*/ true + ); } } } @@ -14763,17 +25775,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { mappedType.containsError = true; return errorType; } - const templateType = getTemplateTypeFromMappedType(mappedType.target as MappedType || mappedType); - const mapper = appendTypeMapping(mappedType.mapper, getTypeParameterFromMappedType(mappedType), symbol.links.keyType); + const templateType = getTemplateTypeFromMappedType( + (mappedType.target as MappedType) || mappedType + ); + const mapper = appendTypeMapping( + mappedType.mapper, + getTypeParameterFromMappedType(mappedType), + symbol.links.keyType + ); const propType = instantiateType(templateType, mapper); // When creating an optional property in strictNullChecks mode, if 'undefined' isn't assignable to the // type, we include 'undefined' in the type. Similarly, when creating a non-optional property in strictNullChecks // mode, if the underlying property is optional we remove 'undefined' from the type. - let type = strictNullChecks && symbol.flags & SymbolFlags.Optional && !maybeTypeOfKind(propType, TypeFlags.Undefined | TypeFlags.Void) ? getOptionalType(propType, /*isProperty*/ true) : - symbol.links.checkFlags & CheckFlags.StripOptional ? removeMissingOrUndefinedType(propType) : - propType; + let type = + strictNullChecks && + symbol.flags & SymbolFlags.Optional && + !maybeTypeOfKind(propType, TypeFlags.Undefined | TypeFlags.Void) + ? getOptionalType(propType, /*isProperty*/ true) + : symbol.links.checkFlags & CheckFlags.StripOptional + ? removeMissingOrUndefinedType(propType) + : propType; if (!popTypeResolution()) { - error(currentNode, Diagnostics.Type_of_property_0_circularly_references_itself_in_mapped_type_1, symbolToString(symbol), typeToString(mappedType)); + error( + currentNode, + Diagnostics.Type_of_property_0_circularly_references_itself_in_mapped_type_1, + symbolToString(symbol), + typeToString(mappedType) + ); type = errorType; } symbol.links.type ??= type; @@ -14782,36 +25810,67 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getTypeParameterFromMappedType(type: MappedType) { - return type.typeParameter || - (type.typeParameter = getDeclaredTypeOfTypeParameter(getSymbolOfDeclaration(type.declaration.typeParameter))); + return ( + type.typeParameter || + (type.typeParameter = getDeclaredTypeOfTypeParameter( + getSymbolOfDeclaration(type.declaration.typeParameter) + )) + ); } function getConstraintTypeFromMappedType(type: MappedType) { - return type.constraintType || - (type.constraintType = getConstraintOfTypeParameter(getTypeParameterFromMappedType(type)) || errorType); + return ( + type.constraintType || + (type.constraintType = + getConstraintOfTypeParameter( + getTypeParameterFromMappedType(type) + ) || errorType) + ); } function getNameTypeFromMappedType(type: MappedType) { - return type.declaration.nameType ? - type.nameType || (type.nameType = instantiateType(getTypeFromTypeNode(type.declaration.nameType), type.mapper)) : - undefined; + return type.declaration.nameType + ? type.nameType || + (type.nameType = instantiateType( + getTypeFromTypeNode(type.declaration.nameType), + type.mapper + )) + : undefined; } function getTemplateTypeFromMappedType(type: MappedType) { - return type.templateType || - (type.templateType = type.declaration.type ? - instantiateType(addOptionality(getTypeFromTypeNode(type.declaration.type), /*isProperty*/ true, !!(getMappedTypeModifiers(type) & MappedTypeModifiers.IncludeOptional)), type.mapper) : - errorType); + return ( + type.templateType || + (type.templateType = type.declaration.type + ? instantiateType( + addOptionality( + getTypeFromTypeNode(type.declaration.type), + /*isProperty*/ true, + !!( + getMappedTypeModifiers(type) & + MappedTypeModifiers.IncludeOptional + ) + ), + type.mapper + ) + : errorType) + ); } function getConstraintDeclarationForMappedType(type: MappedType) { - return getEffectiveConstraintOfTypeParameter(type.declaration.typeParameter); + return getEffectiveConstraintOfTypeParameter( + type.declaration.typeParameter + ); } function isMappedTypeWithKeyofConstraintDeclaration(type: MappedType) { - const constraintDeclaration = getConstraintDeclarationForMappedType(type)!; // TODO: GH#18217 - return constraintDeclaration.kind === SyntaxKind.TypeOperator && - (constraintDeclaration as TypeOperatorNode).operator === SyntaxKind.KeyOfKeyword; + const constraintDeclaration = + getConstraintDeclarationForMappedType(type)!; // TODO: GH#18217 + return ( + constraintDeclaration.kind === SyntaxKind.TypeOperator && + (constraintDeclaration as TypeOperatorNode).operator === + SyntaxKind.KeyOfKeyword + ); } function getModifiersTypeFromMappedType(type: MappedType) { @@ -14820,16 +25879,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If the constraint declaration is a 'keyof T' node, the modifiers type is T. We check // AST nodes here because, when T is a non-generic type, the logic below eagerly resolves // 'keyof T' to a literal union type and we can't recover T from that type. - type.modifiersType = instantiateType(getTypeFromTypeNode((getConstraintDeclarationForMappedType(type) as TypeOperatorNode).type), type.mapper); - } - else { + type.modifiersType = instantiateType( + getTypeFromTypeNode( + ( + getConstraintDeclarationForMappedType( + type + ) as TypeOperatorNode + ).type + ), + type.mapper + ); + } else { // Otherwise, get the declared constraint type, and if the constraint type is a type parameter, // get the constraint of that type parameter. If the resulting type is an indexed type 'keyof T', // the modifiers type is T. Otherwise, the modifiers type is unknown. - const declaredType = getTypeFromMappedTypeNode(type.declaration) as MappedType; - const constraint = getConstraintTypeFromMappedType(declaredType); - const extendedConstraint = constraint && constraint.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(constraint as TypeParameter) : constraint; - type.modifiersType = extendedConstraint && extendedConstraint.flags & TypeFlags.Index ? instantiateType((extendedConstraint as IndexType).type, type.mapper) : unknownType; + const declaredType = getTypeFromMappedTypeNode( + type.declaration + ) as MappedType; + const constraint = + getConstraintTypeFromMappedType(declaredType); + const extendedConstraint = + constraint && constraint.flags & TypeFlags.TypeParameter + ? getConstraintOfTypeParameter( + constraint as TypeParameter + ) + : constraint; + type.modifiersType = + extendedConstraint && + extendedConstraint.flags & TypeFlags.Index + ? instantiateType( + (extendedConstraint as IndexType).type, + type.mapper + ) + : unknownType; } } return type.modifiersType; @@ -14837,15 +25919,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getMappedTypeModifiers(type: MappedType): MappedTypeModifiers { const declaration = type.declaration; - return (declaration.readonlyToken ? declaration.readonlyToken.kind === SyntaxKind.MinusToken ? MappedTypeModifiers.ExcludeReadonly : MappedTypeModifiers.IncludeReadonly : 0) | - (declaration.questionToken ? declaration.questionToken.kind === SyntaxKind.MinusToken ? MappedTypeModifiers.ExcludeOptional : MappedTypeModifiers.IncludeOptional : 0); + return ( + (declaration.readonlyToken + ? declaration.readonlyToken.kind === SyntaxKind.MinusToken + ? MappedTypeModifiers.ExcludeReadonly + : MappedTypeModifiers.IncludeReadonly + : 0) | + (declaration.questionToken + ? declaration.questionToken.kind === SyntaxKind.MinusToken + ? MappedTypeModifiers.ExcludeOptional + : MappedTypeModifiers.IncludeOptional + : 0) + ); } // Return -1, 0, or 1, where -1 means optionality is stripped (i.e. -?), 0 means optionality is unchanged, and 1 means // optionality is added (i.e. +?). function getMappedTypeOptionality(type: MappedType): number { const modifiers = getMappedTypeModifiers(type); - return modifiers & MappedTypeModifiers.ExcludeOptional ? -1 : modifiers & MappedTypeModifiers.IncludeOptional ? 1 : 0; + return modifiers & MappedTypeModifiers.ExcludeOptional + ? -1 + : modifiers & MappedTypeModifiers.IncludeOptional + ? 1 + : 0; } // Return -1, 0, or 1, for stripped, unchanged, or added optionality respectively. When a homomorphic mapped type doesn't @@ -14853,22 +25949,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // For intersections, return -1 or 1 when all constituents strip or add optionality, otherwise return 0. function getCombinedMappedTypeOptionality(type: Type): number { if (getObjectFlags(type) & ObjectFlags.Mapped) { - return getMappedTypeOptionality(type as MappedType) || getCombinedMappedTypeOptionality(getModifiersTypeFromMappedType(type as MappedType)); + return ( + getMappedTypeOptionality(type as MappedType) || + getCombinedMappedTypeOptionality( + getModifiersTypeFromMappedType(type as MappedType) + ) + ); } if (type.flags & TypeFlags.Intersection) { - const optionality = getCombinedMappedTypeOptionality((type as IntersectionType).types[0]); - return every((type as IntersectionType).types, (t, i) => i === 0 || getCombinedMappedTypeOptionality(t) === optionality) ? optionality : 0; + const optionality = getCombinedMappedTypeOptionality( + (type as IntersectionType).types[0] + ); + return every( + (type as IntersectionType).types, + (t, i) => + i === 0 || + getCombinedMappedTypeOptionality(t) === optionality + ) + ? optionality + : 0; } return 0; } function isPartialMappedType(type: Type) { - return !!(getObjectFlags(type) & ObjectFlags.Mapped && getMappedTypeModifiers(type as MappedType) & MappedTypeModifiers.IncludeOptional); + return !!( + getObjectFlags(type) & ObjectFlags.Mapped && + getMappedTypeModifiers(type as MappedType) & + MappedTypeModifiers.IncludeOptional + ); } function isGenericMappedType(type: Type): type is MappedType { if (getObjectFlags(type) & ObjectFlags.Mapped) { - const constraint = getConstraintTypeFromMappedType(type as MappedType); + const constraint = getConstraintTypeFromMappedType( + type as MappedType + ); if (isGenericIndexType(constraint)) { return true; } @@ -14876,19 +25992,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // To determine this, we substitute the constraint type (that we now know isn't generic) for the iteration // type and check whether the resulting type is generic. const nameType = getNameTypeFromMappedType(type as MappedType); - if (nameType && isGenericIndexType(instantiateType(nameType, makeUnaryTypeMapper(getTypeParameterFromMappedType(type as MappedType), constraint)))) { + if ( + nameType && + isGenericIndexType( + instantiateType( + nameType, + makeUnaryTypeMapper( + getTypeParameterFromMappedType(type as MappedType), + constraint + ) + ) + ) + ) { return true; } } return false; } - function getMappedTypeNameTypeKind(type: MappedType): MappedTypeNameTypeKind { + function getMappedTypeNameTypeKind( + type: MappedType + ): MappedTypeNameTypeKind { const nameType = getNameTypeFromMappedType(type); if (!nameType) { return MappedTypeNameTypeKind.None; } - return isTypeAssignableTo(nameType, getTypeParameterFromMappedType(type)) ? MappedTypeNameTypeKind.Filtering : MappedTypeNameTypeKind.Remapping; + return isTypeAssignableTo( + nameType, + getTypeParameterFromMappedType(type) + ) + ? MappedTypeNameTypeKind.Filtering + : MappedTypeNameTypeKind.Remapping; } function resolveStructuredTypeMembers(type: StructuredType): ResolvedType { @@ -14896,31 +26030,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (type.flags & TypeFlags.Object) { if ((type as ObjectType).objectFlags & ObjectFlags.Reference) { resolveTypeReferenceMembers(type as TypeReference); - } - else if ((type as ObjectType).objectFlags & ObjectFlags.ClassOrInterface) { + } else if ( + (type as ObjectType).objectFlags & + ObjectFlags.ClassOrInterface + ) { resolveClassOrInterfaceMembers(type as InterfaceType); - } - else if ((type as ReverseMappedType).objectFlags & ObjectFlags.ReverseMapped) { + } else if ( + (type as ReverseMappedType).objectFlags & + ObjectFlags.ReverseMapped + ) { resolveReverseMappedTypeMembers(type as ReverseMappedType); - } - else if ((type as ObjectType).objectFlags & ObjectFlags.Anonymous) { + } else if ( + (type as ObjectType).objectFlags & ObjectFlags.Anonymous + ) { resolveAnonymousTypeMembers(type as AnonymousType); - } - else if ((type as MappedType).objectFlags & ObjectFlags.Mapped) { + } else if ( + (type as MappedType).objectFlags & ObjectFlags.Mapped + ) { resolveMappedTypeMembers(type as MappedType); + } else { + Debug.fail( + "Unhandled object type " + + Debug.formatObjectFlags(type.objectFlags) + ); } - else { - Debug.fail("Unhandled object type " + Debug.formatObjectFlags(type.objectFlags)); - } - } - else if (type.flags & TypeFlags.Union) { + } else if (type.flags & TypeFlags.Union) { resolveUnionTypeMembers(type as UnionType); - } - else if (type.flags & TypeFlags.Intersection) { + } else if (type.flags & TypeFlags.Intersection) { resolveIntersectionTypeMembers(type as IntersectionType); - } - else { - Debug.fail("Unhandled type " + Debug.formatTypeFlags(type.flags)); + } else { + Debug.fail( + "Unhandled type " + Debug.formatTypeFlags(type.flags) + ); } } return type as ResolvedType; @@ -14937,7 +26078,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** If the given type is an object type and that type has a property by the given name, * return the symbol for that property. Otherwise return undefined. */ - function getPropertyOfObjectType(type: Type, name: __String): Symbol | undefined { + function getPropertyOfObjectType( + type: Type, + name: __String + ): Symbol | undefined { if (type.flags & TypeFlags.Object) { const resolved = resolveStructuredTypeMembers(type as ObjectType); const symbol = resolved.members.get(name); @@ -14947,13 +26091,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getPropertiesOfUnionOrIntersectionType(type: UnionOrIntersectionType): Symbol[] { + function getPropertiesOfUnionOrIntersectionType( + type: UnionOrIntersectionType + ): Symbol[] { if (!type.resolvedProperties) { const members = createSymbolTable(); for (const current of type.types) { for (const prop of getPropertiesOfType(current)) { if (!members.has(prop.escapedName)) { - const combinedProp = getPropertyOfUnionOrIntersectionType(type, prop.escapedName, /*skipObjectFunctionPropertyAugment*/ !!(type.flags & TypeFlags.Intersection)); + const combinedProp = + getPropertyOfUnionOrIntersectionType( + type, + prop.escapedName, + /*skipObjectFunctionPropertyAugment*/ !!( + type.flags & TypeFlags.Intersection + ) + ); if (combinedProp) { members.set(prop.escapedName, combinedProp); } @@ -14961,7 +26114,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // The properties of a union type are those that are present in all constituent types, so // we only need to check the properties of the first type without index signature - if (type.flags & TypeFlags.Union && getIndexInfosOfType(current).length === 0) { + if ( + type.flags & TypeFlags.Union && + getIndexInfosOfType(current).length === 0 + ) { break; } } @@ -14972,15 +26128,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getPropertiesOfType(type: Type): Symbol[] { type = getReducedApparentType(type); - return type.flags & TypeFlags.UnionOrIntersection ? - getPropertiesOfUnionOrIntersectionType(type as UnionType) : - getPropertiesOfObjectType(type); + return type.flags & TypeFlags.UnionOrIntersection + ? getPropertiesOfUnionOrIntersectionType(type as UnionType) + : getPropertiesOfObjectType(type); } - function forEachPropertyOfType(type: Type, action: (symbol: Symbol, escapedName: __String) => void): void { + function forEachPropertyOfType( + type: Type, + action: (symbol: Symbol, escapedName: __String) => void + ): void { type = getReducedApparentType(type); if (type.flags & TypeFlags.StructuredType) { - resolveStructuredTypeMembers(type as StructuredType).members.forEach((symbol, escapedName) => { + resolveStructuredTypeMembers( + type as StructuredType + ).members.forEach((symbol, escapedName) => { if (isNamedMember(symbol, escapedName)) { action(symbol, escapedName); } @@ -14988,13 +26149,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function isTypeInvalidDueToUnionDiscriminant(contextualType: Type, obj: ObjectLiteralExpression | JsxAttributes): boolean { - const list = obj.properties as NodeArray; - return list.some(property => { - const nameType = property.name && (isJsxNamespacedName(property.name) ? getStringLiteralType(getTextOfJsxAttributeName(property.name)) : getLiteralTypeFromPropertyName(property.name)); - const name = nameType && isTypeUsableAsPropertyName(nameType) ? getPropertyNameFromType(nameType) : undefined; - const expected = name === undefined ? undefined : getTypeOfPropertyOfType(contextualType, name); - return !!expected && isLiteralType(expected) && !isTypeAssignableTo(getTypeOfNode(property), expected); + function isTypeInvalidDueToUnionDiscriminant( + contextualType: Type, + obj: ObjectLiteralExpression | JsxAttributes + ): boolean { + const list = obj.properties as NodeArray< + ObjectLiteralElementLike | JsxAttributeLike + >; + return list.some((property) => { + const nameType = + property.name && + (isJsxNamespacedName(property.name) + ? getStringLiteralType( + getTextOfJsxAttributeName(property.name) + ) + : getLiteralTypeFromPropertyName(property.name)); + const name = + nameType && isTypeUsableAsPropertyName(nameType) + ? getPropertyNameFromType(nameType) + : undefined; + const expected = + name === undefined + ? undefined + : getTypeOfPropertyOfType(contextualType, name); + return ( + !!expected && + isLiteralType(expected) && + !isTypeAssignableTo(getTypeOfNode(property), expected) + ); }); } @@ -15006,9 +26188,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const props = createSymbolTable(); for (const memberType of types) { - for (const { escapedName } of getAugmentedPropertiesOfType(memberType)) { + for (const { escapedName } of getAugmentedPropertiesOfType( + memberType + )) { if (!props.has(escapedName)) { - const prop = createUnionOrIntersectionProperty(unionType as UnionType, escapedName); + const prop = createUnionOrIntersectionProperty( + unionType as UnionType, + escapedName + ); // May be undefined if the property is private if (prop) props.set(escapedName, prop); } @@ -15017,15 +26204,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return arrayFrom(props.values()); } - function getConstraintOfType(type: InstantiableType | UnionOrIntersectionType): Type | undefined { - return type.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(type as TypeParameter) : - type.flags & TypeFlags.IndexedAccess ? getConstraintOfIndexedAccess(type as IndexedAccessType) : - type.flags & TypeFlags.Conditional ? getConstraintOfConditionalType(type as ConditionalType) : - getBaseConstraintOfType(type); + function getConstraintOfType( + type: InstantiableType | UnionOrIntersectionType + ): Type | undefined { + return type.flags & TypeFlags.TypeParameter + ? getConstraintOfTypeParameter(type as TypeParameter) + : type.flags & TypeFlags.IndexedAccess + ? getConstraintOfIndexedAccess(type as IndexedAccessType) + : type.flags & TypeFlags.Conditional + ? getConstraintOfConditionalType(type as ConditionalType) + : getBaseConstraintOfType(type); } - function getConstraintOfTypeParameter(typeParameter: TypeParameter): Type | undefined { - return hasNonCircularBaseConstraint(typeParameter) ? getConstraintFromTypeParameter(typeParameter) : undefined; + function getConstraintOfTypeParameter( + typeParameter: TypeParameter + ): Type | undefined { + return hasNonCircularBaseConstraint(typeParameter) + ? getConstraintFromTypeParameter(typeParameter) + : undefined; } function isConstMappedType(type: MappedType, depth: number): boolean { @@ -15034,19 +26230,54 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isConstTypeVariable(type: Type | undefined, depth = 0): boolean { - return depth < 5 && !!(type && ( - type.flags & TypeFlags.TypeParameter && some((type as TypeParameter).symbol?.declarations, d => hasSyntacticModifier(d, ModifierFlags.Const)) || - type.flags & TypeFlags.UnionOrIntersection && some((type as UnionOrIntersectionType).types, t => isConstTypeVariable(t, depth)) || - type.flags & TypeFlags.IndexedAccess && isConstTypeVariable((type as IndexedAccessType).objectType, depth + 1) || - type.flags & TypeFlags.Conditional && isConstTypeVariable(getConstraintOfConditionalType(type as ConditionalType), depth + 1) || - type.flags & TypeFlags.Substitution && isConstTypeVariable((type as SubstitutionType).baseType, depth) || - getObjectFlags(type) & ObjectFlags.Mapped && isConstMappedType(type as MappedType, depth) || - isGenericTupleType(type) && findIndex(getElementTypes(type), (t, i) => !!(type.target.elementFlags[i] & ElementFlags.Variadic) && isConstTypeVariable(t, depth)) >= 0 - )); + return ( + depth < 5 && + !!( + type && + ((type.flags & TypeFlags.TypeParameter && + some((type as TypeParameter).symbol?.declarations, (d) => + hasSyntacticModifier(d, ModifierFlags.Const) + )) || + (type.flags & TypeFlags.UnionOrIntersection && + some((type as UnionOrIntersectionType).types, (t) => + isConstTypeVariable(t, depth) + )) || + (type.flags & TypeFlags.IndexedAccess && + isConstTypeVariable( + (type as IndexedAccessType).objectType, + depth + 1 + )) || + (type.flags & TypeFlags.Conditional && + isConstTypeVariable( + getConstraintOfConditionalType( + type as ConditionalType + ), + depth + 1 + )) || + (type.flags & TypeFlags.Substitution && + isConstTypeVariable( + (type as SubstitutionType).baseType, + depth + )) || + (getObjectFlags(type) & ObjectFlags.Mapped && + isConstMappedType(type as MappedType, depth)) || + (isGenericTupleType(type) && + findIndex( + getElementTypes(type), + (t, i) => + !!( + type.target.elementFlags[i] & + ElementFlags.Variadic + ) && isConstTypeVariable(t, depth) + ) >= 0)) + ) + ); } function getConstraintOfIndexedAccess(type: IndexedAccessType) { - return hasNonCircularBaseConstraint(type) ? getConstraintFromIndexedAccess(type) : undefined; + return hasNonCircularBaseConstraint(type) + ? getConstraintFromIndexedAccess(type) + : undefined; } function getSimplifiedTypeOrConstraint(type: Type) { @@ -15058,18 +26289,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isMappedTypeGenericIndexedAccess(type)) { // For indexed access types of the form { [P in K]: E }[X], where K is non-generic and X is generic, // we substitute an instantiation of E where P is replaced with X. - return substituteIndexedMappedType(type.objectType as MappedType, type.indexType); + return substituteIndexedMappedType( + type.objectType as MappedType, + type.indexType + ); } const indexConstraint = getSimplifiedTypeOrConstraint(type.indexType); if (indexConstraint && indexConstraint !== type.indexType) { - const indexedAccess = getIndexedAccessTypeOrUndefined(type.objectType, indexConstraint, type.accessFlags); + const indexedAccess = getIndexedAccessTypeOrUndefined( + type.objectType, + indexConstraint, + type.accessFlags + ); if (indexedAccess) { return indexedAccess; } } const objectConstraint = getSimplifiedTypeOrConstraint(type.objectType); if (objectConstraint && objectConstraint !== type.objectType) { - return getIndexedAccessTypeOrUndefined(objectConstraint, type.indexType, type.accessFlags); + return getIndexedAccessTypeOrUndefined( + objectConstraint, + type.indexType, + type.accessFlags + ); } return undefined; } @@ -15082,12 +26324,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // in effect treating `any` like `never` rather than `unknown` in this location. const trueConstraint = getInferredTrueTypeFromConditionalType(type); const falseConstraint = getFalseTypeFromConditionalType(type); - type.resolvedDefaultConstraint = isTypeAny(trueConstraint) ? falseConstraint : isTypeAny(falseConstraint) ? trueConstraint : getUnionType([trueConstraint, falseConstraint]); + type.resolvedDefaultConstraint = isTypeAny(trueConstraint) + ? falseConstraint + : isTypeAny(falseConstraint) + ? trueConstraint + : getUnionType([trueConstraint, falseConstraint]); } return type.resolvedDefaultConstraint; } - function getConstraintOfDistributiveConditionalType(type: ConditionalType): Type | undefined { + function getConstraintOfDistributiveConditionalType( + type: ConditionalType + ): Type | undefined { if (type.resolvedConstraintOfDistributive !== undefined) { return type.resolvedConstraintOfDistributive || undefined; } @@ -15103,11 +26351,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Please note: the distributive constraint is a kludge for emulating what a negated type could to do filter // a union - once negated types exist and are applied to the conditional false branch, this "constraint" // likely doesn't need to exist. - if (type.root.isDistributive && type.restrictiveInstantiation !== type) { - const simplified = getSimplifiedType(type.checkType, /*writing*/ false); - const constraint = simplified === type.checkType ? getConstraintOfType(simplified) : simplified; + if ( + type.root.isDistributive && + type.restrictiveInstantiation !== type + ) { + const simplified = getSimplifiedType( + type.checkType, + /*writing*/ false + ); + const constraint = + simplified === type.checkType + ? getConstraintOfType(simplified) + : simplified; if (constraint && constraint !== type.checkType) { - const instantiated = getConditionalTypeInstantiation(type, prependTypeMapping(type.root.checkType, constraint, type.mapper), /*forConstraint*/ true); + const instantiated = getConditionalTypeInstantiation( + type, + prependTypeMapping( + type.root.checkType, + constraint, + type.mapper + ), + /*forConstraint*/ true + ); if (!(instantiated.flags & TypeFlags.Never)) { type.resolvedConstraintOfDistributive = instantiated; return instantiated; @@ -15119,14 +26384,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getConstraintFromConditionalType(type: ConditionalType) { - return getConstraintOfDistributiveConditionalType(type) || getDefaultConstraintOfConditionalType(type); + return ( + getConstraintOfDistributiveConditionalType(type) || + getDefaultConstraintOfConditionalType(type) + ); } function getConstraintOfConditionalType(type: ConditionalType) { - return hasNonCircularBaseConstraint(type) ? getConstraintFromConditionalType(type) : undefined; + return hasNonCircularBaseConstraint(type) + ? getConstraintFromConditionalType(type) + : undefined; } - function getEffectiveConstraintOfIntersection(types: readonly Type[], targetIsUnion: boolean) { + function getEffectiveConstraintOfIntersection( + types: readonly Type[], + targetIsUnion: boolean + ) { let constraints: Type[] | undefined; let hasDisjointDomainType = false; for (const t of types) { @@ -15134,7 +26407,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We keep following constraints as long as we have an instantiable type that is known // not to be circular or infinite (hence we stop on index access types). let constraint = getConstraintOfType(t); - while (constraint && constraint.flags & (TypeFlags.TypeParameter | TypeFlags.Index | TypeFlags.Conditional)) { + while ( + constraint && + constraint.flags & + (TypeFlags.TypeParameter | + TypeFlags.Index | + TypeFlags.Conditional) + ) { constraint = getConstraintOfType(constraint); } if (constraint) { @@ -15143,8 +26422,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { constraints = append(constraints, t); } } - } - else if (t.flags & TypeFlags.DisjointDomains || isEmptyAnonymousObjectType(t)) { + } else if ( + t.flags & TypeFlags.DisjointDomains || + isEmptyAnonymousObjectType(t) + ) { hasDisjointDomainType = true; } } @@ -15155,23 +26436,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We add any types belong to one of the disjoint domains because they might cause the final // intersection operation to reduce the union constraints. for (const t of types) { - if (t.flags & TypeFlags.DisjointDomains || isEmptyAnonymousObjectType(t)) { + if ( + t.flags & TypeFlags.DisjointDomains || + isEmptyAnonymousObjectType(t) + ) { constraints = append(constraints, t); } } } // The source types were normalized; ensure the result is normalized too. - return getNormalizedType(getIntersectionType(constraints, IntersectionFlags.NoConstraintReduction), /*writing*/ false); + return getNormalizedType( + getIntersectionType( + constraints, + IntersectionFlags.NoConstraintReduction + ), + /*writing*/ false + ); } return undefined; } function getBaseConstraintOfType(type: Type): Type | undefined { - if (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) || isGenericTupleType(type)) { - const constraint = getResolvedBaseConstraint(type as InstantiableType | UnionOrIntersectionType); - return constraint !== noConstraintType && constraint !== circularConstraintType ? constraint : undefined; + if ( + type.flags & + (TypeFlags.InstantiableNonPrimitive | + TypeFlags.UnionOrIntersection | + TypeFlags.TemplateLiteral | + TypeFlags.StringMapping) || + isGenericTupleType(type) + ) { + const constraint = getResolvedBaseConstraint( + type as InstantiableType | UnionOrIntersectionType + ); + return constraint !== noConstraintType && + constraint !== circularConstraintType + ? constraint + : undefined; } - return type.flags & TypeFlags.Index ? stringNumberSymbolType : undefined; + return type.flags & TypeFlags.Index + ? stringNumberSymbolType + : undefined; } /** @@ -15191,16 +26495,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * type variable has no constraint, and the circularConstraintType singleton is returned if the constraint * circularly references the type variable. */ - function getResolvedBaseConstraint(type: InstantiableType | UnionOrIntersectionType): Type { + function getResolvedBaseConstraint( + type: InstantiableType | UnionOrIntersectionType + ): Type { if (type.resolvedBaseConstraint) { return type.resolvedBaseConstraint; } const stack: object[] = []; - return type.resolvedBaseConstraint = getImmediateBaseConstraint(type); + return (type.resolvedBaseConstraint = getImmediateBaseConstraint(type)); function getImmediateBaseConstraint(t: Type): Type { if (!t.immediateBaseConstraint) { - if (!pushTypeResolution(t, TypeSystemPropertyName.ImmediateBaseConstraint)) { + if ( + !pushTypeResolution( + t, + TypeSystemPropertyName.ImmediateBaseConstraint + ) + ) { return circularConstraintType; } let result; @@ -15211,18 +26522,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // yet triggered the deeply nested limiter. We have no test cases that actually get to 50 levels of // nesting, so it is effectively just a safety stop. const identity = getRecursionIdentity(t); - if (stack.length < 10 || stack.length < 50 && !contains(stack, identity)) { + if ( + stack.length < 10 || + (stack.length < 50 && !contains(stack, identity)) + ) { stack.push(identity); - result = computeBaseConstraint(getSimplifiedType(t, /*writing*/ false)); + result = computeBaseConstraint( + getSimplifiedType(t, /*writing*/ false) + ); stack.pop(); } if (!popTypeResolution()) { if (t.flags & TypeFlags.TypeParameter) { - const errorNode = getConstraintDeclaration(t as TypeParameter); + const errorNode = getConstraintDeclaration( + t as TypeParameter + ); if (errorNode) { - const diagnostic = error(errorNode, Diagnostics.Type_parameter_0_has_a_circular_constraint, typeToString(t)); - if (currentNode && !isNodeDescendantOf(errorNode, currentNode) && !isNodeDescendantOf(currentNode, errorNode)) { - addRelatedInfo(diagnostic, createDiagnosticForNode(currentNode, Diagnostics.Circularity_originates_in_type_at_this_location)); + const diagnostic = error( + errorNode, + Diagnostics.Type_parameter_0_has_a_circular_constraint, + typeToString(t) + ); + if ( + currentNode && + !isNodeDescendantOf(errorNode, currentNode) && + !isNodeDescendantOf(currentNode, errorNode) + ) { + addRelatedInfo( + diagnostic, + createDiagnosticForNode( + currentNode, + Diagnostics.Circularity_originates_in_type_at_this_location + ) + ); } } } @@ -15235,15 +26567,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getBaseConstraint(t: Type): Type | undefined { const c = getImmediateBaseConstraint(t); - return c !== noConstraintType && c !== circularConstraintType ? c : undefined; + return c !== noConstraintType && c !== circularConstraintType + ? c + : undefined; } function computeBaseConstraint(t: Type): Type | undefined { if (t.flags & TypeFlags.TypeParameter) { - const constraint = getConstraintFromTypeParameter(t as TypeParameter); - return (t as TypeParameter).isThisType || !constraint ? - constraint : - getBaseConstraint(constraint); + const constraint = getConstraintFromTypeParameter( + t as TypeParameter + ); + return (t as TypeParameter).isThisType || !constraint + ? constraint + : getBaseConstraint(constraint); } if (t.flags & TypeFlags.UnionOrIntersection) { const types = (t as UnionOrIntersectionType).types; @@ -15256,17 +26592,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { different = true; } baseTypes.push(baseType); - } - else { + } else { different = true; } } if (!different) { return t; } - return t.flags & TypeFlags.Union && baseTypes.length === types.length ? getUnionType(baseTypes) : - t.flags & TypeFlags.Intersection && baseTypes.length ? getIntersectionType(baseTypes) : - undefined; + return t.flags & TypeFlags.Union && + baseTypes.length === types.length + ? getUnionType(baseTypes) + : t.flags & TypeFlags.Intersection && baseTypes.length + ? getIntersectionType(baseTypes) + : undefined; } if (t.flags & TypeFlags.Index) { return stringNumberSymbolType; @@ -15274,69 +26612,152 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (t.flags & TypeFlags.TemplateLiteral) { const types = (t as TemplateLiteralType).types; const constraints = mapDefined(types, getBaseConstraint); - return constraints.length === types.length ? getTemplateLiteralType((t as TemplateLiteralType).texts, constraints) : stringType; + return constraints.length === types.length + ? getTemplateLiteralType( + (t as TemplateLiteralType).texts, + constraints + ) + : stringType; } if (t.flags & TypeFlags.StringMapping) { - const constraint = getBaseConstraint((t as StringMappingType).type); - return constraint && constraint !== (t as StringMappingType).type ? getStringMappingType((t as StringMappingType).symbol, constraint) : stringType; + const constraint = getBaseConstraint( + (t as StringMappingType).type + ); + return constraint && + constraint !== (t as StringMappingType).type + ? getStringMappingType( + (t as StringMappingType).symbol, + constraint + ) + : stringType; } if (t.flags & TypeFlags.IndexedAccess) { if (isMappedTypeGenericIndexedAccess(t)) { // For indexed access types of the form { [P in K]: E }[X], where K is non-generic and X is generic, // we substitute an instantiation of E where P is replaced with X. - return getBaseConstraint(substituteIndexedMappedType((t as IndexedAccessType).objectType as MappedType, (t as IndexedAccessType).indexType)); + return getBaseConstraint( + substituteIndexedMappedType( + (t as IndexedAccessType).objectType as MappedType, + (t as IndexedAccessType).indexType + ) + ); } - const baseObjectType = getBaseConstraint((t as IndexedAccessType).objectType); - const baseIndexType = getBaseConstraint((t as IndexedAccessType).indexType); - const baseIndexedAccess = baseObjectType && baseIndexType && getIndexedAccessTypeOrUndefined(baseObjectType, baseIndexType, (t as IndexedAccessType).accessFlags); - return baseIndexedAccess && getBaseConstraint(baseIndexedAccess); + const baseObjectType = getBaseConstraint( + (t as IndexedAccessType).objectType + ); + const baseIndexType = getBaseConstraint( + (t as IndexedAccessType).indexType + ); + const baseIndexedAccess = + baseObjectType && + baseIndexType && + getIndexedAccessTypeOrUndefined( + baseObjectType, + baseIndexType, + (t as IndexedAccessType).accessFlags + ); + return ( + baseIndexedAccess && getBaseConstraint(baseIndexedAccess) + ); } if (t.flags & TypeFlags.Conditional) { - const constraint = getConstraintFromConditionalType(t as ConditionalType); + const constraint = getConstraintFromConditionalType( + t as ConditionalType + ); return constraint && getBaseConstraint(constraint); } if (t.flags & TypeFlags.Substitution) { - return getBaseConstraint(getSubstitutionIntersection(t as SubstitutionType)); + return getBaseConstraint( + getSubstitutionIntersection(t as SubstitutionType) + ); } if (isGenericTupleType(t)) { // We substitute constraints for variadic elements only when the constraints are array types or // non-variadic tuple types as we want to avoid further (possibly unbounded) recursion. const newElements = map(getElementTypes(t), (v, i) => { - const constraint = v.flags & TypeFlags.TypeParameter && t.target.elementFlags[i] & ElementFlags.Variadic && getBaseConstraint(v) || v; - return constraint !== v && everyType(constraint, c => isArrayOrTupleType(c) && !isGenericTupleType(c)) ? constraint : v; + const constraint = + (v.flags & TypeFlags.TypeParameter && + t.target.elementFlags[i] & ElementFlags.Variadic && + getBaseConstraint(v)) || + v; + return constraint !== v && + everyType( + constraint, + (c) => + isArrayOrTupleType(c) && !isGenericTupleType(c) + ) + ? constraint + : v; }); - return createTupleType(newElements, t.target.elementFlags, t.target.readonly, t.target.labeledElementDeclarations); + return createTupleType( + newElements, + t.target.elementFlags, + t.target.readonly, + t.target.labeledElementDeclarations + ); } return t; } } - function getApparentTypeOfIntersectionType(type: IntersectionType, thisArgument: Type) { + function getApparentTypeOfIntersectionType( + type: IntersectionType, + thisArgument: Type + ) { if (type === thisArgument) { - return type.resolvedApparentType || (type.resolvedApparentType = getTypeWithThisArgument(type, thisArgument, /*needApparentType*/ true)); + return ( + type.resolvedApparentType || + (type.resolvedApparentType = getTypeWithThisArgument( + type, + thisArgument, + /*needApparentType*/ true + )) + ); } const key = `I${getTypeId(type)},${getTypeId(thisArgument)}`; - return getCachedType(key) ?? setCachedType(key, getTypeWithThisArgument(type, thisArgument, /*needApparentType*/ true)); + return ( + getCachedType(key) ?? + setCachedType( + key, + getTypeWithThisArgument( + type, + thisArgument, + /*needApparentType*/ true + ) + ) + ); } - function getResolvedTypeParameterDefault(typeParameter: TypeParameter): Type | undefined { + function getResolvedTypeParameterDefault( + typeParameter: TypeParameter + ): Type | undefined { if (!typeParameter.default) { if (typeParameter.target) { - const targetDefault = getResolvedTypeParameterDefault(typeParameter.target); - typeParameter.default = targetDefault ? instantiateType(targetDefault, typeParameter.mapper) : noConstraintType; - } - else { + const targetDefault = getResolvedTypeParameterDefault( + typeParameter.target + ); + typeParameter.default = targetDefault + ? instantiateType(targetDefault, typeParameter.mapper) + : noConstraintType; + } else { // To block recursion, set the initial value to the resolvingDefaultType. typeParameter.default = resolvingDefaultType; - const defaultDeclaration = typeParameter.symbol && forEach(typeParameter.symbol.declarations, decl => isTypeParameterDeclaration(decl) && decl.default); - const defaultType = defaultDeclaration ? getTypeFromTypeNode(defaultDeclaration) : noConstraintType; + const defaultDeclaration = + typeParameter.symbol && + forEach( + typeParameter.symbol.declarations, + (decl) => + isTypeParameterDeclaration(decl) && decl.default + ); + const defaultType = defaultDeclaration + ? getTypeFromTypeNode(defaultDeclaration) + : noConstraintType; if (typeParameter.default === resolvingDefaultType) { // If we have not been called recursively, set the correct default type. typeParameter.default = defaultType; } } - } - else if (typeParameter.default === resolvingDefaultType) { + } else if (typeParameter.default === resolvingDefaultType) { // If we are called recursively for this type parameter, mark the default as circular. typeParameter.default = circularConstraintType; } @@ -15350,24 +26771,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * default type of its target. If the type parameter has no default type or the default is * circular, `undefined` is returned. */ - function getDefaultFromTypeParameter(typeParameter: TypeParameter): Type | undefined { + function getDefaultFromTypeParameter( + typeParameter: TypeParameter + ): Type | undefined { const defaultType = getResolvedTypeParameterDefault(typeParameter); - return defaultType !== noConstraintType && defaultType !== circularConstraintType ? defaultType : undefined; + return defaultType !== noConstraintType && + defaultType !== circularConstraintType + ? defaultType + : undefined; } function hasNonCircularTypeParameterDefault(typeParameter: TypeParameter) { - return getResolvedTypeParameterDefault(typeParameter) !== circularConstraintType; + return ( + getResolvedTypeParameterDefault(typeParameter) !== + circularConstraintType + ); } /** * Indicates whether the declaration of a typeParameter has a default type. */ function hasTypeParameterDefault(typeParameter: TypeParameter): boolean { - return !!(typeParameter.symbol && forEach(typeParameter.symbol.declarations, decl => isTypeParameterDeclaration(decl) && decl.default)); + return !!( + typeParameter.symbol && + forEach( + typeParameter.symbol.declarations, + (decl) => isTypeParameterDeclaration(decl) && decl.default + ) + ); } function getApparentTypeOfMappedType(type: MappedType) { - return type.resolvedApparentType || (type.resolvedApparentType = getResolvedApparentTypeOfMappedType(type)); + return ( + type.resolvedApparentType || + (type.resolvedApparentType = + getResolvedApparentTypeOfMappedType(type)) + ); } function getResolvedApparentTypeOfMappedType(type: MappedType): Type { @@ -15381,23 +26820,52 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // this mapped type to the base constraint. It is safe to recurse when the modifiers type is a // mapped type because we protect again circular constraints in getTypeFromMappedTypeNode. const modifiersType = getModifiersTypeFromMappedType(type); - const baseConstraint = isGenericMappedType(modifiersType) ? getApparentTypeOfMappedType(modifiersType) : getBaseConstraintOfType(modifiersType); - if (baseConstraint && everyType(baseConstraint, t => isArrayOrTupleType(t) || isArrayOrTupleOrIntersection(t))) { - return instantiateType(target, prependTypeMapping(typeVariable, baseConstraint, type.mapper)); + const baseConstraint = isGenericMappedType(modifiersType) + ? getApparentTypeOfMappedType(modifiersType) + : getBaseConstraintOfType(modifiersType); + if ( + baseConstraint && + everyType( + baseConstraint, + (t) => + isArrayOrTupleType(t) || isArrayOrTupleOrIntersection(t) + ) + ) { + return instantiateType( + target, + prependTypeMapping( + typeVariable, + baseConstraint, + type.mapper + ) + ); } } return type; } function isArrayOrTupleOrIntersection(type: Type) { - return !!(type.flags & TypeFlags.Intersection) && every((type as IntersectionType).types, isArrayOrTupleType); + return ( + !!(type.flags & TypeFlags.Intersection) && + every((type as IntersectionType).types, isArrayOrTupleType) + ); } function isMappedTypeGenericIndexedAccess(type: Type) { let objectType; - return !!(type.flags & TypeFlags.IndexedAccess && getObjectFlags(objectType = (type as IndexedAccessType).objectType) & ObjectFlags.Mapped && - !isGenericMappedType(objectType) && isGenericIndexType((type as IndexedAccessType).indexType) && - !(getMappedTypeModifiers(objectType as MappedType) & MappedTypeModifiers.ExcludeOptional) && !(objectType as MappedType).declaration.nameType); + return !!( + type.flags & TypeFlags.IndexedAccess && + getObjectFlags( + (objectType = (type as IndexedAccessType).objectType) + ) & ObjectFlags.Mapped && + !isGenericMappedType(objectType) && + isGenericIndexType((type as IndexedAccessType).indexType) && + !( + getMappedTypeModifiers(objectType as MappedType) & + MappedTypeModifiers.ExcludeOptional + ) && + !(objectType as MappedType).declaration.nameType + ); } /** @@ -15406,20 +26874,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * type itself. */ function getApparentType(type: Type): Type { - const t = type.flags & TypeFlags.Instantiable ? getBaseConstraintOfType(type) || unknownType : type; + const t = + type.flags & TypeFlags.Instantiable + ? getBaseConstraintOfType(type) || unknownType + : type; const objectFlags = getObjectFlags(t); - return objectFlags & ObjectFlags.Mapped ? getApparentTypeOfMappedType(t as MappedType) : - objectFlags & ObjectFlags.Reference && t !== type ? getTypeWithThisArgument(t, type) : - t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(t as IntersectionType, type) : - t.flags & TypeFlags.StringLike ? globalStringType : - t.flags & TypeFlags.NumberLike ? globalNumberType : - t.flags & TypeFlags.BigIntLike ? getGlobalBigIntType() : - t.flags & TypeFlags.BooleanLike ? globalBooleanType : - t.flags & TypeFlags.ESSymbolLike ? getGlobalESSymbolType() : - t.flags & TypeFlags.NonPrimitive ? emptyObjectType : - t.flags & TypeFlags.Index ? stringNumberSymbolType : - t.flags & TypeFlags.Unknown && !strictNullChecks ? emptyObjectType : - t; + return objectFlags & ObjectFlags.Mapped + ? getApparentTypeOfMappedType(t as MappedType) + : objectFlags & ObjectFlags.Reference && t !== type + ? getTypeWithThisArgument(t, type) + : t.flags & TypeFlags.Intersection + ? getApparentTypeOfIntersectionType(t as IntersectionType, type) + : t.flags & TypeFlags.StringLike + ? globalStringType + : t.flags & TypeFlags.NumberLike + ? globalNumberType + : t.flags & TypeFlags.BigIntLike + ? getGlobalBigIntType() + : t.flags & TypeFlags.BooleanLike + ? globalBooleanType + : t.flags & TypeFlags.ESSymbolLike + ? getGlobalESSymbolType() + : t.flags & TypeFlags.NonPrimitive + ? emptyObjectType + : t.flags & TypeFlags.Index + ? stringNumberSymbolType + : t.flags & TypeFlags.Unknown && !strictNullChecks + ? emptyObjectType + : t; } function getReducedApparentType(type: Type): Type { @@ -15430,7 +26912,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getReducedType(getApparentType(getReducedType(type))); } - function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: __String, skipObjectFunctionPropertyAugment?: boolean): Symbol | undefined { + function createUnionOrIntersectionProperty( + containingType: UnionOrIntersectionType, + name: __String, + skipObjectFunctionPropertyAugment?: boolean + ): Symbol | undefined { let singleProp: Symbol | undefined; let propSet: Map | undefined; let indexTypes: Type[] | undefined; @@ -15443,36 +26929,57 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (const current of containingType.types) { const type = getApparentType(current); if (!(isErrorType(type) || type.flags & TypeFlags.Never)) { - const prop = getPropertyOfType(type, name, skipObjectFunctionPropertyAugment); - const modifiers = prop ? getDeclarationModifierFlagsFromSymbol(prop) : 0; + const prop = getPropertyOfType( + type, + name, + skipObjectFunctionPropertyAugment + ); + const modifiers = prop + ? getDeclarationModifierFlagsFromSymbol(prop) + : 0; if (prop) { if (prop.flags & SymbolFlags.ClassMember) { - optionalFlag ??= isUnion ? SymbolFlags.None : SymbolFlags.Optional; + optionalFlag ??= isUnion + ? SymbolFlags.None + : SymbolFlags.Optional; if (isUnion) { optionalFlag |= prop.flags & SymbolFlags.Optional; - } - else { + } else { optionalFlag &= prop.flags; } } if (!singleProp) { singleProp = prop; - } - else if (prop !== singleProp) { - const isInstantiation = (getTargetSymbol(prop) || prop) === (getTargetSymbol(singleProp) || singleProp); + } else if (prop !== singleProp) { + const isInstantiation = + (getTargetSymbol(prop) || prop) === + (getTargetSymbol(singleProp) || singleProp); // If the symbols are instances of one another with identical types - consider the symbols // equivalent and just use the first one, which thus allows us to avoid eliding private // members when intersecting a (this-)instantiations of a class with its raw base or another instance - if (isInstantiation && compareProperties(singleProp, prop, (a, b) => a === b ? Ternary.True : Ternary.False) === Ternary.True) { + if ( + isInstantiation && + compareProperties(singleProp, prop, (a, b) => + a === b ? Ternary.True : Ternary.False + ) === Ternary.True + ) { // If we merged instantiations of a generic type, we replicate the symbol parent resetting behavior we used // to do when we recorded multiple distinct symbols so that we still get, eg, `Array.length` printed // back and not `Array.length` when we're looking at a `.length` access on a `string[] | number[]` - mergedInstantiations = !!singleProp.parent && !!length(getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(singleProp.parent)); - } - else { + mergedInstantiations = + !!singleProp.parent && + !!length( + getLocalTypeParametersOfClassOrInterfaceOrTypeAlias( + singleProp.parent + ) + ); + } else { if (!propSet) { propSet = new Map(); - propSet.set(getSymbolId(singleProp), singleProp); + propSet.set( + getSymbolId(singleProp), + singleProp + ); } const id = getSymbolId(prop); if (!propSet.has(id)) { @@ -15482,29 +26989,49 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (isUnion && isReadonlySymbol(prop)) { checkFlags |= CheckFlags.Readonly; - } - else if (!isUnion && !isReadonlySymbol(prop)) { + } else if (!isUnion && !isReadonlySymbol(prop)) { checkFlags &= ~CheckFlags.Readonly; } - checkFlags |= (!(modifiers & ModifierFlags.NonPublicAccessibilityModifier) ? CheckFlags.ContainsPublic : 0) | - (modifiers & ModifierFlags.Protected ? CheckFlags.ContainsProtected : 0) | - (modifiers & ModifierFlags.Private ? CheckFlags.ContainsPrivate : 0) | - (modifiers & ModifierFlags.Static ? CheckFlags.ContainsStatic : 0); + checkFlags |= + (!( + modifiers & + ModifierFlags.NonPublicAccessibilityModifier + ) + ? CheckFlags.ContainsPublic + : 0) | + (modifiers & ModifierFlags.Protected + ? CheckFlags.ContainsProtected + : 0) | + (modifiers & ModifierFlags.Private + ? CheckFlags.ContainsPrivate + : 0) | + (modifiers & ModifierFlags.Static + ? CheckFlags.ContainsStatic + : 0); if (!isPrototypeProperty(prop)) { syntheticFlag = CheckFlags.SyntheticProperty; } - } - else if (isUnion) { - const indexInfo = !isLateBoundName(name) && getApplicableIndexInfoForName(type, name); + } else if (isUnion) { + const indexInfo = + !isLateBoundName(name) && + getApplicableIndexInfoForName(type, name); if (indexInfo) { - checkFlags |= CheckFlags.WritePartial | (indexInfo.isReadonly ? CheckFlags.Readonly : 0); - indexTypes = append(indexTypes, isTupleType(type) ? getRestTypeOfTupleType(type) || undefinedType : indexInfo.type); - } - else if (isObjectLiteralType(type) && !(getObjectFlags(type) & ObjectFlags.ContainsSpread)) { + checkFlags |= + CheckFlags.WritePartial | + (indexInfo.isReadonly ? CheckFlags.Readonly : 0); + indexTypes = append( + indexTypes, + isTupleType(type) + ? getRestTypeOfTupleType(type) || undefinedType + : indexInfo.type + ); + } else if ( + isObjectLiteralType(type) && + !(getObjectFlags(type) & ObjectFlags.ContainsSpread) + ) { checkFlags |= CheckFlags.WritePartial; indexTypes = append(indexTypes, undefinedType); - } - else { + } else { checkFlags |= CheckFlags.ReadPartial; } } @@ -15512,10 +27039,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if ( !singleProp || - isUnion && + (isUnion && (propSet || checkFlags & CheckFlags.Partial) && - checkFlags & (CheckFlags.ContainsPrivate | CheckFlags.ContainsProtected) && - !(propSet && getCommonDeclarationsOfSymbols(propSet.values())) + checkFlags & + (CheckFlags.ContainsPrivate | + CheckFlags.ContainsProtected) && + !(propSet && getCommonDeclarationsOfSymbols(propSet.values()))) ) { // No property was found, or, in a union, a property has a private or protected declaration in one // constituent, but is missing or has a different declaration in another constituent. @@ -15533,8 +27062,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { clone.links.mapper = links?.mapper; clone.links.writeType = getWriteTypeOfSymbol(singleProp); return clone; - } - else { + } else { return singleProp; } } @@ -15549,8 +27077,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (const prop of props) { if (!firstValueDeclaration) { firstValueDeclaration = prop.valueDeclaration; - } - else if (prop.valueDeclaration && prop.valueDeclaration !== firstValueDeclaration) { + } else if ( + prop.valueDeclaration && + prop.valueDeclaration !== firstValueDeclaration + ) { hasNonUniformValueDeclaration = true; } declarations = addRange(declarations, prop.declarations); @@ -15561,7 +27091,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const writeType = getWriteTypeOfSymbol(prop); if (writeTypes || writeType !== type) { - writeTypes = append(!writeTypes ? propTypes.slice() : writeTypes, writeType); + writeTypes = append( + !writeTypes ? propTypes.slice() : writeTypes, + writeType + ); } if (type !== firstType) { checkFlags |= CheckFlags.HasNonUniformType; @@ -15575,7 +27108,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { propTypes.push(type); } addRange(propTypes, indexTypes); - const result = createSymbol(SymbolFlags.Property | (optionalFlag ?? 0), name, syntheticFlag | checkFlags); + const result = createSymbol( + SymbolFlags.Property | (optionalFlag ?? 0), + name, + syntheticFlag | checkFlags + ); result.links.containingType = containingType; if (!hasNonUniformValueDeclaration && firstValueDeclaration) { result.valueDeclaration = firstValueDeclaration; @@ -15594,11 +27131,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { result.links.deferralParent = containingType; result.links.deferralConstituents = propTypes; result.links.deferralWriteConstituents = writeTypes; - } - else { - result.links.type = isUnion ? getUnionType(propTypes) : getIntersectionType(propTypes); + } else { + result.links.type = isUnion + ? getUnionType(propTypes) + : getIntersectionType(propTypes); if (writeTypes) { - result.links.writeType = isUnion ? getUnionType(writeTypes) : getIntersectionType(writeTypes); + result.links.writeType = isUnion + ? getUnionType(writeTypes) + : getIntersectionType(writeTypes); } } return result; @@ -15609,20 +27149,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // constituents, in which case the isPartial flag is set when the containing type is union type. We need // these partial properties when identifying discriminant properties, but otherwise they are filtered out // and do not appear to be present in the union type. - function getUnionOrIntersectionProperty(type: UnionOrIntersectionType, name: __String, skipObjectFunctionPropertyAugment?: boolean): Symbol | undefined { - let property = skipObjectFunctionPropertyAugment ? - type.propertyCacheWithoutObjectFunctionPropertyAugment?.get(name) : - type.propertyCache?.get(name); + function getUnionOrIntersectionProperty( + type: UnionOrIntersectionType, + name: __String, + skipObjectFunctionPropertyAugment?: boolean + ): Symbol | undefined { + let property = skipObjectFunctionPropertyAugment + ? type.propertyCacheWithoutObjectFunctionPropertyAugment?.get(name) + : type.propertyCache?.get(name); if (!property) { - property = createUnionOrIntersectionProperty(type, name, skipObjectFunctionPropertyAugment); + property = createUnionOrIntersectionProperty( + type, + name, + skipObjectFunctionPropertyAugment + ); if (property) { - const properties = skipObjectFunctionPropertyAugment ? - type.propertyCacheWithoutObjectFunctionPropertyAugment ||= createSymbolTable() : - type.propertyCache ||= createSymbolTable(); + const properties = skipObjectFunctionPropertyAugment + ? (type.propertyCacheWithoutObjectFunctionPropertyAugment ||= + createSymbolTable()) + : (type.propertyCache ||= createSymbolTable()); properties.set(name, property); // Propagate an entry from the non-augmented cache to the augmented cache unless the property is partial. - if (skipObjectFunctionPropertyAugment && !(getCheckFlags(property) & CheckFlags.Partial) && !type.propertyCache?.get(name)) { - const properties = type.propertyCache ||= createSymbolTable(); + if ( + skipObjectFunctionPropertyAugment && + !(getCheckFlags(property) & CheckFlags.Partial) && + !type.propertyCache?.get(name) + ) { + const properties = (type.propertyCache ||= + createSymbolTable()); properties.set(name, property); } } @@ -15640,7 +27194,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { commonDeclarations = new Set(symbol.declarations); continue; } - commonDeclarations.forEach(declaration => { + commonDeclarations.forEach((declaration) => { if (!contains(symbol.declarations, declaration)) { commonDeclarations!.delete(declaration); } @@ -15652,10 +27206,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return commonDeclarations; } - function getPropertyOfUnionOrIntersectionType(type: UnionOrIntersectionType, name: __String, skipObjectFunctionPropertyAugment?: boolean): Symbol | undefined { - const property = getUnionOrIntersectionProperty(type, name, skipObjectFunctionPropertyAugment); + function getPropertyOfUnionOrIntersectionType( + type: UnionOrIntersectionType, + name: __String, + skipObjectFunctionPropertyAugment?: boolean + ): Symbol | undefined { + const property = getUnionOrIntersectionProperty( + type, + name, + skipObjectFunctionPropertyAugment + ); // We need to filter out partial properties in union types - return property && !(getCheckFlags(property) & CheckFlags.ReadPartial) ? property : undefined; + return property && !(getCheckFlags(property) & CheckFlags.ReadPartial) + ? property + : undefined; } /** @@ -15665,15 +27229,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * no constituent property has type 'never', but the intersection of the constituent property types is 'never'. */ function getReducedType(type: Type): Type { - if (type.flags & TypeFlags.Union && (type as UnionType).objectFlags & ObjectFlags.ContainsIntersections) { - return (type as UnionType).resolvedReducedType || ((type as UnionType).resolvedReducedType = getReducedUnionType(type as UnionType)); - } - else if (type.flags & TypeFlags.Intersection) { - if (!((type as IntersectionType).objectFlags & ObjectFlags.IsNeverIntersectionComputed)) { - (type as IntersectionType).objectFlags |= ObjectFlags.IsNeverIntersectionComputed | - (some(getPropertiesOfUnionOrIntersectionType(type as IntersectionType), isNeverReducedProperty) ? ObjectFlags.IsNeverIntersection : 0); + if ( + type.flags & TypeFlags.Union && + (type as UnionType).objectFlags & ObjectFlags.ContainsIntersections + ) { + return ( + (type as UnionType).resolvedReducedType || + ((type as UnionType).resolvedReducedType = getReducedUnionType( + type as UnionType + )) + ); + } else if (type.flags & TypeFlags.Intersection) { + if ( + !( + (type as IntersectionType).objectFlags & + ObjectFlags.IsNeverIntersectionComputed + ) + ) { + (type as IntersectionType).objectFlags |= + ObjectFlags.IsNeverIntersectionComputed | + (some( + getPropertiesOfUnionOrIntersectionType( + type as IntersectionType + ), + isNeverReducedProperty + ) + ? ObjectFlags.IsNeverIntersection + : 0); } - return (type as IntersectionType).objectFlags & ObjectFlags.IsNeverIntersection ? neverType : type; + return (type as IntersectionType).objectFlags & + ObjectFlags.IsNeverIntersection + ? neverType + : type; } return type; } @@ -15691,20 +27278,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isNeverReducedProperty(prop: Symbol) { - return isDiscriminantWithNeverType(prop) || isConflictingPrivateProperty(prop); + return ( + isDiscriminantWithNeverType(prop) || + isConflictingPrivateProperty(prop) + ); } function isDiscriminantWithNeverType(prop: Symbol) { // Return true for a synthetic non-optional property with non-uniform types, where at least one is // a literal type and none is never, that reduces to never. - return !(prop.flags & SymbolFlags.Optional) && - (getCheckFlags(prop) & (CheckFlags.Discriminant | CheckFlags.HasNeverType)) === CheckFlags.Discriminant && - !!(getTypeOfSymbol(prop).flags & TypeFlags.Never); + return ( + !(prop.flags & SymbolFlags.Optional) && + (getCheckFlags(prop) & + (CheckFlags.Discriminant | CheckFlags.HasNeverType)) === + CheckFlags.Discriminant && + !!(getTypeOfSymbol(prop).flags & TypeFlags.Never) + ); } function isConflictingPrivateProperty(prop: Symbol) { // Return true for a synthetic property with multiple declarations, at least one of which is private. - return !prop.valueDeclaration && !!(getCheckFlags(prop) & CheckFlags.ContainsPrivate); + return ( + !prop.valueDeclaration && + !!(getCheckFlags(prop) & CheckFlags.ContainsPrivate) + ); } /** @@ -15715,24 +27312,69 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * literal-typed properties are reducible). */ function isGenericReducibleType(type: Type): boolean { - return !!(type.flags & TypeFlags.Union && (type as UnionType).objectFlags & ObjectFlags.ContainsIntersections && some((type as UnionType).types, isGenericReducibleType) || - type.flags & TypeFlags.Intersection && isReducibleIntersection(type as IntersectionType)); + return !!( + (type.flags & TypeFlags.Union && + (type as UnionType).objectFlags & + ObjectFlags.ContainsIntersections && + some((type as UnionType).types, isGenericReducibleType)) || + (type.flags & TypeFlags.Intersection && + isReducibleIntersection(type as IntersectionType)) + ); } function isReducibleIntersection(type: IntersectionType) { - const uniqueFilled = type.uniqueLiteralFilledInstantiation || (type.uniqueLiteralFilledInstantiation = instantiateType(type, uniqueLiteralMapper)); + const uniqueFilled = + type.uniqueLiteralFilledInstantiation || + (type.uniqueLiteralFilledInstantiation = instantiateType( + type, + uniqueLiteralMapper + )); return getReducedType(uniqueFilled) !== uniqueFilled; } - function elaborateNeverIntersection(errorInfo: DiagnosticMessageChain | undefined, type: Type) { - if (type.flags & TypeFlags.Intersection && getObjectFlags(type) & ObjectFlags.IsNeverIntersection) { - const neverProp = find(getPropertiesOfUnionOrIntersectionType(type as IntersectionType), isDiscriminantWithNeverType); + function elaborateNeverIntersection( + errorInfo: DiagnosticMessageChain | undefined, + type: Type + ) { + if ( + type.flags & TypeFlags.Intersection && + getObjectFlags(type) & ObjectFlags.IsNeverIntersection + ) { + const neverProp = find( + getPropertiesOfUnionOrIntersectionType( + type as IntersectionType + ), + isDiscriminantWithNeverType + ); if (neverProp) { - return chainDiagnosticMessages(errorInfo, Diagnostics.The_intersection_0_was_reduced_to_never_because_property_1_has_conflicting_types_in_some_constituents, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.NoTypeReduction), symbolToString(neverProp)); + return chainDiagnosticMessages( + errorInfo, + Diagnostics.The_intersection_0_was_reduced_to_never_because_property_1_has_conflicting_types_in_some_constituents, + typeToString( + type, + /*enclosingDeclaration*/ undefined, + TypeFormatFlags.NoTypeReduction + ), + symbolToString(neverProp) + ); } - const privateProp = find(getPropertiesOfUnionOrIntersectionType(type as IntersectionType), isConflictingPrivateProperty); + const privateProp = find( + getPropertiesOfUnionOrIntersectionType( + type as IntersectionType + ), + isConflictingPrivateProperty + ); if (privateProp) { - return chainDiagnosticMessages(errorInfo, Diagnostics.The_intersection_0_was_reduced_to_never_because_property_1_exists_in_multiple_constituents_and_is_private_in_some, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.NoTypeReduction), symbolToString(privateProp)); + return chainDiagnosticMessages( + errorInfo, + Diagnostics.The_intersection_0_was_reduced_to_never_because_property_1_exists_in_multiple_constituents_and_is_private_in_some, + typeToString( + type, + /*enclosingDeclaration*/ undefined, + TypeFormatFlags.NoTypeReduction + ), + symbolToString(privateProp) + ); } } return errorInfo; @@ -15746,12 +27388,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param type a type to look up property from * @param name a name of property to look up in a given type */ - function getPropertyOfType(type: Type, name: __String, skipObjectFunctionPropertyAugment?: boolean, includeTypeOnlyMembers?: boolean): Symbol | undefined { + function getPropertyOfType( + type: Type, + name: __String, + skipObjectFunctionPropertyAugment?: boolean, + includeTypeOnlyMembers?: boolean + ): Symbol | undefined { type = getReducedApparentType(type); if (type.flags & TypeFlags.Object) { const resolved = resolveStructuredTypeMembers(type as ObjectType); const symbol = resolved.members.get(name); - if (symbol && !includeTypeOnlyMembers && type.symbol?.flags & SymbolFlags.ValueModule && getSymbolLinks(type.symbol).typeOnlyExportStarMap?.has(name)) { + if ( + symbol && + !includeTypeOnlyMembers && + type.symbol?.flags & SymbolFlags.ValueModule && + getSymbolLinks(type.symbol).typeOnlyExportStarMap?.has(name) + ) { // If this is the type of a module, `resolved.members.get(name)` might have effectively skipped over // an `export type * from './foo'`, leaving `symbolIsValue` unable to see that the symbol is being // viewed through a type-only export. @@ -15761,10 +27413,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return symbol; } if (skipObjectFunctionPropertyAugment) return undefined; - const functionType = resolved === anyFunctionType ? globalFunctionType : - resolved.callSignatures.length ? globalCallableFunctionType : - resolved.constructSignatures.length ? globalNewableFunctionType : - undefined; + const functionType = + resolved === anyFunctionType + ? globalFunctionType + : resolved.callSignatures.length + ? globalCallableFunctionType + : resolved.constructSignatures.length + ? globalNewableFunctionType + : undefined; if (functionType) { const symbol = getPropertyOfObjectType(functionType, name); if (symbol) { @@ -15774,25 +27430,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getPropertyOfObjectType(globalObjectType, name); } if (type.flags & TypeFlags.Intersection) { - const prop = getPropertyOfUnionOrIntersectionType(type as UnionOrIntersectionType, name, /*skipObjectFunctionPropertyAugment*/ true); + const prop = getPropertyOfUnionOrIntersectionType( + type as UnionOrIntersectionType, + name, + /*skipObjectFunctionPropertyAugment*/ true + ); if (prop) { return prop; } if (!skipObjectFunctionPropertyAugment) { - return getPropertyOfUnionOrIntersectionType(type as UnionOrIntersectionType, name, skipObjectFunctionPropertyAugment); + return getPropertyOfUnionOrIntersectionType( + type as UnionOrIntersectionType, + name, + skipObjectFunctionPropertyAugment + ); } return undefined; } if (type.flags & TypeFlags.Union) { - return getPropertyOfUnionOrIntersectionType(type as UnionOrIntersectionType, name, skipObjectFunctionPropertyAugment); + return getPropertyOfUnionOrIntersectionType( + type as UnionOrIntersectionType, + name, + skipObjectFunctionPropertyAugment + ); } return undefined; } - function getSignaturesOfStructuredType(type: Type, kind: SignatureKind): readonly Signature[] { + function getSignaturesOfStructuredType( + type: Type, + kind: SignatureKind + ): readonly Signature[] { if (type.flags & TypeFlags.StructuredType) { const resolved = resolveStructuredTypeMembers(type as ObjectType); - return kind === SignatureKind.Call ? resolved.callSignatures : resolved.constructSignatures; + return kind === SignatureKind.Call + ? resolved.callSignatures + : resolved.constructSignatures; } return emptyArray; } @@ -15801,19 +27474,56 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Return the signatures of the given kind in the given type. Creates synthetic union signatures when necessary and * maps primitive types and type parameters are to their apparent types. */ - function getSignaturesOfType(type: Type, kind: SignatureKind): readonly Signature[] { - const result = getSignaturesOfStructuredType(getReducedApparentType(type), kind); - if (kind === SignatureKind.Call && !length(result) && type.flags & TypeFlags.Union) { + function getSignaturesOfType( + type: Type, + kind: SignatureKind + ): readonly Signature[] { + const result = getSignaturesOfStructuredType( + getReducedApparentType(type), + kind + ); + if ( + kind === SignatureKind.Call && + !length(result) && + type.flags & TypeFlags.Union + ) { if ((type as UnionType).arrayFallbackSignatures) { return (type as UnionType).arrayFallbackSignatures!; } // If the union is all different instantiations of a member of the global array type... let memberName: __String; - if (everyType(type, t => !!t.symbol?.parent && isArrayOrTupleSymbol(t.symbol.parent) && (!memberName ? (memberName = t.symbol.escapedName, true) : memberName === t.symbol.escapedName))) { + if ( + everyType( + type, + (t) => + !!t.symbol?.parent && + isArrayOrTupleSymbol(t.symbol.parent) && + (!memberName + ? ((memberName = t.symbol.escapedName), true) + : memberName === t.symbol.escapedName) + ) + ) { // Transform the type from `(A[] | B[])["member"]` to `(A | B)[]["member"]` (since we pretend array is covariant anyway) - const arrayArg = mapType(type, t => getMappedType((isReadonlyArraySymbol(t.symbol.parent) ? globalReadonlyArrayType : globalArrayType).typeParameters![0], (t as AnonymousType).mapper!)); - const arrayType = createArrayType(arrayArg, someType(type, t => isReadonlyArraySymbol(t.symbol.parent))); - return (type as UnionType).arrayFallbackSignatures = getSignaturesOfType(getTypeOfPropertyOfType(arrayType, memberName!)!, kind); + const arrayArg = mapType(type, (t) => + getMappedType( + (isReadonlyArraySymbol(t.symbol.parent) + ? globalReadonlyArrayType + : globalArrayType + ).typeParameters![0], + (t as AnonymousType).mapper! + ) + ); + const arrayType = createArrayType( + arrayArg, + someType(type, (t) => + isReadonlyArraySymbol(t.symbol.parent) + ) + ); + return ((type as UnionType).arrayFallbackSignatures = + getSignaturesOfType( + getTypeOfPropertyOfType(arrayType, memberName!)!, + kind + )); } (type as UnionType).arrayFallbackSignatures = result; } @@ -15821,24 +27531,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isArrayOrTupleSymbol(symbol: Symbol | undefined) { - if (!symbol || !globalArrayType.symbol || !globalReadonlyArrayType.symbol) { + if ( + !symbol || + !globalArrayType.symbol || + !globalReadonlyArrayType.symbol + ) { return false; } - return !!getSymbolIfSameReference(symbol, globalArrayType.symbol) || !!getSymbolIfSameReference(symbol, globalReadonlyArrayType.symbol); + return ( + !!getSymbolIfSameReference(symbol, globalArrayType.symbol) || + !!getSymbolIfSameReference(symbol, globalReadonlyArrayType.symbol) + ); } function isReadonlyArraySymbol(symbol: Symbol | undefined) { if (!symbol || !globalReadonlyArrayType.symbol) { return false; } - return !!getSymbolIfSameReference(symbol, globalReadonlyArrayType.symbol); + return !!getSymbolIfSameReference( + symbol, + globalReadonlyArrayType.symbol + ); } function findIndexInfo(indexInfos: readonly IndexInfo[], keyType: Type) { - return find(indexInfos, info => info.keyType === keyType); + return find(indexInfos, (info) => info.keyType === keyType); } - function findApplicableIndexInfo(indexInfos: readonly IndexInfo[], keyType: Type) { + function findApplicableIndexInfo( + indexInfos: readonly IndexInfo[], + keyType: Type + ) { // Index signatures for type 'string' are considered only when no other index signatures apply. let stringIndexInfo: IndexInfo | undefined; let applicableInfo: IndexInfo | undefined; @@ -15846,31 +27569,51 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (const info of indexInfos) { if (info.keyType === stringType) { stringIndexInfo = info; - } - else if (isApplicableIndexType(keyType, info.keyType)) { + } else if (isApplicableIndexType(keyType, info.keyType)) { if (!applicableInfo) { applicableInfo = info; - } - else { - (applicableInfos || (applicableInfos = [applicableInfo])).push(info); + } else { + ( + applicableInfos || (applicableInfos = [applicableInfo]) + ).push(info); } } } // When more than one index signature is applicable we create a synthetic IndexInfo. Instead of computing // the intersected key type, we just use unknownType for the key type as nothing actually depends on the // keyType property of the returned IndexInfo. - return applicableInfos ? createIndexInfo(unknownType, getIntersectionType(map(applicableInfos, info => info.type)), reduceLeft(applicableInfos, (isReadonly, info) => isReadonly && info.isReadonly, /*initial*/ true)) : - applicableInfo ? applicableInfo : - stringIndexInfo && isApplicableIndexType(keyType, stringType) ? stringIndexInfo : - undefined; + return applicableInfos + ? createIndexInfo( + unknownType, + getIntersectionType( + map(applicableInfos, (info) => info.type) + ), + reduceLeft( + applicableInfos, + (isReadonly, info) => isReadonly && info.isReadonly, + /*initial*/ true + ) + ) + : applicableInfo + ? applicableInfo + : stringIndexInfo && isApplicableIndexType(keyType, stringType) + ? stringIndexInfo + : undefined; } function isApplicableIndexType(source: Type, target: Type): boolean { // A 'string' index signature applies to types assignable to 'string' or 'number', and a 'number' index // signature applies to types assignable to 'number', `${number}` and numeric string literal types. - return isTypeAssignableTo(source, target) || - target === stringType && isTypeAssignableTo(source, numberType) || - target === numberType && (source === numericStringType || !!(source.flags & TypeFlags.StringLiteral) && isNumericLiteralName((source as StringLiteralType).value)); + return ( + isTypeAssignableTo(source, target) || + (target === stringType && isTypeAssignableTo(source, numberType)) || + (target === numberType && + (source === numericStringType || + (!!(source.flags & TypeFlags.StringLiteral) && + isNumericLiteralName( + (source as StringLiteralType).value + )))) + ); } function getIndexInfosOfStructuredType(type: Type): readonly IndexInfo[] { @@ -15887,7 +27630,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Return the indexing info of the given kind in the given type. Creates synthetic union index types when necessary and // maps primitive types and type parameters are to their apparent types. - function getIndexInfoOfType(type: Type, keyType: Type): IndexInfo | undefined { + function getIndexInfoOfType( + type: Type, + keyType: Type + ): IndexInfo | undefined { return findIndexInfo(getIndexInfosOfType(type), keyType); } @@ -15898,26 +27644,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getApplicableIndexInfos(type: Type, keyType: Type): IndexInfo[] { - return getIndexInfosOfType(type).filter(info => isApplicableIndexType(keyType, info.keyType)); + return getIndexInfosOfType(type).filter((info) => + isApplicableIndexType(keyType, info.keyType) + ); } - function getApplicableIndexInfo(type: Type, keyType: Type): IndexInfo | undefined { + function getApplicableIndexInfo( + type: Type, + keyType: Type + ): IndexInfo | undefined { return findApplicableIndexInfo(getIndexInfosOfType(type), keyType); } - function getApplicableIndexInfoForName(type: Type, name: __String): IndexInfo | undefined { - return getApplicableIndexInfo(type, isLateBoundName(name) ? esSymbolType : getStringLiteralType(unescapeLeadingUnderscores(name))); + function getApplicableIndexInfoForName( + type: Type, + name: __String + ): IndexInfo | undefined { + return getApplicableIndexInfo( + type, + isLateBoundName(name) + ? esSymbolType + : getStringLiteralType(unescapeLeadingUnderscores(name)) + ); } // Return list of type parameters with duplicates removed (duplicate identifier errors are generated in the actual // type checking functions). - function getTypeParametersFromDeclaration(declaration: DeclarationWithTypeParameters): readonly TypeParameter[] | undefined { + function getTypeParametersFromDeclaration( + declaration: DeclarationWithTypeParameters + ): readonly TypeParameter[] | undefined { let result: TypeParameter[] | undefined; for (const node of getEffectiveTypeParameterDeclarations(declaration)) { - result = appendIfUnique(result, getDeclaredTypeOfTypeParameter(node.symbol)); + result = appendIfUnique( + result, + getDeclaredTypeOfTypeParameter(node.symbol) + ); } - return result?.length ? result - : isFunctionDeclaration(declaration) ? getSignatureOfTypeTag(declaration)?.typeParameters + return result?.length + ? result + : isFunctionDeclaration(declaration) + ? getSignatureOfTypeTag(declaration)?.typeParameters : undefined; } @@ -15931,20 +27697,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function tryFindAmbientModule(moduleName: string, withAugmentations: boolean) { + function tryFindAmbientModule( + moduleName: string, + withAugmentations: boolean + ) { if (isExternalModuleNameRelative(moduleName)) { return undefined; } - const symbol = getSymbol(globals, '"' + moduleName + '"' as __String, SymbolFlags.ValueModule); + const symbol = getSymbol( + globals, + ('"' + moduleName + '"') as __String, + SymbolFlags.ValueModule + ); // merged symbol is module declaration symbol combined with all augmentations return symbol && withAugmentations ? getMergedSymbol(symbol) : symbol; } - function hasEffectiveQuestionToken(node: ParameterDeclaration | JSDocParameterTag | JSDocPropertyTag) { - return hasQuestionToken(node) || isOptionalJSDocPropertyLikeTag(node) || isParameter(node) && isJSDocOptionalParameter(node); + function hasEffectiveQuestionToken( + node: ParameterDeclaration | JSDocParameterTag | JSDocPropertyTag + ) { + return ( + hasQuestionToken(node) || + isOptionalJSDocPropertyLikeTag(node) || + (isParameter(node) && isJSDocOptionalParameter(node)) + ); } - function isOptionalParameter(node: ParameterDeclaration | JSDocParameterTag | JSDocPropertyTag) { + function isOptionalParameter( + node: ParameterDeclaration | JSDocParameterTag | JSDocPropertyTag + ) { if (hasEffectiveQuestionToken(node)) { return true; } @@ -15958,23 +27739,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Only consider syntactic or instantiated parameters as optional, not `void` parameters as this function is used // in grammar checks and checking for `void` too early results in parameter types widening too early // and causes some noImplicitAny errors to be lost. - return parameterIndex >= getMinArgumentCount(signature, MinArgumentCountFlags.StrongArityForUntypedJS | MinArgumentCountFlags.VoidIsNonOptional); + return ( + parameterIndex >= + getMinArgumentCount( + signature, + MinArgumentCountFlags.StrongArityForUntypedJS | + MinArgumentCountFlags.VoidIsNonOptional + ) + ); } const iife = getImmediatelyInvokedFunctionExpression(node.parent); if (iife) { - return !node.type && + return ( + !node.type && !node.dotDotDotToken && - node.parent.parameters.indexOf(node) >= getEffectiveCallArguments(iife).length; + node.parent.parameters.indexOf(node) >= + getEffectiveCallArguments(iife).length + ); } return false; } function isOptionalPropertyDeclaration(node: Declaration) { - return isPropertyDeclaration(node) && !hasAccessorModifier(node) && node.questionToken; + return ( + isPropertyDeclaration(node) && + !hasAccessorModifier(node) && + node.questionToken + ); } - function createTypePredicate(kind: TypePredicateKind, parameterName: string | undefined, parameterIndex: number | undefined, type: Type | undefined): TypePredicate { + function createTypePredicate( + kind: TypePredicateKind, + parameterName: string | undefined, + parameterIndex: number | undefined, + type: Type | undefined + ): TypePredicate { return { kind, parameterName, parameterIndex, type } as TypePredicate; } @@ -15982,7 +27782,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Gets the minimum number of type arguments needed to satisfy all non-optional type * parameters. */ - function getMinTypeArgumentCount(typeParameters: readonly TypeParameter[] | undefined): number { + function getMinTypeArgumentCount( + typeParameters: readonly TypeParameter[] | undefined + ): number { let minTypeArgumentCount = 0; if (typeParameters) { for (let i = 0; i < typeParameters.length; i++) { @@ -16002,27 +27804,60 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param typeParameters The requested type parameters. * @param minTypeArgumentCount The minimum number of required type arguments. */ - function fillMissingTypeArguments(typeArguments: readonly Type[], typeParameters: readonly TypeParameter[] | undefined, minTypeArgumentCount: number, isJavaScriptImplicitAny: boolean): Type[]; - function fillMissingTypeArguments(typeArguments: readonly Type[] | undefined, typeParameters: readonly TypeParameter[] | undefined, minTypeArgumentCount: number, isJavaScriptImplicitAny: boolean): Type[] | undefined; - function fillMissingTypeArguments(typeArguments: readonly Type[] | undefined, typeParameters: readonly TypeParameter[] | undefined, minTypeArgumentCount: number, isJavaScriptImplicitAny: boolean) { + function fillMissingTypeArguments( + typeArguments: readonly Type[], + typeParameters: readonly TypeParameter[] | undefined, + minTypeArgumentCount: number, + isJavaScriptImplicitAny: boolean + ): Type[]; + function fillMissingTypeArguments( + typeArguments: readonly Type[] | undefined, + typeParameters: readonly TypeParameter[] | undefined, + minTypeArgumentCount: number, + isJavaScriptImplicitAny: boolean + ): Type[] | undefined; + function fillMissingTypeArguments( + typeArguments: readonly Type[] | undefined, + typeParameters: readonly TypeParameter[] | undefined, + minTypeArgumentCount: number, + isJavaScriptImplicitAny: boolean + ) { const numTypeParameters = length(typeParameters); if (!numTypeParameters) { return []; } const numTypeArguments = length(typeArguments); - if (isJavaScriptImplicitAny || (numTypeArguments >= minTypeArgumentCount && numTypeArguments <= numTypeParameters)) { + if ( + isJavaScriptImplicitAny || + (numTypeArguments >= minTypeArgumentCount && + numTypeArguments <= numTypeParameters) + ) { const result = typeArguments ? typeArguments.slice() : []; // Map invalid forward references in default types to the error type for (let i = numTypeArguments; i < numTypeParameters; i++) { result[i] = errorType; } - const baseDefaultType = getDefaultTypeArgumentType(isJavaScriptImplicitAny); + const baseDefaultType = getDefaultTypeArgumentType( + isJavaScriptImplicitAny + ); for (let i = numTypeArguments; i < numTypeParameters; i++) { - let defaultType = getDefaultFromTypeParameter(typeParameters![i]); - if (isJavaScriptImplicitAny && defaultType && (isTypeIdenticalTo(defaultType, unknownType) || isTypeIdenticalTo(defaultType, emptyObjectType))) { + let defaultType = getDefaultFromTypeParameter( + typeParameters![i] + ); + if ( + isJavaScriptImplicitAny && + defaultType && + (isTypeIdenticalTo(defaultType, unknownType) || + isTypeIdenticalTo(defaultType, emptyObjectType)) + ) { defaultType = anyType; } - result[i] = defaultType ? instantiateType(defaultType, createTypeMapper(typeParameters!, result)) : baseDefaultType; + result[i] = defaultType + ? instantiateType( + defaultType, + createTypeMapper(typeParameters!, result) + ) + : baseDefaultType; } result.length = typeParameters!.length; return result; @@ -16030,22 +27865,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return typeArguments && typeArguments.slice(); } - function getSignatureFromDeclaration(declaration: SignatureDeclaration | JSDocSignature): Signature { + function getSignatureFromDeclaration( + declaration: SignatureDeclaration | JSDocSignature + ): Signature { const links = getNodeLinks(declaration); if (!links.resolvedSignature) { const parameters: Symbol[] = []; let flags = SignatureFlags.None; let minArgumentCount = 0; let thisParameter: Symbol | undefined; - let thisTag: JSDocThisTag | undefined = isInJSFile(declaration) ? getJSDocThisTag(declaration) : undefined; + let thisTag: JSDocThisTag | undefined = isInJSFile(declaration) + ? getJSDocThisTag(declaration) + : undefined; let hasThisParameter = false; const iife = getImmediatelyInvokedFunctionExpression(declaration); - const isJSConstructSignature = isJSDocConstructSignature(declaration); - const isUntypedSignatureInJSFile = !iife && + const isJSConstructSignature = + isJSDocConstructSignature(declaration); + const isUntypedSignatureInJSFile = + !iife && isInJSFile(declaration) && isValueSignatureDeclaration(declaration) && !hasJSDocParameterTags(declaration) && - !some(declaration.parameters, p => !!getJSDocType(p)) && + !some(declaration.parameters, (p) => !!getJSDocType(p)) && !getJSDocType(declaration) && !getContextualSignatureForFunctionLikeDeclaration(declaration); if (isUntypedSignatureInJSFile) { @@ -16055,7 +27896,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If this is a JSDoc construct signature, then skip the first parameter in the // parameter list. The first parameter represents the return type of the construct // signature. - for (let i = isJSConstructSignature ? 1 : 0; i < declaration.parameters.length; i++) { + for ( + let i = isJSConstructSignature ? 1 : 0; + i < declaration.parameters.length; + i++ + ) { const param = declaration.parameters[i]; if (isInJSFile(param) && isJSDocThisTag(param)) { thisTag = param; @@ -16063,17 +27908,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } let paramSymbol = param.symbol; - const type = isJSDocParameterTag(param) ? (param.typeExpression && param.typeExpression.type) : param.type; + const type = isJSDocParameterTag(param) + ? param.typeExpression && param.typeExpression.type + : param.type; // Include parameter symbol instead of property symbol in the signature - if (paramSymbol && !!(paramSymbol.flags & SymbolFlags.Property) && !isBindingPattern(param.name)) { - const resolvedSymbol = resolveName(param, paramSymbol.escapedName, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*isUse*/ false); + if ( + paramSymbol && + !!(paramSymbol.flags & SymbolFlags.Property) && + !isBindingPattern(param.name) + ) { + const resolvedSymbol = resolveName( + param, + paramSymbol.escapedName, + SymbolFlags.Value, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ false + ); paramSymbol = resolvedSymbol!; } - if (i === 0 && paramSymbol.escapedName === InternalSymbolName.This) { + if ( + i === 0 && + paramSymbol.escapedName === InternalSymbolName.This + ) { hasThisParameter = true; thisParameter = param.symbol; - } - else { + } else { parameters.push(paramSymbol); } @@ -16082,9 +27941,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Record a new minimum argument count if this is not an optional parameter - const isOptionalParameter = hasEffectiveQuestionToken(param) || - isParameter(param) && param.initializer || isRestParameter(param) || - iife && parameters.length > iife.arguments.length && !type; + const isOptionalParameter = + hasEffectiveQuestionToken(param) || + (isParameter(param) && param.initializer) || + isRestParameter(param) || + (iife && + parameters.length > iife.arguments.length && + !type); if (!isOptionalParameter) { minArgumentCount = parameters.length; } @@ -16092,36 +27955,80 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If only one accessor includes a this-type annotation, the other behaves as if it had the same type annotation if ( - (declaration.kind === SyntaxKind.GetAccessor || declaration.kind === SyntaxKind.SetAccessor) && + (declaration.kind === SyntaxKind.GetAccessor || + declaration.kind === SyntaxKind.SetAccessor) && hasBindableName(declaration) && (!hasThisParameter || !thisParameter) ) { - const otherKind = declaration.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor : SyntaxKind.GetAccessor; - const other = getDeclarationOfKind(getSymbolOfDeclaration(declaration), otherKind); + const otherKind = + declaration.kind === SyntaxKind.GetAccessor + ? SyntaxKind.SetAccessor + : SyntaxKind.GetAccessor; + const other = getDeclarationOfKind( + getSymbolOfDeclaration(declaration), + otherKind + ); if (other) { thisParameter = getAnnotatedAccessorThisParameter(other); } } if (thisTag && thisTag.typeExpression) { - thisParameter = createSymbolWithType(createSymbol(SymbolFlags.FunctionScopedVariable, InternalSymbolName.This), getTypeFromTypeNode(thisTag.typeExpression)); + thisParameter = createSymbolWithType( + createSymbol( + SymbolFlags.FunctionScopedVariable, + InternalSymbolName.This + ), + getTypeFromTypeNode(thisTag.typeExpression) + ); } - const hostDeclaration = isJSDocSignature(declaration) ? getEffectiveJSDocHost(declaration) : declaration; - const classType = hostDeclaration && isConstructorDeclaration(hostDeclaration) ? - getDeclaredTypeOfClassOrInterface(getMergedSymbol((hostDeclaration.parent as ClassDeclaration).symbol)) - : undefined; - const typeParameters = classType ? classType.localTypeParameters : getTypeParametersFromDeclaration(declaration); - if (hasRestParameter(declaration) || isInJSFile(declaration) && maybeAddJsSyntheticRestParameter(declaration, parameters)) { + const hostDeclaration = isJSDocSignature(declaration) + ? getEffectiveJSDocHost(declaration) + : declaration; + const classType = + hostDeclaration && isConstructorDeclaration(hostDeclaration) + ? getDeclaredTypeOfClassOrInterface( + getMergedSymbol( + (hostDeclaration.parent as ClassDeclaration) + .symbol + ) + ) + : undefined; + const typeParameters = classType + ? classType.localTypeParameters + : getTypeParametersFromDeclaration(declaration); + if ( + hasRestParameter(declaration) || + (isInJSFile(declaration) && + maybeAddJsSyntheticRestParameter(declaration, parameters)) + ) { flags |= SignatureFlags.HasRestParameter; } if ( - isConstructorTypeNode(declaration) && hasSyntacticModifier(declaration, ModifierFlags.Abstract) || - isConstructorDeclaration(declaration) && hasSyntacticModifier(declaration.parent, ModifierFlags.Abstract) + (isConstructorTypeNode(declaration) && + hasSyntacticModifier( + declaration, + ModifierFlags.Abstract + )) || + (isConstructorDeclaration(declaration) && + hasSyntacticModifier( + declaration.parent, + ModifierFlags.Abstract + )) ) { flags |= SignatureFlags.Abstract; } - links.resolvedSignature = createSignature(declaration, typeParameters, thisParameter, parameters, /*resolvedReturnType*/ undefined, /*resolvedTypePredicate*/ undefined, minArgumentCount, flags); + links.resolvedSignature = createSignature( + declaration, + typeParameters, + thisParameter, + parameters, + /*resolvedReturnType*/ undefined, + /*resolvedTypePredicate*/ undefined, + minArgumentCount, + flags + ); } return links.resolvedSignature; } @@ -16132,27 +28039,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * OR * 2. It has at least one parameter, and the last parameter has a matching `@param` with a type that starts with `...` */ - function maybeAddJsSyntheticRestParameter(declaration: SignatureDeclaration | JSDocSignature, parameters: Symbol[]): boolean { - if (isJSDocSignature(declaration) || !containsArgumentsReference(declaration)) { + function maybeAddJsSyntheticRestParameter( + declaration: SignatureDeclaration | JSDocSignature, + parameters: Symbol[] + ): boolean { + if ( + isJSDocSignature(declaration) || + !containsArgumentsReference(declaration) + ) { return false; } const lastParam = lastOrUndefined(declaration.parameters); - const lastParamTags = lastParam ? getJSDocParameterTags(lastParam) : getJSDocTags(declaration).filter(isJSDocParameterTag); - const lastParamVariadicType = firstDefined(lastParamTags, p => p.typeExpression && isJSDocVariadicType(p.typeExpression.type) ? p.typeExpression.type : undefined); + const lastParamTags = lastParam + ? getJSDocParameterTags(lastParam) + : getJSDocTags(declaration).filter(isJSDocParameterTag); + const lastParamVariadicType = firstDefined(lastParamTags, (p) => + p.typeExpression && isJSDocVariadicType(p.typeExpression.type) + ? p.typeExpression.type + : undefined + ); - const syntheticArgsSymbol = createSymbol(SymbolFlags.Variable, "args" as __String, CheckFlags.RestParameter); + const syntheticArgsSymbol = createSymbol( + SymbolFlags.Variable, + "args" as __String, + CheckFlags.RestParameter + ); if (lastParamVariadicType) { // Parameter has effective annotation, lock in type - syntheticArgsSymbol.links.type = createArrayType(getTypeFromTypeNode(lastParamVariadicType.type)); - } - else { + syntheticArgsSymbol.links.type = createArrayType( + getTypeFromTypeNode(lastParamVariadicType.type) + ); + } else { // Parameter has no annotation // 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 // cached by `getTypeOfSymbol` yet. syntheticArgsSymbol.links.checkFlags |= CheckFlags.DeferredType; syntheticArgsSymbol.links.deferralParent = neverType; syntheticArgsSymbol.links.deferralConstituents = [anyArrayType]; - syntheticArgsSymbol.links.deferralWriteConstituents = [anyArrayType]; + syntheticArgsSymbol.links.deferralWriteConstituents = [ + anyArrayType, + ]; } if (lastParamVariadicType) { // Replace the last parameter with a rest parameter. @@ -16162,33 +28088,49 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; } - function getSignatureOfTypeTag(node: SignatureDeclaration | JSDocSignature) { + function getSignatureOfTypeTag( + node: SignatureDeclaration | JSDocSignature + ) { // should be attached to a function declaration or expression - if (!(isInJSFile(node) && isFunctionLikeDeclaration(node))) return undefined; + if (!(isInJSFile(node) && isFunctionLikeDeclaration(node))) + return undefined; const typeTag = getJSDocTypeTag(node); - return typeTag?.typeExpression && getSingleCallSignature(getTypeFromTypeNode(typeTag.typeExpression)); + return ( + typeTag?.typeExpression && + getSingleCallSignature(getTypeFromTypeNode(typeTag.typeExpression)) + ); } - function getParameterTypeOfTypeTag(func: FunctionLikeDeclaration, parameter: ParameterDeclaration) { + function getParameterTypeOfTypeTag( + func: FunctionLikeDeclaration, + parameter: ParameterDeclaration + ) { const signature = getSignatureOfTypeTag(func); if (!signature) return undefined; const pos = func.parameters.indexOf(parameter); - return parameter.dotDotDotToken ? getRestTypeAtPosition(signature, pos) : getTypeAtPosition(signature, pos); + return parameter.dotDotDotToken + ? getRestTypeAtPosition(signature, pos) + : getTypeAtPosition(signature, pos); } - function getReturnTypeOfTypeTag(node: SignatureDeclaration | JSDocSignature) { + function getReturnTypeOfTypeTag( + node: SignatureDeclaration | JSDocSignature + ) { const signature = getSignatureOfTypeTag(node); return signature && getReturnTypeOfSignature(signature); } - function containsArgumentsReference(declaration: SignatureDeclaration): boolean { + function containsArgumentsReference( + declaration: SignatureDeclaration + ): boolean { const links = getNodeLinks(declaration); if (links.containsArgumentsReference === undefined) { if (links.flags & NodeCheckFlags.CaptureArguments) { links.containsArgumentsReference = true; - } - else { - links.containsArgumentsReference = traverse((declaration as FunctionLikeDeclaration).body!); + } else { + links.containsArgumentsReference = traverse( + (declaration as FunctionLikeDeclaration).body! + ); } } return links.containsArgumentsReference; @@ -16197,24 +28139,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!node) return false; switch (node.kind) { case SyntaxKind.Identifier: - return (node as Identifier).escapedText === argumentsSymbol.escapedName && getReferencedValueSymbol(node as Identifier) === argumentsSymbol; + return ( + (node as Identifier).escapedText === + argumentsSymbol.escapedName && + getReferencedValueSymbol(node as Identifier) === + argumentsSymbol + ); case SyntaxKind.PropertyDeclaration: case SyntaxKind.MethodDeclaration: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: - return (node as NamedDeclaration).name!.kind === SyntaxKind.ComputedPropertyName - && traverse((node as NamedDeclaration).name!); + return ( + (node as NamedDeclaration).name!.kind === + SyntaxKind.ComputedPropertyName && + traverse((node as NamedDeclaration).name!) + ); case SyntaxKind.PropertyAccessExpression: case SyntaxKind.ElementAccessExpression: - return traverse((node as PropertyAccessExpression | ElementAccessExpression).expression); + return traverse( + ( + node as + | PropertyAccessExpression + | ElementAccessExpression + ).expression + ); case SyntaxKind.PropertyAssignment: return traverse((node as PropertyAssignment).initializer); default: - return !nodeStartsNewLexicalEnvironment(node) && !isPartOfTypeNode(node) && !!forEachChild(node, traverse); + return ( + !nodeStartsNewLexicalEnvironment(node) && + !isPartOfTypeNode(node) && + !!forEachChild(node, traverse) + ); } } } @@ -16230,7 +28190,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // precedes the implementation node (i.e. has the same parent and ends where the implementation starts). if (i > 0 && (decl as FunctionLikeDeclaration).body) { const previous = symbol.declarations[i - 1]; - if (decl.parent === previous.parent && decl.kind === previous.kind && decl.pos === previous.end) { + if ( + decl.parent === previous.parent && + decl.kind === previous.kind && + decl.pos === previous.end + ) { continue; } } @@ -16239,10 +28203,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (length(tags)) { for (const tag of tags) { const jsDocSignature = tag.typeExpression; - if (jsDocSignature.type === undefined && !isConstructorDeclaration(decl)) { + if ( + jsDocSignature.type === undefined && + !isConstructorDeclaration(decl) + ) { reportImplicitAny(jsDocSignature, anyType); } - result.push(getSignatureFromDeclaration(jsDocSignature)); + result.push( + getSignatureFromDeclaration(jsDocSignature) + ); } continue; } @@ -16253,7 +28222,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { (!isFunctionExpressionOrArrowFunction(decl) && !isObjectLiteralMethod(decl) && getSignatureOfTypeTag(decl)) || - getSignatureFromDeclaration(decl), + getSignatureFromDeclaration(decl) ); } return result; @@ -16277,84 +28246,175 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getTypePredicateOfSignature(signature: Signature): TypePredicate | undefined { + function getTypePredicateOfSignature( + signature: Signature + ): TypePredicate | undefined { if (!signature.resolvedTypePredicate) { if (signature.target) { - const targetTypePredicate = getTypePredicateOfSignature(signature.target); - signature.resolvedTypePredicate = targetTypePredicate ? instantiateTypePredicate(targetTypePredicate, signature.mapper!) : noTypePredicate; - } - else if (signature.compositeSignatures) { - signature.resolvedTypePredicate = getUnionOrIntersectionTypePredicate(signature.compositeSignatures, signature.compositeKind) || noTypePredicate; - } - else { - const type = signature.declaration && getEffectiveReturnTypeNode(signature.declaration); + const targetTypePredicate = getTypePredicateOfSignature( + signature.target + ); + signature.resolvedTypePredicate = targetTypePredicate + ? instantiateTypePredicate( + targetTypePredicate, + signature.mapper! + ) + : noTypePredicate; + } else if (signature.compositeSignatures) { + signature.resolvedTypePredicate = + getUnionOrIntersectionTypePredicate( + signature.compositeSignatures, + signature.compositeKind + ) || noTypePredicate; + } else { + const type = + signature.declaration && + getEffectiveReturnTypeNode(signature.declaration); let jsdocPredicate: TypePredicate | undefined; if (!type) { - const jsdocSignature = getSignatureOfTypeTag(signature.declaration!); + const jsdocSignature = getSignatureOfTypeTag( + signature.declaration! + ); if (jsdocSignature && signature !== jsdocSignature) { - jsdocPredicate = getTypePredicateOfSignature(jsdocSignature); + jsdocPredicate = + getTypePredicateOfSignature(jsdocSignature); } } if (type || jsdocPredicate) { - signature.resolvedTypePredicate = type && isTypePredicateNode(type) ? - createTypePredicateFromTypePredicateNode(type, signature) : - jsdocPredicate || noTypePredicate; - } - else if (signature.declaration && isFunctionLikeDeclaration(signature.declaration) && (!signature.resolvedReturnType || signature.resolvedReturnType.flags & TypeFlags.Boolean) && getParameterCount(signature) > 0) { + signature.resolvedTypePredicate = + type && isTypePredicateNode(type) + ? createTypePredicateFromTypePredicateNode( + type, + signature + ) + : jsdocPredicate || noTypePredicate; + } else if ( + signature.declaration && + isFunctionLikeDeclaration(signature.declaration) && + (!signature.resolvedReturnType || + signature.resolvedReturnType.flags & + TypeFlags.Boolean) && + getParameterCount(signature) > 0 + ) { const { declaration } = signature; signature.resolvedTypePredicate = noTypePredicate; // avoid infinite loop - signature.resolvedTypePredicate = getTypePredicateFromBody(declaration) || noTypePredicate; - } - else { + signature.resolvedTypePredicate = + getTypePredicateFromBody(declaration) || + noTypePredicate; + } else { signature.resolvedTypePredicate = noTypePredicate; } } Debug.assert(!!signature.resolvedTypePredicate); } - return signature.resolvedTypePredicate === noTypePredicate ? undefined : signature.resolvedTypePredicate; + return signature.resolvedTypePredicate === noTypePredicate + ? undefined + : signature.resolvedTypePredicate; } - function createTypePredicateFromTypePredicateNode(node: TypePredicateNode, signature: Signature): TypePredicate { + function createTypePredicateFromTypePredicateNode( + node: TypePredicateNode, + signature: Signature + ): TypePredicate { const parameterName = node.parameterName; const type = node.type && getTypeFromTypeNode(node.type); - return parameterName.kind === SyntaxKind.ThisType ? - createTypePredicate(node.assertsModifier ? TypePredicateKind.AssertsThis : TypePredicateKind.This, /*parameterName*/ undefined, /*parameterIndex*/ undefined, type) : - createTypePredicate(node.assertsModifier ? TypePredicateKind.AssertsIdentifier : TypePredicateKind.Identifier, parameterName.escapedText as string, findIndex(signature.parameters, p => p.escapedName === parameterName.escapedText), type); - } - - function getUnionOrIntersectionType(types: Type[], kind: TypeFlags | undefined, unionReduction?: UnionReduction) { - return kind !== TypeFlags.Intersection ? getUnionType(types, unionReduction) : getIntersectionType(types); + return parameterName.kind === SyntaxKind.ThisType + ? createTypePredicate( + node.assertsModifier + ? TypePredicateKind.AssertsThis + : TypePredicateKind.This, + /*parameterName*/ undefined, + /*parameterIndex*/ undefined, + type + ) + : createTypePredicate( + node.assertsModifier + ? TypePredicateKind.AssertsIdentifier + : TypePredicateKind.Identifier, + parameterName.escapedText as string, + findIndex( + signature.parameters, + (p) => p.escapedName === parameterName.escapedText + ), + type + ); + } + + function getUnionOrIntersectionType( + types: Type[], + kind: TypeFlags | undefined, + unionReduction?: UnionReduction + ) { + return kind !== TypeFlags.Intersection + ? getUnionType(types, unionReduction) + : getIntersectionType(types); } function getReturnTypeOfSignature(signature: Signature): Type { if (!signature.resolvedReturnType) { - if (!pushTypeResolution(signature, TypeSystemPropertyName.ResolvedReturnType)) { + if ( + !pushTypeResolution( + signature, + TypeSystemPropertyName.ResolvedReturnType + ) + ) { return errorType; } - let type = signature.target ? instantiateType(getReturnTypeOfSignature(signature.target), signature.mapper) : - signature.compositeSignatures ? instantiateType(getUnionOrIntersectionType(map(signature.compositeSignatures, getReturnTypeOfSignature), signature.compositeKind, UnionReduction.Subtype), signature.mapper) : - getReturnTypeFromAnnotation(signature.declaration!) || - (nodeIsMissing((signature.declaration as FunctionLikeDeclaration).body) ? anyType : getReturnTypeFromBody(signature.declaration as FunctionLikeDeclaration)); + let type = signature.target + ? instantiateType( + getReturnTypeOfSignature(signature.target), + signature.mapper + ) + : signature.compositeSignatures + ? instantiateType( + getUnionOrIntersectionType( + map( + signature.compositeSignatures, + getReturnTypeOfSignature + ), + signature.compositeKind, + UnionReduction.Subtype + ), + signature.mapper + ) + : getReturnTypeFromAnnotation(signature.declaration!) || + (nodeIsMissing( + (signature.declaration as FunctionLikeDeclaration).body + ) + ? anyType + : getReturnTypeFromBody( + signature.declaration as FunctionLikeDeclaration + )); if (signature.flags & SignatureFlags.IsInnerCallChain) { type = addOptionalTypeMarker(type); - } - else if (signature.flags & SignatureFlags.IsOuterCallChain) { + } else if (signature.flags & SignatureFlags.IsOuterCallChain) { type = getOptionalType(type); } if (!popTypeResolution()) { if (signature.declaration) { - const typeNode = getEffectiveReturnTypeNode(signature.declaration); + const typeNode = getEffectiveReturnTypeNode( + signature.declaration + ); if (typeNode) { - error(typeNode, Diagnostics.Return_type_annotation_circularly_references_itself); - } - else if (noImplicitAny) { - const declaration = signature.declaration as Declaration; + error( + typeNode, + Diagnostics.Return_type_annotation_circularly_references_itself + ); + } else if (noImplicitAny) { + const declaration = + signature.declaration as Declaration; const name = getNameOfDeclaration(declaration); if (name) { - 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)); - } - else { - 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); + 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) + ); + } else { + 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 + ); } } } @@ -16365,29 +28425,47 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return signature.resolvedReturnType; } - function getReturnTypeFromAnnotation(declaration: SignatureDeclaration | JSDocSignature) { + function getReturnTypeFromAnnotation( + declaration: SignatureDeclaration | JSDocSignature + ) { if (declaration.kind === SyntaxKind.Constructor) { - return getDeclaredTypeOfClassOrInterface(getMergedSymbol((declaration.parent as ClassDeclaration).symbol)); + return getDeclaredTypeOfClassOrInterface( + getMergedSymbol((declaration.parent as ClassDeclaration).symbol) + ); } const typeNode = getEffectiveReturnTypeNode(declaration); if (isJSDocSignature(declaration)) { const root = getJSDocRoot(declaration); if (root && isConstructorDeclaration(root.parent) && !typeNode) { - return getDeclaredTypeOfClassOrInterface(getMergedSymbol((root.parent.parent as ClassDeclaration).symbol)); + return getDeclaredTypeOfClassOrInterface( + getMergedSymbol( + (root.parent.parent as ClassDeclaration).symbol + ) + ); } } if (isJSDocConstructSignature(declaration)) { - return getTypeFromTypeNode((declaration.parameters[0] as ParameterDeclaration).type!); // TODO: GH#18217 + return getTypeFromTypeNode( + (declaration.parameters[0] as ParameterDeclaration).type! + ); // TODO: GH#18217 } if (typeNode) { return getTypeFromTypeNode(typeNode); } - if (declaration.kind === SyntaxKind.GetAccessor && hasBindableName(declaration)) { - const jsDocType = isInJSFile(declaration) && getTypeForDeclarationFromJSDocComment(declaration); + if ( + declaration.kind === SyntaxKind.GetAccessor && + hasBindableName(declaration) + ) { + const jsDocType = + isInJSFile(declaration) && + getTypeForDeclarationFromJSDocComment(declaration); if (jsDocType) { return jsDocType; } - const setter = getDeclarationOfKind(getSymbolOfDeclaration(declaration), SyntaxKind.SetAccessor); + const setter = getDeclarationOfKind( + getSymbolOfDeclaration(declaration), + SyntaxKind.SetAccessor + ); const setterType = getAnnotatedAccessorType(setter); if (setterType) { return setterType; @@ -16397,8 +28475,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isResolvingReturnTypeOfSignature(signature: Signature): boolean { - return signature.compositeSignatures && some(signature.compositeSignatures, isResolvingReturnTypeOfSignature) || - !signature.resolvedReturnType && findResolutionCycleStartIndex(signature, TypeSystemPropertyName.ResolvedReturnType) >= 0; + return ( + (signature.compositeSignatures && + some( + signature.compositeSignatures, + isResolvingReturnTypeOfSignature + )) || + (!signature.resolvedReturnType && + findResolutionCycleStartIndex( + signature, + TypeSystemPropertyName.ResolvedReturnType + ) >= 0) + ); } function getRestTypeOfSignature(signature: Signature): Type { @@ -16407,23 +28495,47 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function tryGetRestTypeOfSignature(signature: Signature): Type | undefined { if (signatureHasRestParameter(signature)) { - const sigRestType = getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]); - const restType = isTupleType(sigRestType) ? getRestTypeOfTupleType(sigRestType) : sigRestType; + const sigRestType = getTypeOfSymbol( + signature.parameters[signature.parameters.length - 1] + ); + const restType = isTupleType(sigRestType) + ? getRestTypeOfTupleType(sigRestType) + : sigRestType; return restType && getIndexTypeOfType(restType, numberType); } return undefined; } - function getSignatureInstantiation(signature: Signature, typeArguments: Type[] | undefined, isJavascript: boolean, inferredTypeParameters?: readonly TypeParameter[]): Signature { - const instantiatedSignature = getSignatureInstantiationWithoutFillingInTypeArguments(signature, fillMissingTypeArguments(typeArguments, signature.typeParameters, getMinTypeArgumentCount(signature.typeParameters), isJavascript)); + function getSignatureInstantiation( + signature: Signature, + typeArguments: Type[] | undefined, + isJavascript: boolean, + inferredTypeParameters?: readonly TypeParameter[] + ): Signature { + const instantiatedSignature = + getSignatureInstantiationWithoutFillingInTypeArguments( + signature, + fillMissingTypeArguments( + typeArguments, + signature.typeParameters, + getMinTypeArgumentCount(signature.typeParameters), + isJavascript + ) + ); if (inferredTypeParameters) { - const returnSignature = getSingleCallOrConstructSignature(getReturnTypeOfSignature(instantiatedSignature)); + const returnSignature = getSingleCallOrConstructSignature( + getReturnTypeOfSignature(instantiatedSignature) + ); if (returnSignature) { const newReturnSignature = cloneSignature(returnSignature); newReturnSignature.typeParameters = inferredTypeParameters; - const newReturnType = getOrCreateTypeFromSignature(newReturnSignature) as AnonymousType; + const newReturnType = getOrCreateTypeFromSignature( + newReturnSignature + ) as AnonymousType; newReturnType.mapper = instantiatedSignature.mapper; - const newInstantiatedSignature = cloneSignature(instantiatedSignature); + const newInstantiatedSignature = cloneSignature( + instantiatedSignature + ); newInstantiatedSignature.resolvedReturnType = newReturnType; return newInstantiatedSignature; } @@ -16431,43 +28543,77 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return instantiatedSignature; } - function getSignatureInstantiationWithoutFillingInTypeArguments(signature: Signature, typeArguments: readonly Type[] | undefined): Signature { - const instantiations = signature.instantiations || (signature.instantiations = new Map()); + function getSignatureInstantiationWithoutFillingInTypeArguments( + signature: Signature, + typeArguments: readonly Type[] | undefined + ): Signature { + const instantiations = + signature.instantiations || + (signature.instantiations = new Map()); const id = getTypeListId(typeArguments); let instantiation = instantiations.get(id); if (!instantiation) { - instantiations.set(id, instantiation = createSignatureInstantiation(signature, typeArguments)); + instantiations.set( + id, + (instantiation = createSignatureInstantiation( + signature, + typeArguments + )) + ); } return instantiation; } - function createSignatureInstantiation(signature: Signature, typeArguments: readonly Type[] | undefined): Signature { - return instantiateSignature(signature, createSignatureTypeMapper(signature, typeArguments), /*eraseTypeParameters*/ true); + function createSignatureInstantiation( + signature: Signature, + typeArguments: readonly Type[] | undefined + ): Signature { + return instantiateSignature( + signature, + createSignatureTypeMapper(signature, typeArguments), + /*eraseTypeParameters*/ true + ); } function getTypeParametersForMapper(signature: Signature) { - return sameMap(signature.typeParameters, tp => tp.mapper ? instantiateType(tp, tp.mapper) : tp); + return sameMap(signature.typeParameters, (tp) => + tp.mapper ? instantiateType(tp, tp.mapper) : tp + ); } - function createSignatureTypeMapper(signature: Signature, typeArguments: readonly Type[] | undefined): TypeMapper { - return createTypeMapper(getTypeParametersForMapper(signature)!, typeArguments); + function createSignatureTypeMapper( + signature: Signature, + typeArguments: readonly Type[] | undefined + ): TypeMapper { + return createTypeMapper( + getTypeParametersForMapper(signature)!, + typeArguments + ); } function getErasedSignature(signature: Signature): Signature { - return signature.typeParameters ? - signature.erasedSignatureCache || (signature.erasedSignatureCache = createErasedSignature(signature)) : - signature; + return signature.typeParameters + ? signature.erasedSignatureCache || + (signature.erasedSignatureCache = + createErasedSignature(signature)) + : signature; } function createErasedSignature(signature: Signature) { // Create an instantiation of the signature where all type arguments are the any type. - return instantiateSignature(signature, createTypeEraser(signature.typeParameters!), /*eraseTypeParameters*/ true); + return instantiateSignature( + signature, + createTypeEraser(signature.typeParameters!), + /*eraseTypeParameters*/ true + ); } function getCanonicalSignature(signature: Signature): Signature { - return signature.typeParameters ? - signature.canonicalSignatureCache || (signature.canonicalSignatureCache = createCanonicalSignature(signature)) : - signature; + return signature.typeParameters + ? signature.canonicalSignatureCache || + (signature.canonicalSignatureCache = + createCanonicalSignature(signature)) + : signature; } function createCanonicalSignature(signature: Signature) { @@ -16479,8 +28625,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // that uses the original type identities for all unconstrained type parameters. return getSignatureInstantiation( signature, - map(signature.typeParameters, tp => tp.target && !getConstraintOfTypeParameter(tp.target) ? tp.target : tp), - isInJSFile(signature.declaration), + map(signature.typeParameters, (tp) => + tp.target && !getConstraintOfTypeParameter(tp.target) + ? tp.target + : tp + ), + isInJSFile(signature.declaration) ); } @@ -16491,16 +28641,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return signature.baseSignatureCache; } const typeEraser = createTypeEraser(typeParameters); - const baseConstraintMapper = createTypeMapper(typeParameters, map(typeParameters, tp => getConstraintOfTypeParameter(tp) || unknownType)); - let baseConstraints: readonly Type[] = map(typeParameters, tp => instantiateType(tp, baseConstraintMapper) || unknownType); + const baseConstraintMapper = createTypeMapper( + typeParameters, + map( + typeParameters, + (tp) => getConstraintOfTypeParameter(tp) || unknownType + ) + ); + let baseConstraints: readonly Type[] = map( + typeParameters, + (tp) => instantiateType(tp, baseConstraintMapper) || unknownType + ); // Run N type params thru the immediate constraint mapper up to N times // This way any noncircular interdependent type parameters are definitely resolved to their external dependencies for (let i = 0; i < typeParameters.length - 1; i++) { - baseConstraints = instantiateTypes(baseConstraints, baseConstraintMapper); + baseConstraints = instantiateTypes( + baseConstraints, + baseConstraintMapper + ); } // and then apply a type eraser to remove any remaining circularly dependent type parameters baseConstraints = instantiateTypes(baseConstraints, typeEraser); - return signature.baseSignatureCache = instantiateSignature(signature, createTypeMapper(typeParameters, baseConstraints), /*eraseTypeParameters*/ true); + return (signature.baseSignatureCache = instantiateSignature( + signature, + createTypeMapper(typeParameters, baseConstraints), + /*eraseTypeParameters*/ true + )); } return signature; } @@ -16514,9 +28680,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const kind = signature.declaration?.kind; // If declaration is undefined, it is likely to be the signature of the default constructor. - const isConstructor = kind === undefined || kind === SyntaxKind.Constructor || kind === SyntaxKind.ConstructSignature || kind === SyntaxKind.ConstructorType; - - const type = createObjectType(ObjectFlags.Anonymous | ObjectFlags.SingleSignatureType, signature.declaration?.symbol); + const isConstructor = + kind === undefined || + kind === SyntaxKind.Constructor || + kind === SyntaxKind.ConstructSignature || + kind === SyntaxKind.ConstructorType; + + const type = createObjectType( + ObjectFlags.Anonymous | ObjectFlags.SingleSignatureType, + signature.declaration?.symbol + ); type.members = emptySymbols; type.properties = emptyArray; type.callSignatures = !isConstructor ? [signature] : emptyArray; @@ -16529,24 +28702,44 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getIndexSymbol(symbol: Symbol): Symbol | undefined { - return symbol.members ? getIndexSymbolFromSymbolTable(getMembersOfSymbol(symbol)) : undefined; + return symbol.members + ? getIndexSymbolFromSymbolTable(getMembersOfSymbol(symbol)) + : undefined; } - function getIndexSymbolFromSymbolTable(symbolTable: SymbolTable): Symbol | undefined { + function getIndexSymbolFromSymbolTable( + symbolTable: SymbolTable + ): Symbol | undefined { return symbolTable.get(InternalSymbolName.Index); } - function createIndexInfo(keyType: Type, type: Type, isReadonly: boolean, declaration?: IndexSignatureDeclaration, components?: ElementWithComputedPropertyName[]): IndexInfo { + function createIndexInfo( + keyType: Type, + type: Type, + isReadonly: boolean, + declaration?: IndexSignatureDeclaration, + components?: ElementWithComputedPropertyName[] + ): IndexInfo { return { keyType, type, isReadonly, declaration, components }; } function getIndexInfosOfSymbol(symbol: Symbol): IndexInfo[] { const indexSymbol = getIndexSymbol(symbol); - return indexSymbol ? getIndexInfosOfIndexSymbol(indexSymbol, arrayFrom(getMembersOfSymbol(symbol).values())) : emptyArray; + return indexSymbol + ? getIndexInfosOfIndexSymbol( + indexSymbol, + arrayFrom(getMembersOfSymbol(symbol).values()) + ) + : emptyArray; } // note intentional similarities to index signature building in `checkObjectLiteral` for parity - function getIndexInfosOfIndexSymbol(indexSymbol: Symbol, siblingSymbols: Symbol[] | undefined = indexSymbol.parent ? arrayFrom(getMembersOfSymbol(indexSymbol.parent).values()) : undefined): IndexInfo[] { + function getIndexInfosOfIndexSymbol( + indexSymbol: Symbol, + siblingSymbols: Symbol[] | undefined = indexSymbol.parent + ? arrayFrom(getMembersOfSymbol(indexSymbol.parent).values()) + : undefined + ): IndexInfo[] { if (indexSymbol.declarations) { const indexInfos: IndexInfo[] = []; let hasComputedNumberProperty = false; @@ -16561,17 +28754,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (declaration.parameters.length === 1) { const parameter = declaration.parameters[0]; if (parameter.type) { - forEachType(getTypeFromTypeNode(parameter.type), keyType => { - if (isValidIndexKeyType(keyType) && !findIndexInfo(indexInfos, keyType)) { - indexInfos.push(createIndexInfo(keyType, declaration.type ? getTypeFromTypeNode(declaration.type) : anyType, hasEffectiveModifier(declaration, ModifierFlags.Readonly), declaration)); + forEachType( + getTypeFromTypeNode(parameter.type), + (keyType) => { + if ( + isValidIndexKeyType(keyType) && + !findIndexInfo(indexInfos, keyType) + ) { + indexInfos.push( + createIndexInfo( + keyType, + declaration.type + ? getTypeFromTypeNode( + declaration.type + ) + : anyType, + hasEffectiveModifier( + declaration, + ModifierFlags.Readonly + ), + declaration + ) + ); + } } - }); + ); } } - } - else if (hasLateBindableIndexSignature(declaration)) { - const declName = isBinaryExpression(declaration) ? declaration.left as ElementAccessExpression : (declaration as LateBoundDeclaration).name; - const keyType = isElementAccessExpression(declName) ? checkExpressionCached(declName.argumentExpression) : checkComputedPropertyName(declName); + } else if (hasLateBindableIndexSignature(declaration)) { + const declName = isBinaryExpression(declaration) + ? (declaration.left as ElementAccessExpression) + : (declaration as LateBoundDeclaration).name; + const keyType = isElementAccessExpression(declName) + ? checkExpressionCached(declName.argumentExpression) + : checkComputedPropertyName(declName); if (findIndexInfo(indexInfos, keyType)) { continue; // Explicit index for key type takes priority } @@ -16581,14 +28797,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!hasEffectiveReadonlyModifier(declaration)) { readonlyComputedNumberProperty = false; } - } - else if (isTypeAssignableTo(keyType, esSymbolType)) { + } else if (isTypeAssignableTo(keyType, esSymbolType)) { hasComputedSymbolProperty = true; if (!hasEffectiveReadonlyModifier(declaration)) { readonlyComputedSymbolProperty = false; } - } - else { + } else { hasComputedStringProperty = true; if (!hasEffectiveReadonlyModifier(declaration)) { readonlyComputedStringProperty = false; @@ -16598,26 +28812,81 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } } - const allPropertySymbols = concatenate(computedPropertySymbols, filter(siblingSymbols, s => s !== indexSymbol)); + const allPropertySymbols = concatenate( + computedPropertySymbols, + filter(siblingSymbols, (s) => s !== indexSymbol) + ); // aggregate similar index infos implied to be the same key to the same combined index info - if (hasComputedStringProperty && !findIndexInfo(indexInfos, stringType)) indexInfos.push(getObjectLiteralIndexInfo(readonlyComputedStringProperty, 0, allPropertySymbols, stringType)); - if (hasComputedNumberProperty && !findIndexInfo(indexInfos, numberType)) indexInfos.push(getObjectLiteralIndexInfo(readonlyComputedNumberProperty, 0, allPropertySymbols, numberType)); - if (hasComputedSymbolProperty && !findIndexInfo(indexInfos, esSymbolType)) indexInfos.push(getObjectLiteralIndexInfo(readonlyComputedSymbolProperty, 0, allPropertySymbols, esSymbolType)); + if ( + hasComputedStringProperty && + !findIndexInfo(indexInfos, stringType) + ) + indexInfos.push( + getObjectLiteralIndexInfo( + readonlyComputedStringProperty, + 0, + allPropertySymbols, + stringType + ) + ); + if ( + hasComputedNumberProperty && + !findIndexInfo(indexInfos, numberType) + ) + indexInfos.push( + getObjectLiteralIndexInfo( + readonlyComputedNumberProperty, + 0, + allPropertySymbols, + numberType + ) + ); + if ( + hasComputedSymbolProperty && + !findIndexInfo(indexInfos, esSymbolType) + ) + indexInfos.push( + getObjectLiteralIndexInfo( + readonlyComputedSymbolProperty, + 0, + allPropertySymbols, + esSymbolType + ) + ); return indexInfos; } return emptyArray; } function isValidIndexKeyType(type: Type): boolean { - return !!(type.flags & (TypeFlags.String | TypeFlags.Number | TypeFlags.ESSymbol)) || isPatternLiteralType(type) || - !!(type.flags & TypeFlags.Intersection) && !isGenericType(type) && some((type as IntersectionType).types, isValidIndexKeyType); + return ( + !!( + type.flags & + (TypeFlags.String | TypeFlags.Number | TypeFlags.ESSymbol) + ) || + isPatternLiteralType(type) || + (!!(type.flags & TypeFlags.Intersection) && + !isGenericType(type) && + some((type as IntersectionType).types, isValidIndexKeyType)) + ); } - function getConstraintDeclaration(type: TypeParameter): TypeNode | undefined { - return mapDefined(filter(type.symbol && type.symbol.declarations, isTypeParameterDeclaration), getEffectiveConstraintOfTypeParameter)[0]; + function getConstraintDeclaration( + type: TypeParameter + ): TypeNode | undefined { + return mapDefined( + filter( + type.symbol && type.symbol.declarations, + isTypeParameterDeclaration + ), + getEffectiveConstraintOfTypeParameter + )[0]; } - function getInferredTypeParameterConstraint(typeParameter: TypeParameter, omitTypeReferences?: boolean) { + function getInferredTypeParameterConstraint( + typeParameter: TypeParameter, + omitTypeReferences?: boolean + ) { let inferences: Type[] | undefined; if (typeParameter.symbol?.declarations) { for (const declaration of typeParameter.symbol.declarations) { @@ -16626,14 +28895,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // (such as 'Foo'), T's constraint is inferred from the constraint of the // corresponding type parameter in 'Foo'. When multiple 'infer T' declarations are // present, we form an intersection of the inferred constraint types. - const [childTypeParameter = declaration.parent, grandParent] = walkUpParenthesizedTypesAndGetParentAndChild(declaration.parent.parent); - if (grandParent.kind === SyntaxKind.TypeReference && !omitTypeReferences) { + const [ + childTypeParameter = declaration.parent, + grandParent, + ] = walkUpParenthesizedTypesAndGetParentAndChild( + declaration.parent.parent + ); + if ( + grandParent.kind === SyntaxKind.TypeReference && + !omitTypeReferences + ) { const typeReference = grandParent as TypeReferenceNode; - const typeParameters = getTypeParametersForTypeReferenceOrImport(typeReference); + const typeParameters = + getTypeParametersForTypeReferenceOrImport( + typeReference + ); if (typeParameters) { - const index = typeReference.typeArguments!.indexOf(childTypeParameter as TypeNode); + const index = typeReference.typeArguments!.indexOf( + childTypeParameter as TypeNode + ); if (index < typeParameters.length) { - const declaredConstraint = getConstraintOfTypeParameter(typeParameters[index]); + const declaredConstraint = + getConstraintOfTypeParameter( + typeParameters[index] + ); if (declaredConstraint) { // Type parameter constraints can reference other type parameters so // constraints need to be instantiated. If instantiation produces the @@ -16644,12 +28929,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const mapper = makeDeferredTypeMapper( typeParameters, typeParameters.map((_, index) => () => { - return getEffectiveTypeArgumentAtIndex(typeReference, typeParameters, index); - }), + return getEffectiveTypeArgumentAtIndex( + typeReference, + typeParameters, + index + ); + }) + ); + const constraint = instantiateType( + declaredConstraint, + mapper ); - const constraint = instantiateType(declaredConstraint, mapper); if (constraint !== typeParameter) { - inferences = append(inferences, constraint); + inferences = append( + inferences, + constraint + ); } } } @@ -16658,34 +28953,78 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // When an 'infer T' declaration is immediately contained in a rest parameter declaration, a rest type // or a named rest tuple element, we infer an 'unknown[]' constraint. else if ( - grandParent.kind === SyntaxKind.Parameter && (grandParent as ParameterDeclaration).dotDotDotToken || + (grandParent.kind === SyntaxKind.Parameter && + (grandParent as ParameterDeclaration) + .dotDotDotToken) || grandParent.kind === SyntaxKind.RestType || - grandParent.kind === SyntaxKind.NamedTupleMember && (grandParent as NamedTupleMember).dotDotDotToken + (grandParent.kind === SyntaxKind.NamedTupleMember && + (grandParent as NamedTupleMember).dotDotDotToken) ) { - inferences = append(inferences, createArrayType(unknownType)); + inferences = append( + inferences, + createArrayType(unknownType) + ); } // When an 'infer T' declaration is immediately contained in a string template type, we infer a 'string' // constraint. - else if (grandParent.kind === SyntaxKind.TemplateLiteralTypeSpan) { + else if ( + grandParent.kind === SyntaxKind.TemplateLiteralTypeSpan + ) { inferences = append(inferences, stringType); } // When an 'infer T' declaration is in the constraint position of a mapped type, we infer a 'keyof any' // constraint. - else if (grandParent.kind === SyntaxKind.TypeParameter && grandParent.parent.kind === SyntaxKind.MappedType) { + else if ( + grandParent.kind === SyntaxKind.TypeParameter && + grandParent.parent.kind === SyntaxKind.MappedType + ) { inferences = append(inferences, stringNumberSymbolType); } // When an 'infer T' declaration is the template of a mapped type, and that mapped type is the extends // clause of a conditional whose check type is also a mapped type, give it a constraint equal to the template // of the check type's mapped type else if ( - grandParent.kind === SyntaxKind.MappedType && (grandParent as MappedTypeNode).type && - skipParentheses((grandParent as MappedTypeNode).type!) === declaration.parent && grandParent.parent.kind === SyntaxKind.ConditionalType && - (grandParent.parent as ConditionalTypeNode).extendsType === grandParent && (grandParent.parent as ConditionalTypeNode).checkType.kind === SyntaxKind.MappedType && - ((grandParent.parent as ConditionalTypeNode).checkType as MappedTypeNode).type + grandParent.kind === SyntaxKind.MappedType && + (grandParent as MappedTypeNode).type && + skipParentheses( + (grandParent as MappedTypeNode).type! + ) === declaration.parent && + grandParent.parent.kind === + SyntaxKind.ConditionalType && + (grandParent.parent as ConditionalTypeNode) + .extendsType === grandParent && + (grandParent.parent as ConditionalTypeNode).checkType + .kind === SyntaxKind.MappedType && + ( + (grandParent.parent as ConditionalTypeNode) + .checkType as MappedTypeNode + ).type ) { - const checkMappedType = (grandParent.parent as ConditionalTypeNode).checkType as MappedTypeNode; - const nodeType = getTypeFromTypeNode(checkMappedType.type!); - inferences = append(inferences, instantiateType(nodeType, makeUnaryTypeMapper(getDeclaredTypeOfTypeParameter(getSymbolOfDeclaration(checkMappedType.typeParameter)), checkMappedType.typeParameter.constraint ? getTypeFromTypeNode(checkMappedType.typeParameter.constraint) : stringNumberSymbolType))); + const checkMappedType = ( + grandParent.parent as ConditionalTypeNode + ).checkType as MappedTypeNode; + const nodeType = getTypeFromTypeNode( + checkMappedType.type! + ); + inferences = append( + inferences, + instantiateType( + nodeType, + makeUnaryTypeMapper( + getDeclaredTypeOfTypeParameter( + getSymbolOfDeclaration( + checkMappedType.typeParameter + ) + ), + checkMappedType.typeParameter.constraint + ? getTypeFromTypeNode( + checkMappedType.typeParameter + .constraint + ) + : stringNumberSymbolType + ) + ) + ); } } } @@ -16694,34 +29033,55 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } /** This is a worker function. Use getConstraintOfTypeParameter which guards against circular constraints. */ - function getConstraintFromTypeParameter(typeParameter: TypeParameter): Type | undefined { + function getConstraintFromTypeParameter( + typeParameter: TypeParameter + ): Type | undefined { if (!typeParameter.constraint) { if (typeParameter.target) { - const targetConstraint = getConstraintOfTypeParameter(typeParameter.target); - typeParameter.constraint = targetConstraint ? instantiateType(targetConstraint, typeParameter.mapper) : noConstraintType; - } - else { - const constraintDeclaration = getConstraintDeclaration(typeParameter); + const targetConstraint = getConstraintOfTypeParameter( + typeParameter.target + ); + typeParameter.constraint = targetConstraint + ? instantiateType(targetConstraint, typeParameter.mapper) + : noConstraintType; + } else { + const constraintDeclaration = + getConstraintDeclaration(typeParameter); if (!constraintDeclaration) { - typeParameter.constraint = getInferredTypeParameterConstraint(typeParameter) || noConstraintType; - } - else { + typeParameter.constraint = + getInferredTypeParameterConstraint(typeParameter) || + noConstraintType; + } else { let type = getTypeFromTypeNode(constraintDeclaration); - if (type.flags & TypeFlags.Any && !isErrorType(type)) { // Allow errorType to propegate to keep downstream errors suppressed + if (type.flags & TypeFlags.Any && !isErrorType(type)) { + // Allow errorType to propegate to keep downstream errors suppressed // use stringNumberSymbolType as the base constraint for mapped type key constraints (unknown isn;t assignable to that, but `any` was), // use unknown otherwise - type = constraintDeclaration.parent.parent.kind === SyntaxKind.MappedType ? stringNumberSymbolType : unknownType; + type = + constraintDeclaration.parent.parent.kind === + SyntaxKind.MappedType + ? stringNumberSymbolType + : unknownType; } typeParameter.constraint = type; } } } - return typeParameter.constraint === noConstraintType ? undefined : typeParameter.constraint; + return typeParameter.constraint === noConstraintType + ? undefined + : typeParameter.constraint; } - function getParentSymbolOfTypeParameter(typeParameter: TypeParameter): Symbol | undefined { - const tp = getDeclarationOfKind(typeParameter.symbol, SyntaxKind.TypeParameter)!; - const host = isJSDocTemplateTag(tp.parent) ? getEffectiveContainerForJSDocTemplateTag(tp.parent) : tp.parent; + function getParentSymbolOfTypeParameter( + typeParameter: TypeParameter + ): Symbol | undefined { + const tp = getDeclarationOfKind( + typeParameter.symbol, + SyntaxKind.TypeParameter + )!; + const host = isJSDocTemplateTag(tp.parent) + ? getEffectiveContainerForJSDocTemplateTag(tp.parent) + : tp.parent; return host && getSymbolOfNode(host); } @@ -16733,7 +29093,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { while (i < length) { const startId = types[i].id; let count = 1; - while (i + count < length && types[i + count].id === startId + count) { + while ( + i + count < length && + types[i + count].id === startId + count + ) { count++; } if (result.length) { @@ -16749,15 +29112,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function getAliasId(aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined) { - return aliasSymbol ? `@${getSymbolId(aliasSymbol)}` + (aliasTypeArguments ? `:${getTypeListId(aliasTypeArguments)}` : "") : ""; + function getAliasId( + aliasSymbol: Symbol | undefined, + aliasTypeArguments: readonly Type[] | undefined + ) { + return aliasSymbol + ? `@${getSymbolId(aliasSymbol)}` + + (aliasTypeArguments + ? `:${getTypeListId(aliasTypeArguments)}` + : "") + : ""; } // This function is used to propagate certain flags when creating new object type references and union types. // It is only necessary to do so if a constituent type might be the undefined type, the null type, the type // of an object literal or a non-inferrable type. This is because there are operations in the type checker // that care about the presence of such types at arbitrary depth in a containing type. - function getPropagatingFlagsOfTypes(types: readonly Type[], excludeKinds?: TypeFlags): ObjectFlags { + function getPropagatingFlagsOfTypes( + types: readonly Type[], + excludeKinds?: TypeFlags + ): ObjectFlags { let result: ObjectFlags = 0; for (const type of types) { if (excludeKinds === undefined || !(type.flags & excludeKinds)) { @@ -16767,7 +29141,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result & ObjectFlags.PropagatingFlags; } - function tryCreateTypeReference(target: GenericType, typeArguments: readonly Type[] | undefined): Type { + function tryCreateTypeReference( + target: GenericType, + typeArguments: readonly Type[] | undefined + ): Type { if (some(typeArguments) && target === emptyGenericType) { return unknownType; } @@ -16775,13 +29152,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return createTypeReference(target, typeArguments); } - function createTypeReference(target: GenericType, typeArguments: readonly Type[] | undefined): TypeReference { + function createTypeReference( + target: GenericType, + typeArguments: readonly Type[] | undefined + ): TypeReference { const id = getTypeListId(typeArguments); let type = target.instantiations.get(id); if (!type) { - type = createObjectType(ObjectFlags.Reference, target.symbol) as TypeReference; + type = createObjectType( + ObjectFlags.Reference, + target.symbol + ) as TypeReference; target.instantiations.set(id, type); - type.objectFlags |= typeArguments ? getPropagatingFlagsOfTypes(typeArguments) : 0; + type.objectFlags |= typeArguments + ? getPropagatingFlagsOfTypes(typeArguments) + : 0; type.target = target; type.resolvedTypeArguments = typeArguments; } @@ -16789,20 +29174,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function cloneTypeReference(source: TypeReference): TypeReference { - const type = createTypeWithSymbol(source.flags, source.symbol) as TypeReference; + const type = createTypeWithSymbol( + source.flags, + source.symbol + ) as TypeReference; type.objectFlags = source.objectFlags; type.target = source.target; type.resolvedTypeArguments = source.resolvedTypeArguments; return type; } - function createDeferredTypeReference(target: GenericType, node: TypeReferenceNode | ArrayTypeNode | TupleTypeNode, mapper?: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): DeferredTypeReference { + function createDeferredTypeReference( + target: GenericType, + node: TypeReferenceNode | ArrayTypeNode | TupleTypeNode, + mapper?: TypeMapper, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[] + ): DeferredTypeReference { if (!aliasSymbol) { aliasSymbol = getAliasSymbolForTypeNode(node); - const localAliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol); - aliasTypeArguments = mapper ? instantiateTypes(localAliasTypeArguments, mapper) : localAliasTypeArguments; - } - const type = createObjectType(ObjectFlags.Reference, target.symbol) as DeferredTypeReference; + const localAliasTypeArguments = + getTypeArgumentsForAliasSymbol(aliasSymbol); + aliasTypeArguments = mapper + ? instantiateTypes(localAliasTypeArguments, mapper) + : localAliasTypeArguments; + } + const type = createObjectType( + ObjectFlags.Reference, + target.symbol + ) as DeferredTypeReference; type.target = target; type.node = node; type.mapper = mapper; @@ -16813,23 +29213,49 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getTypeArguments(type: TypeReference): readonly Type[] { if (!type.resolvedTypeArguments) { - if (!pushTypeResolution(type, TypeSystemPropertyName.ResolvedTypeArguments)) { - return concatenate(type.target.outerTypeParameters, type.target.localTypeParameters?.map(() => errorType)) || emptyArray; + if ( + !pushTypeResolution( + type, + TypeSystemPropertyName.ResolvedTypeArguments + ) + ) { + return ( + concatenate( + type.target.outerTypeParameters, + type.target.localTypeParameters?.map(() => errorType) + ) || emptyArray + ); } const node = type.node; - const typeArguments = !node ? emptyArray : - node.kind === SyntaxKind.TypeReference ? concatenate(type.target.outerTypeParameters, getEffectiveTypeArguments(node, type.target.localTypeParameters!)) : - node.kind === SyntaxKind.ArrayType ? [getTypeFromTypeNode(node.elementType)] : - map(node.elements, getTypeFromTypeNode); + const typeArguments = !node + ? emptyArray + : node.kind === SyntaxKind.TypeReference + ? concatenate( + type.target.outerTypeParameters, + getEffectiveTypeArguments( + node, + type.target.localTypeParameters! + ) + ) + : node.kind === SyntaxKind.ArrayType + ? [getTypeFromTypeNode(node.elementType)] + : map(node.elements, getTypeFromTypeNode); if (popTypeResolution()) { - type.resolvedTypeArguments ??= type.mapper ? instantiateTypes(typeArguments, type.mapper) : typeArguments; - } - else { - type.resolvedTypeArguments ??= concatenate(type.target.outerTypeParameters, type.target.localTypeParameters?.map(() => errorType) || emptyArray); + type.resolvedTypeArguments ??= type.mapper + ? instantiateTypes(typeArguments, type.mapper) + : typeArguments; + } else { + type.resolvedTypeArguments ??= concatenate( + type.target.outerTypeParameters, + type.target.localTypeParameters?.map(() => errorType) || + emptyArray + ); error( type.node || currentNode, - type.target.symbol ? Diagnostics.Type_arguments_for_0_circularly_reference_themselves : Diagnostics.Tuple_type_arguments_circularly_reference_themselves, - type.target.symbol && symbolToString(type.target.symbol), + type.target.symbol + ? Diagnostics.Type_arguments_for_0_circularly_reference_themselves + : Diagnostics.Tuple_type_arguments_circularly_reference_themselves, + type.target.symbol && symbolToString(type.target.symbol) ); } } @@ -16843,57 +29269,130 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** * Get type from type-reference that reference to class or interface */ - function getTypeFromClassOrInterfaceReference(node: NodeWithTypeArguments, symbol: Symbol): Type { - const type = getDeclaredTypeOfSymbol(getMergedSymbol(symbol)) as InterfaceType; + function getTypeFromClassOrInterfaceReference( + node: NodeWithTypeArguments, + symbol: Symbol + ): Type { + const type = getDeclaredTypeOfSymbol( + getMergedSymbol(symbol) + ) as InterfaceType; const typeParameters = type.localTypeParameters; if (typeParameters) { const numTypeArguments = length(node.typeArguments); - const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters); + const minTypeArgumentCount = + getMinTypeArgumentCount(typeParameters); const isJs = isInJSFile(node); const isJsImplicitAny = !noImplicitAny && isJs; - if (!isJsImplicitAny && (numTypeArguments < minTypeArgumentCount || numTypeArguments > typeParameters.length)) { - const missingAugmentsTag = isJs && isExpressionWithTypeArguments(node) && !isJSDocAugmentsTag(node.parent); - const diag = minTypeArgumentCount === typeParameters.length ? - missingAugmentsTag ? - Diagnostics.Expected_0_type_arguments_provide_these_with_an_extends_tag : - Diagnostics.Generic_type_0_requires_1_type_argument_s : - missingAugmentsTag ? - Diagnostics.Expected_0_1_type_arguments_provide_these_with_an_extends_tag : - Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments; - - const typeStr = typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType); - error(node, diag, typeStr, minTypeArgumentCount, typeParameters.length); + if ( + !isJsImplicitAny && + (numTypeArguments < minTypeArgumentCount || + numTypeArguments > typeParameters.length) + ) { + const missingAugmentsTag = + isJs && + isExpressionWithTypeArguments(node) && + !isJSDocAugmentsTag(node.parent); + const diag = + minTypeArgumentCount === typeParameters.length + ? missingAugmentsTag + ? Diagnostics.Expected_0_type_arguments_provide_these_with_an_extends_tag + : Diagnostics.Generic_type_0_requires_1_type_argument_s + : missingAugmentsTag + ? Diagnostics.Expected_0_1_type_arguments_provide_these_with_an_extends_tag + : Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments; + + const typeStr = typeToString( + type, + /*enclosingDeclaration*/ undefined, + TypeFormatFlags.WriteArrayAsGenericType + ); + error( + node, + diag, + typeStr, + minTypeArgumentCount, + typeParameters.length + ); if (!isJs) { // TODO: Adopt same permissive behavior in TS as in JS to reduce follow-on editing experience failures (requires editing fillMissingTypeArguments) return errorType; } } - if (node.kind === SyntaxKind.TypeReference && isDeferredTypeReferenceNode(node as TypeReferenceNode, length(node.typeArguments) !== typeParameters.length)) { - return createDeferredTypeReference(type as GenericType, node as TypeReferenceNode, /*mapper*/ undefined); + if ( + node.kind === SyntaxKind.TypeReference && + isDeferredTypeReferenceNode( + node as TypeReferenceNode, + length(node.typeArguments) !== typeParameters.length + ) + ) { + return createDeferredTypeReference( + type as GenericType, + node as TypeReferenceNode, + /*mapper*/ undefined + ); } // In a type reference, the outer type parameters of the referenced class or interface are automatically // supplied as type arguments and the type reference only specifies arguments for the local type parameters // of the class or interface. - const typeArguments = concatenate(type.outerTypeParameters, fillMissingTypeArguments(typeArgumentsFromTypeReferenceNode(node), typeParameters, minTypeArgumentCount, isJs)); + const typeArguments = concatenate( + type.outerTypeParameters, + fillMissingTypeArguments( + typeArgumentsFromTypeReferenceNode(node), + typeParameters, + minTypeArgumentCount, + isJs + ) + ); return createTypeReference(type as GenericType, typeArguments); } return checkNoTypeArguments(node, symbol) ? type : errorType; } - function getTypeAliasInstantiation(symbol: Symbol, typeArguments: readonly Type[] | undefined, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type { + function getTypeAliasInstantiation( + symbol: Symbol, + typeArguments: readonly Type[] | undefined, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[] + ): Type { const type = getDeclaredTypeOfSymbol(symbol); if (type === intrinsicMarkerType) { - const typeKind = intrinsicTypeKinds.get(symbol.escapedName as string); - if (typeKind !== undefined && typeArguments && typeArguments.length === 1) { - return typeKind === IntrinsicTypeKind.NoInfer ? getNoInferType(typeArguments[0]) : getStringMappingType(symbol, typeArguments[0]); + const typeKind = intrinsicTypeKinds.get( + symbol.escapedName as string + ); + if ( + typeKind !== undefined && + typeArguments && + typeArguments.length === 1 + ) { + return typeKind === IntrinsicTypeKind.NoInfer + ? getNoInferType(typeArguments[0]) + : getStringMappingType(symbol, typeArguments[0]); } } const links = getSymbolLinks(symbol); const typeParameters = links.typeParameters!; - const id = getTypeListId(typeArguments) + getAliasId(aliasSymbol, aliasTypeArguments); + const id = + getTypeListId(typeArguments) + + getAliasId(aliasSymbol, aliasTypeArguments); let instantiation = links.instantiations!.get(id); if (!instantiation) { - links.instantiations!.set(id, instantiation = instantiateTypeWithAlias(type, createTypeMapper(typeParameters, fillMissingTypeArguments(typeArguments, typeParameters, getMinTypeArgumentCount(typeParameters), isInJSFile(symbol.valueDeclaration))), aliasSymbol, aliasTypeArguments)); + links.instantiations!.set( + id, + (instantiation = instantiateTypeWithAlias( + type, + createTypeMapper( + typeParameters, + fillMissingTypeArguments( + typeArguments, + typeParameters, + getMinTypeArgumentCount(typeParameters), + isInJSFile(symbol.valueDeclaration) + ) + ), + aliasSymbol, + aliasTypeArguments + )) + ); } return instantiation; } @@ -16903,13 +29402,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * references to the type parameters of the alias. We replace those with the actual type arguments by instantiating the * declared type. Instantiations are cached using the type identities of the type arguments as the key. */ - function getTypeFromTypeAliasReference(node: NodeWithTypeArguments, symbol: Symbol): Type { + function getTypeFromTypeAliasReference( + node: NodeWithTypeArguments, + symbol: Symbol + ): Type { if (getCheckFlags(symbol) & CheckFlags.Unresolved) { const typeArguments = typeArgumentsFromTypeReferenceNode(node); const id = getAliasId(symbol, typeArguments); let errorType = errorTypes.get(id); if (!errorType) { - errorType = createIntrinsicType(TypeFlags.Any, "error", /*objectFlags*/ undefined, `alias ${id}`); + errorType = createIntrinsicType( + TypeFlags.Any, + "error", + /*objectFlags*/ undefined, + `alias ${id}` + ); errorType.aliasSymbol = symbol; errorType.aliasTypeArguments = typeArguments; errorTypes.set(id, errorType); @@ -16920,16 +29427,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const typeParameters = getSymbolLinks(symbol).typeParameters; if (typeParameters) { const numTypeArguments = length(node.typeArguments); - const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters); - if (numTypeArguments < minTypeArgumentCount || numTypeArguments > typeParameters.length) { + const minTypeArgumentCount = + getMinTypeArgumentCount(typeParameters); + if ( + numTypeArguments < minTypeArgumentCount || + numTypeArguments > typeParameters.length + ) { error( node, - minTypeArgumentCount === typeParameters.length ? - Diagnostics.Generic_type_0_requires_1_type_argument_s : - Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments, + minTypeArgumentCount === typeParameters.length + ? Diagnostics.Generic_type_0_requires_1_type_argument_s + : Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments, symbolToString(symbol), minTypeArgumentCount, - typeParameters.length, + typeParameters.length ); return errorType; } @@ -16938,24 +29449,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // accessible--which in turn may lead to a large structural expansion of the type when generating // a .d.ts file. See #43622 for an example. const aliasSymbol = getAliasSymbolForTypeNode(node); - let newAliasSymbol = aliasSymbol && (isLocalTypeAlias(symbol) || !isLocalTypeAlias(aliasSymbol)) ? aliasSymbol : undefined; + let newAliasSymbol = + aliasSymbol && + (isLocalTypeAlias(symbol) || !isLocalTypeAlias(aliasSymbol)) + ? aliasSymbol + : undefined; let aliasTypeArguments: Type[] | undefined; if (newAliasSymbol) { - aliasTypeArguments = getTypeArgumentsForAliasSymbol(newAliasSymbol); - } - else if (isTypeReferenceType(node)) { - const aliasSymbol = resolveTypeReferenceName(node, SymbolFlags.Alias, /*ignoreErrors*/ true); + aliasTypeArguments = + getTypeArgumentsForAliasSymbol(newAliasSymbol); + } else if (isTypeReferenceType(node)) { + const aliasSymbol = resolveTypeReferenceName( + node, + SymbolFlags.Alias, + /*ignoreErrors*/ true + ); // refers to an alias import/export/reexport - by making sure we use the target as an aliasSymbol, // we ensure the exported symbol is used to refer to the type when it's reserialized later if (aliasSymbol && aliasSymbol !== unknownSymbol) { const resolved = resolveAlias(aliasSymbol); if (resolved && resolved.flags & SymbolFlags.TypeAlias) { newAliasSymbol = resolved; - aliasTypeArguments = typeArgumentsFromTypeReferenceNode(node) || (typeParameters ? [] : undefined); + aliasTypeArguments = + typeArgumentsFromTypeReferenceNode(node) || + (typeParameters ? [] : undefined); } } } - return getTypeAliasInstantiation(symbol, typeArgumentsFromTypeReferenceNode(node), newAliasSymbol, aliasTypeArguments); + return getTypeAliasInstantiation( + symbol, + typeArgumentsFromTypeReferenceNode(node), + newAliasSymbol, + aliasTypeArguments + ); } return checkNoTypeArguments(node, symbol) ? type : errorType; } @@ -16965,7 +29491,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return !!(declaration && getContainingFunction(declaration)); } - function getTypeReferenceName(node: TypeReferenceType): EntityNameOrEntityNameExpression | undefined { + function getTypeReferenceName( + node: TypeReferenceType + ): EntityNameOrEntityNameExpression | undefined { switch (node.kind) { case SyntaxKind.TypeReference: return node.typeName; @@ -16976,29 +29504,48 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isEntityNameExpression(expr)) { return expr; } - // fall through; + // fall through; } return undefined; } function getSymbolPath(symbol: Symbol): string { - return symbol.parent ? `${getSymbolPath(symbol.parent)}.${symbol.escapedName}` : symbol.escapedName as string; + return symbol.parent + ? `${getSymbolPath(symbol.parent)}.${symbol.escapedName}` + : (symbol.escapedName as string); } - function getUnresolvedSymbolForEntityName(name: EntityNameOrEntityNameExpression) { - const identifier = name.kind === SyntaxKind.QualifiedName ? name.right : - name.kind === SyntaxKind.PropertyAccessExpression ? name.name : - name; + function getUnresolvedSymbolForEntityName( + name: EntityNameOrEntityNameExpression + ) { + const identifier = + name.kind === SyntaxKind.QualifiedName + ? name.right + : name.kind === SyntaxKind.PropertyAccessExpression + ? name.name + : name; const text = identifier.escapedText; if (text) { - const parentSymbol = name.kind === SyntaxKind.QualifiedName ? getUnresolvedSymbolForEntityName(name.left) : - name.kind === SyntaxKind.PropertyAccessExpression ? getUnresolvedSymbolForEntityName(name.expression) : - undefined; - const path = parentSymbol ? `${getSymbolPath(parentSymbol)}.${text}` : text as string; + const parentSymbol = + name.kind === SyntaxKind.QualifiedName + ? getUnresolvedSymbolForEntityName(name.left) + : name.kind === SyntaxKind.PropertyAccessExpression + ? getUnresolvedSymbolForEntityName(name.expression) + : undefined; + const path = parentSymbol + ? `${getSymbolPath(parentSymbol)}.${text}` + : (text as string); let result = unresolvedSymbols.get(path); if (!result) { - unresolvedSymbols.set(path, result = createSymbol(SymbolFlags.TypeAlias, text, CheckFlags.Unresolved)); + unresolvedSymbols.set( + path, + (result = createSymbol( + SymbolFlags.TypeAlias, + text, + CheckFlags.Unresolved + )) + ); result.parent = parentSymbol; result.links.declaredType = unresolvedType; } @@ -17007,17 +29554,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return unknownSymbol; } - function resolveTypeReferenceName(typeReference: TypeReferenceType, meaning: SymbolFlags, ignoreErrors?: boolean) { + function resolveTypeReferenceName( + typeReference: TypeReferenceType, + meaning: SymbolFlags, + ignoreErrors?: boolean + ) { const name = getTypeReferenceName(typeReference); if (!name) { return unknownSymbol; } const symbol = resolveEntityName(name, meaning, ignoreErrors); - return symbol && symbol !== unknownSymbol ? symbol : - ignoreErrors ? unknownSymbol : getUnresolvedSymbolForEntityName(name); + return symbol && symbol !== unknownSymbol + ? symbol + : ignoreErrors + ? unknownSymbol + : getUnresolvedSymbolForEntityName(name); } - function getTypeReferenceType(node: NodeWithTypeArguments, symbol: Symbol): Type { + function getTypeReferenceType( + node: NodeWithTypeArguments, + symbol: Symbol + ): Type { if (symbol === unknownSymbol) { return errorType; } @@ -17031,14 +29588,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Get type from reference to named type that cannot be generic (enum or type parameter) const res = tryGetDeclaredTypeOfSymbol(symbol); if (res) { - return checkNoTypeArguments(node, symbol) ? getRegularTypeOfLiteralType(res) : errorType; + return checkNoTypeArguments(node, symbol) + ? getRegularTypeOfLiteralType(res) + : errorType; } if (symbol.flags & SymbolFlags.Value && isJSDocTypeReference(node)) { const jsdocType = getTypeFromJSDocValueReference(node, symbol); if (jsdocType) { return jsdocType; - } - else { + } else { // Resolve the type reference as a Type for the purpose of reporting errors. resolveTypeReferenceName(node, SymbolFlags.Type); return getTypeOfSymbol(symbol); @@ -17051,15 +29609,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * A JSdoc TypeReference may be to a value, but resolve it as a type anyway. * Example: import('./b').ConstructorFunction */ - function getTypeFromJSDocValueReference(node: NodeWithTypeArguments, symbol: Symbol): Type | undefined { + function getTypeFromJSDocValueReference( + node: NodeWithTypeArguments, + symbol: Symbol + ): Type | undefined { const links = getNodeLinks(node); if (!links.resolvedJSDocType) { const valueType = getTypeOfSymbol(symbol); let typeType = valueType; if (symbol.valueDeclaration) { - const isImportTypeWithQualifier = node.kind === SyntaxKind.ImportType && (node as ImportTypeNode).qualifier; + const isImportTypeWithQualifier = + node.kind === SyntaxKind.ImportType && + (node as ImportTypeNode).qualifier; // valueType might not have a symbol, eg, {import('./b').STRING_LITERAL} - if (valueType.symbol && valueType.symbol !== symbol && isImportTypeWithQualifier) { + if ( + valueType.symbol && + valueType.symbol !== symbol && + isImportTypeWithQualifier + ) { typeType = getTypeReferenceType(node, valueType.symbol); } } @@ -17069,28 +29636,45 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getNoInferType(type: Type) { - return isNoInferTargetType(type) ? getOrCreateSubstitutionType(type, unknownType) : type; + return isNoInferTargetType(type) + ? getOrCreateSubstitutionType(type, unknownType) + : type; } function isNoInferTargetType(type: Type): boolean { // This is effectively a more conservative and predictable form of couldContainTypeVariables. We want to // preserve NoInfer only for types that could contain type variables, but we don't want to exhaustively // examine all object type members. - return !!(type.flags & TypeFlags.UnionOrIntersection && some((type as UnionOrIntersectionType).types, isNoInferTargetType) || - type.flags & TypeFlags.Substitution && !isNoInferType(type) && isNoInferTargetType((type as SubstitutionType).baseType) || - type.flags & TypeFlags.Object && !isEmptyAnonymousObjectType(type) || - type.flags & (TypeFlags.Instantiable & ~TypeFlags.Substitution) && !isPatternLiteralType(type)); + return !!( + (type.flags & TypeFlags.UnionOrIntersection && + some( + (type as UnionOrIntersectionType).types, + isNoInferTargetType + )) || + (type.flags & TypeFlags.Substitution && + !isNoInferType(type) && + isNoInferTargetType((type as SubstitutionType).baseType)) || + (type.flags & TypeFlags.Object && + !isEmptyAnonymousObjectType(type)) || + (type.flags & (TypeFlags.Instantiable & ~TypeFlags.Substitution) && + !isPatternLiteralType(type)) + ); } function isNoInferType(type: Type) { // A NoInfer type is represented as a substitution type with a TypeFlags.Unknown constraint. - return !!(type.flags & TypeFlags.Substitution && (type as SubstitutionType).constraint.flags & TypeFlags.Unknown); + return !!( + type.flags & TypeFlags.Substitution && + (type as SubstitutionType).constraint.flags & TypeFlags.Unknown + ); } function getSubstitutionType(baseType: Type, constraint: Type) { - return constraint.flags & TypeFlags.AnyOrUnknown || constraint === baseType || baseType.flags & TypeFlags.Any ? - baseType : - getOrCreateSubstitutionType(baseType, constraint); + return constraint.flags & TypeFlags.AnyOrUnknown || + constraint === baseType || + baseType.flags & TypeFlags.Any + ? baseType + : getOrCreateSubstitutionType(baseType, constraint); } function getOrCreateSubstitutionType(baseType: Type, constraint: Type) { @@ -17107,17 +29691,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getSubstitutionIntersection(substitutionType: SubstitutionType) { - return isNoInferType(substitutionType) ? substitutionType.baseType : getIntersectionType([substitutionType.constraint, substitutionType.baseType]); + return isNoInferType(substitutionType) + ? substitutionType.baseType + : getIntersectionType([ + substitutionType.constraint, + substitutionType.baseType, + ]); } function isUnaryTupleTypeNode(node: TypeNode) { - return node.kind === SyntaxKind.TupleType && (node as TupleTypeNode).elements.length === 1; + return ( + node.kind === SyntaxKind.TupleType && + (node as TupleTypeNode).elements.length === 1 + ); } - function getImpliedConstraint(type: Type, checkNode: TypeNode, extendsNode: TypeNode): Type | undefined { - return isUnaryTupleTypeNode(checkNode) && isUnaryTupleTypeNode(extendsNode) ? getImpliedConstraint(type, (checkNode as TupleTypeNode).elements[0], (extendsNode as TupleTypeNode).elements[0]) : - getActualTypeVariable(getTypeFromTypeNode(checkNode)) === getActualTypeVariable(type) ? getTypeFromTypeNode(extendsNode) : - undefined; + function getImpliedConstraint( + type: Type, + checkNode: TypeNode, + extendsNode: TypeNode + ): Type | undefined { + return isUnaryTupleTypeNode(checkNode) && + isUnaryTupleTypeNode(extendsNode) + ? getImpliedConstraint( + type, + (checkNode as TupleTypeNode).elements[0], + (extendsNode as TupleTypeNode).elements[0] + ) + : getActualTypeVariable(getTypeFromTypeNode(checkNode)) === + getActualTypeVariable(type) + ? getTypeFromTypeNode(extendsNode) + : undefined; } function getConditionalFlowTypeOfType(type: Type, node: Node) { @@ -17132,44 +29736,91 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Always substitute on type parameters, regardless of variance, since even // in contravariant positions, they may rely on substituted constraints to be valid - if ((covariant || type.flags & TypeFlags.TypeVariable) && parent.kind === SyntaxKind.ConditionalType && node === (parent as ConditionalTypeNode).trueType) { - const constraint = getImpliedConstraint(type, (parent as ConditionalTypeNode).checkType, (parent as ConditionalTypeNode).extendsType); + if ( + (covariant || type.flags & TypeFlags.TypeVariable) && + parent.kind === SyntaxKind.ConditionalType && + node === (parent as ConditionalTypeNode).trueType + ) { + const constraint = getImpliedConstraint( + type, + (parent as ConditionalTypeNode).checkType, + (parent as ConditionalTypeNode).extendsType + ); if (constraint) { constraints = append(constraints, constraint); } } // Given a homomorphic mapped type { [K in keyof T]: XXX }, where T is constrained to an array or tuple type, in the // template type XXX, K has an added constraint of number | `${number}`. - else if (type.flags & TypeFlags.TypeParameter && parent.kind === SyntaxKind.MappedType && !(parent as MappedTypeNode).nameType && node === (parent as MappedTypeNode).type) { - const mappedType = getTypeFromTypeNode(parent as TypeNode) as MappedType; - if (getTypeParameterFromMappedType(mappedType) === getActualTypeVariable(type)) { - const typeParameter = getHomomorphicTypeVariable(mappedType); + else if ( + type.flags & TypeFlags.TypeParameter && + parent.kind === SyntaxKind.MappedType && + !(parent as MappedTypeNode).nameType && + node === (parent as MappedTypeNode).type + ) { + const mappedType = getTypeFromTypeNode( + parent as TypeNode + ) as MappedType; + if ( + getTypeParameterFromMappedType(mappedType) === + getActualTypeVariable(type) + ) { + const typeParameter = + getHomomorphicTypeVariable(mappedType); if (typeParameter) { - const constraint = getConstraintOfTypeParameter(typeParameter); - if (constraint && everyType(constraint, isArrayOrTupleType)) { - constraints = append(constraints, getUnionType([numberType, numericStringType])); + const constraint = + getConstraintOfTypeParameter(typeParameter); + if ( + constraint && + everyType(constraint, isArrayOrTupleType) + ) { + constraints = append( + constraints, + getUnionType([numberType, numericStringType]) + ); } } } } node = parent; } - return constraints ? getSubstitutionType(type, getIntersectionType(constraints)) : type; + return constraints + ? getSubstitutionType(type, getIntersectionType(constraints)) + : type; } function isJSDocTypeReference(node: Node): node is TypeReferenceNode { - return !!(node.flags & NodeFlags.JSDoc) && (node.kind === SyntaxKind.TypeReference || node.kind === SyntaxKind.ImportType); + return ( + !!(node.flags & NodeFlags.JSDoc) && + (node.kind === SyntaxKind.TypeReference || + node.kind === SyntaxKind.ImportType) + ); } - function checkNoTypeArguments(node: NodeWithTypeArguments, symbol?: Symbol) { + function checkNoTypeArguments( + node: NodeWithTypeArguments, + symbol?: Symbol + ) { if (node.typeArguments) { - error(node, Diagnostics.Type_0_is_not_generic, symbol ? symbolToString(symbol) : (node as TypeReferenceNode).typeName ? declarationNameToString((node as TypeReferenceNode).typeName) : anon); + error( + node, + Diagnostics.Type_0_is_not_generic, + symbol + ? symbolToString(symbol) + : (node as TypeReferenceNode).typeName + ? declarationNameToString( + (node as TypeReferenceNode).typeName + ) + : anon + ); return false; } return true; } - function getIntendedTypeFromJSDocTypeReference(node: TypeReferenceNode): Type | undefined { + function getIntendedTypeFromJSDocTypeReference( + node: TypeReferenceNode + ): Type | undefined { if (isIdentifier(node.typeName)) { const typeArgs = node.typeArguments; switch (node.typeName.escapedText) { @@ -17199,16 +29850,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkNoTypeArguments(node); return globalFunctionType; case "array": - return (!typeArgs || !typeArgs.length) && !noImplicitAny ? anyArrayType : undefined; + return (!typeArgs || !typeArgs.length) && !noImplicitAny + ? anyArrayType + : undefined; case "promise": - return (!typeArgs || !typeArgs.length) && !noImplicitAny ? createPromiseType(anyType) : undefined; + return (!typeArgs || !typeArgs.length) && !noImplicitAny + ? createPromiseType(anyType) + : undefined; case "Object": if (typeArgs && typeArgs.length === 2) { if (isJSDocIndexSignature(node)) { const indexed = getTypeFromTypeNode(typeArgs[0]); const target = getTypeFromTypeNode(typeArgs[1]); - const indexInfo = indexed === stringType || indexed === numberType ? [createIndexInfo(indexed, target, /*isReadonly*/ false)] : emptyArray; - return createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, indexInfo); + const indexInfo = + indexed === stringType || indexed === numberType + ? [ + createIndexInfo( + indexed, + target, + /*isReadonly*/ false + ), + ] + : emptyArray; + return createAnonymousType( + /*symbol*/ undefined, + emptySymbols, + emptyArray, + emptyArray, + indexInfo + ); } return anyType; } @@ -17227,9 +29897,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const links = getNodeLinks(node); if (!links.resolvedType) { // handle LS queries on the `const` in `x as const` by resolving to the type of `x` - if (isConstTypeReference(node) && isAssertionExpression(node.parent)) { + if ( + isConstTypeReference(node) && + isAssertionExpression(node.parent) + ) { links.resolvedSymbol = unknownSymbol; - return links.resolvedType = checkExpressionCached(node.parent.expression); + return (links.resolvedType = checkExpressionCached( + node.parent.expression + )); } let symbol: Symbol | undefined; let type: Type | undefined; @@ -17237,11 +29912,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isJSDocTypeReference(node)) { type = getIntendedTypeFromJSDocTypeReference(node); if (!type) { - symbol = resolveTypeReferenceName(node, meaning, /*ignoreErrors*/ true); + symbol = resolveTypeReferenceName( + node, + meaning, + /*ignoreErrors*/ true + ); if (symbol === unknownSymbol) { - symbol = resolveTypeReferenceName(node, meaning | SymbolFlags.Value); - } - else { + symbol = resolveTypeReferenceName( + node, + meaning | SymbolFlags.Value + ); + } else { resolveTypeReferenceName(node, meaning); // Resolve again to mark errors, if any } type = getTypeReferenceType(node, symbol); @@ -17259,7 +29940,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return links.resolvedType; } - function typeArgumentsFromTypeReferenceNode(node: NodeWithTypeArguments): Type[] | undefined { + function typeArgumentsFromTypeReferenceNode( + node: NodeWithTypeArguments + ): Type[] | undefined { return map(node.typeArguments, getTypeFromTypeNode); } @@ -17271,12 +29954,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // or property access expression(section 4.10), // the widened type(section 3.9) of which becomes the result. const type = checkExpressionWithTypeArguments(node); - links.resolvedType = getRegularTypeOfLiteralType(getWidenedType(type)); + links.resolvedType = getRegularTypeOfLiteralType( + getWidenedType(type) + ); } return links.resolvedType; } - function getTypeOfGlobalSymbol(symbol: Symbol | undefined, arity: number): ObjectType { + function getTypeOfGlobalSymbol( + symbol: Symbol | undefined, + arity: number + ): ObjectType { function getTypeDeclaration(symbol: Symbol): Declaration | undefined { const declarations = symbol.declarations; if (declarations) { @@ -17296,167 +29984,378 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const type = getDeclaredTypeOfSymbol(symbol); if (!(type.flags & TypeFlags.Object)) { - error(getTypeDeclaration(symbol), Diagnostics.Global_type_0_must_be_a_class_or_interface_type, symbolName(symbol)); + error( + getTypeDeclaration(symbol), + Diagnostics.Global_type_0_must_be_a_class_or_interface_type, + symbolName(symbol) + ); return arity ? emptyGenericType : emptyObjectType; } if (length((type as InterfaceType).typeParameters) !== arity) { - error(getTypeDeclaration(symbol), Diagnostics.Global_type_0_must_have_1_type_parameter_s, symbolName(symbol), arity); + error( + getTypeDeclaration(symbol), + Diagnostics.Global_type_0_must_have_1_type_parameter_s, + symbolName(symbol), + arity + ); return arity ? emptyGenericType : emptyObjectType; } return type as ObjectType; } - function getGlobalValueSymbol(name: __String, reportErrors: boolean): Symbol | undefined { - return getGlobalSymbol(name, SymbolFlags.Value, reportErrors ? Diagnostics.Cannot_find_global_value_0 : undefined); + function getGlobalValueSymbol( + name: __String, + reportErrors: boolean + ): Symbol | undefined { + return getGlobalSymbol( + name, + SymbolFlags.Value, + reportErrors ? Diagnostics.Cannot_find_global_value_0 : undefined + ); } - function getGlobalTypeSymbol(name: __String, reportErrors: boolean): Symbol | undefined { - return getGlobalSymbol(name, SymbolFlags.Type, reportErrors ? Diagnostics.Cannot_find_global_type_0 : undefined); + function getGlobalTypeSymbol( + name: __String, + reportErrors: boolean + ): Symbol | undefined { + return getGlobalSymbol( + name, + SymbolFlags.Type, + reportErrors ? Diagnostics.Cannot_find_global_type_0 : undefined + ); } - function getGlobalTypeAliasSymbol(name: __String, arity: number, reportErrors: boolean): Symbol | undefined { - const symbol = getGlobalSymbol(name, SymbolFlags.Type, reportErrors ? Diagnostics.Cannot_find_global_type_0 : undefined); + function getGlobalTypeAliasSymbol( + name: __String, + arity: number, + reportErrors: boolean + ): Symbol | undefined { + const symbol = getGlobalSymbol( + name, + SymbolFlags.Type, + reportErrors ? Diagnostics.Cannot_find_global_type_0 : undefined + ); if (symbol) { // Resolve the declared type of the symbol. This resolves type parameters for the type // alias so that we can check arity. getDeclaredTypeOfSymbol(symbol); if (length(getSymbolLinks(symbol).typeParameters) !== arity) { - const decl = symbol.declarations && find(symbol.declarations, isTypeAliasDeclaration); - error(decl, Diagnostics.Global_type_0_must_have_1_type_parameter_s, symbolName(symbol), arity); + const decl = + symbol.declarations && + find(symbol.declarations, isTypeAliasDeclaration); + error( + decl, + Diagnostics.Global_type_0_must_have_1_type_parameter_s, + symbolName(symbol), + arity + ); return undefined; } } return symbol; } - function getGlobalSymbol(name: __String, meaning: SymbolFlags, diagnostic: DiagnosticMessage | undefined): Symbol | undefined { + function getGlobalSymbol( + name: __String, + meaning: SymbolFlags, + diagnostic: DiagnosticMessage | undefined + ): Symbol | undefined { // Don't track references for global symbols anyway, so value if `isReference` is arbitrary - return resolveName(/*location*/ undefined, name, meaning, diagnostic, /*isUse*/ false, /*excludeGlobals*/ false); + return resolveName( + /*location*/ undefined, + name, + meaning, + diagnostic, + /*isUse*/ false, + /*excludeGlobals*/ false + ); } - function getGlobalType(name: __String, arity: 0, reportErrors: true): ObjectType; - function getGlobalType(name: __String, arity: 0, reportErrors: boolean): ObjectType | undefined; - function getGlobalType(name: __String, arity: number, reportErrors: true): GenericType; - function getGlobalType(name: __String, arity: number, reportErrors: boolean): GenericType | undefined; - function getGlobalType(name: __String, arity: number, reportErrors: boolean): ObjectType | undefined { + function getGlobalType( + name: __String, + arity: 0, + reportErrors: true + ): ObjectType; + function getGlobalType( + name: __String, + arity: 0, + reportErrors: boolean + ): ObjectType | undefined; + function getGlobalType( + name: __String, + arity: number, + reportErrors: true + ): GenericType; + function getGlobalType( + name: __String, + arity: number, + reportErrors: boolean + ): GenericType | undefined; + function getGlobalType( + name: __String, + arity: number, + reportErrors: boolean + ): ObjectType | undefined { const symbol = getGlobalTypeSymbol(name, reportErrors); - return symbol || reportErrors ? getTypeOfGlobalSymbol(symbol, arity) : undefined; + return symbol || reportErrors + ? getTypeOfGlobalSymbol(symbol, arity) + : undefined; } - function getGlobalBuiltinTypes(typeNames: readonly string[], arity: 0): ObjectType[]; - function getGlobalBuiltinTypes(typeNames: readonly string[], arity: number): GenericType[]; - function getGlobalBuiltinTypes(typeNames: readonly string[], arity: number) { + function getGlobalBuiltinTypes( + typeNames: readonly string[], + arity: 0 + ): ObjectType[]; + function getGlobalBuiltinTypes( + typeNames: readonly string[], + arity: number + ): GenericType[]; + function getGlobalBuiltinTypes( + typeNames: readonly string[], + arity: number + ) { let types: Type[] | undefined; for (const typeName of typeNames) { - types = append(types, getGlobalType(typeName as __String, arity, /*reportErrors*/ false)); + types = append( + types, + getGlobalType( + typeName as __String, + arity, + /*reportErrors*/ false + ) + ); } return types ?? emptyArray; } function getGlobalTypedPropertyDescriptorType() { // We always report an error, so store a result in the event we could not resolve the symbol to prevent reporting it multiple times - return deferredGlobalTypedPropertyDescriptorType ||= getGlobalType("TypedPropertyDescriptor" as __String, /*arity*/ 1, /*reportErrors*/ true) || emptyGenericType; + return (deferredGlobalTypedPropertyDescriptorType ||= + getGlobalType( + "TypedPropertyDescriptor" as __String, + /*arity*/ 1, + /*reportErrors*/ true + ) || emptyGenericType); } function getGlobalTemplateStringsArrayType() { // We always report an error, so store a result in the event we could not resolve the symbol to prevent reporting it multiple times - return deferredGlobalTemplateStringsArrayType ||= getGlobalType("TemplateStringsArray" as __String, /*arity*/ 0, /*reportErrors*/ true) || emptyObjectType; + return (deferredGlobalTemplateStringsArrayType ||= + getGlobalType( + "TemplateStringsArray" as __String, + /*arity*/ 0, + /*reportErrors*/ true + ) || emptyObjectType); } function getGlobalImportMetaType() { // We always report an error, so store a result in the event we could not resolve the symbol to prevent reporting it multiple times - return deferredGlobalImportMetaType ||= getGlobalType("ImportMeta" as __String, /*arity*/ 0, /*reportErrors*/ true) || emptyObjectType; + return (deferredGlobalImportMetaType ||= + getGlobalType( + "ImportMeta" as __String, + /*arity*/ 0, + /*reportErrors*/ true + ) || emptyObjectType); } function getGlobalImportMetaExpressionType() { if (!deferredGlobalImportMetaExpressionType) { // Create a synthetic type `ImportMetaExpression { meta: MetaProperty }` - const symbol = createSymbol(SymbolFlags.None, "ImportMetaExpression" as __String); + const symbol = createSymbol( + SymbolFlags.None, + "ImportMetaExpression" as __String + ); const importMetaType = getGlobalImportMetaType(); - const metaPropertySymbol = createSymbol(SymbolFlags.Property, "meta" as __String, CheckFlags.Readonly); + const metaPropertySymbol = createSymbol( + SymbolFlags.Property, + "meta" as __String, + CheckFlags.Readonly + ); metaPropertySymbol.parent = symbol; metaPropertySymbol.links.type = importMetaType; const members = createSymbolTable([metaPropertySymbol]); symbol.members = members; - deferredGlobalImportMetaExpressionType = createAnonymousType(symbol, members, emptyArray, emptyArray, emptyArray); + deferredGlobalImportMetaExpressionType = createAnonymousType( + symbol, + members, + emptyArray, + emptyArray, + emptyArray + ); } return deferredGlobalImportMetaExpressionType; } function getGlobalImportCallOptionsType(reportErrors: boolean) { - return (deferredGlobalImportCallOptionsType ||= getGlobalType("ImportCallOptions" as __String, /*arity*/ 0, reportErrors)) || emptyObjectType; + return ( + (deferredGlobalImportCallOptionsType ||= getGlobalType( + "ImportCallOptions" as __String, + /*arity*/ 0, + reportErrors + )) || emptyObjectType + ); } function getGlobalImportAttributesType(reportErrors: boolean) { - return (deferredGlobalImportAttributesType ||= getGlobalType("ImportAttributes" as __String, /*arity*/ 0, reportErrors)) || emptyObjectType; + return ( + (deferredGlobalImportAttributesType ||= getGlobalType( + "ImportAttributes" as __String, + /*arity*/ 0, + reportErrors + )) || emptyObjectType + ); } - function getGlobalESSymbolConstructorSymbol(reportErrors: boolean): Symbol | undefined { - return deferredGlobalESSymbolConstructorSymbol ||= getGlobalValueSymbol("Symbol" as __String, reportErrors); + function getGlobalESSymbolConstructorSymbol( + reportErrors: boolean + ): Symbol | undefined { + return (deferredGlobalESSymbolConstructorSymbol ||= + getGlobalValueSymbol("Symbol" as __String, reportErrors)); } - function getGlobalESSymbolConstructorTypeSymbol(reportErrors: boolean): Symbol | undefined { - return deferredGlobalESSymbolConstructorTypeSymbol ||= getGlobalTypeSymbol("SymbolConstructor" as __String, reportErrors); + function getGlobalESSymbolConstructorTypeSymbol( + reportErrors: boolean + ): Symbol | undefined { + return (deferredGlobalESSymbolConstructorTypeSymbol ||= + getGlobalTypeSymbol("SymbolConstructor" as __String, reportErrors)); } function getGlobalESSymbolType() { - return (deferredGlobalESSymbolType ||= getGlobalType("Symbol" as __String, /*arity*/ 0, /*reportErrors*/ false)) || emptyObjectType; + return ( + (deferredGlobalESSymbolType ||= getGlobalType( + "Symbol" as __String, + /*arity*/ 0, + /*reportErrors*/ false + )) || emptyObjectType + ); } function getGlobalPromiseType(reportErrors: boolean) { - return (deferredGlobalPromiseType ||= getGlobalType("Promise" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; + return ( + (deferredGlobalPromiseType ||= getGlobalType( + "Promise" as __String, + /*arity*/ 1, + reportErrors + )) || emptyGenericType + ); } function getGlobalPromiseLikeType(reportErrors: boolean) { - return (deferredGlobalPromiseLikeType ||= getGlobalType("PromiseLike" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; + return ( + (deferredGlobalPromiseLikeType ||= getGlobalType( + "PromiseLike" as __String, + /*arity*/ 1, + reportErrors + )) || emptyGenericType + ); } - function getGlobalPromiseConstructorSymbol(reportErrors: boolean): Symbol | undefined { - return deferredGlobalPromiseConstructorSymbol ||= getGlobalValueSymbol("Promise" as __String, reportErrors); + function getGlobalPromiseConstructorSymbol( + reportErrors: boolean + ): Symbol | undefined { + return (deferredGlobalPromiseConstructorSymbol ||= getGlobalValueSymbol( + "Promise" as __String, + reportErrors + )); } function getGlobalPromiseConstructorLikeType(reportErrors: boolean) { - return (deferredGlobalPromiseConstructorLikeType ||= getGlobalType("PromiseConstructorLike" as __String, /*arity*/ 0, reportErrors)) || emptyObjectType; + return ( + (deferredGlobalPromiseConstructorLikeType ||= getGlobalType( + "PromiseConstructorLike" as __String, + /*arity*/ 0, + reportErrors + )) || emptyObjectType + ); } function getGlobalAsyncIterableType(reportErrors: boolean) { - return (deferredGlobalAsyncIterableType ||= getGlobalType("AsyncIterable" as __String, /*arity*/ 3, reportErrors)) || emptyGenericType; + return ( + (deferredGlobalAsyncIterableType ||= getGlobalType( + "AsyncIterable" as __String, + /*arity*/ 3, + reportErrors + )) || emptyGenericType + ); } function getGlobalAsyncIteratorType(reportErrors: boolean) { - return (deferredGlobalAsyncIteratorType ||= getGlobalType("AsyncIterator" as __String, /*arity*/ 3, reportErrors)) || emptyGenericType; + return ( + (deferredGlobalAsyncIteratorType ||= getGlobalType( + "AsyncIterator" as __String, + /*arity*/ 3, + reportErrors + )) || emptyGenericType + ); } function getGlobalAsyncIterableIteratorType(reportErrors: boolean) { - return (deferredGlobalAsyncIterableIteratorType ||= getGlobalType("AsyncIterableIterator" as __String, /*arity*/ 3, reportErrors)) || emptyGenericType; + return ( + (deferredGlobalAsyncIterableIteratorType ||= getGlobalType( + "AsyncIterableIterator" as __String, + /*arity*/ 3, + reportErrors + )) || emptyGenericType + ); } function getGlobalBuiltinAsyncIteratorTypes() { // NOTE: This list does not include all built-in async iterator types, only those that are likely to be encountered frequently. - return deferredGlobalBuiltinAsyncIteratorTypes ??= getGlobalBuiltinTypes(["ReadableStreamAsyncIterator"], 1); + return (deferredGlobalBuiltinAsyncIteratorTypes ??= + getGlobalBuiltinTypes(["ReadableStreamAsyncIterator"], 1)); } function getGlobalAsyncIteratorObjectType(reportErrors: boolean) { - return (deferredGlobalAsyncIteratorObjectType ||= getGlobalType("AsyncIteratorObject" as __String, /*arity*/ 3, reportErrors)) || emptyGenericType; + return ( + (deferredGlobalAsyncIteratorObjectType ||= getGlobalType( + "AsyncIteratorObject" as __String, + /*arity*/ 3, + reportErrors + )) || emptyGenericType + ); } function getGlobalAsyncGeneratorType(reportErrors: boolean) { - return (deferredGlobalAsyncGeneratorType ||= getGlobalType("AsyncGenerator" as __String, /*arity*/ 3, reportErrors)) || emptyGenericType; + return ( + (deferredGlobalAsyncGeneratorType ||= getGlobalType( + "AsyncGenerator" as __String, + /*arity*/ 3, + reportErrors + )) || emptyGenericType + ); } function getGlobalIterableType(reportErrors: boolean) { - return (deferredGlobalIterableType ||= getGlobalType("Iterable" as __String, /*arity*/ 3, reportErrors)) || emptyGenericType; + return ( + (deferredGlobalIterableType ||= getGlobalType( + "Iterable" as __String, + /*arity*/ 3, + reportErrors + )) || emptyGenericType + ); } function getGlobalIteratorType(reportErrors: boolean) { - return (deferredGlobalIteratorType ||= getGlobalType("Iterator" as __String, /*arity*/ 3, reportErrors)) || emptyGenericType; + return ( + (deferredGlobalIteratorType ||= getGlobalType( + "Iterator" as __String, + /*arity*/ 3, + reportErrors + )) || emptyGenericType + ); } function getGlobalIterableIteratorType(reportErrors: boolean) { - return (deferredGlobalIterableIteratorType ||= getGlobalType("IterableIterator" as __String, /*arity*/ 3, reportErrors)) || emptyGenericType; + return ( + (deferredGlobalIterableIteratorType ||= getGlobalType( + "IterableIterator" as __String, + /*arity*/ 3, + reportErrors + )) || emptyGenericType + ); } function getBuiltinIteratorReturnType() { @@ -17465,118 +30364,266 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getGlobalBuiltinIteratorTypes() { // NOTE: This list does not include all built-in iterator types, only those that are likely to be encountered frequently. - return deferredGlobalBuiltinIteratorTypes ??= getGlobalBuiltinTypes(["ArrayIterator", "MapIterator", "SetIterator", "StringIterator"], 1); + return (deferredGlobalBuiltinIteratorTypes ??= getGlobalBuiltinTypes( + ["ArrayIterator", "MapIterator", "SetIterator", "StringIterator"], + 1 + )); } function getGlobalIteratorObjectType(reportErrors: boolean) { - return (deferredGlobalIteratorObjectType ||= getGlobalType("IteratorObject" as __String, /*arity*/ 3, reportErrors)) || emptyGenericType; + return ( + (deferredGlobalIteratorObjectType ||= getGlobalType( + "IteratorObject" as __String, + /*arity*/ 3, + reportErrors + )) || emptyGenericType + ); } function getGlobalGeneratorType(reportErrors: boolean) { - return (deferredGlobalGeneratorType ||= getGlobalType("Generator" as __String, /*arity*/ 3, reportErrors)) || emptyGenericType; + return ( + (deferredGlobalGeneratorType ||= getGlobalType( + "Generator" as __String, + /*arity*/ 3, + reportErrors + )) || emptyGenericType + ); } function getGlobalIteratorYieldResultType(reportErrors: boolean) { - return (deferredGlobalIteratorYieldResultType ||= getGlobalType("IteratorYieldResult" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; + return ( + (deferredGlobalIteratorYieldResultType ||= getGlobalType( + "IteratorYieldResult" as __String, + /*arity*/ 1, + reportErrors + )) || emptyGenericType + ); } function getGlobalIteratorReturnResultType(reportErrors: boolean) { - return (deferredGlobalIteratorReturnResultType ||= getGlobalType("IteratorReturnResult" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; + return ( + (deferredGlobalIteratorReturnResultType ||= getGlobalType( + "IteratorReturnResult" as __String, + /*arity*/ 1, + reportErrors + )) || emptyGenericType + ); } function getGlobalDisposableType(reportErrors: boolean) { - return (deferredGlobalDisposableType ||= getGlobalType("Disposable" as __String, /*arity*/ 0, reportErrors)) || emptyObjectType; + return ( + (deferredGlobalDisposableType ||= getGlobalType( + "Disposable" as __String, + /*arity*/ 0, + reportErrors + )) || emptyObjectType + ); } function getGlobalAsyncDisposableType(reportErrors: boolean) { - return (deferredGlobalAsyncDisposableType ||= getGlobalType("AsyncDisposable" as __String, /*arity*/ 0, reportErrors)) || emptyObjectType; + return ( + (deferredGlobalAsyncDisposableType ||= getGlobalType( + "AsyncDisposable" as __String, + /*arity*/ 0, + reportErrors + )) || emptyObjectType + ); } - function getGlobalTypeOrUndefined(name: __String, arity = 0): ObjectType | undefined { - const symbol = getGlobalSymbol(name, SymbolFlags.Type, /*diagnostic*/ undefined); - return symbol && getTypeOfGlobalSymbol(symbol, arity) as GenericType; + function getGlobalTypeOrUndefined( + name: __String, + arity = 0 + ): ObjectType | undefined { + const symbol = getGlobalSymbol( + name, + SymbolFlags.Type, + /*diagnostic*/ undefined + ); + return symbol && (getTypeOfGlobalSymbol(symbol, arity) as GenericType); } function getGlobalExtractSymbol(): Symbol | undefined { // We always report an error, so cache a result in the event we could not resolve the symbol to prevent reporting it multiple times - deferredGlobalExtractSymbol ||= getGlobalTypeAliasSymbol("Extract" as __String, /*arity*/ 2, /*reportErrors*/ true) || unknownSymbol; - return deferredGlobalExtractSymbol === unknownSymbol ? undefined : deferredGlobalExtractSymbol; + deferredGlobalExtractSymbol ||= + getGlobalTypeAliasSymbol( + "Extract" as __String, + /*arity*/ 2, + /*reportErrors*/ true + ) || unknownSymbol; + return deferredGlobalExtractSymbol === unknownSymbol + ? undefined + : deferredGlobalExtractSymbol; } function getGlobalOmitSymbol(): Symbol | undefined { // We always report an error, so cache a result in the event we could not resolve the symbol to prevent reporting it multiple times - deferredGlobalOmitSymbol ||= getGlobalTypeAliasSymbol("Omit" as __String, /*arity*/ 2, /*reportErrors*/ true) || unknownSymbol; - return deferredGlobalOmitSymbol === unknownSymbol ? undefined : deferredGlobalOmitSymbol; + deferredGlobalOmitSymbol ||= + getGlobalTypeAliasSymbol( + "Omit" as __String, + /*arity*/ 2, + /*reportErrors*/ true + ) || unknownSymbol; + return deferredGlobalOmitSymbol === unknownSymbol + ? undefined + : deferredGlobalOmitSymbol; } function getGlobalAwaitedSymbol(reportErrors: boolean): Symbol | undefined { // Only cache `unknownSymbol` if we are reporting errors so that we don't report the error more than once. - deferredGlobalAwaitedSymbol ||= getGlobalTypeAliasSymbol("Awaited" as __String, /*arity*/ 1, reportErrors) || (reportErrors ? unknownSymbol : undefined); - return deferredGlobalAwaitedSymbol === unknownSymbol ? undefined : deferredGlobalAwaitedSymbol; + deferredGlobalAwaitedSymbol ||= + getGlobalTypeAliasSymbol( + "Awaited" as __String, + /*arity*/ 1, + reportErrors + ) || (reportErrors ? unknownSymbol : undefined); + return deferredGlobalAwaitedSymbol === unknownSymbol + ? undefined + : deferredGlobalAwaitedSymbol; } function getGlobalBigIntType() { - return (deferredGlobalBigIntType ||= getGlobalType("BigInt" as __String, /*arity*/ 0, /*reportErrors*/ false)) || emptyObjectType; + return ( + (deferredGlobalBigIntType ||= getGlobalType( + "BigInt" as __String, + /*arity*/ 0, + /*reportErrors*/ false + )) || emptyObjectType + ); } function getGlobalClassDecoratorContextType(reportErrors: boolean) { - return (deferredGlobalClassDecoratorContextType ??= getGlobalType("ClassDecoratorContext" as __String, /*arity*/ 1, reportErrors)) ?? emptyGenericType; + return ( + (deferredGlobalClassDecoratorContextType ??= getGlobalType( + "ClassDecoratorContext" as __String, + /*arity*/ 1, + reportErrors + )) ?? emptyGenericType + ); } function getGlobalClassMethodDecoratorContextType(reportErrors: boolean) { - return (deferredGlobalClassMethodDecoratorContextType ??= getGlobalType("ClassMethodDecoratorContext" as __String, /*arity*/ 2, reportErrors)) ?? emptyGenericType; + return ( + (deferredGlobalClassMethodDecoratorContextType ??= getGlobalType( + "ClassMethodDecoratorContext" as __String, + /*arity*/ 2, + reportErrors + )) ?? emptyGenericType + ); } function getGlobalClassGetterDecoratorContextType(reportErrors: boolean) { - return (deferredGlobalClassGetterDecoratorContextType ??= getGlobalType("ClassGetterDecoratorContext" as __String, /*arity*/ 2, reportErrors)) ?? emptyGenericType; + return ( + (deferredGlobalClassGetterDecoratorContextType ??= getGlobalType( + "ClassGetterDecoratorContext" as __String, + /*arity*/ 2, + reportErrors + )) ?? emptyGenericType + ); } function getGlobalClassSetterDecoratorContextType(reportErrors: boolean) { - return (deferredGlobalClassSetterDecoratorContextType ??= getGlobalType("ClassSetterDecoratorContext" as __String, /*arity*/ 2, reportErrors)) ?? emptyGenericType; + return ( + (deferredGlobalClassSetterDecoratorContextType ??= getGlobalType( + "ClassSetterDecoratorContext" as __String, + /*arity*/ 2, + reportErrors + )) ?? emptyGenericType + ); } function getGlobalClassAccessorDecoratorContextType(reportErrors: boolean) { - return (deferredGlobalClassAccessorDecoratorContextType ??= getGlobalType("ClassAccessorDecoratorContext" as __String, /*arity*/ 2, reportErrors)) ?? emptyGenericType; + return ( + (deferredGlobalClassAccessorDecoratorContextType ??= getGlobalType( + "ClassAccessorDecoratorContext" as __String, + /*arity*/ 2, + reportErrors + )) ?? emptyGenericType + ); } function getGlobalClassAccessorDecoratorTargetType(reportErrors: boolean) { - return (deferredGlobalClassAccessorDecoratorTargetType ??= getGlobalType("ClassAccessorDecoratorTarget" as __String, /*arity*/ 2, reportErrors)) ?? emptyGenericType; + return ( + (deferredGlobalClassAccessorDecoratorTargetType ??= getGlobalType( + "ClassAccessorDecoratorTarget" as __String, + /*arity*/ 2, + reportErrors + )) ?? emptyGenericType + ); } function getGlobalClassAccessorDecoratorResultType(reportErrors: boolean) { - return (deferredGlobalClassAccessorDecoratorResultType ??= getGlobalType("ClassAccessorDecoratorResult" as __String, /*arity*/ 2, reportErrors)) ?? emptyGenericType; + return ( + (deferredGlobalClassAccessorDecoratorResultType ??= getGlobalType( + "ClassAccessorDecoratorResult" as __String, + /*arity*/ 2, + reportErrors + )) ?? emptyGenericType + ); } function getGlobalClassFieldDecoratorContextType(reportErrors: boolean) { - return (deferredGlobalClassFieldDecoratorContextType ??= getGlobalType("ClassFieldDecoratorContext" as __String, /*arity*/ 2, reportErrors)) ?? emptyGenericType; + return ( + (deferredGlobalClassFieldDecoratorContextType ??= getGlobalType( + "ClassFieldDecoratorContext" as __String, + /*arity*/ 2, + reportErrors + )) ?? emptyGenericType + ); } function getGlobalNaNSymbol(): Symbol | undefined { - return (deferredGlobalNaNSymbol ||= getGlobalValueSymbol("NaN" as __String, /*reportErrors*/ false)); + return (deferredGlobalNaNSymbol ||= getGlobalValueSymbol( + "NaN" as __String, + /*reportErrors*/ false + )); } function getGlobalRecordSymbol(): Symbol | undefined { - deferredGlobalRecordSymbol ||= getGlobalTypeAliasSymbol("Record" as __String, /*arity*/ 2, /*reportErrors*/ true) || unknownSymbol; - return deferredGlobalRecordSymbol === unknownSymbol ? undefined : deferredGlobalRecordSymbol; + deferredGlobalRecordSymbol ||= + getGlobalTypeAliasSymbol( + "Record" as __String, + /*arity*/ 2, + /*reportErrors*/ true + ) || unknownSymbol; + return deferredGlobalRecordSymbol === unknownSymbol + ? undefined + : deferredGlobalRecordSymbol; } /** * Instantiates a global type that is generic with some element type, and returns that instantiation. */ - function createTypeFromGenericGlobalType(genericGlobalType: GenericType, typeArguments: readonly Type[]): ObjectType { - return genericGlobalType !== emptyGenericType ? createTypeReference(genericGlobalType, typeArguments) : emptyObjectType; + function createTypeFromGenericGlobalType( + genericGlobalType: GenericType, + typeArguments: readonly Type[] + ): ObjectType { + return genericGlobalType !== emptyGenericType + ? createTypeReference(genericGlobalType, typeArguments) + : emptyObjectType; } function createTypedPropertyDescriptorType(propertyType: Type): Type { - return createTypeFromGenericGlobalType(getGlobalTypedPropertyDescriptorType(), [propertyType]); + return createTypeFromGenericGlobalType( + getGlobalTypedPropertyDescriptorType(), + [propertyType] + ); } function createIterableType(iteratedType: Type): Type { - return createTypeFromGenericGlobalType(getGlobalIterableType(/*reportErrors*/ true), [iteratedType, voidType, undefinedType]); + return createTypeFromGenericGlobalType( + getGlobalIterableType(/*reportErrors*/ true), + [iteratedType, voidType, undefinedType] + ); } - function createArrayType(elementType: Type, readonly?: boolean): ObjectType { - return createTypeFromGenericGlobalType(readonly ? globalReadonlyArrayType : globalArrayType, [elementType]); + function createArrayType( + elementType: Type, + readonly?: boolean + ): ObjectType { + return createTypeFromGenericGlobalType( + readonly ? globalReadonlyArrayType : globalArrayType, + [elementType] + ); } function getTupleElementFlags(node: TypeNode) { @@ -17586,40 +30633,68 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.RestType: return getRestTypeElementFlags(node as RestTypeNode); case SyntaxKind.NamedTupleMember: - return (node as NamedTupleMember).questionToken ? ElementFlags.Optional : - (node as NamedTupleMember).dotDotDotToken ? getRestTypeElementFlags(node as NamedTupleMember) : - ElementFlags.Required; + return (node as NamedTupleMember).questionToken + ? ElementFlags.Optional + : (node as NamedTupleMember).dotDotDotToken + ? getRestTypeElementFlags(node as NamedTupleMember) + : ElementFlags.Required; default: return ElementFlags.Required; } } function getRestTypeElementFlags(node: RestTypeNode | NamedTupleMember) { - return getArrayElementTypeNode(node.type) ? ElementFlags.Rest : ElementFlags.Variadic; + return getArrayElementTypeNode(node.type) + ? ElementFlags.Rest + : ElementFlags.Variadic; } - function getArrayOrTupleTargetType(node: ArrayTypeNode | TupleTypeNode): GenericType { + function getArrayOrTupleTargetType( + node: ArrayTypeNode | TupleTypeNode + ): GenericType { const readonly = isReadonlyTypeOperator(node.parent); const elementType = getArrayElementTypeNode(node); if (elementType) { return readonly ? globalReadonlyArrayType : globalArrayType; } - const elementFlags = map((node as TupleTypeNode).elements, getTupleElementFlags); - return getTupleTargetType(elementFlags, readonly, map((node as TupleTypeNode).elements, memberIfLabeledElementDeclaration)); + const elementFlags = map( + (node as TupleTypeNode).elements, + getTupleElementFlags + ); + return getTupleTargetType( + elementFlags, + readonly, + map( + (node as TupleTypeNode).elements, + memberIfLabeledElementDeclaration + ) + ); } - function memberIfLabeledElementDeclaration(member: Node): NamedTupleMember | ParameterDeclaration | undefined { - return isNamedTupleMember(member) || isParameter(member) ? member : undefined; + function memberIfLabeledElementDeclaration( + member: Node + ): NamedTupleMember | ParameterDeclaration | undefined { + return isNamedTupleMember(member) || isParameter(member) + ? member + : undefined; } // Return true if the given type reference node is directly aliased or if it needs to be deferred // because it is possibly contained in a circular chain of eagerly resolved types. - function isDeferredTypeReferenceNode(node: TypeReferenceNode | ArrayTypeNode | TupleTypeNode, hasDefaultTypeArguments?: boolean) { - return !!getAliasSymbolForTypeNode(node) || isResolvedByTypeAlias(node) && ( - node.kind === SyntaxKind.ArrayType ? mayResolveTypeAlias(node.elementType) : - node.kind === SyntaxKind.TupleType ? some(node.elements, mayResolveTypeAlias) : - hasDefaultTypeArguments || some(node.typeArguments, mayResolveTypeAlias) - ); + function isDeferredTypeReferenceNode( + node: TypeReferenceNode | ArrayTypeNode | TupleTypeNode, + hasDefaultTypeArguments?: boolean + ) { + return ( + !!getAliasSymbolForTypeNode(node) || + (isResolvedByTypeAlias(node) && + (node.kind === SyntaxKind.ArrayType + ? mayResolveTypeAlias(node.elementType) + : node.kind === SyntaxKind.TupleType + ? some(node.elements, mayResolveTypeAlias) + : hasDefaultTypeArguments || + some(node.typeArguments, mayResolveTypeAlias))) + ); } // Return true when the given node is transitively contained in type constructs that eagerly @@ -17650,11 +30725,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function mayResolveTypeAlias(node: Node): boolean { switch (node.kind) { case SyntaxKind.TypeReference: - return isJSDocTypeReference(node) || !!(resolveTypeReferenceName(node as TypeReferenceNode, SymbolFlags.Type).flags & SymbolFlags.TypeAlias); + return ( + isJSDocTypeReference(node) || + !!( + resolveTypeReferenceName( + node as TypeReferenceNode, + SymbolFlags.Type + ).flags & SymbolFlags.TypeAlias + ) + ); case SyntaxKind.TypeQuery: return true; case SyntaxKind.TypeOperator: - return (node as TypeOperatorNode).operator !== SyntaxKind.UniqueKeyword && mayResolveTypeAlias((node as TypeOperatorNode).type); + return ( + (node as TypeOperatorNode).operator !== + SyntaxKind.UniqueKeyword && + mayResolveTypeAlias((node as TypeOperatorNode).type) + ); case SyntaxKind.ParenthesizedType: case SyntaxKind.OptionalType: case SyntaxKind.NamedTupleMember: @@ -17662,62 +30749,166 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.JSDocNullableType: case SyntaxKind.JSDocNonNullableType: case SyntaxKind.JSDocTypeExpression: - return mayResolveTypeAlias((node as ParenthesizedTypeNode | OptionalTypeNode | JSDocTypeReferencingNode | NamedTupleMember).type); + return mayResolveTypeAlias( + ( + node as + | ParenthesizedTypeNode + | OptionalTypeNode + | JSDocTypeReferencingNode + | NamedTupleMember + ).type + ); case SyntaxKind.RestType: - return (node as RestTypeNode).type.kind !== SyntaxKind.ArrayType || mayResolveTypeAlias(((node as RestTypeNode).type as ArrayTypeNode).elementType); + return ( + (node as RestTypeNode).type.kind !== SyntaxKind.ArrayType || + mayResolveTypeAlias( + ((node as RestTypeNode).type as ArrayTypeNode) + .elementType + ) + ); case SyntaxKind.UnionType: case SyntaxKind.IntersectionType: - return some((node as UnionOrIntersectionTypeNode).types, mayResolveTypeAlias); + return some( + (node as UnionOrIntersectionTypeNode).types, + mayResolveTypeAlias + ); case SyntaxKind.IndexedAccessType: - return mayResolveTypeAlias((node as IndexedAccessTypeNode).objectType) || mayResolveTypeAlias((node as IndexedAccessTypeNode).indexType); + return ( + mayResolveTypeAlias( + (node as IndexedAccessTypeNode).objectType + ) || + mayResolveTypeAlias( + (node as IndexedAccessTypeNode).indexType + ) + ); case SyntaxKind.ConditionalType: - return mayResolveTypeAlias((node as ConditionalTypeNode).checkType) || mayResolveTypeAlias((node as ConditionalTypeNode).extendsType) || - mayResolveTypeAlias((node as ConditionalTypeNode).trueType) || mayResolveTypeAlias((node as ConditionalTypeNode).falseType); + return ( + mayResolveTypeAlias( + (node as ConditionalTypeNode).checkType + ) || + mayResolveTypeAlias( + (node as ConditionalTypeNode).extendsType + ) || + mayResolveTypeAlias( + (node as ConditionalTypeNode).trueType + ) || + mayResolveTypeAlias((node as ConditionalTypeNode).falseType) + ); } return false; } - function getTypeFromArrayOrTupleTypeNode(node: ArrayTypeNode | TupleTypeNode): Type { + function getTypeFromArrayOrTupleTypeNode( + node: ArrayTypeNode | TupleTypeNode + ): Type { const links = getNodeLinks(node); if (!links.resolvedType) { const target = getArrayOrTupleTargetType(node); if (target === emptyGenericType) { links.resolvedType = emptyObjectType; - } - else if (!(node.kind === SyntaxKind.TupleType && some(node.elements, e => !!(getTupleElementFlags(e) & ElementFlags.Variadic))) && isDeferredTypeReferenceNode(node)) { - links.resolvedType = node.kind === SyntaxKind.TupleType && node.elements.length === 0 ? target : - createDeferredTypeReference(target, node, /*mapper*/ undefined); - } - else { - const elementTypes = node.kind === SyntaxKind.ArrayType ? [getTypeFromTypeNode(node.elementType)] : map(node.elements, getTypeFromTypeNode); - links.resolvedType = createNormalizedTypeReference(target, elementTypes); + } else if ( + !( + node.kind === SyntaxKind.TupleType && + some( + node.elements, + (e) => + !!(getTupleElementFlags(e) & ElementFlags.Variadic) + ) + ) && + isDeferredTypeReferenceNode(node) + ) { + links.resolvedType = + node.kind === SyntaxKind.TupleType && + node.elements.length === 0 + ? target + : createDeferredTypeReference( + target, + node, + /*mapper*/ undefined + ); + } else { + const elementTypes = + node.kind === SyntaxKind.ArrayType + ? [getTypeFromTypeNode(node.elementType)] + : map(node.elements, getTypeFromTypeNode); + links.resolvedType = createNormalizedTypeReference( + target, + elementTypes + ); } } return links.resolvedType; } function isReadonlyTypeOperator(node: Node) { - return isTypeOperatorNode(node) && node.operator === SyntaxKind.ReadonlyKeyword; - } - - function createTupleType(elementTypes: readonly Type[], elementFlags?: readonly ElementFlags[], readonly = false, namedMemberDeclarations: readonly (NamedTupleMember | ParameterDeclaration | undefined)[] = []) { - const tupleTarget = getTupleTargetType(elementFlags || map(elementTypes, _ => ElementFlags.Required), readonly, namedMemberDeclarations); - return tupleTarget === emptyGenericType ? emptyObjectType : - elementTypes.length ? createNormalizedTypeReference(tupleTarget, elementTypes) : - tupleTarget; + return ( + isTypeOperatorNode(node) && + node.operator === SyntaxKind.ReadonlyKeyword + ); } - function getTupleTargetType(elementFlags: readonly ElementFlags[], readonly: boolean, namedMemberDeclarations: readonly (NamedTupleMember | ParameterDeclaration | undefined)[]): GenericType { + function createTupleType( + elementTypes: readonly Type[], + elementFlags?: readonly ElementFlags[], + readonly = false, + namedMemberDeclarations: readonly ( + | NamedTupleMember + | ParameterDeclaration + | undefined + )[] = [] + ) { + const tupleTarget = getTupleTargetType( + elementFlags || map(elementTypes, (_) => ElementFlags.Required), + readonly, + namedMemberDeclarations + ); + return tupleTarget === emptyGenericType + ? emptyObjectType + : elementTypes.length + ? createNormalizedTypeReference(tupleTarget, elementTypes) + : tupleTarget; + } + + function getTupleTargetType( + elementFlags: readonly ElementFlags[], + readonly: boolean, + namedMemberDeclarations: readonly ( + | NamedTupleMember + | ParameterDeclaration + | undefined + )[] + ): GenericType { if (elementFlags.length === 1 && elementFlags[0] & ElementFlags.Rest) { // [...X[]] is equivalent to just X[] return readonly ? globalReadonlyArrayType : globalArrayType; } - const key = map(elementFlags, f => f & ElementFlags.Required ? "#" : f & ElementFlags.Optional ? "?" : f & ElementFlags.Rest ? "." : "*").join() + + const key = + map(elementFlags, (f) => + f & ElementFlags.Required + ? "#" + : f & ElementFlags.Optional + ? "?" + : f & ElementFlags.Rest + ? "." + : "*" + ).join() + (readonly ? "R" : "") + - (some(namedMemberDeclarations, node => !!node) ? "," + map(namedMemberDeclarations, node => node ? getNodeId(node) : "_").join(",") : ""); + (some(namedMemberDeclarations, (node) => !!node) + ? "," + + map(namedMemberDeclarations, (node) => + node ? getNodeId(node) : "_" + ).join(",") + : ""); let type = tupleTypes.get(key); if (!type) { - tupleTypes.set(key, type = createTupleTargetType(elementFlags, readonly, namedMemberDeclarations)); + tupleTypes.set( + key, + (type = createTupleTargetType( + elementFlags, + readonly, + namedMemberDeclarations + )) + ); } return type; } @@ -17729,43 +30920,72 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // // Note that the generic type created by this function has no symbol associated with it. The same // is true for each of the synthesized type parameters. - function createTupleTargetType(elementFlags: readonly ElementFlags[], readonly: boolean, namedMemberDeclarations: readonly (NamedTupleMember | ParameterDeclaration | undefined)[]): TupleType { + function createTupleTargetType( + elementFlags: readonly ElementFlags[], + readonly: boolean, + namedMemberDeclarations: readonly ( + | NamedTupleMember + | ParameterDeclaration + | undefined + )[] + ): TupleType { const arity = elementFlags.length; - const minLength = countWhere(elementFlags, f => !!(f & (ElementFlags.Required | ElementFlags.Variadic))); + const minLength = countWhere( + elementFlags, + (f) => !!(f & (ElementFlags.Required | ElementFlags.Variadic)) + ); let typeParameters: TypeParameter[] | undefined; const properties: Symbol[] = []; let combinedFlags = 0 as ElementFlags; if (arity) { typeParameters = new Array(arity); for (let i = 0; i < arity; i++) { - const typeParameter = typeParameters[i] = createTypeParameter(); + const typeParameter = (typeParameters[i] = + createTypeParameter()); const flags = elementFlags[i]; combinedFlags |= flags; if (!(combinedFlags & ElementFlags.Variable)) { - const property = createSymbol(SymbolFlags.Property | (flags & ElementFlags.Optional ? SymbolFlags.Optional : 0), "" + i as __String, readonly ? CheckFlags.Readonly : 0); - property.links.tupleLabelDeclaration = namedMemberDeclarations?.[i]; + const property = createSymbol( + SymbolFlags.Property | + (flags & ElementFlags.Optional + ? SymbolFlags.Optional + : 0), + ("" + i) as __String, + readonly ? CheckFlags.Readonly : 0 + ); + property.links.tupleLabelDeclaration = + namedMemberDeclarations?.[i]; property.links.type = typeParameter; properties.push(property); } } } const fixedLength = properties.length; - const lengthSymbol = createSymbol(SymbolFlags.Property, "length" as __String, readonly ? CheckFlags.Readonly : 0); + const lengthSymbol = createSymbol( + SymbolFlags.Property, + "length" as __String, + readonly ? CheckFlags.Readonly : 0 + ); if (combinedFlags & ElementFlags.Variable) { lengthSymbol.links.type = numberType; - } - else { + } else { const literalTypes = []; - for (let i = minLength; i <= arity; i++) literalTypes.push(getNumberLiteralType(i)); + for (let i = minLength; i <= arity; i++) + literalTypes.push(getNumberLiteralType(i)); lengthSymbol.links.type = getUnionType(literalTypes); } properties.push(lengthSymbol); - const type = createObjectType(ObjectFlags.Tuple | ObjectFlags.Reference) as TupleType & InterfaceTypeWithDeclaredMembers; + const type = createObjectType( + ObjectFlags.Tuple | ObjectFlags.Reference + ) as TupleType & InterfaceTypeWithDeclaredMembers; type.typeParameters = typeParameters; type.outerTypeParameters = undefined; type.localTypeParameters = typeParameters; type.instantiations = new Map(); - type.instantiations.set(getTypeListId(type.typeParameters), type as GenericType); + type.instantiations.set( + getTypeListId(type.typeParameters), + type as GenericType + ); type.target = type as GenericType; type.resolvedTypeArguments = type.typeParameters; type.thisType = createTypeParameter(); @@ -17785,22 +31005,48 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return type; } - function createNormalizedTypeReference(target: GenericType, typeArguments: readonly Type[] | undefined) { - return target.objectFlags & ObjectFlags.Tuple ? createNormalizedTupleType(target as TupleType, typeArguments!) : createTypeReference(target, typeArguments); + function createNormalizedTypeReference( + target: GenericType, + typeArguments: readonly Type[] | undefined + ) { + return target.objectFlags & ObjectFlags.Tuple + ? createNormalizedTupleType(target as TupleType, typeArguments!) + : createTypeReference(target, typeArguments); } - function createNormalizedTupleType(target: TupleType, elementTypes: readonly Type[]): Type { + function createNormalizedTupleType( + target: TupleType, + elementTypes: readonly Type[] + ): Type { if (!(target.combinedFlags & ElementFlags.NonRequired)) { // No need to normalize when we only have regular required elements return createTypeReference(target, elementTypes); } if (target.combinedFlags & ElementFlags.Variadic) { // Transform [A, ...(X | Y | Z)] into [A, ...X] | [A, ...Y] | [A, ...Z] - const unionIndex = findIndex(elementTypes, (t, i) => !!(target.elementFlags[i] & ElementFlags.Variadic && t.flags & (TypeFlags.Never | TypeFlags.Union))); + const unionIndex = findIndex( + elementTypes, + (t, i) => + !!( + target.elementFlags[i] & ElementFlags.Variadic && + t.flags & (TypeFlags.Never | TypeFlags.Union) + ) + ); if (unionIndex >= 0) { - return checkCrossProductUnion(map(elementTypes, (t, i) => target.elementFlags[i] & ElementFlags.Variadic ? t : unknownType)) ? - mapType(elementTypes[unionIndex], t => createNormalizedTupleType(target, replaceElement(elementTypes, unionIndex, t))) : - errorType; + return checkCrossProductUnion( + map(elementTypes, (t, i) => + target.elementFlags[i] & ElementFlags.Variadic + ? t + : unknownType + ) + ) + ? mapType(elementTypes[unionIndex], (t) => + createNormalizedTupleType( + target, + replaceElement(elementTypes, unionIndex, t) + ) + ) + : errorType; } } // We have optional, rest, or variadic elements that may need normalizing. Normalization ensures that all variadic @@ -17810,7 +31056,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // In either layout, zero or more generic variadic elements may be present at any location. const expandedTypes: Type[] = []; const expandedFlags: ElementFlags[] = []; - const expandedDeclarations: (NamedTupleMember | ParameterDeclaration | undefined)[] = []; + const expandedDeclarations: ( + | NamedTupleMember + | ParameterDeclaration + | undefined + )[] = []; let lastRequiredIndex = -1; let firstRestIndex = -1; let lastOptionalOrRestIndex = -1; @@ -17819,53 +31069,104 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const flags = target.elementFlags[i]; if (flags & ElementFlags.Variadic) { if (type.flags & TypeFlags.Any) { - addElement(type, ElementFlags.Rest, target.labeledElementDeclarations?.[i]); - } - else if (type.flags & TypeFlags.InstantiableNonPrimitive || isGenericMappedType(type)) { + addElement( + type, + ElementFlags.Rest, + target.labeledElementDeclarations?.[i] + ); + } else if ( + type.flags & TypeFlags.InstantiableNonPrimitive || + isGenericMappedType(type) + ) { // Generic variadic elements stay as they are. - addElement(type, ElementFlags.Variadic, target.labeledElementDeclarations?.[i]); - } - else if (isTupleType(type)) { + addElement( + type, + ElementFlags.Variadic, + target.labeledElementDeclarations?.[i] + ); + } else if (isTupleType(type)) { const elements = getElementTypes(type); if (elements.length + expandedTypes.length >= 10_000) { error( currentNode, isPartOfTypeNode(currentNode!) ? Diagnostics.Type_produces_a_tuple_type_that_is_too_large_to_represent - : Diagnostics.Expression_produces_a_tuple_type_that_is_too_large_to_represent, + : Diagnostics.Expression_produces_a_tuple_type_that_is_too_large_to_represent ); return errorType; } // Spread variadic elements with tuple types into the resulting tuple. - forEach(elements, (t, n) => addElement(t, type.target.elementFlags[n], type.target.labeledElementDeclarations?.[n])); - } - else { + forEach(elements, (t, n) => + addElement( + t, + type.target.elementFlags[n], + type.target.labeledElementDeclarations?.[n] + ) + ); + } else { // Treat everything else as an array type and create a rest element. - addElement(isArrayLikeType(type) && getIndexTypeOfType(type, numberType) || errorType, ElementFlags.Rest, target.labeledElementDeclarations?.[i]); + addElement( + (isArrayLikeType(type) && + getIndexTypeOfType(type, numberType)) || + errorType, + ElementFlags.Rest, + target.labeledElementDeclarations?.[i] + ); } - } - else { + } else { // Copy other element kinds with no change. addElement(type, flags, target.labeledElementDeclarations?.[i]); } } // Turn optional elements preceding the last required element into required elements for (let i = 0; i < lastRequiredIndex; i++) { - if (expandedFlags[i] & ElementFlags.Optional) expandedFlags[i] = ElementFlags.Required; + if (expandedFlags[i] & ElementFlags.Optional) + expandedFlags[i] = ElementFlags.Required; } if (firstRestIndex >= 0 && firstRestIndex < lastOptionalOrRestIndex) { // Turn elements between first rest and last optional/rest into a single rest element - expandedTypes[firstRestIndex] = getUnionType(sameMap(expandedTypes.slice(firstRestIndex, lastOptionalOrRestIndex + 1), (t, i) => expandedFlags[firstRestIndex + i] & ElementFlags.Variadic ? getIndexedAccessType(t, numberType) : t)); - expandedTypes.splice(firstRestIndex + 1, lastOptionalOrRestIndex - firstRestIndex); - expandedFlags.splice(firstRestIndex + 1, lastOptionalOrRestIndex - firstRestIndex); - expandedDeclarations.splice(firstRestIndex + 1, lastOptionalOrRestIndex - firstRestIndex); + expandedTypes[firstRestIndex] = getUnionType( + sameMap( + expandedTypes.slice( + firstRestIndex, + lastOptionalOrRestIndex + 1 + ), + (t, i) => + expandedFlags[firstRestIndex + i] & + ElementFlags.Variadic + ? getIndexedAccessType(t, numberType) + : t + ) + ); + expandedTypes.splice( + firstRestIndex + 1, + lastOptionalOrRestIndex - firstRestIndex + ); + expandedFlags.splice( + firstRestIndex + 1, + lastOptionalOrRestIndex - firstRestIndex + ); + expandedDeclarations.splice( + firstRestIndex + 1, + lastOptionalOrRestIndex - firstRestIndex + ); } - const tupleTarget = getTupleTargetType(expandedFlags, target.readonly, expandedDeclarations); - return tupleTarget === emptyGenericType ? emptyObjectType : - expandedFlags.length ? createTypeReference(tupleTarget, expandedTypes) : - tupleTarget; - - function addElement(type: Type, flags: ElementFlags, declaration: NamedTupleMember | ParameterDeclaration | undefined) { + const tupleTarget = getTupleTargetType( + expandedFlags, + target.readonly, + expandedDeclarations + ); + return tupleTarget === emptyGenericType + ? emptyObjectType + : expandedFlags.length + ? createTypeReference(tupleTarget, expandedTypes) + : tupleTarget; + + function addElement( + type: Type, + flags: ElementFlags, + declaration: NamedTupleMember | ParameterDeclaration | undefined + ) { if (flags & ElementFlags.Required) { lastRequiredIndex = expandedFlags.length; } @@ -17875,32 +31176,62 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (flags & (ElementFlags.Optional | ElementFlags.Rest)) { lastOptionalOrRestIndex = expandedFlags.length; } - expandedTypes.push(flags & ElementFlags.Optional ? addOptionality(type, /*isProperty*/ true) : type); + expandedTypes.push( + flags & ElementFlags.Optional + ? addOptionality(type, /*isProperty*/ true) + : type + ); expandedFlags.push(flags); expandedDeclarations.push(declaration); } } - function sliceTupleType(type: TupleTypeReference, index: number, endSkipCount = 0) { + function sliceTupleType( + type: TupleTypeReference, + index: number, + endSkipCount = 0 + ) { const target = type.target; const endIndex = getTypeReferenceArity(type) - endSkipCount; - return index > target.fixedLength ? getRestArrayTypeOfTupleType(type) || createTupleType(emptyArray) : - createTupleType(getTypeArguments(type).slice(index, endIndex), target.elementFlags.slice(index, endIndex), /*readonly*/ false, target.labeledElementDeclarations && target.labeledElementDeclarations.slice(index, endIndex)); + return index > target.fixedLength + ? getRestArrayTypeOfTupleType(type) || createTupleType(emptyArray) + : createTupleType( + getTypeArguments(type).slice(index, endIndex), + target.elementFlags.slice(index, endIndex), + /*readonly*/ false, + target.labeledElementDeclarations && + target.labeledElementDeclarations.slice(index, endIndex) + ); } function getKnownKeysOfTupleType(type: TupleTypeReference) { - return getUnionType(append(arrayOf(type.target.fixedLength, i => getStringLiteralType("" + i)), getIndexType(type.target.readonly ? globalReadonlyArrayType : globalArrayType))); + return getUnionType( + append( + arrayOf(type.target.fixedLength, (i) => + getStringLiteralType("" + i) + ), + getIndexType( + type.target.readonly + ? globalReadonlyArrayType + : globalArrayType + ) + ) + ); } // Return count of starting consecutive tuple elements of the given kind(s) function getStartElementCount(type: TupleType, flags: ElementFlags) { - const index = findIndex(type.elementFlags, f => !(f & flags)); + const index = findIndex(type.elementFlags, (f) => !(f & flags)); return index >= 0 ? index : type.elementFlags.length; } // Return count of ending consecutive tuple elements of the given kind(s) function getEndElementCount(type: TupleType, flags: ElementFlags) { - return type.elementFlags.length - findLastIndex(type.elementFlags, f => !(f & flags)) - 1; + return ( + type.elementFlags.length - + findLastIndex(type.elementFlags, (f) => !(f & flags)) - + 1 + ); } function getTotalFixedElementCount(type: TupleType) { @@ -17910,11 +31241,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getElementTypes(type: TupleTypeReference): readonly Type[] { const typeArguments = getTypeArguments(type); const arity = getTypeReferenceArity(type); - return typeArguments.length === arity ? typeArguments : typeArguments.slice(0, arity); + return typeArguments.length === arity + ? typeArguments + : typeArguments.slice(0, arity); } function getTypeFromOptionalTypeNode(node: OptionalTypeNode): Type { - return addOptionality(getTypeFromTypeNode(node.type), /*isProperty*/ true); + return addOptionality( + getTypeFromTypeNode(node.type), + /*isProperty*/ true + ); } function getTypeId(type: Type): TypeId { @@ -17939,16 +31275,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We ignore 'never' types in unions if (!(flags & TypeFlags.Never)) { includes |= flags & TypeFlags.IncludesMask; - if (flags & TypeFlags.Instantiable) includes |= TypeFlags.IncludesInstantiable; - if (flags & TypeFlags.Intersection && getObjectFlags(type) & ObjectFlags.IsConstrainedTypeVariable) includes |= TypeFlags.IncludesConstrainedTypeVariable; + if (flags & TypeFlags.Instantiable) + includes |= TypeFlags.IncludesInstantiable; + if ( + flags & TypeFlags.Intersection && + getObjectFlags(type) & ObjectFlags.IsConstrainedTypeVariable + ) + includes |= TypeFlags.IncludesConstrainedTypeVariable; if (type === wildcardType) includes |= TypeFlags.IncludesWildcard; if (isErrorType(type)) includes |= TypeFlags.IncludesError; if (!strictNullChecks && flags & TypeFlags.Nullable) { - if (!(getObjectFlags(type) & ObjectFlags.ContainsWideningType)) includes |= TypeFlags.IncludesNonWideningType; - } - else { + if (!(getObjectFlags(type) & ObjectFlags.ContainsWideningType)) + includes |= TypeFlags.IncludesNonWideningType; + } else { const len = typeSet.length; - const index = len && type.id > typeSet[len - 1].id ? ~len : binarySearch(typeSet, type, getTypeId, compareValues); + const index = + len && type.id > typeSet[len - 1].id + ? ~len + : binarySearch(typeSet, type, getTypeId, compareValues); if (index < 0) { typeSet.splice(~index, 0, type); } @@ -17959,23 +31303,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Add the given types to the given type set. Order is preserved, duplicates are removed, // and nested types of the given kind are flattened into the set. - function addTypesToUnion(typeSet: Type[], includes: TypeFlags, types: readonly Type[]): TypeFlags { + function addTypesToUnion( + typeSet: Type[], + includes: TypeFlags, + types: readonly Type[] + ): TypeFlags { let lastType: Type | undefined; for (const type of types) { // We skip the type if it is the same as the last type we processed. This simple test particularly // saves a lot of work for large lists of the same union type, such as when resolving `Record[A]`, // where A and B are large union types. if (type !== lastType) { - includes = type.flags & TypeFlags.Union ? - addTypesToUnion(typeSet, includes | (isNamedUnionType(type) ? TypeFlags.Union : 0), (type as UnionType).types) : - addTypeToUnion(typeSet, includes, type); + includes = + type.flags & TypeFlags.Union + ? addTypesToUnion( + typeSet, + includes | + (isNamedUnionType(type) + ? TypeFlags.Union + : 0), + (type as UnionType).types + ) + : addTypeToUnion(typeSet, includes, type); lastType = type; } } return includes; } - function removeSubtypes(types: Type[], hasObjectTypes: boolean): Type[] | undefined { + function removeSubtypes( + types: Type[], + hasObjectTypes: boolean + ): Type[] | undefined { // [] and [T] immediately reduce to [] and [T] respectively if (types.length < 2) { return types; @@ -17990,20 +31349,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We assume that redundant primitive types have already been removed from the types array and that there // are no any and unknown types in the array. Thus, the only possible supertypes for primitive types are empty // object types, and if none of those are present we can exclude primitive types from the subtype check. - const hasEmptyObject = hasObjectTypes && some(types, t => !!(t.flags & TypeFlags.Object) && !isGenericMappedType(t) && isEmptyResolvedType(resolveStructuredTypeMembers(t as ObjectType))); + const hasEmptyObject = + hasObjectTypes && + some( + types, + (t) => + !!(t.flags & TypeFlags.Object) && + !isGenericMappedType(t) && + isEmptyResolvedType( + resolveStructuredTypeMembers(t as ObjectType) + ) + ); const len = types.length; let i = len; let count = 0; while (i > 0) { i--; const source = types[i]; - if (hasEmptyObject || source.flags & TypeFlags.StructuredOrInstantiable) { + if ( + hasEmptyObject || + source.flags & TypeFlags.StructuredOrInstantiable + ) { // A type parameter with a union constraint may be a subtype of some union, but not a subtype of the // individual constituents of that union. For example, `T extends A | B` is a subtype of `A | B`, but not // a subtype of just `A` or just `B`. When we encounter such a type parameter, we therefore check if the // type parameter is a subtype of a union of all the other types. - if (source.flags & TypeFlags.TypeParameter && getBaseConstraintOrType(source).flags & TypeFlags.Union) { - if (isTypeRelatedTo(source, getUnionType(map(types, t => t === source ? neverType : t)), strictSubtypeRelation)) { + if ( + source.flags & TypeFlags.TypeParameter && + getBaseConstraintOrType(source).flags & TypeFlags.Union + ) { + if ( + isTypeRelatedTo( + source, + getUnionType( + map(types, (t) => + t === source ? neverType : t + ) + ), + strictSubtypeRelation + ) + ) { orderedRemoveItemAt(types, i); } continue; @@ -18011,10 +31396,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Find the first property with a unit type, if any. When constituents have a property by the same name // but of a different unit type, we can quickly disqualify them from subtype checks. This helps subtype // reduction of large discriminated union types. - const keyProperty = source.flags & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.InstantiableNonPrimitive) ? - find(getPropertiesOfType(source), p => isUnitType(getTypeOfSymbol(p))) : - undefined; - const keyPropertyType = keyProperty && getRegularTypeOfLiteralType(getTypeOfSymbol(keyProperty)); + const keyProperty = + source.flags & + (TypeFlags.Object | + TypeFlags.Intersection | + TypeFlags.InstantiableNonPrimitive) + ? find(getPropertiesOfType(source), (p) => + isUnitType(getTypeOfSymbol(p)) + ) + : undefined; + const keyPropertyType = + keyProperty && + getRegularTypeOfLiteralType(getTypeOfSymbol(keyProperty)); for (const target of types) { if (source !== target) { if (count === 100000) { @@ -18024,24 +31417,54 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // caps union types at 1000 unique object types. const estimatedCount = (count / (len - i)) * len; if (estimatedCount > 1000000) { - tracing?.instant(tracing.Phase.CheckTypes, "removeSubtypes_DepthLimit", { typeIds: types.map(t => t.id) }); - error(currentNode, Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent); + tracing?.instant( + tracing.Phase.CheckTypes, + "removeSubtypes_DepthLimit", + { typeIds: types.map((t) => t.id) } + ); + error( + currentNode, + Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent + ); return undefined; } } count++; - if (keyProperty && target.flags & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.InstantiableNonPrimitive)) { - const t = getTypeOfPropertyOfType(target, keyProperty.escapedName); - if (t && isUnitType(t) && getRegularTypeOfLiteralType(t) !== keyPropertyType) { + if ( + keyProperty && + target.flags & + (TypeFlags.Object | + TypeFlags.Intersection | + TypeFlags.InstantiableNonPrimitive) + ) { + const t = getTypeOfPropertyOfType( + target, + keyProperty.escapedName + ); + if ( + t && + isUnitType(t) && + getRegularTypeOfLiteralType(t) !== + keyPropertyType + ) { continue; } } if ( - isTypeRelatedTo(source, target, strictSubtypeRelation) && ( - !(getObjectFlags(getTargetType(source)) & ObjectFlags.Class) || - !(getObjectFlags(getTargetType(target)) & ObjectFlags.Class) || - isTypeDerivedFrom(source, target) - ) + isTypeRelatedTo( + source, + target, + strictSubtypeRelation + ) && + (!( + getObjectFlags(getTargetType(source)) & + ObjectFlags.Class + ) || + !( + getObjectFlags(getTargetType(target)) & + ObjectFlags.Class + ) || + isTypeDerivedFrom(source, target)) ) { orderedRemoveItemAt(types, i); break; @@ -18054,18 +31477,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return types; } - function removeRedundantLiteralTypes(types: Type[], includes: TypeFlags, reduceVoidUndefined: boolean) { + function removeRedundantLiteralTypes( + types: Type[], + includes: TypeFlags, + reduceVoidUndefined: boolean + ) { let i = types.length; while (i > 0) { i--; const t = types[i]; const flags = t.flags; - const remove = flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) && includes & TypeFlags.String || - flags & TypeFlags.NumberLiteral && includes & TypeFlags.Number || - flags & TypeFlags.BigIntLiteral && includes & TypeFlags.BigInt || - flags & TypeFlags.UniqueESSymbol && includes & TypeFlags.ESSymbol || - reduceVoidUndefined && flags & TypeFlags.Undefined && includes & TypeFlags.Void || - isFreshLiteralType(t) && containsType(types, (t as LiteralType).regularType); + const remove = + (flags & + (TypeFlags.StringLiteral | + TypeFlags.TemplateLiteral | + TypeFlags.StringMapping) && + includes & TypeFlags.String) || + (flags & TypeFlags.NumberLiteral && + includes & TypeFlags.Number) || + (flags & TypeFlags.BigIntLiteral && + includes & TypeFlags.BigInt) || + (flags & TypeFlags.UniqueESSymbol && + includes & TypeFlags.ESSymbol) || + (reduceVoidUndefined && + flags & TypeFlags.Undefined && + includes & TypeFlags.Void) || + (isFreshLiteralType(t) && + containsType(types, (t as LiteralType).regularType)); if (remove) { orderedRemoveItemAt(types, i); } @@ -18073,32 +31511,59 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function removeStringLiteralsMatchedByTemplateLiterals(types: Type[]) { - const templates = filter(types, isPatternLiteralType) as (TemplateLiteralType | StringMappingType)[]; + const templates = filter(types, isPatternLiteralType) as ( + | TemplateLiteralType + | StringMappingType + )[]; if (templates.length) { let i = types.length; while (i > 0) { i--; const t = types[i]; - if (t.flags & TypeFlags.StringLiteral && some(templates, template => isTypeMatchedByTemplateLiteralOrStringMapping(t, template))) { + if ( + t.flags & TypeFlags.StringLiteral && + some(templates, (template) => + isTypeMatchedByTemplateLiteralOrStringMapping( + t, + template + ) + ) + ) { orderedRemoveItemAt(types, i); } } } } - function isTypeMatchedByTemplateLiteralOrStringMapping(type: Type, template: TemplateLiteralType | StringMappingType) { - return template.flags & TypeFlags.TemplateLiteral ? - isTypeMatchedByTemplateLiteralType(type, template as TemplateLiteralType) : - isMemberOfStringMapping(type, template); + function isTypeMatchedByTemplateLiteralOrStringMapping( + type: Type, + template: TemplateLiteralType | StringMappingType + ) { + return template.flags & TypeFlags.TemplateLiteral + ? isTypeMatchedByTemplateLiteralType( + type, + template as TemplateLiteralType + ) + : isMemberOfStringMapping(type, template); } function removeConstrainedTypeVariables(types: Type[]) { const typeVariables: TypeVariable[] = []; // First collect a list of the type variables occurring in constraining intersections. for (const type of types) { - if (type.flags & TypeFlags.Intersection && getObjectFlags(type) & ObjectFlags.IsConstrainedTypeVariable) { - const index = (type as IntersectionType).types[0].flags & TypeFlags.TypeVariable ? 0 : 1; - pushIfUnique(typeVariables, (type as IntersectionType).types[index]); + if ( + type.flags & TypeFlags.Intersection && + getObjectFlags(type) & ObjectFlags.IsConstrainedTypeVariable + ) { + const index = + (type as IntersectionType).types[0].flags & + TypeFlags.TypeVariable + ? 0 + : 1; + pushIfUnique( + typeVariables, + (type as IntersectionType).types[index] + ); } } // For each type variable, check if the constraining intersections for that type variable fully @@ -18108,24 +31573,51 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const primitives: Type[] = []; // First collect the primitive types from the constraining intersections. for (const type of types) { - if (type.flags & TypeFlags.Intersection && getObjectFlags(type) & ObjectFlags.IsConstrainedTypeVariable) { - const index = (type as IntersectionType).types[0].flags & TypeFlags.TypeVariable ? 0 : 1; - if ((type as IntersectionType).types[index] === typeVariable) { - insertType(primitives, (type as IntersectionType).types[1 - index]); + if ( + type.flags & TypeFlags.Intersection && + getObjectFlags(type) & ObjectFlags.IsConstrainedTypeVariable + ) { + const index = + (type as IntersectionType).types[0].flags & + TypeFlags.TypeVariable + ? 0 + : 1; + if ( + (type as IntersectionType).types[index] === typeVariable + ) { + insertType( + primitives, + (type as IntersectionType).types[1 - index] + ); } } } // If every constituent in the type variable's constraint is covered by an intersection of the type // variable and that constituent, remove those intersections and substitute the type variable. const constraint = getBaseConstraintOfType(typeVariable)!; - if (everyType(constraint, t => containsType(primitives, t))) { + if (everyType(constraint, (t) => containsType(primitives, t))) { let i = types.length; while (i > 0) { i--; const type = types[i]; - if (type.flags & TypeFlags.Intersection && getObjectFlags(type) & ObjectFlags.IsConstrainedTypeVariable) { - const index = (type as IntersectionType).types[0].flags & TypeFlags.TypeVariable ? 0 : 1; - if ((type as IntersectionType).types[index] === typeVariable && containsType(primitives, (type as IntersectionType).types[1 - index])) { + if ( + type.flags & TypeFlags.Intersection && + getObjectFlags(type) & + ObjectFlags.IsConstrainedTypeVariable + ) { + const index = + (type as IntersectionType).types[0].flags & + TypeFlags.TypeVariable + ? 0 + : 1; + if ( + (type as IntersectionType).types[index] === + typeVariable && + containsType( + primitives, + (type as IntersectionType).types[1 - index] + ) + ) { orderedRemoveItemAt(types, i); } } @@ -18136,24 +31628,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isNamedUnionType(type: Type) { - return !!(type.flags & TypeFlags.Union && (type.aliasSymbol || (type as UnionType).origin)); + return !!( + type.flags & TypeFlags.Union && + (type.aliasSymbol || (type as UnionType).origin) + ); } function addNamedUnions(namedUnions: Type[], types: readonly Type[]) { for (const t of types) { if (t.flags & TypeFlags.Union) { const origin = (t as UnionType).origin; - if (t.aliasSymbol || origin && !(origin.flags & TypeFlags.Union)) { + if ( + t.aliasSymbol || + (origin && !(origin.flags & TypeFlags.Union)) + ) { pushIfUnique(namedUnions, t); - } - else if (origin && origin.flags & TypeFlags.Union) { + } else if (origin && origin.flags & TypeFlags.Union) { addNamedUnions(namedUnions, (origin as UnionType).types); } } } } - function createOriginUnionOrIntersectionType(flags: TypeFlags, types: Type[]) { + function createOriginUnionOrIntersectionType( + flags: TypeFlags, + types: Type[] + ) { const result = createOriginType(flags) as UnionOrIntersectionType; result.types = types; return result; @@ -18166,7 +31666,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // expression constructs such as array literals and the || and ?: operators). Named types can // circularly reference themselves and therefore cannot be subtype reduced during their declaration. // For example, "type Item = string | (() => Item)" is a named type that circularly references itself. - function getUnionType(types: readonly Type[], unionReduction: UnionReduction = UnionReduction.Literal, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[], origin?: Type): Type { + function getUnionType( + types: readonly Type[], + unionReduction: UnionReduction = UnionReduction.Literal, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[], + origin?: Type + ): Type { if (types.length === 0) { return neverType; } @@ -18174,55 +31680,118 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return types[0]; } // We optimize for the common case of unioning a union type with some other type (such as `undefined`). - if (types.length === 2 && !origin && (types[0].flags & TypeFlags.Union || types[1].flags & TypeFlags.Union)) { - const infix = unionReduction === UnionReduction.None ? "N" : unionReduction === UnionReduction.Subtype ? "S" : "L"; + if ( + types.length === 2 && + !origin && + (types[0].flags & TypeFlags.Union || + types[1].flags & TypeFlags.Union) + ) { + const infix = + unionReduction === UnionReduction.None + ? "N" + : unionReduction === UnionReduction.Subtype + ? "S" + : "L"; const index = types[0].id < types[1].id ? 0 : 1; - const id = types[index].id + infix + types[1 - index].id + getAliasId(aliasSymbol, aliasTypeArguments); + const id = + types[index].id + + infix + + types[1 - index].id + + getAliasId(aliasSymbol, aliasTypeArguments); let type = unionOfUnionTypes.get(id); if (!type) { - type = getUnionTypeWorker(types, unionReduction, aliasSymbol, aliasTypeArguments, /*origin*/ undefined); + type = getUnionTypeWorker( + types, + unionReduction, + aliasSymbol, + aliasTypeArguments, + /*origin*/ undefined + ); unionOfUnionTypes.set(id, type); } return type; } - return getUnionTypeWorker(types, unionReduction, aliasSymbol, aliasTypeArguments, origin); + return getUnionTypeWorker( + types, + unionReduction, + aliasSymbol, + aliasTypeArguments, + origin + ); } - function getUnionTypeWorker(types: readonly Type[], unionReduction: UnionReduction, aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined, origin: Type | undefined): Type { + function getUnionTypeWorker( + types: readonly Type[], + unionReduction: UnionReduction, + aliasSymbol: Symbol | undefined, + aliasTypeArguments: readonly Type[] | undefined, + origin: Type | undefined + ): Type { let typeSet: Type[] | undefined = []; const includes = addTypesToUnion(typeSet, 0 as TypeFlags, types); if (unionReduction !== UnionReduction.None) { if (includes & TypeFlags.AnyOrUnknown) { - return includes & TypeFlags.Any ? - includes & TypeFlags.IncludesWildcard ? wildcardType : - includes & TypeFlags.IncludesError ? errorType : anyType : - unknownType; + return includes & TypeFlags.Any + ? includes & TypeFlags.IncludesWildcard + ? wildcardType + : includes & TypeFlags.IncludesError + ? errorType + : anyType + : unknownType; } if (includes & TypeFlags.Undefined) { // If type set contains both undefinedType and missingType, remove missingType - if (typeSet.length >= 2 && typeSet[0] === undefinedType && typeSet[1] === missingType) { + if ( + typeSet.length >= 2 && + typeSet[0] === undefinedType && + typeSet[1] === missingType + ) { orderedRemoveItemAt(typeSet, 1); } } - if (includes & (TypeFlags.Enum | TypeFlags.Literal | TypeFlags.UniqueESSymbol | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) || includes & TypeFlags.Void && includes & TypeFlags.Undefined) { - removeRedundantLiteralTypes(typeSet, includes, !!(unionReduction & UnionReduction.Subtype)); + if ( + includes & + (TypeFlags.Enum | + TypeFlags.Literal | + TypeFlags.UniqueESSymbol | + TypeFlags.TemplateLiteral | + TypeFlags.StringMapping) || + (includes & TypeFlags.Void && includes & TypeFlags.Undefined) + ) { + removeRedundantLiteralTypes( + typeSet, + includes, + !!(unionReduction & UnionReduction.Subtype) + ); } - if (includes & TypeFlags.StringLiteral && includes & (TypeFlags.TemplateLiteral | TypeFlags.StringMapping)) { + if ( + includes & TypeFlags.StringLiteral && + includes & (TypeFlags.TemplateLiteral | TypeFlags.StringMapping) + ) { removeStringLiteralsMatchedByTemplateLiterals(typeSet); } if (includes & TypeFlags.IncludesConstrainedTypeVariable) { removeConstrainedTypeVariables(typeSet); } if (unionReduction === UnionReduction.Subtype) { - typeSet = removeSubtypes(typeSet, !!(includes & TypeFlags.Object)); + typeSet = removeSubtypes( + typeSet, + !!(includes & TypeFlags.Object) + ); if (!typeSet) { return errorType; } } if (typeSet.length === 0) { - return includes & TypeFlags.Null ? includes & TypeFlags.IncludesNonWideningType ? nullType : nullWideningType : - includes & TypeFlags.Undefined ? includes & TypeFlags.IncludesNonWideningType ? undefinedType : undefinedWideningType : - neverType; + return includes & TypeFlags.Null + ? includes & TypeFlags.IncludesNonWideningType + ? nullType + : nullWideningType + : includes & TypeFlags.Undefined + ? includes & TypeFlags.IncludesNonWideningType + ? undefinedType + : undefinedWideningType + : neverType; } } if (!origin && includes & TypeFlags.Union) { @@ -18230,45 +31799,83 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { addNamedUnions(namedUnions, types); const reducedTypes: Type[] = []; for (const t of typeSet) { - if (!some(namedUnions, union => containsType((union as UnionType).types, t))) { + if ( + !some(namedUnions, (union) => + containsType((union as UnionType).types, t) + ) + ) { reducedTypes.push(t); } } - if (!aliasSymbol && namedUnions.length === 1 && reducedTypes.length === 0) { + if ( + !aliasSymbol && + namedUnions.length === 1 && + reducedTypes.length === 0 + ) { return namedUnions[0]; } // We create a denormalized origin type only when the union was created from one or more named unions // (unions with alias symbols or origins) and when there is no overlap between those named unions. - const namedTypesCount = reduceLeft(namedUnions, (sum, union) => sum + (union as UnionType).types.length, 0); + const namedTypesCount = reduceLeft( + namedUnions, + (sum, union) => sum + (union as UnionType).types.length, + 0 + ); if (namedTypesCount + reducedTypes.length === typeSet.length) { for (const t of namedUnions) { insertType(reducedTypes, t); } - origin = createOriginUnionOrIntersectionType(TypeFlags.Union, reducedTypes); + origin = createOriginUnionOrIntersectionType( + TypeFlags.Union, + reducedTypes + ); } } - const objectFlags = (includes & TypeFlags.NotPrimitiveUnion ? 0 : ObjectFlags.PrimitiveUnion) | - (includes & TypeFlags.Intersection ? ObjectFlags.ContainsIntersections : 0); - return getUnionTypeFromSortedList(typeSet, objectFlags, aliasSymbol, aliasTypeArguments, origin); + const objectFlags = + (includes & TypeFlags.NotPrimitiveUnion + ? 0 + : ObjectFlags.PrimitiveUnion) | + (includes & TypeFlags.Intersection + ? ObjectFlags.ContainsIntersections + : 0); + return getUnionTypeFromSortedList( + typeSet, + objectFlags, + aliasSymbol, + aliasTypeArguments, + origin + ); } - function getUnionOrIntersectionTypePredicate(signatures: readonly Signature[], kind: TypeFlags | undefined): TypePredicate | undefined { + function getUnionOrIntersectionTypePredicate( + signatures: readonly Signature[], + kind: TypeFlags | undefined + ): TypePredicate | undefined { let last: TypePredicate | undefined; const types: Type[] = []; for (const sig of signatures) { const pred = getTypePredicateOfSignature(sig); if (pred) { // Constituent type predicates must all have matching kinds. We don't create composite type predicates for assertions. - if (pred.kind !== TypePredicateKind.This && pred.kind !== TypePredicateKind.Identifier || last && !typePredicateKindsMatch(last, pred)) { + if ( + (pred.kind !== TypePredicateKind.This && + pred.kind !== TypePredicateKind.Identifier) || + (last && !typePredicateKindsMatch(last, pred)) + ) { return undefined; } last = pred; types.push(pred.type); - } - else { + } else { // In composite union signatures we permit and ignore signatures with a return type `false`. - const returnType = kind !== TypeFlags.Intersection ? getReturnTypeOfSignature(sig) : undefined; - if (returnType !== falseType && returnType !== regularFalseType) { + const returnType = + kind !== TypeFlags.Intersection + ? getReturnTypeOfSignature(sig) + : undefined; + if ( + returnType !== falseType && + returnType !== regularFalseType + ) { return undefined; } } @@ -18277,35 +31884,61 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } const compositeType = getUnionOrIntersectionType(types, kind); - return createTypePredicate(last.kind, last.parameterName, last.parameterIndex, compositeType); + return createTypePredicate( + last.kind, + last.parameterName, + last.parameterIndex, + compositeType + ); } - function typePredicateKindsMatch(a: TypePredicate, b: TypePredicate): boolean { + function typePredicateKindsMatch( + a: TypePredicate, + b: TypePredicate + ): boolean { return a.kind === b.kind && a.parameterIndex === b.parameterIndex; } // This function assumes the constituent type list is sorted and deduplicated. - function getUnionTypeFromSortedList(types: Type[], precomputedObjectFlags: ObjectFlags, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[], origin?: Type): Type { + function getUnionTypeFromSortedList( + types: Type[], + precomputedObjectFlags: ObjectFlags, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[], + origin?: Type + ): Type { if (types.length === 0) { return neverType; } if (types.length === 1) { return types[0]; } - const typeKey = !origin ? getTypeListId(types) : - origin.flags & TypeFlags.Union ? `|${getTypeListId((origin as UnionType).types)}` : - origin.flags & TypeFlags.Intersection ? `&${getTypeListId((origin as IntersectionType).types)}` : - `#${(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 + const typeKey = !origin + ? getTypeListId(types) + : origin.flags & TypeFlags.Union + ? `|${getTypeListId((origin as UnionType).types)}` + : origin.flags & TypeFlags.Intersection + ? `&${getTypeListId((origin as IntersectionType).types)}` + : `#${(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 const id = typeKey + getAliasId(aliasSymbol, aliasTypeArguments); let type = unionTypes.get(id); if (!type) { type = createType(TypeFlags.Union) as UnionType; - type.objectFlags = precomputedObjectFlags | getPropagatingFlagsOfTypes(types, /*excludeKinds*/ TypeFlags.Nullable); + type.objectFlags = + precomputedObjectFlags | + getPropagatingFlagsOfTypes( + types, + /*excludeKinds*/ TypeFlags.Nullable + ); type.types = types; type.origin = origin; type.aliasSymbol = aliasSymbol; type.aliasTypeArguments = aliasTypeArguments; - if (types.length === 2 && types[0].flags & TypeFlags.BooleanLiteral && types[1].flags & TypeFlags.BooleanLiteral) { + if ( + types.length === 2 && + types[0].flags & TypeFlags.BooleanLiteral && + types[1].flags & TypeFlags.BooleanLiteral + ) { type.flags |= TypeFlags.Boolean; (type as UnionType & IntrinsicType).intrinsicName = "boolean"; } @@ -18318,34 +31951,49 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const links = getNodeLinks(node); if (!links.resolvedType) { const aliasSymbol = getAliasSymbolForTypeNode(node); - links.resolvedType = getUnionType(map(node.types, getTypeFromTypeNode), UnionReduction.Literal, aliasSymbol, getTypeArgumentsForAliasSymbol(aliasSymbol)); + links.resolvedType = getUnionType( + map(node.types, getTypeFromTypeNode), + UnionReduction.Literal, + aliasSymbol, + getTypeArgumentsForAliasSymbol(aliasSymbol) + ); } return links.resolvedType; } - function addTypeToIntersection(typeSet: Map, includes: TypeFlags, type: Type) { + function addTypeToIntersection( + typeSet: Map, + includes: TypeFlags, + type: Type + ) { const flags = type.flags; if (flags & TypeFlags.Intersection) { - return addTypesToIntersection(typeSet, includes, (type as IntersectionType).types); + return addTypesToIntersection( + typeSet, + includes, + (type as IntersectionType).types + ); } if (isEmptyAnonymousObjectType(type)) { if (!(includes & TypeFlags.IncludesEmptyObject)) { includes |= TypeFlags.IncludesEmptyObject; typeSet.set(type.id.toString(), type); } - } - else { + } else { if (flags & TypeFlags.AnyOrUnknown) { - if (type === wildcardType) includes |= TypeFlags.IncludesWildcard; + if (type === wildcardType) + includes |= TypeFlags.IncludesWildcard; if (isErrorType(type)) includes |= TypeFlags.IncludesError; - } - else if (strictNullChecks || !(flags & TypeFlags.Nullable)) { + } else if (strictNullChecks || !(flags & TypeFlags.Nullable)) { if (type === missingType) { includes |= TypeFlags.IncludesMissingType; type = undefinedType; } if (!typeSet.has(type.id.toString())) { - if (type.flags & TypeFlags.Unit && includes & TypeFlags.Unit) { + if ( + type.flags & TypeFlags.Unit && + includes & TypeFlags.Unit + ) { // We have seen two distinct unit types which means we should reduce to an // empty intersection. Adding TypeFlags.NonPrimitive causes that to happen. includes |= TypeFlags.NonPrimitive; @@ -18360,9 +32008,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Add the given types to the given type set. Order is preserved, freshness is removed from literal // types, duplicates are removed, and nested types of the given kind are flattened into the set. - function addTypesToIntersection(typeSet: Map, includes: TypeFlags, types: readonly Type[]) { + function addTypesToIntersection( + typeSet: Map, + includes: TypeFlags, + types: readonly Type[] + ) { for (const type of types) { - includes = addTypeToIntersection(typeSet, includes, getRegularTypeOfLiteralType(type)); + includes = addTypeToIntersection( + typeSet, + includes, + getRegularTypeOfLiteralType(type) + ); } return includes; } @@ -18372,12 +32028,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { while (i > 0) { i--; const t = types[i]; - const remove = t.flags & TypeFlags.String && includes & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) || - t.flags & TypeFlags.Number && includes & TypeFlags.NumberLiteral || - t.flags & TypeFlags.BigInt && includes & TypeFlags.BigIntLiteral || - t.flags & TypeFlags.ESSymbol && includes & TypeFlags.UniqueESSymbol || - t.flags & TypeFlags.Void && includes & TypeFlags.Undefined || - isEmptyAnonymousObjectType(t) && includes & TypeFlags.DefinitelyNonNullable; + const remove = + (t.flags & TypeFlags.String && + includes & + (TypeFlags.StringLiteral | + TypeFlags.TemplateLiteral | + TypeFlags.StringMapping)) || + (t.flags & TypeFlags.Number && + includes & TypeFlags.NumberLiteral) || + (t.flags & TypeFlags.BigInt && + includes & TypeFlags.BigIntLiteral) || + (t.flags & TypeFlags.ESSymbol && + includes & TypeFlags.UniqueESSymbol) || + (t.flags & TypeFlags.Void && includes & TypeFlags.Undefined) || + (isEmptyAnonymousObjectType(t) && + includes & TypeFlags.DefinitelyNonNullable); if (remove) { orderedRemoveItemAt(types, i); } @@ -18396,11 +32061,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (type === undefinedType) { return containsType(u.types, missingType); } - const primitive = type.flags & TypeFlags.StringLiteral ? stringType : - type.flags & (TypeFlags.Enum | TypeFlags.NumberLiteral) ? numberType : - type.flags & TypeFlags.BigIntLiteral ? bigintType : - type.flags & TypeFlags.UniqueESSymbol ? esSymbolType : - undefined; + const primitive = + type.flags & TypeFlags.StringLiteral + ? stringType + : type.flags & + (TypeFlags.Enum | TypeFlags.NumberLiteral) + ? numberType + : type.flags & TypeFlags.BigIntLiteral + ? bigintType + : type.flags & TypeFlags.UniqueESSymbol + ? esSymbolType + : undefined; if (!primitive || !containsType(u.types, primitive)) { return false; } @@ -18415,18 +32086,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { */ function extractRedundantTemplateLiterals(types: Type[]): boolean { let i = types.length; - const literals = filter(types, t => !!(t.flags & TypeFlags.StringLiteral)); + const literals = filter( + types, + (t) => !!(t.flags & TypeFlags.StringLiteral) + ); while (i > 0) { i--; const t = types[i]; - if (!(t.flags & (TypeFlags.TemplateLiteral | TypeFlags.StringMapping))) continue; + if ( + !( + t.flags & + (TypeFlags.TemplateLiteral | TypeFlags.StringMapping) + ) + ) + continue; for (const t2 of literals) { if (isTypeSubtypeOf(t2, t)) { // For example, `get${T}` & "getX" is just "getX", and Lowercase & "foo" is just "foo" orderedRemoveItemAt(types, i); break; - } - else if (isPatternLiteralType(t)) { + } else if (isPatternLiteralType(t)) { return true; } } @@ -18436,7 +32115,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function removeFromEach(types: Type[], flag: TypeFlags) { for (let i = 0; i < types.length; i++) { - types[i] = filterType(types[i], t => !(t.flags & flag)); + types[i] = filterType(types[i], (t) => !(t.flags & flag)); } } @@ -18445,7 +32124,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // other unions and return true. Otherwise, do nothing and return false. function intersectUnionsOfPrimitiveTypes(types: Type[]) { let unionTypes: UnionType[] | undefined; - const index = findIndex(types, t => !!(getObjectFlags(t) & ObjectFlags.PrimitiveUnion)); + const index = findIndex( + types, + (t) => !!(getObjectFlags(t) & ObjectFlags.PrimitiveUnion) + ); if (index < 0) { return false; } @@ -18455,10 +32137,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { while (i < types.length) { const t = types[i]; if (getObjectFlags(t) & ObjectFlags.PrimitiveUnion) { - (unionTypes || (unionTypes = [types[index] as UnionType])).push(t as UnionType); + (unionTypes || (unionTypes = [types[index] as UnionType])).push( + t as UnionType + ); orderedRemoveItemAt(types, i); - } - else { + } else { i++; } } @@ -18476,10 +32159,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (insertType(checked, t)) { if (eachUnionContains(unionTypes, t)) { // undefinedType/missingType should always come sorted first so we leverage that here - if (t === undefinedType && result.length && result[0] === missingType) { + if ( + t === undefinedType && + result.length && + result[0] === missingType + ) { continue; } - if (t === missingType && result.length && result[0] === undefinedType) { + if ( + t === missingType && + result.length && + result[0] === undefinedType + ) { result[0] = missingType; continue; } @@ -18489,13 +32180,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } // Finally replace the first union with the result - types[index] = getUnionTypeFromSortedList(result, ObjectFlags.PrimitiveUnion); + types[index] = getUnionTypeFromSortedList( + result, + ObjectFlags.PrimitiveUnion + ); return true; } - function createIntersectionType(types: Type[], objectFlags: ObjectFlags, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]) { + function createIntersectionType( + types: Type[], + objectFlags: ObjectFlags, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[] + ) { const result = createType(TypeFlags.Intersection) as IntersectionType; - result.objectFlags = objectFlags | getPropagatingFlagsOfTypes(types, /*excludeKinds*/ TypeFlags.Nullable); + result.objectFlags = + objectFlags | + getPropagatingFlagsOfTypes( + types, + /*excludeKinds*/ TypeFlags.Nullable + ); result.types = types; result.aliasSymbol = aliasSymbol; result.aliasTypeArguments = aliasTypeArguments; @@ -18512,9 +32216,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // a type alias of the form "type List = T & { next: List }" cannot be reduced during its declaration. // Also, unlike union types, the order of the constituent types is preserved in order that overload resolution // for intersections of types with signatures can be deterministic. - function getIntersectionType(types: readonly Type[], flags = IntersectionFlags.None, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type { + function getIntersectionType( + types: readonly Type[], + flags = IntersectionFlags.None, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[] + ): Type { const typeMembershipMap = new Map(); - const includes = addTypesToIntersection(typeMembershipMap, 0 as TypeFlags, types); + const includes = addTypesToIntersection( + typeMembershipMap, + 0 as TypeFlags, + types + ); const typeSet: Type[] = arrayFrom(typeMembershipMap.values()); let objectFlags = ObjectFlags.None; // An intersection type is considered empty if it contains @@ -18527,37 +32240,76 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // a void-like type and a type known to be non-void-like, or // a non-primitive type and a type known to be primitive. if (includes & TypeFlags.Never) { - return contains(typeSet, silentNeverType) ? silentNeverType : neverType; + return contains(typeSet, silentNeverType) + ? silentNeverType + : neverType; } if ( - strictNullChecks && includes & TypeFlags.Nullable && includes & (TypeFlags.Object | TypeFlags.NonPrimitive | TypeFlags.IncludesEmptyObject) || - includes & TypeFlags.NonPrimitive && includes & (TypeFlags.DisjointDomains & ~TypeFlags.NonPrimitive) || - includes & TypeFlags.StringLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.StringLike) || - includes & TypeFlags.NumberLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.NumberLike) || - includes & TypeFlags.BigIntLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.BigIntLike) || - includes & TypeFlags.ESSymbolLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.ESSymbolLike) || - includes & TypeFlags.VoidLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.VoidLike) + (strictNullChecks && + includes & TypeFlags.Nullable && + includes & + (TypeFlags.Object | + TypeFlags.NonPrimitive | + TypeFlags.IncludesEmptyObject)) || + (includes & TypeFlags.NonPrimitive && + includes & + (TypeFlags.DisjointDomains & ~TypeFlags.NonPrimitive)) || + (includes & TypeFlags.StringLike && + includes & + (TypeFlags.DisjointDomains & ~TypeFlags.StringLike)) || + (includes & TypeFlags.NumberLike && + includes & + (TypeFlags.DisjointDomains & ~TypeFlags.NumberLike)) || + (includes & TypeFlags.BigIntLike && + includes & + (TypeFlags.DisjointDomains & ~TypeFlags.BigIntLike)) || + (includes & TypeFlags.ESSymbolLike && + includes & + (TypeFlags.DisjointDomains & ~TypeFlags.ESSymbolLike)) || + (includes & TypeFlags.VoidLike && + includes & (TypeFlags.DisjointDomains & ~TypeFlags.VoidLike)) ) { return neverType; } - if (includes & (TypeFlags.TemplateLiteral | TypeFlags.StringMapping) && includes & TypeFlags.StringLiteral && extractRedundantTemplateLiterals(typeSet)) { + if ( + includes & (TypeFlags.TemplateLiteral | TypeFlags.StringMapping) && + includes & TypeFlags.StringLiteral && + extractRedundantTemplateLiterals(typeSet) + ) { return neverType; } if (includes & TypeFlags.Any) { - return includes & TypeFlags.IncludesWildcard ? wildcardType : includes & TypeFlags.IncludesError ? errorType : anyType; + return includes & TypeFlags.IncludesWildcard + ? wildcardType + : includes & TypeFlags.IncludesError + ? errorType + : anyType; } if (!strictNullChecks && includes & TypeFlags.Nullable) { - return includes & TypeFlags.IncludesEmptyObject ? neverType : includes & TypeFlags.Undefined ? undefinedType : nullType; + return includes & TypeFlags.IncludesEmptyObject + ? neverType + : includes & TypeFlags.Undefined + ? undefinedType + : nullType; } if ( - includes & TypeFlags.String && includes & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) || - includes & TypeFlags.Number && includes & TypeFlags.NumberLiteral || - includes & TypeFlags.BigInt && includes & TypeFlags.BigIntLiteral || - includes & TypeFlags.ESSymbol && includes & TypeFlags.UniqueESSymbol || - includes & TypeFlags.Void && includes & TypeFlags.Undefined || - includes & TypeFlags.IncludesEmptyObject && includes & TypeFlags.DefinitelyNonNullable + (includes & TypeFlags.String && + includes & + (TypeFlags.StringLiteral | + TypeFlags.TemplateLiteral | + TypeFlags.StringMapping)) || + (includes & TypeFlags.Number && + includes & TypeFlags.NumberLiteral) || + (includes & TypeFlags.BigInt && + includes & TypeFlags.BigIntLiteral) || + (includes & TypeFlags.ESSymbol && + includes & TypeFlags.UniqueESSymbol) || + (includes & TypeFlags.Void && includes & TypeFlags.Undefined) || + (includes & TypeFlags.IncludesEmptyObject && + includes & TypeFlags.DefinitelyNonNullable) ) { - if (!(flags & IntersectionFlags.NoSupertypeReduction)) removeRedundantSupertypes(typeSet, includes); + if (!(flags & IntersectionFlags.NoSupertypeReduction)) + removeRedundantSupertypes(typeSet, includes); } if (includes & TypeFlags.IncludesMissingType) { typeSet[typeSet.indexOf(undefinedType)] = missingType; @@ -18568,24 +32320,48 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (typeSet.length === 1) { return typeSet[0]; } - if (typeSet.length === 2 && !(flags & IntersectionFlags.NoConstraintReduction)) { - const typeVarIndex = typeSet[0].flags & TypeFlags.TypeVariable ? 0 : 1; + if ( + typeSet.length === 2 && + !(flags & IntersectionFlags.NoConstraintReduction) + ) { + const typeVarIndex = + typeSet[0].flags & TypeFlags.TypeVariable ? 0 : 1; const typeVariable = typeSet[typeVarIndex]; const primitiveType = typeSet[1 - typeVarIndex]; if ( typeVariable.flags & TypeFlags.TypeVariable && - (primitiveType.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive) && !isGenericStringLikeType(primitiveType) || includes & TypeFlags.IncludesEmptyObject) + ((primitiveType.flags & + (TypeFlags.Primitive | TypeFlags.NonPrimitive) && + !isGenericStringLikeType(primitiveType)) || + includes & TypeFlags.IncludesEmptyObject) ) { // We have an intersection T & P or P & T, where T is a type variable and P is a primitive type, the object type, or {}. const constraint = getBaseConstraintOfType(typeVariable); // Check that T's constraint is similarly composed of primitive types, the object type, or {}. - if (constraint && everyType(constraint, t => !!(t.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive)) || isEmptyAnonymousObjectType(t))) { + if ( + constraint && + everyType( + constraint, + (t) => + !!( + t.flags & + (TypeFlags.Primitive | TypeFlags.NonPrimitive) + ) || isEmptyAnonymousObjectType(t) + ) + ) { // If T's constraint is a subtype of P, simply return T. For example, given `T extends "a" | "b"`, // the intersection `T & string` reduces to just T. if (isTypeStrictSubtypeOf(constraint, primitiveType)) { return typeVariable; } - if (!(constraint.flags & TypeFlags.Union && someType(constraint, c => isTypeStrictSubtypeOf(c, primitiveType)))) { + if ( + !( + constraint.flags & TypeFlags.Union && + someType(constraint, (c) => + isTypeStrictSubtypeOf(c, primitiveType) + ) + ) + ) { // No constituent of T's constraint is a subtype of P. If P is also not a subtype of T's constraint, // then the constraint and P are unrelated, and the intersection reduces to never. For example, given // `T extends "a" | "b"`, the intersection `T & number` reduces to never. @@ -18601,7 +32377,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } } - const id = getTypeListId(typeSet) + (flags & IntersectionFlags.NoConstraintReduction ? "*" : getAliasId(aliasSymbol, aliasTypeArguments)); + const id = + getTypeListId(typeSet) + + (flags & IntersectionFlags.NoConstraintReduction + ? "*" + : getAliasId(aliasSymbol, aliasTypeArguments)); let result = intersectionTypes.get(id); if (!result) { if (includes & TypeFlags.Union) { @@ -18609,42 +32389,118 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // When the intersection creates a reduced set (which might mean that *all* union types have // disappeared), we restart the operation to get a new set of combined flags. Once we have // reduced we'll never reduce again, so this occurs at most once. - result = getIntersectionType(typeSet, flags, aliasSymbol, aliasTypeArguments); - } - else if (every(typeSet, t => !!(t.flags & TypeFlags.Union && (t as UnionType).types[0].flags & TypeFlags.Undefined))) { - const containedUndefinedType = some(typeSet, containsMissingType) ? missingType : undefinedType; + result = getIntersectionType( + typeSet, + flags, + aliasSymbol, + aliasTypeArguments + ); + } else if ( + every( + typeSet, + (t) => + !!( + t.flags & TypeFlags.Union && + (t as UnionType).types[0].flags & + TypeFlags.Undefined + ) + ) + ) { + const containedUndefinedType = some( + typeSet, + containsMissingType + ) + ? missingType + : undefinedType; removeFromEach(typeSet, TypeFlags.Undefined); - result = getUnionType([getIntersectionType(typeSet, flags), containedUndefinedType], UnionReduction.Literal, aliasSymbol, aliasTypeArguments); - } - else if (every(typeSet, t => !!(t.flags & TypeFlags.Union && ((t as UnionType).types[0].flags & TypeFlags.Null || (t as UnionType).types[1].flags & TypeFlags.Null)))) { + result = getUnionType( + [ + getIntersectionType(typeSet, flags), + containedUndefinedType, + ], + UnionReduction.Literal, + aliasSymbol, + aliasTypeArguments + ); + } else if ( + every( + typeSet, + (t) => + !!( + t.flags & TypeFlags.Union && + ((t as UnionType).types[0].flags & + TypeFlags.Null || + (t as UnionType).types[1].flags & + TypeFlags.Null) + ) + ) + ) { removeFromEach(typeSet, TypeFlags.Null); - result = getUnionType([getIntersectionType(typeSet, flags), nullType], UnionReduction.Literal, aliasSymbol, aliasTypeArguments); - } - else if (typeSet.length >= 3 && types.length > 2) { + result = getUnionType( + [getIntersectionType(typeSet, flags), nullType], + UnionReduction.Literal, + aliasSymbol, + aliasTypeArguments + ); + } else if (typeSet.length >= 3 && types.length > 2) { // When we have three or more constituents, more than two inputs (to head off infinite reexpansion), some of which are unions, we employ a "divide and conquer" strategy // where A & B & C & D is processed as (A & B) & (C & D). Since intersections of unions often produce far smaller // unions of intersections than the full cartesian product (due to some intersections becoming `never`), this can // dramatically reduce the overall work. const middle = Math.floor(typeSet.length / 2); - result = getIntersectionType([getIntersectionType(typeSet.slice(0, middle), flags), getIntersectionType(typeSet.slice(middle), flags)], flags, aliasSymbol, aliasTypeArguments); - } - else { + result = getIntersectionType( + [ + getIntersectionType( + typeSet.slice(0, middle), + flags + ), + getIntersectionType(typeSet.slice(middle), flags), + ], + flags, + aliasSymbol, + aliasTypeArguments + ); + } else { // We are attempting to construct a type of the form X & (A | B) & (C | D). Transform this into a type of // the form X & A & C | X & A & D | X & B & C | X & B & D. If the estimated size of the resulting union type // exceeds 100000 constituents, report an error. if (!checkCrossProductUnion(typeSet)) { return errorType; } - const constituents = getCrossProductIntersections(typeSet, flags); + const constituents = getCrossProductIntersections( + typeSet, + flags + ); // We attach a denormalized origin type when at least one constituent of the cross-product union is an // intersection (i.e. when the intersection didn't just reduce one or more unions to smaller unions) and // the denormalized origin has fewer constituents than the union itself. - const origin = some(constituents, t => !!(t.flags & TypeFlags.Intersection)) && getConstituentCountOfTypes(constituents) > getConstituentCountOfTypes(typeSet) ? createOriginUnionOrIntersectionType(TypeFlags.Intersection, typeSet) : undefined; - result = getUnionType(constituents, UnionReduction.Literal, aliasSymbol, aliasTypeArguments, origin); + const origin = + some( + constituents, + (t) => !!(t.flags & TypeFlags.Intersection) + ) && + getConstituentCountOfTypes(constituents) > + getConstituentCountOfTypes(typeSet) + ? createOriginUnionOrIntersectionType( + TypeFlags.Intersection, + typeSet + ) + : undefined; + result = getUnionType( + constituents, + UnionReduction.Literal, + aliasSymbol, + aliasTypeArguments, + origin + ); } - } - else { - result = createIntersectionType(typeSet, objectFlags, aliasSymbol, aliasTypeArguments); + } else { + result = createIntersectionType( + typeSet, + objectFlags, + aliasSymbol, + aliasTypeArguments + ); } intersectionTypes.set(id, result); } @@ -18652,20 +32508,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getCrossProductUnionSize(types: readonly Type[]) { - return reduceLeft(types, (n, t) => t.flags & TypeFlags.Union ? n * (t as UnionType).types.length : t.flags & TypeFlags.Never ? 0 : n, 1); + return reduceLeft( + types, + (n, t) => + t.flags & TypeFlags.Union + ? n * (t as UnionType).types.length + : t.flags & TypeFlags.Never + ? 0 + : n, + 1 + ); } function checkCrossProductUnion(types: readonly Type[]) { const size = getCrossProductUnionSize(types); if (size >= 100000) { - tracing?.instant(tracing.Phase.CheckTypes, "checkCrossProductUnion_DepthLimit", { typeIds: types.map(t => t.id), size }); - error(currentNode, Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent); + tracing?.instant( + tracing.Phase.CheckTypes, + "checkCrossProductUnion_DepthLimit", + { typeIds: types.map((t) => t.id), size } + ); + error( + currentNode, + Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent + ); return false; } return true; } - function getCrossProductIntersections(types: readonly Type[], flags: IntersectionFlags) { + function getCrossProductIntersections( + types: readonly Type[], + flags: IntersectionFlags + ) { const count = getCrossProductUnionSize(types); const intersections: Type[] = []; for (let i = 0; i < count; i++) { @@ -18686,9 +32561,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getConstituentCount(type: Type): number { - return !(type.flags & TypeFlags.UnionOrIntersection) || type.aliasSymbol ? 1 : - type.flags & TypeFlags.Union && (type as UnionType).origin ? getConstituentCount((type as UnionType).origin!) : - getConstituentCountOfTypes((type as UnionOrIntersectionType).types); + return !(type.flags & TypeFlags.UnionOrIntersection) || type.aliasSymbol + ? 1 + : type.flags & TypeFlags.Union && (type as UnionType).origin + ? getConstituentCount((type as UnionType).origin!) + : getConstituentCountOfTypes( + (type as UnionOrIntersectionType).types + ); } function getConstituentCountOfTypes(types: Type[]): number { @@ -18703,31 +32582,59 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We perform no supertype reduction for X & {} or {} & X, where X is one of string, number, bigint, // or a pattern literal template type. This enables union types like "a" | "b" | string & {} or // "aa" | "ab" | `a${string}` which preserve the literal types for purposes of statement completion. - const emptyIndex = types.length === 2 ? types.indexOf(emptyTypeLiteralType) : -1; + const emptyIndex = + types.length === 2 ? types.indexOf(emptyTypeLiteralType) : -1; const t = emptyIndex >= 0 ? types[1 - emptyIndex] : unknownType; - const noSupertypeReduction = !!(t.flags & (TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt) || t.flags & TypeFlags.TemplateLiteral && isPatternLiteralType(t)); - links.resolvedType = getIntersectionType(types, noSupertypeReduction ? IntersectionFlags.NoSupertypeReduction : 0, aliasSymbol, getTypeArgumentsForAliasSymbol(aliasSymbol)); + const noSupertypeReduction = !!( + t.flags & + (TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt) || + (t.flags & TypeFlags.TemplateLiteral && isPatternLiteralType(t)) + ); + links.resolvedType = getIntersectionType( + types, + noSupertypeReduction + ? IntersectionFlags.NoSupertypeReduction + : 0, + aliasSymbol, + getTypeArgumentsForAliasSymbol(aliasSymbol) + ); } return links.resolvedType; } - function createIndexType(type: InstantiableType | UnionOrIntersectionType, indexFlags: IndexFlags) { + function createIndexType( + type: InstantiableType | UnionOrIntersectionType, + indexFlags: IndexFlags + ) { const result = createType(TypeFlags.Index) as IndexType; result.type = type; result.indexFlags = indexFlags; return result; } - function createOriginIndexType(type: InstantiableType | UnionOrIntersectionType) { + function createOriginIndexType( + type: InstantiableType | UnionOrIntersectionType + ) { const result = createOriginType(TypeFlags.Index) as IndexType; result.type = type; return result; } - function getIndexTypeForGenericType(type: InstantiableType | UnionOrIntersectionType, indexFlags: IndexFlags) { - return indexFlags & IndexFlags.StringsOnly ? - type.resolvedStringIndexType || (type.resolvedStringIndexType = createIndexType(type, IndexFlags.StringsOnly)) : - type.resolvedIndexType || (type.resolvedIndexType = createIndexType(type, IndexFlags.None)); + function getIndexTypeForGenericType( + type: InstantiableType | UnionOrIntersectionType, + indexFlags: IndexFlags + ) { + return indexFlags & IndexFlags.StringsOnly + ? type.resolvedStringIndexType || + (type.resolvedStringIndexType = createIndexType( + type, + IndexFlags.StringsOnly + )) + : type.resolvedIndexType || + (type.resolvedIndexType = createIndexType( + type, + IndexFlags.None + )); } /** @@ -18737,10 +32644,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * reduction in the constraintType) when possible. * @param noIndexSignatures Indicates if _string_ index signatures should be elided. (other index signatures are always reported) */ - function getIndexTypeForMappedType(type: MappedType, indexFlags: IndexFlags) { + function getIndexTypeForMappedType( + type: MappedType, + indexFlags: IndexFlags + ) { const typeParameter = getTypeParameterFromMappedType(type); const constraintType = getConstraintTypeFromMappedType(type); - const nameType = getNameTypeFromMappedType(type.target as MappedType || type); + const nameType = getNameTypeFromMappedType( + (type.target as MappedType) || type + ); if (!nameType && !(indexFlags & IndexFlags.NoIndexSignatures)) { // no mapping and no filtering required, just quickly bail to returning the constraint in the common case return constraintType; @@ -18757,27 +32669,53 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Include the generic component in the resulting type. forEachType(constraintType, addMemberForKeyType); - } - else if (isMappedTypeWithKeyofConstraintDeclaration(type)) { - const modifiersType = getApparentType(getModifiersTypeFromMappedType(type)); // The 'T' in 'keyof T' - forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType(modifiersType, TypeFlags.StringOrNumberLiteralOrUnique, !!(indexFlags & IndexFlags.StringsOnly), addMemberForKeyType); - } - else { - forEachType(getLowerBoundOfKeyType(constraintType), addMemberForKeyType); + } else if (isMappedTypeWithKeyofConstraintDeclaration(type)) { + const modifiersType = getApparentType( + getModifiersTypeFromMappedType(type) + ); // The 'T' in 'keyof T' + forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType( + modifiersType, + TypeFlags.StringOrNumberLiteralOrUnique, + !!(indexFlags & IndexFlags.StringsOnly), + addMemberForKeyType + ); + } else { + forEachType( + getLowerBoundOfKeyType(constraintType), + addMemberForKeyType + ); } // We had to pick apart the constraintType to potentially map/filter it - compare the final resulting list with the // original constraintType, so we can return the union that preserves aliases/origin data if possible. - const result = indexFlags & IndexFlags.NoIndexSignatures ? filterType(getUnionType(keyTypes), t => !(t.flags & (TypeFlags.Any | TypeFlags.String))) : getUnionType(keyTypes); - if (result.flags & TypeFlags.Union && constraintType.flags & TypeFlags.Union && getTypeListId((result as UnionType).types) === getTypeListId((constraintType as UnionType).types)) { + const result = + indexFlags & IndexFlags.NoIndexSignatures + ? filterType( + getUnionType(keyTypes), + (t) => !(t.flags & (TypeFlags.Any | TypeFlags.String)) + ) + : getUnionType(keyTypes); + if ( + result.flags & TypeFlags.Union && + constraintType.flags & TypeFlags.Union && + getTypeListId((result as UnionType).types) === + getTypeListId((constraintType as UnionType).types) + ) { return constraintType; } return result; function addMemberForKeyType(keyType: Type) { - const propNameType = nameType ? instantiateType(nameType, appendTypeMapping(type.mapper, typeParameter, keyType)) : keyType; + const propNameType = nameType + ? instantiateType( + nameType, + appendTypeMapping(type.mapper, typeParameter, keyType) + ) + : keyType; // `keyof` currently always returns `string | number` for concrete `string` index signatures - the below ternary keeps that behavior for mapped types // See `getLiteralTypeFromProperties` where there's a similar ternary to cause the same behavior. - keyTypes.push(propNameType === stringType ? stringOrNumberType : propNameType); + keyTypes.push( + propNameType === stringType ? stringOrNumberType : propNameType + ); } } @@ -18788,19 +32726,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // they're the same type regardless of what's being distributed over. function hasDistributiveNameType(mappedType: MappedType) { const typeVariable = getTypeParameterFromMappedType(mappedType); - return isDistributive(getNameTypeFromMappedType(mappedType) || typeVariable); + return isDistributive( + getNameTypeFromMappedType(mappedType) || typeVariable + ); function isDistributive(type: Type): boolean { - return type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Primitive | TypeFlags.Never | TypeFlags.TypeParameter | TypeFlags.Object | TypeFlags.NonPrimitive) ? true : - type.flags & TypeFlags.Conditional ? (type as ConditionalType).root.isDistributive && (type as ConditionalType).checkType === typeVariable : - type.flags & (TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral) ? every((type as UnionOrIntersectionType | TemplateLiteralType).types, isDistributive) : - type.flags & TypeFlags.IndexedAccess ? isDistributive((type as IndexedAccessType).objectType) && isDistributive((type as IndexedAccessType).indexType) : - type.flags & TypeFlags.Substitution ? isDistributive((type as SubstitutionType).baseType) && isDistributive((type as SubstitutionType).constraint) : - type.flags & TypeFlags.StringMapping ? isDistributive((type as StringMappingType).type) : - false; - } - } - - function getLiteralTypeFromPropertyName(name: PropertyName | JsxAttributeName) { + return type.flags & + (TypeFlags.AnyOrUnknown | + TypeFlags.Primitive | + TypeFlags.Never | + TypeFlags.TypeParameter | + TypeFlags.Object | + TypeFlags.NonPrimitive) + ? true + : type.flags & TypeFlags.Conditional + ? (type as ConditionalType).root.isDistributive && + (type as ConditionalType).checkType === typeVariable + : type.flags & + (TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral) + ? every( + (type as UnionOrIntersectionType | TemplateLiteralType) + .types, + isDistributive + ) + : type.flags & TypeFlags.IndexedAccess + ? isDistributive((type as IndexedAccessType).objectType) && + isDistributive((type as IndexedAccessType).indexType) + : type.flags & TypeFlags.Substitution + ? isDistributive((type as SubstitutionType).baseType) && + isDistributive((type as SubstitutionType).constraint) + : type.flags & TypeFlags.StringMapping + ? isDistributive((type as StringMappingType).type) + : false; + } + } + + function getLiteralTypeFromPropertyName( + name: PropertyName | JsxAttributeName + ) { if (isPrivateIdentifier(name)) { return neverType; } @@ -18812,7 +32774,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const propertyName = getPropertyNameForPropertyNameNode(name); if (propertyName !== undefined) { - return getStringLiteralType(unescapeLeadingUnderscores(propertyName)); + return getStringLiteralType( + unescapeLeadingUnderscores(propertyName) + ); } if (isExpression(name)) { return getRegularTypeOfLiteralType(checkExpression(name)); @@ -18820,13 +32784,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return neverType; } - function getLiteralTypeFromProperty(prop: Symbol, include: TypeFlags, includeNonPublic?: boolean) { - if (includeNonPublic || !(getDeclarationModifierFlagsFromSymbol(prop) & ModifierFlags.NonPublicAccessibilityModifier)) { + function getLiteralTypeFromProperty( + prop: Symbol, + include: TypeFlags, + includeNonPublic?: boolean + ) { + if ( + includeNonPublic || + !( + getDeclarationModifierFlagsFromSymbol(prop) & + ModifierFlags.NonPublicAccessibilityModifier + ) + ) { let type = getSymbolLinks(getLateBoundSymbol(prop)).nameType; if (!type) { - const name = getNameOfDeclaration(prop.valueDeclaration) as PropertyName | JsxAttributeName; - type = prop.escapedName === InternalSymbolName.Default ? getStringLiteralType("default") : - name && getLiteralTypeFromPropertyName(name) || (!isKnownSymbol(prop) ? getStringLiteralType(symbolName(prop)) : undefined); + const name = getNameOfDeclaration(prop.valueDeclaration) as + | PropertyName + | JsxAttributeName; + type = + prop.escapedName === InternalSymbolName.Default + ? getStringLiteralType("default") + : (name && getLiteralTypeFromPropertyName(name)) || + (!isKnownSymbol(prop) + ? getStringLiteralType(symbolName(prop)) + : undefined); } if (type && type.flags & include) { return type; @@ -18836,42 +32817,115 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isKeyTypeIncluded(keyType: Type, include: TypeFlags): boolean { - return !!(keyType.flags & include || keyType.flags & TypeFlags.Intersection && some((keyType as IntersectionType).types, t => isKeyTypeIncluded(t, include))); + return !!( + keyType.flags & include || + (keyType.flags & TypeFlags.Intersection && + some((keyType as IntersectionType).types, (t) => + isKeyTypeIncluded(t, include) + )) + ); } - function getLiteralTypeFromProperties(type: Type, include: TypeFlags, includeOrigin: boolean) { - const origin = includeOrigin && (getObjectFlags(type) & (ObjectFlags.ClassOrInterface | ObjectFlags.Reference) || type.aliasSymbol) ? createOriginIndexType(type) : undefined; - const propertyTypes = map(getPropertiesOfType(type), prop => getLiteralTypeFromProperty(prop, include)); - const indexKeyTypes = map(getIndexInfosOfType(type), info => - info !== enumNumberIndexInfo && isKeyTypeIncluded(info.keyType, include) ? - info.keyType === stringType && include & TypeFlags.Number ? stringOrNumberType : info.keyType : neverType); - return getUnionType(concatenate(propertyTypes, indexKeyTypes), UnionReduction.Literal, /*aliasSymbol*/ undefined, /*aliasTypeArguments*/ undefined, origin); + function getLiteralTypeFromProperties( + type: Type, + include: TypeFlags, + includeOrigin: boolean + ) { + const origin = + includeOrigin && + (getObjectFlags(type) & + (ObjectFlags.ClassOrInterface | ObjectFlags.Reference) || + type.aliasSymbol) + ? createOriginIndexType(type) + : undefined; + const propertyTypes = map(getPropertiesOfType(type), (prop) => + getLiteralTypeFromProperty(prop, include) + ); + const indexKeyTypes = map(getIndexInfosOfType(type), (info) => + info !== enumNumberIndexInfo && + isKeyTypeIncluded(info.keyType, include) + ? info.keyType === stringType && include & TypeFlags.Number + ? stringOrNumberType + : info.keyType + : neverType + ); + return getUnionType( + concatenate(propertyTypes, indexKeyTypes), + UnionReduction.Literal, + /*aliasSymbol*/ undefined, + /*aliasTypeArguments*/ undefined, + origin + ); } function shouldDeferIndexType(type: Type, indexFlags = IndexFlags.None) { - return !!(type.flags & TypeFlags.InstantiableNonPrimitive || + return !!( + type.flags & TypeFlags.InstantiableNonPrimitive || isGenericTupleType(type) || - isGenericMappedType(type) && (!hasDistributiveNameType(type) || getMappedTypeNameTypeKind(type) === MappedTypeNameTypeKind.Remapping) || - type.flags & TypeFlags.Union && !(indexFlags & IndexFlags.NoReducibleCheck) && isGenericReducibleType(type) || - type.flags & TypeFlags.Intersection && maybeTypeOfKind(type, TypeFlags.Instantiable) && some((type as IntersectionType).types, isEmptyAnonymousObjectType)); + (isGenericMappedType(type) && + (!hasDistributiveNameType(type) || + getMappedTypeNameTypeKind(type) === + MappedTypeNameTypeKind.Remapping)) || + (type.flags & TypeFlags.Union && + !(indexFlags & IndexFlags.NoReducibleCheck) && + isGenericReducibleType(type)) || + (type.flags & TypeFlags.Intersection && + maybeTypeOfKind(type, TypeFlags.Instantiable) && + some( + (type as IntersectionType).types, + isEmptyAnonymousObjectType + )) + ); } function getIndexType(type: Type, indexFlags = IndexFlags.None): Type { type = getReducedType(type); - return isNoInferType(type) ? getNoInferType(getIndexType((type as SubstitutionType).baseType, indexFlags)) : - shouldDeferIndexType(type, indexFlags) ? getIndexTypeForGenericType(type as InstantiableType | UnionOrIntersectionType, indexFlags) : - type.flags & TypeFlags.Union ? getIntersectionType(map((type as UnionType).types, t => getIndexType(t, indexFlags))) : - type.flags & TypeFlags.Intersection ? getUnionType(map((type as IntersectionType).types, t => getIndexType(t, indexFlags))) : - getObjectFlags(type) & ObjectFlags.Mapped ? getIndexTypeForMappedType(type as MappedType, indexFlags) : - type === wildcardType ? wildcardType : - type.flags & TypeFlags.Unknown ? neverType : - type.flags & (TypeFlags.Any | TypeFlags.Never) ? stringNumberSymbolType : - getLiteralTypeFromProperties(type, (indexFlags & IndexFlags.NoIndexSignatures ? TypeFlags.StringLiteral : TypeFlags.StringLike) | (indexFlags & IndexFlags.StringsOnly ? 0 : TypeFlags.NumberLike | TypeFlags.ESSymbolLike), indexFlags === IndexFlags.None); + return isNoInferType(type) + ? getNoInferType( + getIndexType((type as SubstitutionType).baseType, indexFlags) + ) + : shouldDeferIndexType(type, indexFlags) + ? getIndexTypeForGenericType( + type as InstantiableType | UnionOrIntersectionType, + indexFlags + ) + : type.flags & TypeFlags.Union + ? getIntersectionType( + map((type as UnionType).types, (t) => + getIndexType(t, indexFlags) + ) + ) + : type.flags & TypeFlags.Intersection + ? getUnionType( + map((type as IntersectionType).types, (t) => + getIndexType(t, indexFlags) + ) + ) + : getObjectFlags(type) & ObjectFlags.Mapped + ? getIndexTypeForMappedType(type as MappedType, indexFlags) + : type === wildcardType + ? wildcardType + : type.flags & TypeFlags.Unknown + ? neverType + : type.flags & (TypeFlags.Any | TypeFlags.Never) + ? stringNumberSymbolType + : getLiteralTypeFromProperties( + type, + (indexFlags & IndexFlags.NoIndexSignatures + ? TypeFlags.StringLiteral + : TypeFlags.StringLike) | + (indexFlags & IndexFlags.StringsOnly + ? 0 + : TypeFlags.NumberLike | TypeFlags.ESSymbolLike), + indexFlags === IndexFlags.None + ); } function getExtractStringType(type: Type) { const extractTypeAlias = getGlobalExtractSymbol(); - return extractTypeAlias ? getTypeAliasInstantiation(extractTypeAlias, [type, stringType]) : stringType; + return extractTypeAlias + ? getTypeAliasInstantiation(extractTypeAlias, [type, stringType]) + : stringType; } function getIndexTypeOrString(type: Type): Type { @@ -18884,12 +32938,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!links.resolvedType) { switch (node.operator) { case SyntaxKind.KeyOfKeyword: - links.resolvedType = getIndexType(getTypeFromTypeNode(node.type)); + links.resolvedType = getIndexType( + getTypeFromTypeNode(node.type) + ); break; case SyntaxKind.UniqueKeyword: - links.resolvedType = node.type.kind === SyntaxKind.SymbolKeyword - ? getESSymbolLikeTypeForNode(walkUpParenthesizedTypes(node.parent)) - : errorType; + links.resolvedType = + node.type.kind === SyntaxKind.SymbolKeyword + ? getESSymbolLikeTypeForNode( + walkUpParenthesizedTypes(node.parent) + ) + : errorType; break; case SyntaxKind.ReadonlyKeyword: links.resolvedType = getTypeFromTypeNode(node.type); @@ -18905,19 +32964,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const links = getNodeLinks(node); if (!links.resolvedType) { links.resolvedType = getTemplateLiteralType( - [node.head.text, ...map(node.templateSpans, span => span.literal.text)], - map(node.templateSpans, span => getTypeFromTypeNode(span.type)), + [ + node.head.text, + ...map(node.templateSpans, (span) => span.literal.text), + ], + map(node.templateSpans, (span) => + getTypeFromTypeNode(span.type) + ) ); } return links.resolvedType; } - function getTemplateLiteralType(texts: readonly string[], types: readonly Type[]): Type { - const unionIndex = findIndex(types, t => !!(t.flags & (TypeFlags.Never | TypeFlags.Union))); + function getTemplateLiteralType( + texts: readonly string[], + types: readonly Type[] + ): Type { + const unionIndex = findIndex( + types, + (t) => !!(t.flags & (TypeFlags.Never | TypeFlags.Union)) + ); if (unionIndex >= 0) { - return checkCrossProductUnion(types) ? - mapType(types[unionIndex], t => getTemplateLiteralType(texts, replaceElement(types, unionIndex, t))) : - errorType; + return checkCrossProductUnion(types) + ? mapType(types[unionIndex], (t) => + getTemplateLiteralType( + texts, + replaceElement(types, unionIndex, t) + ) + ) + : errorType; } if (contains(types, wildcardType)) { return wildcardType; @@ -18932,8 +33007,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getStringLiteralType(text); } newTexts.push(text); - if (every(newTexts, t => t === "")) { - if (every(newTypes, t => !!(t.flags & TypeFlags.String))) { + if (every(newTexts, (t) => t === "")) { + if (every(newTypes, (t) => !!(t.flags & TypeFlags.String))) { return stringType; } // Normalize `${Mapping}` into Mapping @@ -18941,31 +33016,49 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return newTypes[0]; } } - const id = `${getTypeListId(newTypes)}|${map(newTexts, t => t.length).join(",")}|${newTexts.join("")}`; + const id = `${getTypeListId(newTypes)}|${map( + newTexts, + (t) => t.length + ).join(",")}|${newTexts.join("")}`; let type = templateLiteralTypes.get(id); if (!type) { - templateLiteralTypes.set(id, type = createTemplateLiteralType(newTexts, newTypes)); + templateLiteralTypes.set( + id, + (type = createTemplateLiteralType(newTexts, newTypes)) + ); } return type; - function addSpans(texts: readonly string[], types: readonly Type[]): boolean { + function addSpans( + texts: readonly string[], + types: readonly Type[] + ): boolean { for (let i = 0; i < types.length; i++) { const t = types[i]; - if (t.flags & (TypeFlags.Literal | TypeFlags.Null | TypeFlags.Undefined)) { + if ( + t.flags & + (TypeFlags.Literal | TypeFlags.Null | TypeFlags.Undefined) + ) { text += getTemplateStringForType(t) || ""; text += texts[i + 1]; - } - else if (t.flags & TypeFlags.TemplateLiteral) { + } else if (t.flags & TypeFlags.TemplateLiteral) { text += (t as TemplateLiteralType).texts[0]; - if (!addSpans((t as TemplateLiteralType).texts, (t as TemplateLiteralType).types)) return false; + if ( + !addSpans( + (t as TemplateLiteralType).texts, + (t as TemplateLiteralType).types + ) + ) + return false; text += texts[i + 1]; - } - else if (isGenericIndexType(t) || isPatternLiteralPlaceholderType(t)) { + } else if ( + isGenericIndexType(t) || + isPatternLiteralPlaceholderType(t) + ) { newTypes.push(t); newTexts.push(text); text = texts[i + 1]; - } - else { + } else { return false; } } @@ -18974,30 +33067,59 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getTemplateStringForType(type: Type) { - return type.flags & TypeFlags.StringLiteral ? (type as StringLiteralType).value : - type.flags & TypeFlags.NumberLiteral ? "" + (type as NumberLiteralType).value : - type.flags & TypeFlags.BigIntLiteral ? pseudoBigIntToString((type as BigIntLiteralType).value) : - type.flags & (TypeFlags.BooleanLiteral | TypeFlags.Nullable) ? (type as IntrinsicType).intrinsicName : - undefined; + return type.flags & TypeFlags.StringLiteral + ? (type as StringLiteralType).value + : type.flags & TypeFlags.NumberLiteral + ? "" + (type as NumberLiteralType).value + : type.flags & TypeFlags.BigIntLiteral + ? pseudoBigIntToString((type as BigIntLiteralType).value) + : type.flags & (TypeFlags.BooleanLiteral | TypeFlags.Nullable) + ? (type as IntrinsicType).intrinsicName + : undefined; } - function createTemplateLiteralType(texts: readonly string[], types: readonly Type[]) { - const type = createType(TypeFlags.TemplateLiteral) as TemplateLiteralType; + function createTemplateLiteralType( + texts: readonly string[], + types: readonly Type[] + ) { + const type = createType( + TypeFlags.TemplateLiteral + ) as TemplateLiteralType; type.texts = texts; type.types = types; return type; } function getStringMappingType(symbol: Symbol, type: Type): Type { - return type.flags & (TypeFlags.Union | TypeFlags.Never) ? mapType(type, t => getStringMappingType(symbol, t)) : - type.flags & TypeFlags.StringLiteral ? getStringLiteralType(applyStringMapping(symbol, (type as StringLiteralType).value)) : - type.flags & TypeFlags.TemplateLiteral ? getTemplateLiteralType(...applyTemplateStringMapping(symbol, (type as TemplateLiteralType).texts, (type as TemplateLiteralType).types)) : - // Mapping> === Mapping - type.flags & TypeFlags.StringMapping && symbol === type.symbol ? type : - type.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.StringMapping) || isGenericIndexType(type) ? getStringMappingTypeForGenericType(symbol, type) : - // This handles Mapping<`${number}`> and Mapping<`${bigint}`> - isPatternLiteralPlaceholderType(type) ? getStringMappingTypeForGenericType(symbol, getTemplateLiteralType(["", ""], [type])) : - type; + return type.flags & (TypeFlags.Union | TypeFlags.Never) + ? mapType(type, (t) => getStringMappingType(symbol, t)) + : type.flags & TypeFlags.StringLiteral + ? getStringLiteralType( + applyStringMapping(symbol, (type as StringLiteralType).value) + ) + : type.flags & TypeFlags.TemplateLiteral + ? getTemplateLiteralType( + ...applyTemplateStringMapping( + symbol, + (type as TemplateLiteralType).texts, + (type as TemplateLiteralType).types + ) + ) + : // Mapping> === Mapping + type.flags & TypeFlags.StringMapping && symbol === type.symbol + ? type + : type.flags & + (TypeFlags.Any | + TypeFlags.String | + TypeFlags.StringMapping) || isGenericIndexType(type) + ? getStringMappingTypeForGenericType(symbol, type) + : // This handles Mapping<`${number}`> and Mapping<`${bigint}`> + isPatternLiteralPlaceholderType(type) + ? getStringMappingTypeForGenericType( + symbol, + getTemplateLiteralType(["", ""], [type]) + ) + : type; } function applyStringMapping(symbol: Symbol, str: string) { @@ -19014,36 +33136,89 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return str; } - function applyTemplateStringMapping(symbol: Symbol, texts: readonly string[], types: readonly Type[]): [texts: readonly string[], types: readonly Type[]] { + function applyTemplateStringMapping( + symbol: Symbol, + texts: readonly string[], + types: readonly Type[] + ): [texts: readonly string[], types: readonly Type[]] { switch (intrinsicTypeKinds.get(symbol.escapedName as string)) { case IntrinsicTypeKind.Uppercase: - return [texts.map(t => t.toUpperCase()), types.map(t => getStringMappingType(symbol, t))]; + return [ + texts.map((t) => t.toUpperCase()), + types.map((t) => getStringMappingType(symbol, t)), + ]; case IntrinsicTypeKind.Lowercase: - return [texts.map(t => t.toLowerCase()), types.map(t => getStringMappingType(symbol, t))]; + return [ + texts.map((t) => t.toLowerCase()), + types.map((t) => getStringMappingType(symbol, t)), + ]; 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]; + 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, + ]; 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]; + 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, + ]; } return [texts, types]; } - function getStringMappingTypeForGenericType(symbol: Symbol, type: Type): Type { + function getStringMappingTypeForGenericType( + symbol: Symbol, + type: Type + ): Type { const id = `${getSymbolId(symbol)},${getTypeId(type)}`; let result = stringMappingTypes.get(id); if (!result) { - stringMappingTypes.set(id, result = createStringMappingType(symbol, type)); + stringMappingTypes.set( + id, + (result = createStringMappingType(symbol, type)) + ); } return result; } function createStringMappingType(symbol: Symbol, type: Type) { - const result = createTypeWithSymbol(TypeFlags.StringMapping, symbol) as StringMappingType; + const result = createTypeWithSymbol( + TypeFlags.StringMapping, + symbol + ) as StringMappingType; result.type = type; return result; } - function createIndexedAccessType(objectType: Type, indexType: Type, accessFlags: AccessFlags, aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined) { + function createIndexedAccessType( + objectType: Type, + indexType: Type, + accessFlags: AccessFlags, + aliasSymbol: Symbol | undefined, + aliasTypeArguments: readonly Type[] | undefined + ) { const type = createType(TypeFlags.IndexedAccess) as IndexedAccessType; type.objectType = objectType; type.indexType = indexType; @@ -19082,114 +33257,275 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function getPropertyNameFromIndex(indexType: Type, accessNode: PropertyName | ObjectBindingPattern | ArrayBindingPattern | IndexedAccessTypeNode | ElementAccessExpression | SyntheticExpression | undefined) { - return isTypeUsableAsPropertyName(indexType) ? - getPropertyNameFromType(indexType) : - accessNode && isPropertyName(accessNode) ? - // late bound names are handled in the first branch, so here we only need to handle normal names - getPropertyNameForPropertyNameNode(accessNode) : - undefined; + function getPropertyNameFromIndex( + indexType: Type, + accessNode: + | PropertyName + | ObjectBindingPattern + | ArrayBindingPattern + | IndexedAccessTypeNode + | ElementAccessExpression + | SyntheticExpression + | undefined + ) { + return isTypeUsableAsPropertyName(indexType) + ? getPropertyNameFromType(indexType) + : accessNode && isPropertyName(accessNode) + ? // late bound names are handled in the first branch, so here we only need to handle normal names + getPropertyNameForPropertyNameNode(accessNode) + : undefined; } function isUncalledFunctionReference(node: Node, symbol: Symbol) { if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method)) { - const parent = findAncestor(node.parent, n => !isAccessExpression(n)) || node.parent; + const parent = + findAncestor(node.parent, (n) => !isAccessExpression(n)) || + node.parent; if (isCallLikeExpression(parent)) { - return isCallOrNewExpression(parent) && isIdentifier(node) && hasMatchingArgument(parent, node); + return ( + isCallOrNewExpression(parent) && + isIdentifier(node) && + hasMatchingArgument(parent, node) + ); } - return every(symbol.declarations, d => !isFunctionLike(d) || isDeprecatedDeclaration(d)); + return every( + symbol.declarations, + (d) => !isFunctionLike(d) || isDeprecatedDeclaration(d) + ); } return true; } - function getPropertyTypeForIndexType(originalObjectType: Type, objectType: Type, indexType: Type, fullIndexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression | undefined, accessFlags: AccessFlags) { - const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode : undefined; - const propName = accessNode && isPrivateIdentifier(accessNode) ? undefined : getPropertyNameFromIndex(indexType, accessNode); + function getPropertyTypeForIndexType( + originalObjectType: Type, + objectType: Type, + indexType: Type, + fullIndexType: Type, + accessNode: + | ElementAccessExpression + | IndexedAccessTypeNode + | PropertyName + | BindingName + | SyntheticExpression + | undefined, + accessFlags: AccessFlags + ) { + const accessExpression = + accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression + ? accessNode + : undefined; + const propName = + accessNode && isPrivateIdentifier(accessNode) + ? undefined + : getPropertyNameFromIndex(indexType, accessNode); if (propName !== undefined) { if (accessFlags & AccessFlags.Contextual) { - return getTypeOfPropertyOfContextualType(objectType, propName) || anyType; + return ( + getTypeOfPropertyOfContextualType(objectType, propName) || + anyType + ); } const prop = getPropertyOfType(objectType, propName); if (prop) { - if (accessFlags & AccessFlags.ReportDeprecated && accessNode && prop.declarations && isDeprecatedSymbol(prop) && isUncalledFunctionReference(accessNode, prop)) { - const deprecatedNode = accessExpression?.argumentExpression ?? (isIndexedAccessTypeNode(accessNode) ? accessNode.indexType : accessNode); - addDeprecatedSuggestion(deprecatedNode, prop.declarations, propName as string); + if ( + accessFlags & AccessFlags.ReportDeprecated && + accessNode && + prop.declarations && + isDeprecatedSymbol(prop) && + isUncalledFunctionReference(accessNode, prop) + ) { + const deprecatedNode = + accessExpression?.argumentExpression ?? + (isIndexedAccessTypeNode(accessNode) + ? accessNode.indexType + : accessNode); + addDeprecatedSuggestion( + deprecatedNode, + prop.declarations, + propName as string + ); } if (accessExpression) { - markPropertyAsReferenced(prop, accessExpression, isSelfTypeAccess(accessExpression.expression, objectType.symbol)); - if (isAssignmentToReadonlyEntity(accessExpression, prop, getAssignmentTargetKind(accessExpression))) { - error(accessExpression.argumentExpression, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, symbolToString(prop)); + markPropertyAsReferenced( + prop, + accessExpression, + isSelfTypeAccess( + accessExpression.expression, + objectType.symbol + ) + ); + if ( + isAssignmentToReadonlyEntity( + accessExpression, + prop, + getAssignmentTargetKind(accessExpression) + ) + ) { + error( + accessExpression.argumentExpression, + Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, + symbolToString(prop) + ); return undefined; } if (accessFlags & AccessFlags.CacheSymbol) { getNodeLinks(accessNode!).resolvedSymbol = prop; } - if (isThisPropertyAccessInConstructor(accessExpression, prop)) { + if ( + isThisPropertyAccessInConstructor( + accessExpression, + prop + ) + ) { return autoType; } } - const propType = accessFlags & AccessFlags.Writing ? getWriteTypeOfSymbol(prop) : getTypeOfSymbol(prop); - return accessExpression && getAssignmentTargetKind(accessExpression) !== AssignmentKind.Definite ? getFlowTypeOfReference(accessExpression, propType) : - accessNode && isIndexedAccessTypeNode(accessNode) && containsMissingType(propType) ? getUnionType([propType, undefinedType]) : - propType; + const propType = + accessFlags & AccessFlags.Writing + ? getWriteTypeOfSymbol(prop) + : getTypeOfSymbol(prop); + return accessExpression && + getAssignmentTargetKind(accessExpression) !== + AssignmentKind.Definite + ? getFlowTypeOfReference(accessExpression, propType) + : accessNode && + isIndexedAccessTypeNode(accessNode) && + containsMissingType(propType) + ? getUnionType([propType, undefinedType]) + : propType; } - if (everyType(objectType, isTupleType) && isNumericLiteralName(propName)) { + if ( + everyType(objectType, isTupleType) && + isNumericLiteralName(propName) + ) { const index = +propName; - if (accessNode && everyType(objectType, t => !((t as TupleTypeReference).target.combinedFlags & ElementFlags.Variable)) && !(accessFlags & AccessFlags.AllowMissing)) { - const indexNode = getIndexNodeForAccessExpression(accessNode); + if ( + accessNode && + everyType( + objectType, + (t) => + !( + (t as TupleTypeReference).target.combinedFlags & + ElementFlags.Variable + ) + ) && + !(accessFlags & AccessFlags.AllowMissing) + ) { + const indexNode = + getIndexNodeForAccessExpression(accessNode); if (isTupleType(objectType)) { if (index < 0) { - error(indexNode, Diagnostics.A_tuple_type_cannot_be_indexed_with_a_negative_value); + error( + indexNode, + Diagnostics.A_tuple_type_cannot_be_indexed_with_a_negative_value + ); return undefinedType; } - error(indexNode, Diagnostics.Tuple_type_0_of_length_1_has_no_element_at_index_2, typeToString(objectType), getTypeReferenceArity(objectType), unescapeLeadingUnderscores(propName)); - } - else { - error(indexNode, Diagnostics.Property_0_does_not_exist_on_type_1, unescapeLeadingUnderscores(propName), typeToString(objectType)); + error( + indexNode, + Diagnostics.Tuple_type_0_of_length_1_has_no_element_at_index_2, + typeToString(objectType), + getTypeReferenceArity(objectType), + unescapeLeadingUnderscores(propName) + ); + } else { + error( + indexNode, + Diagnostics.Property_0_does_not_exist_on_type_1, + unescapeLeadingUnderscores(propName), + typeToString(objectType) + ); } } if (index >= 0) { - errorIfWritingToReadonlyIndex(getIndexInfoOfType(objectType, numberType)); - return getTupleElementTypeOutOfStartCount(objectType, index, accessFlags & AccessFlags.IncludeUndefined ? missingType : undefined); + errorIfWritingToReadonlyIndex( + getIndexInfoOfType(objectType, numberType) + ); + return getTupleElementTypeOutOfStartCount( + objectType, + index, + accessFlags & AccessFlags.IncludeUndefined + ? missingType + : undefined + ); } } } - if (!(indexType.flags & TypeFlags.Nullable) && isTypeAssignableToKind(indexType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbolLike)) { + if ( + !(indexType.flags & TypeFlags.Nullable) && + isTypeAssignableToKind( + indexType, + TypeFlags.StringLike | + TypeFlags.NumberLike | + TypeFlags.ESSymbolLike + ) + ) { if (objectType.flags & (TypeFlags.Any | TypeFlags.Never)) { return objectType; } // If no index signature is applicable, we default to the string index signature. In effect, this means the string // index signature applies even when accessing with a symbol-like type. - const indexInfo = getApplicableIndexInfo(objectType, indexType) || getIndexInfoOfType(objectType, stringType); + const indexInfo = + getApplicableIndexInfo(objectType, indexType) || + getIndexInfoOfType(objectType, stringType); if (indexInfo) { - if (accessFlags & AccessFlags.NoIndexSignatures && indexInfo.keyType !== numberType) { + if ( + accessFlags & AccessFlags.NoIndexSignatures && + indexInfo.keyType !== numberType + ) { if (accessExpression) { if (accessFlags & AccessFlags.Writing) { - error(accessExpression, Diagnostics.Type_0_is_generic_and_can_only_be_indexed_for_reading, typeToString(originalObjectType)); - } - else { - error(accessExpression, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(originalObjectType)); + error( + accessExpression, + Diagnostics.Type_0_is_generic_and_can_only_be_indexed_for_reading, + typeToString(originalObjectType) + ); + } else { + error( + accessExpression, + Diagnostics.Type_0_cannot_be_used_to_index_type_1, + typeToString(indexType), + typeToString(originalObjectType) + ); } } return undefined; } - if (accessNode && indexInfo.keyType === stringType && !isTypeAssignableToKind(indexType, TypeFlags.String | TypeFlags.Number)) { - const indexNode = getIndexNodeForAccessExpression(accessNode); - error(indexNode, Diagnostics.Type_0_cannot_be_used_as_an_index_type, typeToString(indexType)); - return accessFlags & AccessFlags.IncludeUndefined ? getUnionType([indexInfo.type, missingType]) : indexInfo.type; + if ( + accessNode && + indexInfo.keyType === stringType && + !isTypeAssignableToKind( + indexType, + TypeFlags.String | TypeFlags.Number + ) + ) { + const indexNode = + getIndexNodeForAccessExpression(accessNode); + error( + indexNode, + Diagnostics.Type_0_cannot_be_used_as_an_index_type, + typeToString(indexType) + ); + return accessFlags & AccessFlags.IncludeUndefined + ? getUnionType([indexInfo.type, missingType]) + : indexInfo.type; } errorIfWritingToReadonlyIndex(indexInfo); // When accessing an enum object with its own type, // e.g. E[E.A] for enum E { A }, undefined shouldn't // be included in the result type if ( - (accessFlags & AccessFlags.IncludeUndefined) && - !(objectType.symbol && - objectType.symbol.flags & (SymbolFlags.RegularEnum | SymbolFlags.ConstEnum) && - (indexType.symbol && - indexType.flags & TypeFlags.EnumLiteral && - getParentOfSymbol(indexType.symbol) === objectType.symbol)) + accessFlags & AccessFlags.IncludeUndefined && + !( + objectType.symbol && + objectType.symbol.flags & + (SymbolFlags.RegularEnum | SymbolFlags.ConstEnum) && + indexType.symbol && + indexType.flags & TypeFlags.EnumLiteral && + getParentOfSymbol(indexType.symbol) === + objectType.symbol + ) ) { return getUnionType([indexInfo.type, missingType]); } @@ -19203,67 +33539,173 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (accessExpression && !isConstEnumObjectType(objectType)) { if (isObjectLiteralType(objectType)) { - if (noImplicitAny && indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) { - diagnostics.add(createDiagnosticForNode(accessExpression, Diagnostics.Property_0_does_not_exist_on_type_1, (indexType as StringLiteralType).value, typeToString(objectType))); + if ( + noImplicitAny && + indexType.flags & + (TypeFlags.StringLiteral | TypeFlags.NumberLiteral) + ) { + diagnostics.add( + createDiagnosticForNode( + accessExpression, + Diagnostics.Property_0_does_not_exist_on_type_1, + (indexType as StringLiteralType).value, + typeToString(objectType) + ) + ); return undefinedType; - } - else if (indexType.flags & (TypeFlags.Number | TypeFlags.String)) { - const types = map((objectType as ResolvedType).properties, property => { - return getTypeOfSymbol(property); - }); + } else if ( + indexType.flags & + (TypeFlags.Number | TypeFlags.String) + ) { + const types = map( + (objectType as ResolvedType).properties, + (property) => { + return getTypeOfSymbol(property); + } + ); return getUnionType(append(types, undefinedType)); } } - if (objectType.symbol === globalThisSymbol && propName !== undefined && globalThisSymbol.exports!.has(propName) && (globalThisSymbol.exports!.get(propName)!.flags & SymbolFlags.BlockScoped)) { - error(accessExpression, Diagnostics.Property_0_does_not_exist_on_type_1, unescapeLeadingUnderscores(propName), typeToString(objectType)); - } - else if (noImplicitAny && !(accessFlags & AccessFlags.SuppressNoImplicitAnyError)) { - if (propName !== undefined && typeHasStaticProperty(propName, objectType)) { + if ( + objectType.symbol === globalThisSymbol && + propName !== undefined && + globalThisSymbol.exports!.has(propName) && + globalThisSymbol.exports!.get(propName)!.flags & + SymbolFlags.BlockScoped + ) { + error( + accessExpression, + Diagnostics.Property_0_does_not_exist_on_type_1, + unescapeLeadingUnderscores(propName), + typeToString(objectType) + ); + } else if ( + noImplicitAny && + !(accessFlags & AccessFlags.SuppressNoImplicitAnyError) + ) { + if ( + propName !== undefined && + typeHasStaticProperty(propName, objectType) + ) { const typeName = typeToString(objectType); - 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) + "]"); - } - else if (getIndexTypeOfType(objectType, numberType)) { - error(accessExpression.argumentExpression, Diagnostics.Element_implicitly_has_an_any_type_because_index_expression_is_not_of_type_number); - } - else { + 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 + ) + + "]" + ); + } else if (getIndexTypeOfType(objectType, numberType)) { + error( + accessExpression.argumentExpression, + Diagnostics.Element_implicitly_has_an_any_type_because_index_expression_is_not_of_type_number + ); + } else { let suggestion: string | undefined; - if (propName !== undefined && (suggestion = getSuggestionForNonexistentProperty(propName as string, objectType))) { + if ( + propName !== undefined && + (suggestion = getSuggestionForNonexistentProperty( + propName as string, + objectType + )) + ) { if (suggestion !== undefined) { - error(accessExpression.argumentExpression, Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2, propName as string, typeToString(objectType), suggestion); + error( + accessExpression.argumentExpression, + Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2, + propName as string, + typeToString(objectType), + suggestion + ); } - } - else { - const suggestion = getSuggestionForNonexistentIndexSignature(objectType, accessExpression, indexType); + } else { + const suggestion = + getSuggestionForNonexistentIndexSignature( + objectType, + accessExpression, + indexType + ); if (suggestion !== undefined) { - 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); - } - else { - let errorInfo: DiagnosticMessageChain | undefined; + 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 + ); + } else { + let errorInfo: + | DiagnosticMessageChain + | undefined; if (indexType.flags & TypeFlags.EnumLiteral) { - errorInfo = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Property_0_does_not_exist_on_type_1, "[" + typeToString(indexType) + "]", typeToString(objectType)); - } - else if (indexType.flags & TypeFlags.UniqueESSymbol) { - const symbolName = getFullyQualifiedName((indexType as UniqueESSymbolType).symbol, accessExpression); - errorInfo = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Property_0_does_not_exist_on_type_1, "[" + symbolName + "]", typeToString(objectType)); - } - else if (indexType.flags & TypeFlags.StringLiteral) { - errorInfo = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Property_0_does_not_exist_on_type_1, (indexType as StringLiteralType).value, typeToString(objectType)); - } - else if (indexType.flags & TypeFlags.NumberLiteral) { - errorInfo = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Property_0_does_not_exist_on_type_1, (indexType as NumberLiteralType).value, typeToString(objectType)); - } - else if (indexType.flags & (TypeFlags.Number | TypeFlags.String)) { - errorInfo = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.No_index_signature_with_a_parameter_of_type_0_was_found_on_type_1, typeToString(indexType), typeToString(objectType)); + errorInfo = chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Property_0_does_not_exist_on_type_1, + "[" + typeToString(indexType) + "]", + typeToString(objectType) + ); + } else if ( + indexType.flags & TypeFlags.UniqueESSymbol + ) { + const symbolName = getFullyQualifiedName( + (indexType as UniqueESSymbolType) + .symbol, + accessExpression + ); + errorInfo = chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Property_0_does_not_exist_on_type_1, + "[" + symbolName + "]", + typeToString(objectType) + ); + } else if ( + indexType.flags & TypeFlags.StringLiteral + ) { + errorInfo = chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Property_0_does_not_exist_on_type_1, + (indexType as StringLiteralType).value, + typeToString(objectType) + ); + } else if ( + indexType.flags & TypeFlags.NumberLiteral + ) { + errorInfo = chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Property_0_does_not_exist_on_type_1, + (indexType as NumberLiteralType).value, + typeToString(objectType) + ); + } else if ( + indexType.flags & + (TypeFlags.Number | TypeFlags.String) + ) { + errorInfo = chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.No_index_signature_with_a_parameter_of_type_0_was_found_on_type_1, + typeToString(indexType), + typeToString(objectType) + ); } errorInfo = chainDiagnosticMessages( errorInfo, Diagnostics.Element_implicitly_has_an_any_type_because_expression_of_type_0_can_t_be_used_to_index_type_1, typeToString(fullIndexType), - typeToString(objectType), + typeToString(objectType) + ); + diagnostics.add( + createDiagnosticForNodeFromMessageChain( + getSourceFileOfNode(accessExpression), + accessExpression, + errorInfo + ) ); - diagnostics.add(createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(accessExpression), accessExpression, errorInfo)); } } } @@ -19271,7 +33713,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } } - if (accessFlags & AccessFlags.AllowMissing && isObjectLiteralType(objectType)) { + if ( + accessFlags & AccessFlags.AllowMissing && + isObjectLiteralType(objectType) + ) { return undefinedType; } if (isJSLiteralType(objectType)) { @@ -19279,15 +33724,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (accessNode) { const indexNode = getIndexNodeForAccessExpression(accessNode); - if (indexNode.kind !== SyntaxKind.BigIntLiteral && indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) { - error(indexNode, Diagnostics.Property_0_does_not_exist_on_type_1, "" + (indexType as StringLiteralType | NumberLiteralType).value, typeToString(objectType)); - } - else if (indexType.flags & (TypeFlags.String | TypeFlags.Number)) { - error(indexNode, Diagnostics.Type_0_has_no_matching_index_signature_for_type_1, typeToString(objectType), typeToString(indexType)); - } - else { - const typeString = indexNode.kind === SyntaxKind.BigIntLiteral ? "bigint" : typeToString(indexType); - error(indexNode, Diagnostics.Type_0_cannot_be_used_as_an_index_type, typeString); + if ( + indexNode.kind !== SyntaxKind.BigIntLiteral && + indexType.flags & + (TypeFlags.StringLiteral | TypeFlags.NumberLiteral) + ) { + error( + indexNode, + Diagnostics.Property_0_does_not_exist_on_type_1, + "" + + (indexType as StringLiteralType | NumberLiteralType) + .value, + typeToString(objectType) + ); + } else if ( + indexType.flags & + (TypeFlags.String | TypeFlags.Number) + ) { + error( + indexNode, + Diagnostics.Type_0_has_no_matching_index_signature_for_type_1, + typeToString(objectType), + typeToString(indexType) + ); + } else { + const typeString = + indexNode.kind === SyntaxKind.BigIntLiteral + ? "bigint" + : typeToString(indexType); + error( + indexNode, + Diagnostics.Type_0_cannot_be_used_as_an_index_type, + typeString + ); } } if (isTypeAny(indexType)) { @@ -19295,18 +33764,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } return undefined; - function errorIfWritingToReadonlyIndex(indexInfo: IndexInfo | undefined): void { - if (indexInfo && indexInfo.isReadonly && accessExpression && (isAssignmentTarget(accessExpression) || isDeleteTarget(accessExpression))) { - error(accessExpression, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(objectType)); + function errorIfWritingToReadonlyIndex( + indexInfo: IndexInfo | undefined + ): void { + if ( + indexInfo && + indexInfo.isReadonly && + accessExpression && + (isAssignmentTarget(accessExpression) || + isDeleteTarget(accessExpression)) + ) { + error( + accessExpression, + Diagnostics.Index_signature_in_type_0_only_permits_reading, + typeToString(objectType) + ); } } } - function getIndexNodeForAccessExpression(accessNode: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression) { - return accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode.argumentExpression : - accessNode.kind === SyntaxKind.IndexedAccessType ? accessNode.indexType : - accessNode.kind === SyntaxKind.ComputedPropertyName ? accessNode.expression : - accessNode; + function getIndexNodeForAccessExpression( + accessNode: + | ElementAccessExpression + | IndexedAccessTypeNode + | PropertyName + | BindingName + | SyntheticExpression + ) { + return accessNode.kind === SyntaxKind.ElementAccessExpression + ? accessNode.argumentExpression + : accessNode.kind === SyntaxKind.IndexedAccessType + ? accessNode.indexType + : accessNode.kind === SyntaxKind.ComputedPropertyName + ? accessNode.expression + : accessNode; } function isPatternLiteralPlaceholderType(type: Type): boolean { @@ -19315,27 +33806,51 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // more object type tags. let seenPlaceholder = false; for (const t of (type as IntersectionType).types) { - if (t.flags & (TypeFlags.Literal | TypeFlags.Nullable) || isPatternLiteralPlaceholderType(t)) { + if ( + t.flags & (TypeFlags.Literal | TypeFlags.Nullable) || + isPatternLiteralPlaceholderType(t) + ) { seenPlaceholder = true; - } - else if (!(t.flags & TypeFlags.Object)) { + } else if (!(t.flags & TypeFlags.Object)) { return false; } } return seenPlaceholder; } - return !!(type.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt)) || isPatternLiteralType(type); + return ( + !!( + type.flags & + (TypeFlags.Any | + TypeFlags.String | + TypeFlags.Number | + TypeFlags.BigInt) + ) || isPatternLiteralType(type) + ); } function isPatternLiteralType(type: Type) { // A pattern literal type is a template literal or a string mapping type that contains only // non-generic pattern literal placeholders. - return !!(type.flags & TypeFlags.TemplateLiteral) && every((type as TemplateLiteralType).types, isPatternLiteralPlaceholderType) || - !!(type.flags & TypeFlags.StringMapping) && isPatternLiteralPlaceholderType((type as StringMappingType).type); + return ( + (!!(type.flags & TypeFlags.TemplateLiteral) && + every( + (type as TemplateLiteralType).types, + isPatternLiteralPlaceholderType + )) || + (!!(type.flags & TypeFlags.StringMapping) && + isPatternLiteralPlaceholderType( + (type as StringMappingType).type + )) + ); } function isGenericStringLikeType(type: Type) { - return !!(type.flags & (TypeFlags.TemplateLiteral | TypeFlags.StringMapping)) && !isPatternLiteralType(type); + return ( + !!( + type.flags & + (TypeFlags.TemplateLiteral | TypeFlags.StringMapping) + ) && !isPatternLiteralType(type) + ); } function isGenericType(type: Type): boolean { @@ -19343,7 +33858,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isGenericObjectType(type: Type): boolean { - return !!(getGenericObjectFlags(type) & ObjectFlags.IsGenericObjectType); + return !!( + getGenericObjectFlags(type) & ObjectFlags.IsGenericObjectType + ); } function isGenericIndexType(type: Type): boolean { @@ -19351,45 +33868,105 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getGenericObjectFlags(type: Type): ObjectFlags { - if (type.flags & (TypeFlags.UnionOrIntersection)) { - if (!((type as UnionOrIntersectionType).objectFlags & ObjectFlags.IsGenericTypeComputed)) { - (type as UnionOrIntersectionType).objectFlags |= ObjectFlags.IsGenericTypeComputed | - reduceLeft((type as UnionOrIntersectionType).types, (flags, t) => flags | getGenericObjectFlags(t), 0); + if (type.flags & TypeFlags.UnionOrIntersection) { + if ( + !( + (type as UnionOrIntersectionType).objectFlags & + ObjectFlags.IsGenericTypeComputed + ) + ) { + (type as UnionOrIntersectionType).objectFlags |= + ObjectFlags.IsGenericTypeComputed | + reduceLeft( + (type as UnionOrIntersectionType).types, + (flags, t) => flags | getGenericObjectFlags(t), + 0 + ); } - return (type as UnionOrIntersectionType).objectFlags & ObjectFlags.IsGenericType; + return ( + (type as UnionOrIntersectionType).objectFlags & + ObjectFlags.IsGenericType + ); } if (type.flags & TypeFlags.Substitution) { - if (!((type as SubstitutionType).objectFlags & ObjectFlags.IsGenericTypeComputed)) { - (type as SubstitutionType).objectFlags |= ObjectFlags.IsGenericTypeComputed | - getGenericObjectFlags((type as SubstitutionType).baseType) | getGenericObjectFlags((type as SubstitutionType).constraint); + if ( + !( + (type as SubstitutionType).objectFlags & + ObjectFlags.IsGenericTypeComputed + ) + ) { + (type as SubstitutionType).objectFlags |= + ObjectFlags.IsGenericTypeComputed | + getGenericObjectFlags((type as SubstitutionType).baseType) | + getGenericObjectFlags( + (type as SubstitutionType).constraint + ); } - return (type as SubstitutionType).objectFlags & ObjectFlags.IsGenericType; + return ( + (type as SubstitutionType).objectFlags & + ObjectFlags.IsGenericType + ); } - return (type.flags & TypeFlags.InstantiableNonPrimitive || isGenericMappedType(type) || isGenericTupleType(type) ? ObjectFlags.IsGenericObjectType : 0) | - (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.Index) || isGenericStringLikeType(type) ? ObjectFlags.IsGenericIndexType : 0); + return ( + (type.flags & TypeFlags.InstantiableNonPrimitive || + isGenericMappedType(type) || + isGenericTupleType(type) + ? ObjectFlags.IsGenericObjectType + : 0) | + (type.flags & + (TypeFlags.InstantiableNonPrimitive | TypeFlags.Index) || + isGenericStringLikeType(type) + ? ObjectFlags.IsGenericIndexType + : 0) + ); } function getSimplifiedType(type: Type, writing: boolean): Type { - return type.flags & TypeFlags.IndexedAccess ? getSimplifiedIndexedAccessType(type as IndexedAccessType, writing) : - type.flags & TypeFlags.Conditional ? getSimplifiedConditionalType(type as ConditionalType, writing) : - type; + return type.flags & TypeFlags.IndexedAccess + ? getSimplifiedIndexedAccessType(type as IndexedAccessType, writing) + : type.flags & TypeFlags.Conditional + ? getSimplifiedConditionalType(type as ConditionalType, writing) + : type; } - function distributeIndexOverObjectType(objectType: Type, indexType: Type, writing: boolean) { + function distributeIndexOverObjectType( + objectType: Type, + indexType: Type, + writing: boolean + ) { // (T | U)[K] -> T[K] | U[K] (reading) // (T | U)[K] -> T[K] & U[K] (writing) // (T & U)[K] -> T[K] & U[K] - if (objectType.flags & TypeFlags.Union || objectType.flags & TypeFlags.Intersection && !shouldDeferIndexType(objectType)) { - const types = map((objectType as UnionOrIntersectionType).types, t => getSimplifiedType(getIndexedAccessType(t, indexType), writing)); - return objectType.flags & TypeFlags.Intersection || writing ? getIntersectionType(types) : getUnionType(types); + if ( + objectType.flags & TypeFlags.Union || + (objectType.flags & TypeFlags.Intersection && + !shouldDeferIndexType(objectType)) + ) { + const types = map( + (objectType as UnionOrIntersectionType).types, + (t) => + getSimplifiedType( + getIndexedAccessType(t, indexType), + writing + ) + ); + return objectType.flags & TypeFlags.Intersection || writing + ? getIntersectionType(types) + : getUnionType(types); } } - function distributeObjectOverIndexType(objectType: Type, indexType: Type, writing: boolean) { + function distributeObjectOverIndexType( + objectType: Type, + indexType: Type, + writing: boolean + ) { // T[A | B] -> T[A] | T[B] (reading) // T[A | B] -> T[A] & T[B] (writing) if (indexType.flags & TypeFlags.Union) { - const types = map((indexType as UnionType).types, t => getSimplifiedType(getIndexedAccessType(objectType, t), writing)); + const types = map((indexType as UnionType).types, (t) => + getSimplifiedType(getIndexedAccessType(objectType, t), writing) + ); return writing ? getIntersectionType(types) : getUnionType(types); } } @@ -19397,7 +33974,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Transform an indexed access to a simpler form, if possible. Return the simpler form, or return // the type itself if no transformation is possible. The writing flag indicates that the type is // the target of an assignment. - function getSimplifiedIndexedAccessType(type: IndexedAccessType, writing: boolean): Type { + function getSimplifiedIndexedAccessType( + type: IndexedAccessType, + writing: boolean + ): Type { const cache = writing ? "simplifiedForWriting" : "simplifiedForReading"; if (type[cache]) { return type[cache] === circularConstraintType ? type : type[cache]; @@ -19409,18 +33989,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const indexType = getSimplifiedType(type.indexType, writing); // T[A | B] -> T[A] | T[B] (reading) // T[A | B] -> T[A] & T[B] (writing) - const distributedOverIndex = distributeObjectOverIndexType(objectType, indexType, writing); + const distributedOverIndex = distributeObjectOverIndexType( + objectType, + indexType, + writing + ); if (distributedOverIndex) { - return type[cache] = distributedOverIndex; + return (type[cache] = distributedOverIndex); } // Only do the inner distributions if the index can no longer be instantiated to cause index distribution again if (!(indexType.flags & TypeFlags.Instantiable)) { // (T | U)[K] -> T[K] | U[K] (reading) // (T | U)[K] -> T[K] & U[K] (writing) // (T & U)[K] -> T[K] & U[K] - const distributedOverObject = distributeIndexOverObjectType(objectType, indexType, writing); + const distributedOverObject = distributeIndexOverObjectType( + objectType, + indexType, + writing + ); if (distributedOverObject) { - return type[cache] = distributedOverObject; + return (type[cache] = distributedOverObject); } } // So ultimately (reading): @@ -19429,42 +34017,84 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // A generic tuple type indexed by a number exists only when the index type doesn't select a // fixed element. We simplify to either the combined type of all elements (when the index type // the actual number type) or to the combined type of all non-fixed elements. - if (isGenericTupleType(objectType) && indexType.flags & TypeFlags.NumberLike) { - const elementType = getElementTypeOfSliceOfTupleType(objectType, indexType.flags & TypeFlags.Number ? 0 : objectType.target.fixedLength, /*endSkipCount*/ 0, writing); + if ( + isGenericTupleType(objectType) && + indexType.flags & TypeFlags.NumberLike + ) { + const elementType = getElementTypeOfSliceOfTupleType( + objectType, + indexType.flags & TypeFlags.Number + ? 0 + : objectType.target.fixedLength, + /*endSkipCount*/ 0, + writing + ); if (elementType) { - return type[cache] = elementType; + return (type[cache] = elementType); } } // If the object type is a mapped type { [P in K]: E }, where K is generic, or { [P in K as N]: E }, where // K is generic and N is assignable to P, instantiate E using a mapper that substitutes the index type for P. // For example, for an index access { [P in K]: Box }[X], we construct the type Box. if (isGenericMappedType(objectType)) { - if (getMappedTypeNameTypeKind(objectType) !== MappedTypeNameTypeKind.Remapping) { - return type[cache] = mapType(substituteIndexedMappedType(objectType, type.indexType), t => getSimplifiedType(t, writing)); + if ( + getMappedTypeNameTypeKind(objectType) !== + MappedTypeNameTypeKind.Remapping + ) { + return (type[cache] = mapType( + substituteIndexedMappedType(objectType, type.indexType), + (t) => getSimplifiedType(t, writing) + )); } } - return type[cache] = type; + return (type[cache] = type); } - function getSimplifiedConditionalType(type: ConditionalType, writing: boolean) { + function getSimplifiedConditionalType( + type: ConditionalType, + writing: boolean + ) { const checkType = type.checkType; const extendsType = type.extendsType; const trueType = getTrueTypeFromConditionalType(type); const falseType = getFalseTypeFromConditionalType(type); // Simplifications for types of the form `T extends U ? T : never` and `T extends U ? never : T`. - if (falseType.flags & TypeFlags.Never && getActualTypeVariable(trueType) === getActualTypeVariable(checkType)) { - if (checkType.flags & TypeFlags.Any || isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(extendsType))) { // Always true + if ( + falseType.flags & TypeFlags.Never && + getActualTypeVariable(trueType) === getActualTypeVariable(checkType) + ) { + if ( + checkType.flags & TypeFlags.Any || + isTypeAssignableTo( + getRestrictiveInstantiation(checkType), + getRestrictiveInstantiation(extendsType) + ) + ) { + // Always true return getSimplifiedType(trueType, writing); - } - else if (isIntersectionEmpty(checkType, extendsType)) { // Always false + } else if (isIntersectionEmpty(checkType, extendsType)) { + // Always false return neverType; } - } - else if (trueType.flags & TypeFlags.Never && getActualTypeVariable(falseType) === getActualTypeVariable(checkType)) { - if (!(checkType.flags & TypeFlags.Any) && isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(extendsType))) { // Always true + } else if ( + trueType.flags & TypeFlags.Never && + getActualTypeVariable(falseType) === + getActualTypeVariable(checkType) + ) { + if ( + !(checkType.flags & TypeFlags.Any) && + isTypeAssignableTo( + getRestrictiveInstantiation(checkType), + getRestrictiveInstantiation(extendsType) + ) + ) { + // Always true return neverType; - } - else if (checkType.flags & TypeFlags.Any || isIntersectionEmpty(checkType, extendsType)) { // Always false + } else if ( + checkType.flags & TypeFlags.Any || + isIntersectionEmpty(checkType, extendsType) + ) { + // Always false return getSimplifiedType(falseType, writing); } } @@ -19475,7 +34105,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Invokes union simplification logic to determine if an intersection is considered empty as a union constituent */ function isIntersectionEmpty(type1: Type, type2: Type) { - return !!(getUnionType([intersectTypes(type1, type2), neverType]).flags & TypeFlags.Never); + return !!( + getUnionType([intersectTypes(type1, type2), neverType]).flags & + TypeFlags.Never + ); } // Given an indexed access on a mapped type of the form { [P in K]: E }[X], return an instantiation of E where P is @@ -19484,31 +34117,82 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // are optional. If the modifiers type is generic, conservatively estimate optionality by recursively looking for // mapped types that include '?' modifiers. function substituteIndexedMappedType(objectType: MappedType, index: Type) { - const mapper = createTypeMapper([getTypeParameterFromMappedType(objectType)], [index]); + const mapper = createTypeMapper( + [getTypeParameterFromMappedType(objectType)], + [index] + ); const templateMapper = combineTypeMappers(objectType.mapper, mapper); - const instantiatedTemplateType = instantiateType(getTemplateTypeFromMappedType(objectType.target as MappedType || objectType), templateMapper); - const isOptional = getMappedTypeOptionality(objectType) > 0 || (isGenericType(objectType) ? - getCombinedMappedTypeOptionality(getModifiersTypeFromMappedType(objectType)) > 0 : - couldAccessOptionalProperty(objectType, index)); - return addOptionality(instantiatedTemplateType, /*isProperty*/ true, isOptional); + const instantiatedTemplateType = instantiateType( + getTemplateTypeFromMappedType( + (objectType.target as MappedType) || objectType + ), + templateMapper + ); + const isOptional = + getMappedTypeOptionality(objectType) > 0 || + (isGenericType(objectType) + ? getCombinedMappedTypeOptionality( + getModifiersTypeFromMappedType(objectType) + ) > 0 + : couldAccessOptionalProperty(objectType, index)); + return addOptionality( + instantiatedTemplateType, + /*isProperty*/ true, + isOptional + ); } // Return true if an indexed access with the given object and index types could access an optional property. function couldAccessOptionalProperty(objectType: Type, indexType: Type) { const indexConstraint = getBaseConstraintOfType(indexType); - return !!indexConstraint && some(getPropertiesOfType(objectType), p => - !!(p.flags & SymbolFlags.Optional) && - isTypeAssignableTo(getLiteralTypeFromProperty(p, TypeFlags.StringOrNumberLiteralOrUnique), indexConstraint)); + return ( + !!indexConstraint && + some( + getPropertiesOfType(objectType), + (p) => + !!(p.flags & SymbolFlags.Optional) && + isTypeAssignableTo( + getLiteralTypeFromProperty( + p, + TypeFlags.StringOrNumberLiteralOrUnique + ), + indexConstraint + ) + ) + ); } - function getIndexedAccessType(objectType: Type, indexType: Type, accessFlags = AccessFlags.None, accessNode?: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type { - return getIndexedAccessTypeOrUndefined(objectType, indexType, accessFlags, accessNode, aliasSymbol, aliasTypeArguments) || (accessNode ? errorType : unknownType); + function getIndexedAccessType( + objectType: Type, + indexType: Type, + accessFlags = AccessFlags.None, + accessNode?: + | ElementAccessExpression + | IndexedAccessTypeNode + | PropertyName + | BindingName + | SyntheticExpression, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[] + ): Type { + return ( + getIndexedAccessTypeOrUndefined( + objectType, + indexType, + accessFlags, + accessNode, + aliasSymbol, + aliasTypeArguments + ) || (accessNode ? errorType : unknownType) + ); } function indexTypeLessThan(indexType: Type, limit: number) { - return everyType(indexType, t => { + return everyType(indexType, (t) => { if (t.flags & TypeFlags.StringOrNumberLiteral) { - const propName = getPropertyNameFromType(t as StringLiteralType | NumberLiteralType); + const propName = getPropertyNameFromType( + t as StringLiteralType | NumberLiteralType + ); if (isNumericLiteralName(propName)) { const index = +propName; return index >= 0 && index < limit; @@ -19518,19 +34202,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { }); } - function getIndexedAccessTypeOrUndefined(objectType: Type, indexType: Type, accessFlags = AccessFlags.None, accessNode?: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type | undefined { + function getIndexedAccessTypeOrUndefined( + objectType: Type, + indexType: Type, + accessFlags = AccessFlags.None, + accessNode?: + | ElementAccessExpression + | IndexedAccessTypeNode + | PropertyName + | BindingName + | SyntheticExpression, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[] + ): Type | undefined { if (objectType === wildcardType || indexType === wildcardType) { return wildcardType; } objectType = getReducedType(objectType); // If the object type has a string index signature and no other members we know that the result will // always be the type of that index signature and we can simplify accordingly. - if (isStringIndexSignatureOnlyType(objectType) && !(indexType.flags & TypeFlags.Nullable) && isTypeAssignableToKind(indexType, TypeFlags.String | TypeFlags.Number)) { + if ( + isStringIndexSignatureOnlyType(objectType) && + !(indexType.flags & TypeFlags.Nullable) && + isTypeAssignableToKind( + indexType, + TypeFlags.String | TypeFlags.Number + ) + ) { indexType = stringType; } // In noUncheckedIndexedAccess mode, indexed access operations that occur in an expression in a read position and resolve to // an index signature have 'undefined' included in their type. - if (compilerOptions.noUncheckedIndexedAccess && accessFlags & AccessFlags.ExpressionPosition) accessFlags |= AccessFlags.IncludeUndefined; + if ( + compilerOptions.noUncheckedIndexedAccess && + accessFlags & AccessFlags.ExpressionPosition + ) + accessFlags |= AccessFlags.IncludeUndefined; // If the index type is generic, or if the object type is generic and doesn't originate in an expression and // the operation isn't exclusively indexing the fixed (non-variadic) portion of a tuple type, we are performing // a higher-order index access where we cannot meaningfully access the properties of the object type. Note that @@ -19538,19 +34245,47 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // preserve backwards compatibility. For example, an element access 'this["foo"]' has always been resolved // eagerly using the constraint type of 'this' at the given location. if ( - isGenericIndexType(indexType) || (accessNode && accessNode.kind !== SyntaxKind.IndexedAccessType ? - isGenericTupleType(objectType) && !indexTypeLessThan(indexType, getTotalFixedElementCount(objectType.target)) : - isGenericObjectType(objectType) && !(isTupleType(objectType) && indexTypeLessThan(indexType, getTotalFixedElementCount(objectType.target))) || isGenericReducibleType(objectType)) + isGenericIndexType(indexType) || + (accessNode && accessNode.kind !== SyntaxKind.IndexedAccessType + ? isGenericTupleType(objectType) && + !indexTypeLessThan( + indexType, + getTotalFixedElementCount(objectType.target) + ) + : (isGenericObjectType(objectType) && + !( + isTupleType(objectType) && + indexTypeLessThan( + indexType, + getTotalFixedElementCount(objectType.target) + ) + )) || + isGenericReducibleType(objectType)) ) { if (objectType.flags & TypeFlags.AnyOrUnknown) { return objectType; } // Defer the operation by creating an indexed access type. const persistentAccessFlags = accessFlags & AccessFlags.Persistent; - const id = objectType.id + "," + indexType.id + "," + persistentAccessFlags + getAliasId(aliasSymbol, aliasTypeArguments); + const id = + objectType.id + + "," + + indexType.id + + "," + + persistentAccessFlags + + getAliasId(aliasSymbol, aliasTypeArguments); let type = indexedAccessTypes.get(id); if (!type) { - indexedAccessTypes.set(id, type = createIndexedAccessType(objectType, indexType, persistentAccessFlags, aliasSymbol, aliasTypeArguments)); + indexedAccessTypes.set( + id, + (type = createIndexedAccessType( + objectType, + indexType, + persistentAccessFlags, + aliasSymbol, + aliasTypeArguments + )) + ); } return type; @@ -19559,19 +34294,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We treat boolean as different from other unions to improve errors; // skipping straight to getPropertyTypeForIndexType gives errors with 'boolean' instead of 'true'. const apparentObjectType = getReducedApparentType(objectType); - if (indexType.flags & TypeFlags.Union && !(indexType.flags & TypeFlags.Boolean)) { + if ( + indexType.flags & TypeFlags.Union && + !(indexType.flags & TypeFlags.Boolean) + ) { const propTypes: Type[] = []; let wasMissingProp = false; for (const t of (indexType as UnionType).types) { - const propType = getPropertyTypeForIndexType(objectType, apparentObjectType, t, indexType, accessNode, accessFlags | (wasMissingProp ? AccessFlags.SuppressNoImplicitAnyError : 0)); + const propType = getPropertyTypeForIndexType( + objectType, + apparentObjectType, + t, + indexType, + accessNode, + accessFlags | + (wasMissingProp + ? AccessFlags.SuppressNoImplicitAnyError + : 0) + ); if (propType) { propTypes.push(propType); - } - else if (!accessNode) { + } else if (!accessNode) { // If there's no error node, we can immeditely stop, since error reporting is off return undefined; - } - else { + } else { // Otherwise we set a flag and return at the end of the loop so we still mark all errors wasMissingProp = true; } @@ -19580,10 +34326,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } return accessFlags & AccessFlags.Writing - ? getIntersectionType(propTypes, IntersectionFlags.None, aliasSymbol, aliasTypeArguments) - : getUnionType(propTypes, UnionReduction.Literal, aliasSymbol, aliasTypeArguments); - } - return getPropertyTypeForIndexType(objectType, apparentObjectType, indexType, indexType, accessNode, accessFlags | AccessFlags.CacheSymbol | AccessFlags.ReportDeprecated); + ? getIntersectionType( + propTypes, + IntersectionFlags.None, + aliasSymbol, + aliasTypeArguments + ) + : getUnionType( + propTypes, + UnionReduction.Literal, + aliasSymbol, + aliasTypeArguments + ); + } + return getPropertyTypeForIndexType( + objectType, + apparentObjectType, + indexType, + indexType, + accessNode, + accessFlags | AccessFlags.CacheSymbol | AccessFlags.ReportDeprecated + ); } function getTypeFromIndexedAccessTypeNode(node: IndexedAccessTypeNode) { @@ -19592,7 +34355,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const objectType = getTypeFromTypeNode(node.objectType); const indexType = getTypeFromTypeNode(node.indexType); const potentialAlias = getAliasSymbolForTypeNode(node); - links.resolvedType = getIndexedAccessType(objectType, indexType, AccessFlags.None, node, potentialAlias, getTypeArgumentsForAliasSymbol(potentialAlias)); + links.resolvedType = getIndexedAccessType( + objectType, + indexType, + AccessFlags.None, + node, + potentialAlias, + getTypeArgumentsForAliasSymbol(potentialAlias) + ); } return links.resolvedType; } @@ -19600,10 +34370,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getTypeFromMappedTypeNode(node: MappedTypeNode): Type { const links = getNodeLinks(node); if (!links.resolvedType) { - const type = createObjectType(ObjectFlags.Mapped, node.symbol) as MappedType; + const type = createObjectType( + ObjectFlags.Mapped, + node.symbol + ) as MappedType; type.declaration = node; type.aliasSymbol = getAliasSymbolForTypeNode(node); - type.aliasTypeArguments = getTypeArgumentsForAliasSymbol(type.aliasSymbol); + type.aliasTypeArguments = getTypeArgumentsForAliasSymbol( + type.aliasSymbol + ); links.resolvedType = type; // Eagerly resolve the constraint type which forces an error if the constraint type circularly // references itself through one or more type aliases. @@ -19617,26 +34392,51 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getActualTypeVariable((type as SubstitutionType).baseType); } if ( - type.flags & TypeFlags.IndexedAccess && ( - (type as IndexedAccessType).objectType.flags & TypeFlags.Substitution || - (type as IndexedAccessType).indexType.flags & TypeFlags.Substitution - ) + type.flags & TypeFlags.IndexedAccess && + ((type as IndexedAccessType).objectType.flags & + TypeFlags.Substitution || + (type as IndexedAccessType).indexType.flags & + TypeFlags.Substitution) ) { - return getIndexedAccessType(getActualTypeVariable((type as IndexedAccessType).objectType), getActualTypeVariable((type as IndexedAccessType).indexType)); + return getIndexedAccessType( + getActualTypeVariable((type as IndexedAccessType).objectType), + getActualTypeVariable((type as IndexedAccessType).indexType) + ); } return type; } function isSimpleTupleType(node: TypeNode): boolean { - return isTupleTypeNode(node) && length(node.elements) > 0 && - !some(node.elements, e => isOptionalTypeNode(e) || isRestTypeNode(e) || isNamedTupleMember(e) && !!(e.questionToken || e.dotDotDotToken)); + return ( + isTupleTypeNode(node) && + length(node.elements) > 0 && + !some( + node.elements, + (e) => + isOptionalTypeNode(e) || + isRestTypeNode(e) || + (isNamedTupleMember(e) && + !!(e.questionToken || e.dotDotDotToken)) + ) + ); } function isDeferredType(type: Type, checkTuples: boolean) { - return isGenericType(type) || checkTuples && isTupleType(type) && some(getElementTypes(type), isGenericType); + return ( + isGenericType(type) || + (checkTuples && + isTupleType(type) && + some(getElementTypes(type), isGenericType)) + ); } - function getConditionalType(root: ConditionalRoot, mapper: TypeMapper | undefined, forConstraint: boolean, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type { + function getConditionalType( + root: ConditionalRoot, + mapper: TypeMapper | undefined, + forConstraint: boolean, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[] + ): Type { let result; let extraTypes: Type[] | undefined; let tailCount = 0; @@ -19647,10 +34447,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // cases we increment the tail recursion counter and stop after 1000 iterations. while (true) { if (tailCount === 1000) { - error(currentNode, Diagnostics.Type_instantiation_is_excessively_deep_and_possibly_infinite); + error( + currentNode, + Diagnostics.Type_instantiation_is_excessively_deep_and_possibly_infinite + ); return errorType; } - const checkType = instantiateType(getActualTypeVariable(root.checkType), mapper); + const checkType = instantiateType( + getActualTypeVariable(root.checkType), + mapper + ); const extendsType = instantiateType(root.extendsType, mapper); if (checkType === errorType || extendsType === errorType) { return errorType; @@ -19663,8 +34469,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // When the check and extends types are simple tuple types of the same arity, we defer resolution of the // conditional type when any tuple elements are generic. This is such that non-distributable conditional // types can be written `[X] extends [Y] ? ...` and be deferred similarly to `X extends Y ? ...`. - const checkTuples = isSimpleTupleType(checkTypeNode) && isSimpleTupleType(extendsTypeNode) && - length((checkTypeNode as TupleTypeNode).elements) === length((extendsTypeNode as TupleTypeNode).elements); + const checkTuples = + isSimpleTupleType(checkTypeNode) && + isSimpleTupleType(extendsTypeNode) && + length((checkTypeNode as TupleTypeNode).elements) === + length((extendsTypeNode as TupleTypeNode).elements); const checkTypeDeferred = isDeferredType(checkType, checkTuples); let combinedMapper: TypeMapper | undefined; if (root.inferTypeParameters) { @@ -19682,44 +34491,92 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // This means we have two mappers that need applying: // * The original `mapper` used to create this conditional // * The mapper that maps the infer type parameter to its inference result (`context.mapper`) - const context = createInferenceContext(root.inferTypeParameters, /*signature*/ undefined, InferenceFlags.None); + const context = createInferenceContext( + root.inferTypeParameters, + /*signature*/ undefined, + InferenceFlags.None + ); if (mapper) { - context.nonFixingMapper = combineTypeMappers(context.nonFixingMapper, mapper); + context.nonFixingMapper = combineTypeMappers( + context.nonFixingMapper, + mapper + ); } if (!checkTypeDeferred) { // We don't want inferences from constraints as they may cause us to eagerly resolve the // conditional type instead of deferring resolution. Also, we always want strict function // types rules (i.e. proper contravariance) for inferences. - inferTypes(context.inferences, checkType, extendsType, InferencePriority.NoConstraints | InferencePriority.AlwaysStrict); + inferTypes( + context.inferences, + checkType, + extendsType, + InferencePriority.NoConstraints | + InferencePriority.AlwaysStrict + ); } // It's possible for 'infer T' type paramteters to be given uninstantiated constraints when the // those type parameters are used in type references (see getInferredTypeParameterConstraint). For // that reason we need context.mapper to be first in the combined mapper. See #42636 for examples. - combinedMapper = mapper ? combineTypeMappers(context.mapper, mapper) : context.mapper; + combinedMapper = mapper + ? combineTypeMappers(context.mapper, mapper) + : context.mapper; } // Instantiate the extends type including inferences for 'infer T' type parameters - const inferredExtendsType = combinedMapper ? instantiateType(root.extendsType, combinedMapper) : extendsType; + const inferredExtendsType = combinedMapper + ? instantiateType(root.extendsType, combinedMapper) + : extendsType; // We attempt to resolve the conditional type only when the check and extends types are non-generic - if (!checkTypeDeferred && !isDeferredType(inferredExtendsType, checkTuples)) { + if ( + !checkTypeDeferred && + !isDeferredType(inferredExtendsType, checkTuples) + ) { // Return falseType for a definitely false extends check. We check an instantiations of the two // types with type parameters mapped to the wildcard type, the most permissive instantiations // possible (the wildcard type is assignable to and from all types). If those are not related, // then no instantiations will be and we can just return the false branch type. - if (!(inferredExtendsType.flags & TypeFlags.AnyOrUnknown) && (checkType.flags & TypeFlags.Any || !isTypeAssignableTo(getPermissiveInstantiation(checkType), getPermissiveInstantiation(inferredExtendsType)))) { + if ( + !(inferredExtendsType.flags & TypeFlags.AnyOrUnknown) && + (checkType.flags & TypeFlags.Any || + !isTypeAssignableTo( + getPermissiveInstantiation(checkType), + getPermissiveInstantiation(inferredExtendsType) + )) + ) { // Return union of trueType and falseType for 'any' since it matches anything. Furthermore, for a // distributive conditional type applied to the constraint of a type variable, include trueType if // there are possible values of the check type that are also possible values of the extends type. // We use a reverse assignability check as it is less expensive than the comparable relationship // and avoids false positives of a non-empty intersection check. - if (checkType.flags & TypeFlags.Any || forConstraint && !(inferredExtendsType.flags & TypeFlags.Never) && someType(getPermissiveInstantiation(inferredExtendsType), t => isTypeAssignableTo(t, getPermissiveInstantiation(checkType)))) { - (extraTypes || (extraTypes = [])).push(instantiateType(getTypeFromTypeNode(root.node.trueType), combinedMapper || mapper)); + if ( + checkType.flags & TypeFlags.Any || + (forConstraint && + !(inferredExtendsType.flags & TypeFlags.Never) && + someType( + getPermissiveInstantiation(inferredExtendsType), + (t) => + isTypeAssignableTo( + t, + getPermissiveInstantiation(checkType) + ) + )) + ) { + (extraTypes || (extraTypes = [])).push( + instantiateType( + getTypeFromTypeNode(root.node.trueType), + combinedMapper || mapper + ) + ); } // If falseType is an immediately nested conditional type that isn't distributive or has an // identical checkType, switch to that type and loop. const falseType = getTypeFromTypeNode(root.node.falseType); if (falseType.flags & TypeFlags.Conditional) { const newRoot = (falseType as ConditionalType).root; - if (newRoot.node.parent === root.node && (!newRoot.isDistributive || newRoot.checkType === root.checkType)) { + if ( + newRoot.node.parent === root.node && + (!newRoot.isDistributive || + newRoot.checkType === root.checkType) + ) { root = newRoot; continue; } @@ -19735,7 +34592,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // that has no constraint. This ensures that, for example, the type // type Foo = T extends { x: string } ? string : number // doesn't immediately resolve to 'string' instead of being deferred. - if (inferredExtendsType.flags & TypeFlags.AnyOrUnknown || isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(inferredExtendsType))) { + if ( + inferredExtendsType.flags & TypeFlags.AnyOrUnknown || + isTypeAssignableTo( + getRestrictiveInstantiation(checkType), + getRestrictiveInstantiation(inferredExtendsType) + ) + ) { const trueType = getTypeFromTypeNode(root.node.trueType); const trueMapper = combinedMapper || mapper; if (canTailRecurse(trueType, trueMapper)) { @@ -19753,7 +34616,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { result.mapper = mapper; result.combinedMapper = combinedMapper; result.aliasSymbol = aliasSymbol || root.aliasSymbol; - result.aliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(root.aliasTypeArguments, mapper!); // TODO: GH#18217 + result.aliasTypeArguments = aliasSymbol + ? aliasTypeArguments + : instantiateTypes(root.aliasTypeArguments, mapper!); // TODO: GH#18217 break; } return extraTypes ? getUnionType(append(extraTypes, result)) : result; @@ -19761,15 +34626,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // (b) are non distributive, have a check type that is unaffected by instantiation, or have a non-union check // type. Note that recursion is possible only through aliased conditional types, so we only increment the tail // recursion counter for those. - function canTailRecurse(newType: Type, newMapper: TypeMapper | undefined) { + function canTailRecurse( + newType: Type, + newMapper: TypeMapper | undefined + ) { if (newType.flags & TypeFlags.Conditional && newMapper) { const newRoot = (newType as ConditionalType).root; if (newRoot.outerTypeParameters) { - const typeParamMapper = combineTypeMappers((newType as ConditionalType).mapper, newMapper); - const typeArguments = map(newRoot.outerTypeParameters, t => getMappedType(t, typeParamMapper)); - const newRootMapper = createTypeMapper(newRoot.outerTypeParameters, typeArguments); - const newCheckType = newRoot.isDistributive ? getMappedType(newRoot.checkType, newRootMapper) : undefined; - if (!newCheckType || newCheckType === newRoot.checkType || !(newCheckType.flags & (TypeFlags.Union | TypeFlags.Never))) { + const typeParamMapper = combineTypeMappers( + (newType as ConditionalType).mapper, + newMapper + ); + const typeArguments = map( + newRoot.outerTypeParameters, + (t) => getMappedType(t, typeParamMapper) + ); + const newRootMapper = createTypeMapper( + newRoot.outerTypeParameters, + typeArguments + ); + const newCheckType = newRoot.isDistributive + ? getMappedType(newRoot.checkType, newRootMapper) + : undefined; + if ( + !newCheckType || + newCheckType === newRoot.checkType || + !( + newCheckType.flags & + (TypeFlags.Union | TypeFlags.Never) + ) + ) { root = newRoot; mapper = newRootMapper; aliasSymbol = undefined; @@ -19786,21 +34672,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getTrueTypeFromConditionalType(type: ConditionalType) { - return type.resolvedTrueType || (type.resolvedTrueType = instantiateType(getTypeFromTypeNode(type.root.node.trueType), type.mapper)); + return ( + type.resolvedTrueType || + (type.resolvedTrueType = instantiateType( + getTypeFromTypeNode(type.root.node.trueType), + type.mapper + )) + ); } function getFalseTypeFromConditionalType(type: ConditionalType) { - return type.resolvedFalseType || (type.resolvedFalseType = instantiateType(getTypeFromTypeNode(type.root.node.falseType), type.mapper)); + return ( + type.resolvedFalseType || + (type.resolvedFalseType = instantiateType( + getTypeFromTypeNode(type.root.node.falseType), + type.mapper + )) + ); } function getInferredTrueTypeFromConditionalType(type: ConditionalType) { - return type.resolvedInferredTrueType || (type.resolvedInferredTrueType = type.combinedMapper ? instantiateType(getTypeFromTypeNode(type.root.node.trueType), type.combinedMapper) : getTrueTypeFromConditionalType(type)); + return ( + type.resolvedInferredTrueType || + (type.resolvedInferredTrueType = type.combinedMapper + ? instantiateType( + getTypeFromTypeNode(type.root.node.trueType), + type.combinedMapper + ) + : getTrueTypeFromConditionalType(type)) + ); } - function getInferTypeParameters(node: ConditionalTypeNode): TypeParameter[] | undefined { + function getInferTypeParameters( + node: ConditionalTypeNode + ): TypeParameter[] | undefined { let result: TypeParameter[] | undefined; if (node.locals) { - node.locals.forEach(symbol => { + node.locals.forEach((symbol) => { if (symbol.flags & SymbolFlags.TypeParameter) { result = append(result, getDeclaredTypeOfSymbol(symbol)); } @@ -19810,9 +34718,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isDistributionDependent(root: ConditionalRoot) { - return root.isDistributive && ( - isTypeParameterPossiblyReferenced(root.checkType as TypeParameter, root.node.trueType) || - isTypeParameterPossiblyReferenced(root.checkType as TypeParameter, root.node.falseType) + return ( + root.isDistributive && + (isTypeParameterPossiblyReferenced( + root.checkType as TypeParameter, + root.node.trueType + ) || + isTypeParameterPossiblyReferenced( + root.checkType as TypeParameter, + root.node.falseType + )) ); } @@ -19821,9 +34736,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!links.resolvedType) { const checkType = getTypeFromTypeNode(node.checkType); const aliasSymbol = getAliasSymbolForTypeNode(node); - const aliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol); - const allOuterTypeParameters = getOuterTypeParameters(node, /*includeThisTypes*/ true); - const outerTypeParameters = aliasTypeArguments ? allOuterTypeParameters : filter(allOuterTypeParameters, tp => isTypeParameterPossiblyReferenced(tp, node)); + const aliasTypeArguments = + getTypeArgumentsForAliasSymbol(aliasSymbol); + const allOuterTypeParameters = getOuterTypeParameters( + node, + /*includeThisTypes*/ true + ); + const outerTypeParameters = aliasTypeArguments + ? allOuterTypeParameters + : filter(allOuterTypeParameters, (tp) => + isTypeParameterPossiblyReferenced(tp, node) + ); const root: ConditionalRoot = { node, checkType, @@ -19835,10 +34758,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { aliasSymbol, aliasTypeArguments, }; - links.resolvedType = getConditionalType(root, /*mapper*/ undefined, /*forConstraint*/ false); + links.resolvedType = getConditionalType( + root, + /*mapper*/ undefined, + /*forConstraint*/ false + ); if (outerTypeParameters) { root.instantiations = new Map(); - root.instantiations.set(getTypeListId(outerTypeParameters), links.resolvedType); + root.instantiations.set( + getTypeListId(outerTypeParameters), + links.resolvedType + ); } } return links.resolvedType; @@ -19847,7 +34777,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getTypeFromInferTypeNode(node: InferTypeNode): Type { const links = getNodeLinks(node); if (!links.resolvedType) { - links.resolvedType = getDeclaredTypeOfTypeParameter(getSymbolOfDeclaration(node.typeParameter)); + links.resolvedType = getDeclaredTypeOfTypeParameter( + getSymbolOfDeclaration(node.typeParameter) + ); } return links.resolvedType; } @@ -19855,8 +34787,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getIdentifierChain(node: EntityName): Identifier[] { if (isIdentifier(node)) { return [node]; - } - else { + } else { return append(getIdentifierChain(node.left), node.right); } } @@ -19867,50 +34798,94 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!isLiteralImportTypeNode(node)) { error(node.argument, Diagnostics.String_literal_expected); links.resolvedSymbol = unknownSymbol; - return links.resolvedType = errorType; + return (links.resolvedType = errorType); } - const targetMeaning = node.isTypeOf ? SymbolFlags.Value : node.flags & NodeFlags.JSDoc ? SymbolFlags.Value | SymbolFlags.Type : SymbolFlags.Type; + const targetMeaning = node.isTypeOf + ? SymbolFlags.Value + : node.flags & NodeFlags.JSDoc + ? SymbolFlags.Value | SymbolFlags.Type + : SymbolFlags.Type; // TODO: Future work: support unions/generics/whatever via a deferred import-type - const innerModuleSymbol = resolveExternalModuleName(node, node.argument.literal); + const innerModuleSymbol = resolveExternalModuleName( + node, + node.argument.literal + ); if (!innerModuleSymbol) { links.resolvedSymbol = unknownSymbol; - return links.resolvedType = errorType; + return (links.resolvedType = errorType); } - const isExportEquals = !!innerModuleSymbol.exports?.get(InternalSymbolName.ExportEquals); - const moduleSymbol = resolveExternalModuleSymbol(innerModuleSymbol, /*dontResolveAlias*/ false); + const isExportEquals = !!innerModuleSymbol.exports?.get( + InternalSymbolName.ExportEquals + ); + const moduleSymbol = resolveExternalModuleSymbol( + innerModuleSymbol, + /*dontResolveAlias*/ false + ); if (!nodeIsMissing(node.qualifier)) { - const nameStack: Identifier[] = getIdentifierChain(node.qualifier!); + const nameStack: Identifier[] = getIdentifierChain( + node.qualifier! + ); let currentNamespace = moduleSymbol; let current: Identifier | undefined; - while (current = nameStack.shift()) { - const meaning = nameStack.length ? SymbolFlags.Namespace : targetMeaning; + while ((current = nameStack.shift())) { + const meaning = nameStack.length + ? SymbolFlags.Namespace + : targetMeaning; // typeof a.b.c is normally resolved using `checkExpression` which in turn defers to `checkQualifiedName` // That, in turn, ultimately uses `getPropertyOfType` on the type of the symbol, which differs slightly from // the `exports` lookup process that only looks up namespace members which is used for most type references - const mergedResolvedSymbol = getMergedSymbol(resolveSymbol(currentNamespace)); - const symbolFromVariable = node.isTypeOf || isInJSFile(node) && isExportEquals - ? getPropertyOfType(getTypeOfSymbol(mergedResolvedSymbol), current.escapedText, /*skipObjectFunctionPropertyAugment*/ false, /*includeTypeOnlyMembers*/ true) - : undefined; - const symbolFromModule = node.isTypeOf ? undefined : getSymbol(getExportsOfSymbol(mergedResolvedSymbol), current.escapedText, meaning); + const mergedResolvedSymbol = getMergedSymbol( + resolveSymbol(currentNamespace) + ); + const symbolFromVariable = + node.isTypeOf || (isInJSFile(node) && isExportEquals) + ? getPropertyOfType( + getTypeOfSymbol(mergedResolvedSymbol), + current.escapedText, + /*skipObjectFunctionPropertyAugment*/ false, + /*includeTypeOnlyMembers*/ true + ) + : undefined; + const symbolFromModule = node.isTypeOf + ? undefined + : getSymbol( + getExportsOfSymbol(mergedResolvedSymbol), + current.escapedText, + meaning + ); const next = symbolFromModule ?? symbolFromVariable; if (!next) { - error(current, Diagnostics.Namespace_0_has_no_exported_member_1, getFullyQualifiedName(currentNamespace), declarationNameToString(current)); - return links.resolvedType = errorType; + error( + current, + Diagnostics.Namespace_0_has_no_exported_member_1, + getFullyQualifiedName(currentNamespace), + declarationNameToString(current) + ); + return (links.resolvedType = errorType); } getNodeLinks(current).resolvedSymbol = next; getNodeLinks(current.parent).resolvedSymbol = next; currentNamespace = next; } - links.resolvedType = resolveImportSymbolType(node, links, currentNamespace, targetMeaning); - } - else { + links.resolvedType = resolveImportSymbolType( + node, + links, + currentNamespace, + targetMeaning + ); + } else { if (moduleSymbol.flags & targetMeaning) { - links.resolvedType = resolveImportSymbolType(node, links, moduleSymbol, targetMeaning); - } - else { - const errorMessage = targetMeaning === SymbolFlags.Value - ? Diagnostics.Module_0_does_not_refer_to_a_value_but_is_used_as_a_value_here - : Diagnostics.Module_0_does_not_refer_to_a_type_but_is_used_as_a_type_here_Did_you_mean_typeof_import_0; + links.resolvedType = resolveImportSymbolType( + node, + links, + moduleSymbol, + targetMeaning + ); + } else { + const errorMessage = + targetMeaning === SymbolFlags.Value + ? Diagnostics.Module_0_does_not_refer_to_a_value_but_is_used_as_a_value_here + : Diagnostics.Module_0_does_not_refer_to_a_type_but_is_used_as_a_type_here_Did_you_mean_typeof_import_0; error(node, errorMessage, node.argument.literal.text); @@ -19922,29 +34897,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return links.resolvedType; } - function resolveImportSymbolType(node: ImportTypeNode, links: NodeLinks, symbol: Symbol, meaning: SymbolFlags) { + function resolveImportSymbolType( + node: ImportTypeNode, + links: NodeLinks, + symbol: Symbol, + meaning: SymbolFlags + ) { const resolvedSymbol = resolveSymbol(symbol); links.resolvedSymbol = resolvedSymbol; if (meaning === SymbolFlags.Value) { - return getInstantiationExpressionType(getTypeOfSymbol(symbol), node); // intentionally doesn't use resolved symbol so type is cached as expected on the alias - } - else { + return getInstantiationExpressionType( + getTypeOfSymbol(symbol), + node + ); // intentionally doesn't use resolved symbol so type is cached as expected on the alias + } else { return getTypeReferenceType(node, resolvedSymbol); // getTypeReferenceType doesn't handle aliases - it must get the resolved symbol } } - function getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node: TypeLiteralNode | FunctionOrConstructorTypeNode | JSDocTypeLiteral | JSDocFunctionType | JSDocSignature): Type { + function getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode( + node: + | TypeLiteralNode + | FunctionOrConstructorTypeNode + | JSDocTypeLiteral + | JSDocFunctionType + | JSDocSignature + ): Type { const links = getNodeLinks(node); if (!links.resolvedType) { // Deferred resolution of members is handled by resolveObjectTypeMembers const aliasSymbol = getAliasSymbolForTypeNode(node); - if (!node.symbol || getMembersOfSymbol(node.symbol).size === 0 && !aliasSymbol) { + if ( + !node.symbol || + (getMembersOfSymbol(node.symbol).size === 0 && !aliasSymbol) + ) { links.resolvedType = emptyTypeLiteralType; - } - else { + } else { let type = createObjectType(ObjectFlags.Anonymous, node.symbol); type.aliasSymbol = aliasSymbol; - type.aliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol); + type.aliasTypeArguments = + getTypeArgumentsForAliasSymbol(aliasSymbol); if (isJSDocTypeLiteral(node) && node.isArrayType) { type = createArrayType(type); } @@ -19956,14 +34948,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getAliasSymbolForTypeNode(node: Node) { let host = node.parent; - while (isParenthesizedTypeNode(host) || isJSDocTypeExpression(host) || isTypeOperatorNode(host) && host.operator === SyntaxKind.ReadonlyKeyword) { + while ( + isParenthesizedTypeNode(host) || + isJSDocTypeExpression(host) || + (isTypeOperatorNode(host) && + host.operator === SyntaxKind.ReadonlyKeyword) + ) { host = host.parent; } return isTypeAlias(host) ? getSymbolOfDeclaration(host) : undefined; } function getTypeArgumentsForAliasSymbol(symbol: Symbol | undefined) { - return symbol ? getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol) : undefined; + return symbol + ? getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol) + : undefined; } function isNonGenericObjectType(type: Type) { @@ -19971,21 +34970,53 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isEmptyObjectTypeOrSpreadsIntoEmptyObject(type: Type) { - return isEmptyObjectType(type) || !!(type.flags & (TypeFlags.Null | TypeFlags.Undefined | TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.EnumLike | TypeFlags.NonPrimitive | TypeFlags.Index)); + return ( + isEmptyObjectType(type) || + !!( + type.flags & + (TypeFlags.Null | + TypeFlags.Undefined | + TypeFlags.BooleanLike | + TypeFlags.NumberLike | + TypeFlags.BigIntLike | + TypeFlags.StringLike | + TypeFlags.EnumLike | + TypeFlags.NonPrimitive | + TypeFlags.Index) + ) + ); } - function tryMergeUnionOfObjectTypeAndEmptyObject(type: Type, readonly: boolean): Type { + function tryMergeUnionOfObjectTypeAndEmptyObject( + type: Type, + readonly: boolean + ): Type { if (!(type.flags & TypeFlags.Union)) { return type; } - if (every((type as UnionType).types, isEmptyObjectTypeOrSpreadsIntoEmptyObject)) { - return find((type as UnionType).types, isEmptyObjectType) || emptyObjectType; + if ( + every( + (type as UnionType).types, + isEmptyObjectTypeOrSpreadsIntoEmptyObject + ) + ) { + return ( + find((type as UnionType).types, isEmptyObjectType) || + emptyObjectType + ); } - const firstType = find((type as UnionType).types, t => !isEmptyObjectTypeOrSpreadsIntoEmptyObject(t)); + const firstType = find( + (type as UnionType).types, + (t) => !isEmptyObjectTypeOrSpreadsIntoEmptyObject(t) + ); if (!firstType) { return type; } - const secondType = find((type as UnionType).types, t => t !== firstType && !isEmptyObjectTypeOrSpreadsIntoEmptyObject(t)); + const secondType = find( + (type as UnionType).types, + (t) => + t !== firstType && !isEmptyObjectTypeOrSpreadsIntoEmptyObject(t) + ); if (secondType) { return type; } @@ -19995,22 +35026,44 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // gets the type as if it had been spread, but where everything in the spread is made optional const members = createSymbolTable(); for (const prop of getPropertiesOfType(type)) { - if (getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected)) { + if ( + getDeclarationModifierFlagsFromSymbol(prop) & + (ModifierFlags.Private | ModifierFlags.Protected) + ) { // do nothing, skip privates - } - else if (isSpreadableProperty(prop)) { - const isSetonlyAccessor = prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor); + } else if (isSpreadableProperty(prop)) { + const isSetonlyAccessor = + prop.flags & SymbolFlags.SetAccessor && + !(prop.flags & SymbolFlags.GetAccessor); const flags = SymbolFlags.Property | SymbolFlags.Optional; - const result = createSymbol(flags, prop.escapedName, getIsLateCheckFlag(prop) | (readonly ? CheckFlags.Readonly : 0)); - result.links.type = isSetonlyAccessor ? undefinedType : addOptionality(getTypeOfSymbol(prop), /*isProperty*/ true); + const result = createSymbol( + flags, + prop.escapedName, + getIsLateCheckFlag(prop) | + (readonly ? CheckFlags.Readonly : 0) + ); + result.links.type = isSetonlyAccessor + ? undefinedType + : addOptionality( + getTypeOfSymbol(prop), + /*isProperty*/ true + ); result.declarations = prop.declarations; result.links.nameType = getSymbolLinks(prop).nameType; result.links.syntheticOrigin = prop; members.set(prop.escapedName, result); } } - const spread = createAnonymousType(type.symbol, members, emptyArray, emptyArray, getIndexInfosOfType(type)); - spread.objectFlags |= ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral; + const spread = createAnonymousType( + type.symbol, + members, + emptyArray, + emptyArray, + getIndexInfosOfType(type) + ); + spread.objectFlags |= + ObjectFlags.ObjectLiteral | + ObjectFlags.ContainsObjectOrArrayLiteral; return spread; } } @@ -20020,7 +35073,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * this function should be called in a left folding style, with left = previous result of getSpreadType * and right = the new element to be spread. */ - function getSpreadType(left: Type, right: Type, symbol: Symbol | undefined, objectFlags: ObjectFlags, readonly: boolean): Type { + function getSpreadType( + left: Type, + right: Type, + symbol: Symbol | undefined, + objectFlags: ObjectFlags, + readonly: boolean + ): Type { if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) { return anyType; } @@ -20036,16 +35095,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { left = tryMergeUnionOfObjectTypeAndEmptyObject(left, readonly); if (left.flags & TypeFlags.Union) { return checkCrossProductUnion([left, right]) - ? mapType(left, t => getSpreadType(t, right, symbol, objectFlags, readonly)) + ? mapType(left, (t) => + getSpreadType(t, right, symbol, objectFlags, readonly) + ) : errorType; } right = tryMergeUnionOfObjectTypeAndEmptyObject(right, readonly); if (right.flags & TypeFlags.Union) { return checkCrossProductUnion([left, right]) - ? mapType(right, t => getSpreadType(left, t, symbol, objectFlags, readonly)) + ? mapType(right, (t) => + getSpreadType(left, t, symbol, objectFlags, readonly) + ) : errorType; } - if (right.flags & (TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.EnumLike | TypeFlags.NonPrimitive | TypeFlags.Index)) { + if ( + right.flags & + (TypeFlags.BooleanLike | + TypeFlags.NumberLike | + TypeFlags.BigIntLike | + TypeFlags.StringLike | + TypeFlags.EnumLike | + TypeFlags.NonPrimitive | + TypeFlags.Index) + ) { return left; } @@ -20059,8 +35131,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (left.flags & TypeFlags.Intersection) { const types = (left as IntersectionType).types; const lastLeft = types[types.length - 1]; - if (isNonGenericObjectType(lastLeft) && isNonGenericObjectType(right)) { - return getIntersectionType(concatenate(types.slice(0, types.length - 1), [getSpreadType(lastLeft, right, symbol, objectFlags, readonly)])); + if ( + isNonGenericObjectType(lastLeft) && + isNonGenericObjectType(right) + ) { + return getIntersectionType( + concatenate(types.slice(0, types.length - 1), [ + getSpreadType( + lastLeft, + right, + symbol, + objectFlags, + readonly + ), + ]) + ); } } return getIntersectionType([left, right]); @@ -20068,68 +35153,125 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const members = createSymbolTable(); const skippedPrivateMembers = new Set<__String>(); - const indexInfos = left === emptyObjectType ? getIndexInfosOfType(right) : getUnionIndexInfos([left, right]); + const indexInfos = + left === emptyObjectType + ? getIndexInfosOfType(right) + : getUnionIndexInfos([left, right]); for (const rightProp of getPropertiesOfType(right)) { - if (getDeclarationModifierFlagsFromSymbol(rightProp) & (ModifierFlags.Private | ModifierFlags.Protected)) { + if ( + getDeclarationModifierFlagsFromSymbol(rightProp) & + (ModifierFlags.Private | ModifierFlags.Protected) + ) { skippedPrivateMembers.add(rightProp.escapedName); - } - else if (isSpreadableProperty(rightProp)) { - members.set(rightProp.escapedName, getSpreadSymbol(rightProp, readonly)); + } else if (isSpreadableProperty(rightProp)) { + members.set( + rightProp.escapedName, + getSpreadSymbol(rightProp, readonly) + ); } } for (const leftProp of getPropertiesOfType(left)) { - if (skippedPrivateMembers.has(leftProp.escapedName) || !isSpreadableProperty(leftProp)) { + if ( + skippedPrivateMembers.has(leftProp.escapedName) || + !isSpreadableProperty(leftProp) + ) { continue; } if (members.has(leftProp.escapedName)) { const rightProp = members.get(leftProp.escapedName)!; const rightType = getTypeOfSymbol(rightProp); if (rightProp.flags & SymbolFlags.Optional) { - const declarations = concatenate(leftProp.declarations, rightProp.declarations); - const flags = SymbolFlags.Property | (leftProp.flags & SymbolFlags.Optional); + const declarations = concatenate( + leftProp.declarations, + rightProp.declarations + ); + const flags = + SymbolFlags.Property | + (leftProp.flags & SymbolFlags.Optional); const result = createSymbol(flags, leftProp.escapedName); // Optimization: avoid calculating the union type if spreading into the exact same type. // This is common, e.g. spreading one options bag into another where the bags have the // same type, or have properties which overlap. If the unions are large, it may turn out // to be expensive to perform subtype reduction. const leftType = getTypeOfSymbol(leftProp); - const leftTypeWithoutUndefined = removeMissingOrUndefinedType(leftType); - const rightTypeWithoutUndefined = removeMissingOrUndefinedType(rightType); - result.links.type = leftTypeWithoutUndefined === rightTypeWithoutUndefined ? leftType : getUnionType([leftType, rightTypeWithoutUndefined], UnionReduction.Subtype); + const leftTypeWithoutUndefined = + removeMissingOrUndefinedType(leftType); + const rightTypeWithoutUndefined = + removeMissingOrUndefinedType(rightType); + result.links.type = + leftTypeWithoutUndefined === rightTypeWithoutUndefined + ? leftType + : getUnionType( + [leftType, rightTypeWithoutUndefined], + UnionReduction.Subtype + ); result.links.leftSpread = leftProp; result.links.rightSpread = rightProp; result.declarations = declarations; result.links.nameType = getSymbolLinks(leftProp).nameType; members.set(leftProp.escapedName, result); } - } - else { - members.set(leftProp.escapedName, getSpreadSymbol(leftProp, readonly)); + } else { + members.set( + leftProp.escapedName, + getSpreadSymbol(leftProp, readonly) + ); } } - const spread = createAnonymousType(symbol, members, emptyArray, emptyArray, sameMap(indexInfos, info => getIndexInfoWithReadonly(info, readonly))); - spread.objectFlags |= ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral | ObjectFlags.ContainsSpread | objectFlags; + const spread = createAnonymousType( + symbol, + members, + emptyArray, + emptyArray, + sameMap(indexInfos, (info) => + getIndexInfoWithReadonly(info, readonly) + ) + ); + spread.objectFlags |= + ObjectFlags.ObjectLiteral | + ObjectFlags.ContainsObjectOrArrayLiteral | + ObjectFlags.ContainsSpread | + objectFlags; return spread; } /** We approximate own properties as non-methods plus methods that are inside the object literal */ function isSpreadableProperty(prop: Symbol): boolean { - return !some(prop.declarations, isPrivateIdentifierClassElementDeclaration) && - (!(prop.flags & (SymbolFlags.Method | SymbolFlags.GetAccessor | SymbolFlags.SetAccessor)) || - !prop.declarations?.some(decl => isClassLike(decl.parent))); + return ( + !some( + prop.declarations, + isPrivateIdentifierClassElementDeclaration + ) && + (!( + prop.flags & + (SymbolFlags.Method | + SymbolFlags.GetAccessor | + SymbolFlags.SetAccessor) + ) || + !prop.declarations?.some((decl) => isClassLike(decl.parent))) + ); } function getSpreadSymbol(prop: Symbol, readonly: boolean) { - const isSetonlyAccessor = prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor); + const isSetonlyAccessor = + prop.flags & SymbolFlags.SetAccessor && + !(prop.flags & SymbolFlags.GetAccessor); if (!isSetonlyAccessor && readonly === isReadonlySymbol(prop)) { return prop; } - const flags = SymbolFlags.Property | (prop.flags & SymbolFlags.Optional); - const result = createSymbol(flags, prop.escapedName, getIsLateCheckFlag(prop) | (readonly ? CheckFlags.Readonly : 0)); - result.links.type = isSetonlyAccessor ? undefinedType : getTypeOfSymbol(prop); + const flags = + SymbolFlags.Property | (prop.flags & SymbolFlags.Optional); + const result = createSymbol( + flags, + prop.escapedName, + getIsLateCheckFlag(prop) | (readonly ? CheckFlags.Readonly : 0) + ); + result.links.type = isSetonlyAccessor + ? undefinedType + : getTypeOfSymbol(prop); result.declarations = prop.declarations; result.links.nameType = getSymbolLinks(prop).nameType; result.links.syntheticOrigin = prop; @@ -20137,10 +35279,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getIndexInfoWithReadonly(info: IndexInfo, readonly: boolean) { - return info.isReadonly !== readonly ? createIndexInfo(info.keyType, info.type, readonly, info.declaration, info.components) : info; - } - - function createLiteralType(flags: TypeFlags, value: string | number | PseudoBigInt, symbol?: Symbol, regularType?: LiteralType) { + return info.isReadonly !== readonly + ? createIndexInfo( + info.keyType, + info.type, + readonly, + info.declaration, + info.components + ) + : info; + } + + function createLiteralType( + flags: TypeFlags, + value: string | number | PseudoBigInt, + symbol?: Symbol, + regularType?: LiteralType + ) { const type = createTypeWithSymbol(flags, symbol!) as LiteralType; type.value = value; type.regularType = regularType || type; @@ -20150,7 +35305,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getFreshTypeOfLiteralType(type: Type): Type { if (type.flags & TypeFlags.Freshable) { if (!(type as FreshableType).freshType) { - const freshType = createLiteralType(type.flags, (type as LiteralType).value, (type as LiteralType).symbol, type as LiteralType); + const freshType = createLiteralType( + type.flags, + (type as LiteralType).value, + (type as LiteralType).symbol, + type as LiteralType + ); freshType.freshType = freshType; (type as FreshableType).freshType = freshType; } @@ -20160,40 +35320,90 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getRegularTypeOfLiteralType(type: Type): Type { - return type.flags & TypeFlags.Freshable ? (type as FreshableType).regularType : - type.flags & TypeFlags.Union ? ((type as UnionType).regularType || ((type as UnionType).regularType = mapType(type, getRegularTypeOfLiteralType) as UnionType)) : - type; + return type.flags & TypeFlags.Freshable + ? (type as FreshableType).regularType + : type.flags & TypeFlags.Union + ? (type as UnionType).regularType || + ((type as UnionType).regularType = mapType( + type, + getRegularTypeOfLiteralType + ) as UnionType) + : type; } function isFreshLiteralType(type: Type) { - return !!(type.flags & TypeFlags.Freshable) && (type as LiteralType).freshType === type; + return ( + !!(type.flags & TypeFlags.Freshable) && + (type as LiteralType).freshType === type + ); } function getStringLiteralType(value: string): StringLiteralType { let type; - return stringLiteralTypes.get(value) || - (stringLiteralTypes.set(value, type = createLiteralType(TypeFlags.StringLiteral, value) as StringLiteralType), type); + return ( + stringLiteralTypes.get(value) || + (stringLiteralTypes.set( + value, + (type = createLiteralType( + TypeFlags.StringLiteral, + value + ) as StringLiteralType) + ), + type) + ); } function getNumberLiteralType(value: number): NumberLiteralType { let type; - return numberLiteralTypes.get(value) || - (numberLiteralTypes.set(value, type = createLiteralType(TypeFlags.NumberLiteral, value) as NumberLiteralType), type); + return ( + numberLiteralTypes.get(value) || + (numberLiteralTypes.set( + value, + (type = createLiteralType( + TypeFlags.NumberLiteral, + value + ) as NumberLiteralType) + ), + type) + ); } function getBigIntLiteralType(value: PseudoBigInt): BigIntLiteralType { let type; const key = pseudoBigIntToString(value); - return bigIntLiteralTypes.get(key) || - (bigIntLiteralTypes.set(key, type = createLiteralType(TypeFlags.BigIntLiteral, value) as BigIntLiteralType), type); + return ( + bigIntLiteralTypes.get(key) || + (bigIntLiteralTypes.set( + key, + (type = createLiteralType( + TypeFlags.BigIntLiteral, + value + ) as BigIntLiteralType) + ), + type) + ); } - function getEnumLiteralType(value: string | number, enumId: number, symbol: Symbol): LiteralType { + function getEnumLiteralType( + value: string | number, + enumId: number, + symbol: Symbol + ): LiteralType { let type; const key = `${enumId}${typeof value === "string" ? "@" : "#"}${value}`; - const flags = TypeFlags.EnumLiteral | (typeof value === "string" ? TypeFlags.StringLiteral : TypeFlags.NumberLiteral); - return enumLiteralTypes.get(key) || - (enumLiteralTypes.set(key, type = createLiteralType(flags, value, symbol)), type); + const flags = + TypeFlags.EnumLiteral | + (typeof value === "string" + ? TypeFlags.StringLiteral + : TypeFlags.NumberLiteral); + return ( + enumLiteralTypes.get(key) || + (enumLiteralTypes.set( + key, + (type = createLiteralType(flags, value, symbol)) + ), + type) + ); } function getTypeFromLiteralTypeNode(node: LiteralTypeNode): Type { @@ -20202,14 +35412,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const links = getNodeLinks(node); if (!links.resolvedType) { - links.resolvedType = getRegularTypeOfLiteralType(checkExpression(node.literal)); + links.resolvedType = getRegularTypeOfLiteralType( + checkExpression(node.literal) + ); } return links.resolvedType; } function createUniqueESSymbolType(symbol: Symbol) { - const type = createTypeWithSymbol(TypeFlags.UniqueESSymbol, symbol) as UniqueESSymbolType; - type.escapedName = `__@${type.symbol.escapedName}@${getSymbolId(type.symbol)}` as __String; + const type = createTypeWithSymbol( + TypeFlags.UniqueESSymbol, + symbol + ) as UniqueESSymbolType; + type.escapedName = `__@${type.symbol.escapedName}@${getSymbolId( + type.symbol + )}` as __String; return type; } @@ -20221,46 +35438,94 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } if (isValidESSymbolDeclaration(node)) { - const symbol = isCommonJsExportPropertyAssignment(node) ? getSymbolOfNode((node as BinaryExpression).left) : getSymbolOfNode(node); + const symbol = isCommonJsExportPropertyAssignment(node) + ? getSymbolOfNode((node as BinaryExpression).left) + : getSymbolOfNode(node); if (symbol) { const links = getSymbolLinks(symbol); - return links.uniqueESSymbolType || (links.uniqueESSymbolType = createUniqueESSymbolType(symbol)); + return ( + links.uniqueESSymbolType || + (links.uniqueESSymbolType = + createUniqueESSymbolType(symbol)) + ); } } return esSymbolType; } function getThisType(node: Node): Type { - const container = getThisContainer(node, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); + const container = getThisContainer( + node, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false + ); const parent = container && container.parent; - if (parent && (isClassLike(parent) || parent.kind === SyntaxKind.InterfaceDeclaration)) { + if ( + parent && + (isClassLike(parent) || + parent.kind === SyntaxKind.InterfaceDeclaration) + ) { if ( !isStatic(container) && - (!isConstructorDeclaration(container) || isNodeDescendantOf(node, container.body)) + (!isConstructorDeclaration(container) || + isNodeDescendantOf(node, container.body)) ) { - return getDeclaredTypeOfClassOrInterface(getSymbolOfDeclaration(parent as ClassLikeDeclaration | InterfaceDeclaration)).thisType!; + return getDeclaredTypeOfClassOrInterface( + getSymbolOfDeclaration( + parent as ClassLikeDeclaration | InterfaceDeclaration + ) + ).thisType!; } } // inside x.prototype = { ... } - if (parent && isObjectLiteralExpression(parent) && isBinaryExpression(parent.parent) && getAssignmentDeclarationKind(parent.parent) === AssignmentDeclarationKind.Prototype) { - return getDeclaredTypeOfClassOrInterface(getSymbolOfNode(parent.parent.left)!.parent!).thisType!; + if ( + parent && + isObjectLiteralExpression(parent) && + isBinaryExpression(parent.parent) && + getAssignmentDeclarationKind(parent.parent) === + AssignmentDeclarationKind.Prototype + ) { + return getDeclaredTypeOfClassOrInterface( + getSymbolOfNode(parent.parent.left)!.parent! + ).thisType!; } // /** @return {this} */ // x.prototype.m = function() { ... } - const host = node.flags & NodeFlags.JSDoc ? getHostSignatureFromJSDoc(node) : undefined; - if (host && isFunctionExpression(host) && isBinaryExpression(host.parent) && getAssignmentDeclarationKind(host.parent) === AssignmentDeclarationKind.PrototypeProperty) { - return getDeclaredTypeOfClassOrInterface(getSymbolOfNode(host.parent.left)!.parent!).thisType!; + const host = + node.flags & NodeFlags.JSDoc + ? getHostSignatureFromJSDoc(node) + : undefined; + if ( + host && + isFunctionExpression(host) && + isBinaryExpression(host.parent) && + getAssignmentDeclarationKind(host.parent) === + AssignmentDeclarationKind.PrototypeProperty + ) { + return getDeclaredTypeOfClassOrInterface( + getSymbolOfNode(host.parent.left)!.parent! + ).thisType!; } // inside constructor function C() { ... } - if (isJSConstructor(container) && isNodeDescendantOf(node, container.body)) { - return getDeclaredTypeOfClassOrInterface(getSymbolOfDeclaration(container)).thisType!; + if ( + isJSConstructor(container) && + isNodeDescendantOf(node, container.body) + ) { + return getDeclaredTypeOfClassOrInterface( + getSymbolOfDeclaration(container) + ).thisType!; } - error(node, Diagnostics.A_this_type_is_available_only_in_a_non_static_member_of_a_class_or_interface); + error( + node, + Diagnostics.A_this_type_is_available_only_in_a_non_static_member_of_a_class_or_interface + ); return errorType; } - function getTypeFromThisTypeNode(node: ThisExpression | ThisTypeNode): Type { + function getTypeFromThisTypeNode( + node: ThisExpression | ThisTypeNode + ): Type { const links = getNodeLinks(node); if (!links.resolvedType) { links.resolvedType = getThisType(node); @@ -20269,18 +35534,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getTypeFromRestTypeNode(node: RestTypeNode | NamedTupleMember) { - return getTypeFromTypeNode(getArrayElementTypeNode(node.type) || node.type); + return getTypeFromTypeNode( + getArrayElementTypeNode(node.type) || node.type + ); } function getArrayElementTypeNode(node: TypeNode): TypeNode | undefined { switch (node.kind) { case SyntaxKind.ParenthesizedType: - return getArrayElementTypeNode((node as ParenthesizedTypeNode).type); + return getArrayElementTypeNode( + (node as ParenthesizedTypeNode).type + ); case SyntaxKind.TupleType: if ((node as TupleTypeNode).elements.length === 1) { node = (node as TupleTypeNode).elements[0]; - if (node.kind === SyntaxKind.RestType || node.kind === SyntaxKind.NamedTupleMember && (node as NamedTupleMember).dotDotDotToken) { - return getArrayElementTypeNode((node as RestTypeNode | NamedTupleMember).type); + if ( + node.kind === SyntaxKind.RestType || + (node.kind === SyntaxKind.NamedTupleMember && + (node as NamedTupleMember).dotDotDotToken) + ) { + return getArrayElementTypeNode( + (node as RestTypeNode | NamedTupleMember).type + ); } } break; @@ -20292,12 +35567,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getTypeFromNamedTupleTypeNode(node: NamedTupleMember): Type { const links = getNodeLinks(node); - return links.resolvedType || (links.resolvedType = node.dotDotDotToken ? getTypeFromRestTypeNode(node) : - addOptionality(getTypeFromTypeNode(node.type), /*isProperty*/ true, !!node.questionToken)); + return ( + links.resolvedType || + (links.resolvedType = node.dotDotDotToken + ? getTypeFromRestTypeNode(node) + : addOptionality( + getTypeFromTypeNode(node.type), + /*isProperty*/ true, + !!node.questionToken + )) + ); } function getTypeFromTypeNode(node: TypeNode): Type { - return getConditionalFlowTypeOfType(getTypeFromTypeNodeWorker(node), node); + return getConditionalFlowTypeOfType( + getTypeFromTypeNodeWorker(node), + node + ); } function getTypeFromTypeNodeWorker(node: TypeNode): Type { @@ -20328,42 +35614,66 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.NeverKeyword: return neverType; case SyntaxKind.ObjectKeyword: - return node.flags & NodeFlags.JavaScriptFile && !noImplicitAny ? anyType : nonPrimitiveType; + return node.flags & NodeFlags.JavaScriptFile && !noImplicitAny + ? anyType + : nonPrimitiveType; case SyntaxKind.IntrinsicKeyword: return intrinsicMarkerType; case SyntaxKind.ThisType: case SyntaxKind.ThisKeyword as TypeNodeSyntaxKind: // 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`. - return getTypeFromThisTypeNode(node as ThisExpression | ThisTypeNode); + return getTypeFromThisTypeNode( + node as ThisExpression | ThisTypeNode + ); case SyntaxKind.LiteralType: return getTypeFromLiteralTypeNode(node as LiteralTypeNode); case SyntaxKind.TypeReference: return getTypeFromTypeReference(node as TypeReferenceNode); case SyntaxKind.TypePredicate: - return (node as TypePredicateNode).assertsModifier ? voidType : booleanType; + return (node as TypePredicateNode).assertsModifier + ? voidType + : booleanType; case SyntaxKind.ExpressionWithTypeArguments: - return getTypeFromTypeReference(node as ExpressionWithTypeArguments); + return getTypeFromTypeReference( + node as ExpressionWithTypeArguments + ); case SyntaxKind.TypeQuery: return getTypeFromTypeQueryNode(node as TypeQueryNode); case SyntaxKind.ArrayType: case SyntaxKind.TupleType: - return getTypeFromArrayOrTupleTypeNode(node as ArrayTypeNode | TupleTypeNode); + return getTypeFromArrayOrTupleTypeNode( + node as ArrayTypeNode | TupleTypeNode + ); case SyntaxKind.OptionalType: return getTypeFromOptionalTypeNode(node as OptionalTypeNode); case SyntaxKind.UnionType: return getTypeFromUnionTypeNode(node as UnionTypeNode); case SyntaxKind.IntersectionType: - return getTypeFromIntersectionTypeNode(node as IntersectionTypeNode); + return getTypeFromIntersectionTypeNode( + node as IntersectionTypeNode + ); case SyntaxKind.JSDocNullableType: - return getTypeFromJSDocNullableTypeNode(node as JSDocNullableType); + return getTypeFromJSDocNullableTypeNode( + node as JSDocNullableType + ); case SyntaxKind.JSDocOptionalType: - return addOptionality(getTypeFromTypeNode((node as JSDocOptionalType).type)); + return addOptionality( + getTypeFromTypeNode((node as JSDocOptionalType).type) + ); case SyntaxKind.NamedTupleMember: return getTypeFromNamedTupleTypeNode(node as NamedTupleMember); case SyntaxKind.ParenthesizedType: case SyntaxKind.JSDocNonNullableType: case SyntaxKind.JSDocTypeExpression: - return getTypeFromTypeNode((node as ParenthesizedTypeNode | JSDocTypeReferencingNode | JSDocTypeExpression | NamedTupleMember).type); + return getTypeFromTypeNode( + ( + node as + | ParenthesizedTypeNode + | JSDocTypeReferencingNode + | JSDocTypeExpression + | NamedTupleMember + ).type + ); case SyntaxKind.RestType: return getTypeFromRestTypeNode(node as RestTypeNode); case SyntaxKind.JSDocVariadicType: @@ -20374,19 +35684,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.JSDocTypeLiteral: case SyntaxKind.JSDocFunctionType: case SyntaxKind.JSDocSignature: - return getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node as TypeLiteralNode | FunctionOrConstructorTypeNode | JSDocTypeLiteral | JSDocFunctionType | JSDocSignature); + return getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode( + node as + | TypeLiteralNode + | FunctionOrConstructorTypeNode + | JSDocTypeLiteral + | JSDocFunctionType + | JSDocSignature + ); case SyntaxKind.TypeOperator: return getTypeFromTypeOperatorNode(node as TypeOperatorNode); case SyntaxKind.IndexedAccessType: - return getTypeFromIndexedAccessTypeNode(node as IndexedAccessTypeNode); + return getTypeFromIndexedAccessTypeNode( + node as IndexedAccessTypeNode + ); case SyntaxKind.MappedType: return getTypeFromMappedTypeNode(node as MappedTypeNode); case SyntaxKind.ConditionalType: - return getTypeFromConditionalTypeNode(node as ConditionalTypeNode); + return getTypeFromConditionalTypeNode( + node as ConditionalTypeNode + ); case SyntaxKind.InferType: return getTypeFromInferTypeNode(node as InferTypeNode); case SyntaxKind.TemplateLiteralType: - return getTypeFromTemplateTypeNode(node as TemplateLiteralTypeNode); + return getTypeFromTemplateTypeNode( + node as TemplateLiteralTypeNode + ); case SyntaxKind.ImportType: return getTypeFromImportTypeNode(node as ImportTypeNode); // This function assumes that an identifier, qualified name, or property access expression is a type expression @@ -20402,9 +35725,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function instantiateList(items: readonly T[], mapper: TypeMapper, instantiator: (item: T, mapper: TypeMapper) => T): readonly T[]; - function instantiateList(items: readonly T[] | undefined, mapper: TypeMapper, instantiator: (item: T, mapper: TypeMapper) => T): readonly T[] | undefined; - function instantiateList(items: readonly T[] | undefined, mapper: TypeMapper, instantiator: (item: T, mapper: TypeMapper) => T): readonly T[] | undefined { + function instantiateList( + items: readonly T[], + mapper: TypeMapper, + instantiator: (item: T, mapper: TypeMapper) => T + ): readonly T[]; + function instantiateList( + items: readonly T[] | undefined, + mapper: TypeMapper, + instantiator: (item: T, mapper: TypeMapper) => T + ): readonly T[] | undefined; + function instantiateList( + items: readonly T[] | undefined, + mapper: TypeMapper, + instantiator: (item: T, mapper: TypeMapper) => T + ): readonly T[] | undefined { if (items && items.length) { for (let i = 0; i < items.length; i++) { const item = items[i]; @@ -20422,22 +35757,50 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return items; } - function instantiateTypes(types: readonly Type[], mapper: TypeMapper): readonly Type[]; - function instantiateTypes(types: readonly Type[] | undefined, mapper: TypeMapper): readonly Type[] | undefined; - function instantiateTypes(types: readonly Type[] | undefined, mapper: TypeMapper): readonly Type[] | undefined { + function instantiateTypes( + types: readonly Type[], + mapper: TypeMapper + ): readonly Type[]; + function instantiateTypes( + types: readonly Type[] | undefined, + mapper: TypeMapper + ): readonly Type[] | undefined; + function instantiateTypes( + types: readonly Type[] | undefined, + mapper: TypeMapper + ): readonly Type[] | undefined { return instantiateList(types, mapper, instantiateType); } - function instantiateSignatures(signatures: readonly Signature[], mapper: TypeMapper): readonly Signature[] { - return instantiateList(signatures, mapper, instantiateSignature); + function instantiateSignatures( + signatures: readonly Signature[], + mapper: TypeMapper + ): readonly Signature[] { + return instantiateList( + signatures, + mapper, + instantiateSignature + ); } - function instantiateIndexInfos(indexInfos: readonly IndexInfo[], mapper: TypeMapper): readonly IndexInfo[] { - return instantiateList(indexInfos, mapper, instantiateIndexInfo); + function instantiateIndexInfos( + indexInfos: readonly IndexInfo[], + mapper: TypeMapper + ): readonly IndexInfo[] { + return instantiateList( + indexInfos, + mapper, + instantiateIndexInfo + ); } - function createTypeMapper(sources: readonly TypeParameter[], targets: readonly Type[] | undefined): TypeMapper { - return sources.length === 1 ? makeUnaryTypeMapper(sources[0], targets ? targets[0] : anyType) : makeArrayTypeMapper(sources, targets); + function createTypeMapper( + sources: readonly TypeParameter[], + targets: readonly Type[] | undefined + ): TypeMapper { + return sources.length === 1 + ? makeUnaryTypeMapper(sources[0], targets ? targets[0] : anyType) + : makeArrayTypeMapper(sources, targets); } function getMappedType(type: Type, mapper: TypeMapper): Type { @@ -20469,27 +35832,58 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case TypeMapKind.Composite: case TypeMapKind.Merged: const t1 = getMappedType(type, mapper.mapper1); - return t1 !== type && mapper.kind === TypeMapKind.Composite ? instantiateType(t1, mapper.mapper2) : getMappedType(t1, mapper.mapper2); + return t1 !== type && mapper.kind === TypeMapKind.Composite + ? instantiateType(t1, mapper.mapper2) + : getMappedType(t1, mapper.mapper2); } } function makeUnaryTypeMapper(source: Type, target: Type): TypeMapper { - return Debug.attachDebugPrototypeIfDebug({ kind: TypeMapKind.Simple, source, target }); + return Debug.attachDebugPrototypeIfDebug({ + kind: TypeMapKind.Simple, + source, + target, + }); } - function makeArrayTypeMapper(sources: readonly TypeParameter[], targets: readonly Type[] | undefined): TypeMapper { - return Debug.attachDebugPrototypeIfDebug({ kind: TypeMapKind.Array, sources, targets }); + function makeArrayTypeMapper( + sources: readonly TypeParameter[], + targets: readonly Type[] | undefined + ): TypeMapper { + return Debug.attachDebugPrototypeIfDebug({ + kind: TypeMapKind.Array, + sources, + targets, + }); } - function makeFunctionTypeMapper(func: (t: Type) => Type, debugInfo: () => string): TypeMapper { - return Debug.attachDebugPrototypeIfDebug({ kind: TypeMapKind.Function, func, debugInfo: Debug.isDebugging ? debugInfo : undefined }); + function makeFunctionTypeMapper( + func: (t: Type) => Type, + debugInfo: () => string + ): TypeMapper { + return Debug.attachDebugPrototypeIfDebug({ + kind: TypeMapKind.Function, + func, + debugInfo: Debug.isDebugging ? debugInfo : undefined, + }); } - function makeDeferredTypeMapper(sources: readonly TypeParameter[], targets: (() => Type)[]) { - return Debug.attachDebugPrototypeIfDebug({ kind: TypeMapKind.Deferred, sources, targets }); + function makeDeferredTypeMapper( + sources: readonly TypeParameter[], + targets: (() => Type)[] + ) { + return Debug.attachDebugPrototypeIfDebug({ + kind: TypeMapKind.Deferred, + sources, + targets, + }); } - function makeCompositeTypeMapper(kind: TypeMapKind.Composite | TypeMapKind.Merged, mapper1: TypeMapper, mapper2: TypeMapper): TypeMapper { + function makeCompositeTypeMapper( + kind: TypeMapKind.Composite | TypeMapKind.Merged, + mapper1: TypeMapper, + mapper2: TypeMapper + ): TypeMapper { return Debug.attachDebugPrototypeIfDebug({ kind, mapper1, mapper2 }); } @@ -20501,9 +35895,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Maps forward-references to later types parameters to the empty object type. * This is used during inference when instantiating type parameter defaults. */ - function createBackreferenceMapper(context: InferenceContext, index: number): TypeMapper { + function createBackreferenceMapper( + context: InferenceContext, + index: number + ): TypeMapper { const forwardInferences = context.inferences.slice(index); - return createTypeMapper(map(forwardInferences, i => i.typeParameter), map(forwardInferences, () => unknownType)); + return createTypeMapper( + map(forwardInferences, (i) => i.typeParameter), + map(forwardInferences, () => unknownType) + ); } /** @@ -20511,29 +35911,69 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * to their inferences at the time of creation. */ function createOuterReturnMapper(context: InferenceContext) { - return context.outerReturnMapper ??= mergeTypeMappers(context.returnMapper, cloneInferenceContext(context).mapper); + return (context.outerReturnMapper ??= mergeTypeMappers( + context.returnMapper, + cloneInferenceContext(context).mapper + )); } - function combineTypeMappers(mapper1: TypeMapper | undefined, mapper2: TypeMapper): TypeMapper { - return mapper1 ? makeCompositeTypeMapper(TypeMapKind.Composite, mapper1, mapper2) : mapper2; + function combineTypeMappers( + mapper1: TypeMapper | undefined, + mapper2: TypeMapper + ): TypeMapper { + return mapper1 + ? makeCompositeTypeMapper(TypeMapKind.Composite, mapper1, mapper2) + : mapper2; } - function mergeTypeMappers(mapper1: TypeMapper | undefined, mapper2: TypeMapper): TypeMapper { - return mapper1 ? makeCompositeTypeMapper(TypeMapKind.Merged, mapper1, mapper2) : mapper2; + function mergeTypeMappers( + mapper1: TypeMapper | undefined, + mapper2: TypeMapper + ): TypeMapper { + return mapper1 + ? makeCompositeTypeMapper(TypeMapKind.Merged, mapper1, mapper2) + : mapper2; } - function prependTypeMapping(source: Type, target: Type, mapper: TypeMapper | undefined) { - return !mapper ? makeUnaryTypeMapper(source, target) : makeCompositeTypeMapper(TypeMapKind.Merged, makeUnaryTypeMapper(source, target), mapper); + function prependTypeMapping( + source: Type, + target: Type, + mapper: TypeMapper | undefined + ) { + return !mapper + ? makeUnaryTypeMapper(source, target) + : makeCompositeTypeMapper( + TypeMapKind.Merged, + makeUnaryTypeMapper(source, target), + mapper + ); } - function appendTypeMapping(mapper: TypeMapper | undefined, source: Type, target: Type) { - return !mapper ? makeUnaryTypeMapper(source, target) : makeCompositeTypeMapper(TypeMapKind.Merged, mapper, makeUnaryTypeMapper(source, target)); + function appendTypeMapping( + mapper: TypeMapper | undefined, + source: Type, + target: Type + ) { + return !mapper + ? makeUnaryTypeMapper(source, target) + : makeCompositeTypeMapper( + TypeMapKind.Merged, + mapper, + makeUnaryTypeMapper(source, target) + ); } function getRestrictiveTypeParameter(tp: TypeParameter) { - return !tp.constraint && !getConstraintDeclaration(tp) || tp.constraint === noConstraintType ? tp : tp.restrictiveInstantiation || ( - tp.restrictiveInstantiation = createTypeParameter(tp.symbol), (tp.restrictiveInstantiation as TypeParameter).constraint = noConstraintType, tp.restrictiveInstantiation - ); + return (!tp.constraint && !getConstraintDeclaration(tp)) || + tp.constraint === noConstraintType + ? tp + : tp.restrictiveInstantiation || + ((tp.restrictiveInstantiation = createTypeParameter( + tp.symbol + )), + ((tp.restrictiveInstantiation as TypeParameter).constraint = + noConstraintType), + tp.restrictiveInstantiation); } function cloneTypeParameter(typeParameter: TypeParameter): TypeParameter { @@ -20542,18 +35982,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function instantiateTypePredicate(predicate: TypePredicate, mapper: TypeMapper): TypePredicate { - return createTypePredicate(predicate.kind, predicate.parameterName, predicate.parameterIndex, instantiateType(predicate.type, mapper)); + function instantiateTypePredicate( + predicate: TypePredicate, + mapper: TypeMapper + ): TypePredicate { + return createTypePredicate( + predicate.kind, + predicate.parameterName, + predicate.parameterIndex, + instantiateType(predicate.type, mapper) + ); } - function instantiateSignature(signature: Signature, mapper: TypeMapper, eraseTypeParameters?: boolean): Signature { + function instantiateSignature( + signature: Signature, + mapper: TypeMapper, + eraseTypeParameters?: boolean + ): Signature { let freshTypeParameters: TypeParameter[] | undefined; if (signature.typeParameters && !eraseTypeParameters) { // First create a fresh set of type parameters, then include a mapping from the old to the // new type parameters in the mapper function. Finally store this mapper in the new type // parameters such that we can use it when instantiating constraints. - freshTypeParameters = map(signature.typeParameters, cloneTypeParameter); - mapper = combineTypeMappers(createTypeMapper(signature.typeParameters, freshTypeParameters), mapper); + freshTypeParameters = map( + signature.typeParameters, + cloneTypeParameter + ); + mapper = combineTypeMappers( + createTypeMapper(signature.typeParameters, freshTypeParameters), + mapper + ); for (const tp of freshTypeParameters) { tp.mapper = mapper; } @@ -20561,7 +36019,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Don't compute resolvedReturnType and resolvedTypePredicate now, // because using `mapper` now could trigger inferences to become fixed. (See `createInferenceContext`.) // See GH#17600. - const result = createSignature(signature.declaration, freshTypeParameters, signature.thisParameter && instantiateSymbol(signature.thisParameter, mapper), instantiateList(signature.parameters, mapper, instantiateSymbol), /*resolvedReturnType*/ undefined, /*resolvedTypePredicate*/ undefined, signature.minArgumentCount, signature.flags & SignatureFlags.PropagatingFlags); + const result = createSignature( + signature.declaration, + freshTypeParameters, + signature.thisParameter && + instantiateSymbol(signature.thisParameter, mapper), + instantiateList(signature.parameters, mapper, instantiateSymbol), + /*resolvedReturnType*/ undefined, + /*resolvedTypePredicate*/ undefined, + signature.minArgumentCount, + signature.flags & SignatureFlags.PropagatingFlags + ); result.target = signature; result.mapper = mapper; return result; @@ -20576,7 +36044,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return symbol; } // If we're a setter, check writeType. - if (links.writeType && !couldContainTypeVariables(links.writeType)) { + if ( + links.writeType && + !couldContainTypeVariables(links.writeType) + ) { return symbol; } } @@ -20589,7 +36060,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Keep the flags from the symbol we're instantiating. Mark that is instantiated, and // also transient so that we can just store data on it directly. - const result = createSymbol(symbol.flags, symbol.escapedName, CheckFlags.Instantiated | getCheckFlags(symbol) & (CheckFlags.Readonly | CheckFlags.Late | CheckFlags.OptionalParameter | CheckFlags.RestParameter)); + const result = createSymbol( + symbol.flags, + symbol.escapedName, + CheckFlags.Instantiated | + (getCheckFlags(symbol) & + (CheckFlags.Readonly | + CheckFlags.Late | + CheckFlags.OptionalParameter | + CheckFlags.RestParameter)) + ); result.declarations = symbol.declarations; result.parent = symbol.parent; result.links.target = symbol; @@ -20603,29 +36083,64 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function getObjectTypeInstantiation(type: AnonymousType | DeferredTypeReference, mapper: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]) { - const declaration = type.objectFlags & ObjectFlags.Reference ? (type as TypeReference).node! : - type.objectFlags & ObjectFlags.InstantiationExpressionType ? (type as InstantiationExpressionType).node : - type.symbol.declarations![0]; + function getObjectTypeInstantiation( + type: AnonymousType | DeferredTypeReference, + mapper: TypeMapper, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[] + ) { + const declaration = + type.objectFlags & ObjectFlags.Reference + ? (type as TypeReference).node! + : type.objectFlags & ObjectFlags.InstantiationExpressionType + ? (type as InstantiationExpressionType).node + : type.symbol.declarations![0]; const links = getNodeLinks(declaration); - const target = type.objectFlags & ObjectFlags.Reference ? links.resolvedType! as DeferredTypeReference : - type.objectFlags & ObjectFlags.Instantiated ? type.target! : type; + const target = + type.objectFlags & ObjectFlags.Reference + ? (links.resolvedType! as DeferredTypeReference) + : type.objectFlags & ObjectFlags.Instantiated + ? type.target! + : type; let typeParameters = links.outerTypeParameters; if (!typeParameters) { // The first time an anonymous type is instantiated we compute and store a list of the type // parameters that are in scope (and therefore potentially referenced). For type literals that // aren't the right hand side of a generic type alias declaration we optimize by reducing the // set of type parameters to those that are possibly referenced in the literal. - let outerTypeParameters = getOuterTypeParameters(declaration, /*includeThisTypes*/ true); + let outerTypeParameters = getOuterTypeParameters( + declaration, + /*includeThisTypes*/ true + ); if (isJSConstructor(declaration)) { - const templateTagParameters = getTypeParametersFromDeclaration(declaration as DeclarationWithTypeParameters); - outerTypeParameters = addRange(outerTypeParameters, templateTagParameters); + const templateTagParameters = getTypeParametersFromDeclaration( + declaration as DeclarationWithTypeParameters + ); + outerTypeParameters = addRange( + outerTypeParameters, + templateTagParameters + ); } typeParameters = outerTypeParameters || emptyArray; - const allDeclarations = type.objectFlags & (ObjectFlags.Reference | ObjectFlags.InstantiationExpressionType) ? [declaration] : type.symbol.declarations!; - typeParameters = (target.objectFlags & (ObjectFlags.Reference | ObjectFlags.InstantiationExpressionType) || target.symbol.flags & SymbolFlags.Method || target.symbol.flags & SymbolFlags.TypeLiteral) && !target.aliasTypeArguments ? - filter(typeParameters, tp => some(allDeclarations, d => isTypeParameterPossiblyReferenced(tp, d))) : - typeParameters; + const allDeclarations = + type.objectFlags & + (ObjectFlags.Reference | + ObjectFlags.InstantiationExpressionType) + ? [declaration] + : type.symbol.declarations!; + typeParameters = + (target.objectFlags & + (ObjectFlags.Reference | + ObjectFlags.InstantiationExpressionType) || + target.symbol.flags & SymbolFlags.Method || + target.symbol.flags & SymbolFlags.TypeLiteral) && + !target.aliasTypeArguments + ? filter(typeParameters, (tp) => + some(allDeclarations, (d) => + isTypeParameterPossiblyReferenced(tp, d) + ) + ) + : typeParameters; links.outerTypeParameters = typeParameters; } if (typeParameters.length) { @@ -20633,37 +36148,98 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // mapper to the type parameters to produce the effective list of type arguments, and compute the // instantiation cache key from the type IDs of the type arguments. const combinedMapper = combineTypeMappers(type.mapper, mapper); - const typeArguments = map(typeParameters, t => getMappedType(t, combinedMapper)); + const typeArguments = map(typeParameters, (t) => + getMappedType(t, combinedMapper) + ); const newAliasSymbol = aliasSymbol || type.aliasSymbol; - const newAliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(type.aliasTypeArguments, mapper); - const id = getTypeListId(typeArguments) + getAliasId(newAliasSymbol, newAliasTypeArguments); + const newAliasTypeArguments = aliasSymbol + ? aliasTypeArguments + : instantiateTypes(type.aliasTypeArguments, mapper); + const id = + getTypeListId(typeArguments) + + getAliasId(newAliasSymbol, newAliasTypeArguments); if (!target.instantiations) { target.instantiations = new Map(); - target.instantiations.set(getTypeListId(typeParameters) + getAliasId(target.aliasSymbol, target.aliasTypeArguments), target); + target.instantiations.set( + getTypeListId(typeParameters) + + getAliasId( + target.aliasSymbol, + target.aliasTypeArguments + ), + target + ); } let result = target.instantiations.get(id); if (!result) { let newMapper = createTypeMapper(typeParameters, typeArguments); - if (target.objectFlags & ObjectFlags.SingleSignatureType && mapper) { + if ( + target.objectFlags & ObjectFlags.SingleSignatureType && + mapper + ) { newMapper = combineTypeMappers(newMapper, mapper); } - result = target.objectFlags & ObjectFlags.Reference ? createDeferredTypeReference((type as DeferredTypeReference).target, (type as DeferredTypeReference).node, newMapper, newAliasSymbol, newAliasTypeArguments) : - target.objectFlags & ObjectFlags.Mapped ? instantiateMappedType(target as MappedType, newMapper, newAliasSymbol, newAliasTypeArguments) : - instantiateAnonymousType(target, newMapper, newAliasSymbol, newAliasTypeArguments); + result = + target.objectFlags & ObjectFlags.Reference + ? createDeferredTypeReference( + (type as DeferredTypeReference).target, + (type as DeferredTypeReference).node, + newMapper, + newAliasSymbol, + newAliasTypeArguments + ) + : target.objectFlags & ObjectFlags.Mapped + ? instantiateMappedType( + target as MappedType, + newMapper, + newAliasSymbol, + newAliasTypeArguments + ) + : instantiateAnonymousType( + target, + newMapper, + newAliasSymbol, + newAliasTypeArguments + ); target.instantiations.set(id, result); // Set cached result early in case we recursively invoke instantiation while eagerly computing type variable visibility below const resultObjectFlags = getObjectFlags(result); - if (result.flags & TypeFlags.ObjectFlagsType && !(resultObjectFlags & ObjectFlags.CouldContainTypeVariablesComputed)) { - const resultCouldContainTypeVariables = some(typeArguments, couldContainTypeVariables); // one of the input type arguments might be or contain the result - if (!(getObjectFlags(result) & ObjectFlags.CouldContainTypeVariablesComputed)) { + if ( + result.flags & TypeFlags.ObjectFlagsType && + !( + resultObjectFlags & + ObjectFlags.CouldContainTypeVariablesComputed + ) + ) { + const resultCouldContainTypeVariables = some( + typeArguments, + couldContainTypeVariables + ); // one of the input type arguments might be or contain the result + if ( + !( + getObjectFlags(result) & + ObjectFlags.CouldContainTypeVariablesComputed + ) + ) { // if `result` is one of the object types we tried to make (it may not be, due to how `instantiateMappedType` works), we can carry forward the type variable containment check from the input type arguments - if (resultObjectFlags & (ObjectFlags.Mapped | ObjectFlags.Anonymous | ObjectFlags.Reference)) { - (result as ObjectFlagsType).objectFlags |= ObjectFlags.CouldContainTypeVariablesComputed | (resultCouldContainTypeVariables ? ObjectFlags.CouldContainTypeVariables : 0); + if ( + resultObjectFlags & + (ObjectFlags.Mapped | + ObjectFlags.Anonymous | + ObjectFlags.Reference) + ) { + (result as ObjectFlagsType).objectFlags |= + ObjectFlags.CouldContainTypeVariablesComputed | + (resultCouldContainTypeVariables + ? ObjectFlags.CouldContainTypeVariables + : 0); } // If none of the type arguments for the outer type parameters contain type variables, it follows // that the instantiated type doesn't reference type variables. // Intrinsics have `CouldContainTypeVariablesComputed` pre-set, so this should only cover unions and intersections resulting from `instantiateMappedType` else { - (result as ObjectFlagsType).objectFlags |= !resultCouldContainTypeVariables ? ObjectFlags.CouldContainTypeVariablesComputed : 0; + (result as ObjectFlagsType).objectFlags |= + !resultCouldContainTypeVariables + ? ObjectFlags.CouldContainTypeVariablesComputed + : 0; } } } @@ -20674,8 +36250,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function maybeTypeParameterReference(node: Node) { - return !(node.parent.kind === SyntaxKind.TypeReference && (node.parent as TypeReferenceNode).typeArguments && node === (node.parent as TypeReferenceNode).typeName || - node.parent.kind === SyntaxKind.ImportType && (node.parent as ImportTypeNode).typeArguments && node === (node.parent as ImportTypeNode).qualifier); + return !( + (node.parent.kind === SyntaxKind.TypeReference && + (node.parent as TypeReferenceNode).typeArguments && + node === (node.parent as TypeReferenceNode).typeName) || + (node.parent.kind === SyntaxKind.ImportType && + (node.parent as ImportTypeNode).typeArguments && + node === (node.parent as ImportTypeNode).qualifier) + ); } function isTypeParameterPossiblyReferenced(tp: TypeParameter, node: Node) { @@ -20683,10 +36265,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // between the node and the type parameter declaration, if the node contains actual references to the // type parameter, or if the node contains type queries that we can't prove couldn't contain references to the type parameter, // we consider the type parameter possibly referenced. - if (tp.symbol && tp.symbol.declarations && tp.symbol.declarations.length === 1) { + if ( + tp.symbol && + tp.symbol.declarations && + tp.symbol.declarations.length === 1 + ) { const container = tp.symbol.declarations[0].parent; for (let n = node; n !== container; n = n.parent) { - if (!n || n.kind === SyntaxKind.Block || n.kind === SyntaxKind.ConditionalType && forEachChild((n as ConditionalTypeNode).extendsType, containsReference)) { + if ( + !n || + n.kind === SyntaxKind.Block || + (n.kind === SyntaxKind.ConditionalType && + forEachChild( + (n as ConditionalTypeNode).extendsType, + containsReference + )) + ) { return true; } } @@ -20698,29 +36292,59 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ThisType: return !!tp.isThisType; case SyntaxKind.Identifier: - return !tp.isThisType && isPartOfTypeNode(node) && maybeTypeParameterReference(node) && - getTypeFromTypeNodeWorker(node as TypeNode) === tp; // use worker because we're looking for === equality + return ( + !tp.isThisType && + isPartOfTypeNode(node) && + maybeTypeParameterReference(node) && + getTypeFromTypeNodeWorker(node as TypeNode) === tp + ); // use worker because we're looking for === equality case SyntaxKind.TypeQuery: const entityName = (node as TypeQueryNode).exprName; const firstIdentifier = getFirstIdentifier(entityName); - if (!isThisIdentifier(firstIdentifier)) { // Don't attempt to analyze typeof this.xxx - const firstIdentifierSymbol = getResolvedSymbol(firstIdentifier); + if (!isThisIdentifier(firstIdentifier)) { + // Don't attempt to analyze typeof this.xxx + const firstIdentifierSymbol = + getResolvedSymbol(firstIdentifier); const tpDeclaration = tp.symbol.declarations![0]; // There is exactly one declaration, otherwise `containsReference` is not called - const tpScope = tpDeclaration.kind === SyntaxKind.TypeParameter ? tpDeclaration.parent : // Type parameter is a regular type parameter, e.g. foo - tp.isThisType ? tpDeclaration : // Type parameter is the this type, and its declaration is the class declaration. - undefined; // Type parameter's declaration was unrecognized, e.g. comes from JSDoc annotation. + const tpScope = + tpDeclaration.kind === SyntaxKind.TypeParameter + ? tpDeclaration.parent // Type parameter is a regular type parameter, e.g. foo + : tp.isThisType + ? tpDeclaration // Type parameter is the this type, and its declaration is the class declaration. + : undefined; // Type parameter's declaration was unrecognized, e.g. comes from JSDoc annotation. if (firstIdentifierSymbol.declarations && tpScope) { - return some(firstIdentifierSymbol.declarations, idDecl => isNodeDescendantOf(idDecl, tpScope)) || - some((node as TypeQueryNode).typeArguments, containsReference); + return ( + some( + firstIdentifierSymbol.declarations, + (idDecl) => + isNodeDescendantOf(idDecl, tpScope) + ) || + some( + (node as TypeQueryNode).typeArguments, + containsReference + ) + ); } } return true; case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: - return !(node as FunctionLikeDeclaration).type && !!(node as FunctionLikeDeclaration).body || - some((node as FunctionLikeDeclaration).typeParameters, containsReference) || - some((node as FunctionLikeDeclaration).parameters, containsReference) || - !!(node as FunctionLikeDeclaration).type && containsReference((node as FunctionLikeDeclaration).type!); + return ( + (!(node as FunctionLikeDeclaration).type && + !!(node as FunctionLikeDeclaration).body) || + some( + (node as FunctionLikeDeclaration).typeParameters, + containsReference + ) || + some( + (node as FunctionLikeDeclaration).parameters, + containsReference + ) || + (!!(node as FunctionLikeDeclaration).type && + containsReference( + (node as FunctionLikeDeclaration).type! + )) + ); } return !!forEachChild(node, containsReference); } @@ -20729,7 +36353,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getHomomorphicTypeVariable(type: MappedType) { const constraintType = getConstraintTypeFromMappedType(type); if (constraintType.flags & TypeFlags.Index) { - const typeVariable = getActualTypeVariable((constraintType as IndexType).type); + const typeVariable = getActualTypeVariable( + (constraintType as IndexType).type + ); if (typeVariable.flags & TypeFlags.TypeParameter) { return typeVariable as TypeParameter; } @@ -20737,7 +36363,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - function instantiateMappedType(type: MappedType, mapper: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type { + function instantiateMappedType( + type: MappedType, + mapper: TypeMapper, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[] + ): Type { // For a homomorphic mapped type { [P in keyof T]: X }, where T is some type variable, the mapping // operation depends on T as follows: // * If T is a primitive type no mapping is performed and the result is simply T. @@ -20753,40 +36384,100 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (typeVariable) { const mappedTypeVariable = instantiateType(typeVariable, mapper); if (typeVariable !== mappedTypeVariable) { - return mapTypeWithAlias(getReducedType(mappedTypeVariable), instantiateConstituent, aliasSymbol, aliasTypeArguments); + return mapTypeWithAlias( + getReducedType(mappedTypeVariable), + instantiateConstituent, + aliasSymbol, + aliasTypeArguments + ); } } // If the constraint type of the instantiation is the wildcard type, return the wildcard type. - return instantiateType(getConstraintTypeFromMappedType(type), mapper) === wildcardType ? wildcardType : instantiateAnonymousType(type, mapper, aliasSymbol, aliasTypeArguments); + return instantiateType( + getConstraintTypeFromMappedType(type), + mapper + ) === wildcardType + ? wildcardType + : instantiateAnonymousType( + type, + mapper, + aliasSymbol, + aliasTypeArguments + ); function instantiateConstituent(t: Type): Type { - if (t.flags & (TypeFlags.AnyOrUnknown | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object | TypeFlags.Intersection) && t !== wildcardType && !isErrorType(t)) { + if ( + t.flags & + (TypeFlags.AnyOrUnknown | + TypeFlags.InstantiableNonPrimitive | + TypeFlags.Object | + TypeFlags.Intersection) && + t !== wildcardType && + !isErrorType(t) + ) { if (!type.declaration.nameType) { let constraint; if ( - isArrayType(t) || t.flags & TypeFlags.Any && findResolutionCycleStartIndex(typeVariable!, TypeSystemPropertyName.ImmediateBaseConstraint) < 0 && - (constraint = getConstraintOfTypeParameter(typeVariable!)) && everyType(constraint, isArrayOrTupleType) + isArrayType(t) || + (t.flags & TypeFlags.Any && + findResolutionCycleStartIndex( + typeVariable!, + TypeSystemPropertyName.ImmediateBaseConstraint + ) < 0 && + (constraint = getConstraintOfTypeParameter( + typeVariable! + )) && + everyType(constraint, isArrayOrTupleType)) ) { - return instantiateMappedArrayType(t, type, prependTypeMapping(typeVariable!, t, mapper)); + return instantiateMappedArrayType( + t, + type, + prependTypeMapping(typeVariable!, t, mapper) + ); } if (isTupleType(t)) { - return instantiateMappedTupleType(t, type, typeVariable!, mapper); + return instantiateMappedTupleType( + t, + type, + typeVariable!, + mapper + ); } if (isArrayOrTupleOrIntersection(t)) { - return getIntersectionType(map((t as IntersectionType).types, instantiateConstituent)); + return getIntersectionType( + map( + (t as IntersectionType).types, + instantiateConstituent + ) + ); } } - return instantiateAnonymousType(type, prependTypeMapping(typeVariable!, t, mapper)); + return instantiateAnonymousType( + type, + prependTypeMapping(typeVariable!, t, mapper) + ); } return t; } } - function getModifiedReadonlyState(state: boolean, modifiers: MappedTypeModifiers) { - return modifiers & MappedTypeModifiers.IncludeReadonly ? true : modifiers & MappedTypeModifiers.ExcludeReadonly ? false : state; - } - - function instantiateMappedTupleType(tupleType: TupleTypeReference, mappedType: MappedType, typeVariable: TypeVariable, mapper: TypeMapper) { + function getModifiedReadonlyState( + state: boolean, + modifiers: MappedTypeModifiers + ) { + return modifiers & MappedTypeModifiers.IncludeReadonly + ? true + : modifiers & MappedTypeModifiers.ExcludeReadonly + ? false + : state; + } + + function instantiateMappedTupleType( + tupleType: TupleTypeReference, + mappedType: MappedType, + typeVariable: TypeVariable, + mapper: TypeMapper + ) { // We apply the mapped type's template type to each of the fixed part elements. For variadic elements, we // apply the mapped type itself to the variadic element type. For other elements in the variable part of the // tuple, we surround the element type with an array type and apply the mapped type to that. This ensures @@ -20798,79 +36489,218 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // const elementFlags = tupleType.target.elementFlags; const fixedLength = tupleType.target.fixedLength; - const fixedMapper = fixedLength ? prependTypeMapping(typeVariable, tupleType, mapper) : mapper; + const fixedMapper = fixedLength + ? prependTypeMapping(typeVariable, tupleType, mapper) + : mapper; const newElementTypes = map(getElementTypes(tupleType), (type, i) => { const flags = elementFlags[i]; - return i < fixedLength ? instantiateMappedTypeTemplate(mappedType, getStringLiteralType("" + i), !!(flags & ElementFlags.Optional), fixedMapper) : - flags & ElementFlags.Variadic ? instantiateType(mappedType, prependTypeMapping(typeVariable, type, mapper)) : - getElementTypeOfArrayType(instantiateType(mappedType, prependTypeMapping(typeVariable, createArrayType(type), mapper))) ?? unknownType; + return i < fixedLength + ? instantiateMappedTypeTemplate( + mappedType, + getStringLiteralType("" + i), + !!(flags & ElementFlags.Optional), + fixedMapper + ) + : flags & ElementFlags.Variadic + ? instantiateType( + mappedType, + prependTypeMapping(typeVariable, type, mapper) + ) + : getElementTypeOfArrayType( + instantiateType( + mappedType, + prependTypeMapping( + typeVariable, + createArrayType(type), + mapper + ) + ) + ) ?? unknownType; }); const modifiers = getMappedTypeModifiers(mappedType); - const newElementFlags = modifiers & MappedTypeModifiers.IncludeOptional ? map(elementFlags, f => f & ElementFlags.Required ? ElementFlags.Optional : f) : - modifiers & MappedTypeModifiers.ExcludeOptional ? map(elementFlags, f => f & ElementFlags.Optional ? ElementFlags.Required : f) : - elementFlags; - const newReadonly = getModifiedReadonlyState(tupleType.target.readonly, getMappedTypeModifiers(mappedType)); - return contains(newElementTypes, errorType) ? errorType : - createTupleType(newElementTypes, newElementFlags, newReadonly, tupleType.target.labeledElementDeclarations); - } - - function instantiateMappedArrayType(arrayType: Type, mappedType: MappedType, mapper: TypeMapper) { - const elementType = instantiateMappedTypeTemplate(mappedType, numberType, /*isOptional*/ true, mapper); - return isErrorType(elementType) ? errorType : - createArrayType(elementType, getModifiedReadonlyState(isReadonlyArrayType(arrayType), getMappedTypeModifiers(mappedType))); - } - - function instantiateMappedTypeTemplate(type: MappedType, key: Type, isOptional: boolean, mapper: TypeMapper) { - const templateMapper = appendTypeMapping(mapper, getTypeParameterFromMappedType(type), key); - const propType = instantiateType(getTemplateTypeFromMappedType(type.target as MappedType || type), templateMapper); + const newElementFlags = + modifiers & MappedTypeModifiers.IncludeOptional + ? map(elementFlags, (f) => + f & ElementFlags.Required ? ElementFlags.Optional : f + ) + : modifiers & MappedTypeModifiers.ExcludeOptional + ? map(elementFlags, (f) => + f & ElementFlags.Optional ? ElementFlags.Required : f + ) + : elementFlags; + const newReadonly = getModifiedReadonlyState( + tupleType.target.readonly, + getMappedTypeModifiers(mappedType) + ); + return contains(newElementTypes, errorType) + ? errorType + : createTupleType( + newElementTypes, + newElementFlags, + newReadonly, + tupleType.target.labeledElementDeclarations + ); + } + + function instantiateMappedArrayType( + arrayType: Type, + mappedType: MappedType, + mapper: TypeMapper + ) { + const elementType = instantiateMappedTypeTemplate( + mappedType, + numberType, + /*isOptional*/ true, + mapper + ); + return isErrorType(elementType) + ? errorType + : createArrayType( + elementType, + getModifiedReadonlyState( + isReadonlyArrayType(arrayType), + getMappedTypeModifiers(mappedType) + ) + ); + } + + function instantiateMappedTypeTemplate( + type: MappedType, + key: Type, + isOptional: boolean, + mapper: TypeMapper + ) { + const templateMapper = appendTypeMapping( + mapper, + getTypeParameterFromMappedType(type), + key + ); + const propType = instantiateType( + getTemplateTypeFromMappedType((type.target as MappedType) || type), + templateMapper + ); const modifiers = getMappedTypeModifiers(type); - return strictNullChecks && modifiers & MappedTypeModifiers.IncludeOptional && !maybeTypeOfKind(propType, TypeFlags.Undefined | TypeFlags.Void) ? getOptionalType(propType, /*isProperty*/ true) : - strictNullChecks && modifiers & MappedTypeModifiers.ExcludeOptional && isOptional ? getTypeWithFacts(propType, TypeFacts.NEUndefined) : - propType; - } - - function instantiateAnonymousType(type: AnonymousType, mapper: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): AnonymousType { - Debug.assert(type.symbol, "anonymous type must have symbol to be instantiated"); - const result = createObjectType(type.objectFlags & ~(ObjectFlags.CouldContainTypeVariablesComputed | ObjectFlags.CouldContainTypeVariables) | ObjectFlags.Instantiated, type.symbol) as AnonymousType; + return strictNullChecks && + modifiers & MappedTypeModifiers.IncludeOptional && + !maybeTypeOfKind(propType, TypeFlags.Undefined | TypeFlags.Void) + ? getOptionalType(propType, /*isProperty*/ true) + : strictNullChecks && + modifiers & MappedTypeModifiers.ExcludeOptional && + isOptional + ? getTypeWithFacts(propType, TypeFacts.NEUndefined) + : propType; + } + + function instantiateAnonymousType( + type: AnonymousType, + mapper: TypeMapper, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[] + ): AnonymousType { + Debug.assert( + type.symbol, + "anonymous type must have symbol to be instantiated" + ); + const result = createObjectType( + (type.objectFlags & + ~( + ObjectFlags.CouldContainTypeVariablesComputed | + ObjectFlags.CouldContainTypeVariables + )) | + ObjectFlags.Instantiated, + type.symbol + ) as AnonymousType; if (type.objectFlags & ObjectFlags.Mapped) { - (result as MappedType).declaration = (type as MappedType).declaration; + (result as MappedType).declaration = ( + type as MappedType + ).declaration; // C.f. instantiateSignature - const origTypeParameter = getTypeParameterFromMappedType(type as MappedType); + const origTypeParameter = getTypeParameterFromMappedType( + type as MappedType + ); const freshTypeParameter = cloneTypeParameter(origTypeParameter); (result as MappedType).typeParameter = freshTypeParameter; - mapper = combineTypeMappers(makeUnaryTypeMapper(origTypeParameter, freshTypeParameter), mapper); + mapper = combineTypeMappers( + makeUnaryTypeMapper(origTypeParameter, freshTypeParameter), + mapper + ); freshTypeParameter.mapper = mapper; } if (type.objectFlags & ObjectFlags.InstantiationExpressionType) { - (result as InstantiationExpressionType).node = (type as InstantiationExpressionType).node; + (result as InstantiationExpressionType).node = ( + type as InstantiationExpressionType + ).node; } result.target = type; result.mapper = mapper; result.aliasSymbol = aliasSymbol || type.aliasSymbol; - result.aliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(type.aliasTypeArguments, mapper); - result.objectFlags |= result.aliasTypeArguments ? getPropagatingFlagsOfTypes(result.aliasTypeArguments) : 0; + result.aliasTypeArguments = aliasSymbol + ? aliasTypeArguments + : instantiateTypes(type.aliasTypeArguments, mapper); + result.objectFlags |= result.aliasTypeArguments + ? getPropagatingFlagsOfTypes(result.aliasTypeArguments) + : 0; return result; } - function getConditionalTypeInstantiation(type: ConditionalType, mapper: TypeMapper, forConstraint: boolean, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type { + function getConditionalTypeInstantiation( + type: ConditionalType, + mapper: TypeMapper, + forConstraint: boolean, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[] + ): Type { const root = type.root; if (root.outerTypeParameters) { // We are instantiating a conditional type that has one or more type parameters in scope. Apply the // mapper to the type parameters to produce the effective list of type arguments, and compute the // instantiation cache key from the type IDs of the type arguments. - const typeArguments = map(root.outerTypeParameters, t => getMappedType(t, mapper)); - const id = (forConstraint ? "C" : "") + getTypeListId(typeArguments) + getAliasId(aliasSymbol, aliasTypeArguments); + const typeArguments = map(root.outerTypeParameters, (t) => + getMappedType(t, mapper) + ); + const id = + (forConstraint ? "C" : "") + + getTypeListId(typeArguments) + + getAliasId(aliasSymbol, aliasTypeArguments); let result = root.instantiations!.get(id); if (!result) { - const newMapper = createTypeMapper(root.outerTypeParameters, typeArguments); + const newMapper = createTypeMapper( + root.outerTypeParameters, + typeArguments + ); const checkType = root.checkType; - const distributionType = root.isDistributive ? getReducedType(getMappedType(checkType, newMapper)) : undefined; + const distributionType = root.isDistributive + ? getReducedType(getMappedType(checkType, newMapper)) + : undefined; // Distributive conditional types are distributed over union types. For example, when the // distributive conditional type T extends U ? X : Y is instantiated with A | B for T, the // result is (A extends U ? X : Y) | (B extends U ? X : Y). - result = distributionType && checkType !== distributionType && distributionType.flags & (TypeFlags.Union | TypeFlags.Never) ? - mapTypeWithAlias(distributionType, t => getConditionalType(root, prependTypeMapping(checkType, t, newMapper), forConstraint), aliasSymbol, aliasTypeArguments) : - getConditionalType(root, newMapper, forConstraint, aliasSymbol, aliasTypeArguments); + result = + distributionType && + checkType !== distributionType && + distributionType.flags & (TypeFlags.Union | TypeFlags.Never) + ? mapTypeWithAlias( + distributionType, + (t) => + getConditionalType( + root, + prependTypeMapping( + checkType, + t, + newMapper + ), + forConstraint + ), + aliasSymbol, + aliasTypeArguments + ) + : getConditionalType( + root, + newMapper, + forConstraint, + aliasSymbol, + aliasTypeArguments + ); root.instantiations!.set(id, result); } return result; @@ -20879,12 +36709,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function instantiateType(type: Type, mapper: TypeMapper | undefined): Type; - function instantiateType(type: Type | undefined, mapper: TypeMapper | undefined): Type | undefined; - function instantiateType(type: Type | undefined, mapper: TypeMapper | undefined): Type | undefined { - return type && mapper ? instantiateTypeWithAlias(type, mapper, /*aliasSymbol*/ undefined, /*aliasTypeArguments*/ undefined) : type; + function instantiateType( + type: Type | undefined, + mapper: TypeMapper | undefined + ): Type | undefined; + function instantiateType( + type: Type | undefined, + mapper: TypeMapper | undefined + ): Type | undefined { + return type && mapper + ? instantiateTypeWithAlias( + type, + mapper, + /*aliasSymbol*/ undefined, + /*aliasTypeArguments*/ undefined + ) + : type; } - function instantiateTypeWithAlias(type: Type, mapper: TypeMapper, aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined): Type { + function instantiateTypeWithAlias( + type: Type, + mapper: TypeMapper, + aliasSymbol: Symbol | undefined, + aliasTypeArguments: readonly Type[] | undefined + ): Type { if (!couldContainTypeVariables(type)) { return type; } @@ -20892,8 +36740,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We have reached 100 recursive type instantiations, or 5M type instantiations caused by the same statement // or expression. There is a very high likelyhood we're dealing with a combination of infinite generic types // that perpetually generate new type identities, so we stop the recursion here by yielding the error type. - tracing?.instant(tracing.Phase.CheckTypes, "instantiateType_DepthLimit", { typeId: type.id, instantiationDepth, instantiationCount }); - error(currentNode, Diagnostics.Type_instantiation_is_excessively_deep_and_possibly_infinite); + tracing?.instant( + tracing.Phase.CheckTypes, + "instantiateType_DepthLimit", + { typeId: type.id, instantiationDepth, instantiationCount } + ); + error( + currentNode, + Diagnostics.Type_instantiation_is_excessively_deep_and_possibly_infinite + ); return errorType; } const index = findActiveMapper(mapper); @@ -20901,7 +36756,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { pushActiveMapper(mapper); } const key = type.id + getAliasId(aliasSymbol, aliasTypeArguments); - const mapperCache = activeTypeMappersCaches[index !== -1 ? index : activeTypeMappersCount - 1]; + const mapperCache = + activeTypeMappersCaches[ + index !== -1 ? index : activeTypeMappersCount - 1 + ]; const cached = mapperCache.get(key); if (cached) { return cached; @@ -20909,63 +36767,133 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { totalInstantiationCount++; instantiationCount++; instantiationDepth++; - const result = instantiateTypeWorker(type, mapper, aliasSymbol, aliasTypeArguments); + const result = instantiateTypeWorker( + type, + mapper, + aliasSymbol, + aliasTypeArguments + ); if (index === -1) { popActiveMapper(); - } - else { + } else { mapperCache.set(key, result); } instantiationDepth--; return result; } - function instantiateTypeWorker(type: Type, mapper: TypeMapper, aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined): Type { + function instantiateTypeWorker( + type: Type, + mapper: TypeMapper, + aliasSymbol: Symbol | undefined, + aliasTypeArguments: readonly Type[] | undefined + ): Type { const flags = type.flags; if (flags & TypeFlags.TypeParameter) { return getMappedType(type, mapper); } if (flags & TypeFlags.Object) { const objectFlags = (type as ObjectType).objectFlags; - if (objectFlags & (ObjectFlags.Reference | ObjectFlags.Anonymous | ObjectFlags.Mapped)) { - if (objectFlags & ObjectFlags.Reference && !(type as TypeReference).node) { - const resolvedTypeArguments = (type as TypeReference).resolvedTypeArguments; - const newTypeArguments = instantiateTypes(resolvedTypeArguments, mapper); - return newTypeArguments !== resolvedTypeArguments ? createNormalizedTypeReference((type as TypeReference).target, newTypeArguments) : type; + if ( + objectFlags & + (ObjectFlags.Reference | + ObjectFlags.Anonymous | + ObjectFlags.Mapped) + ) { + if ( + objectFlags & ObjectFlags.Reference && + !(type as TypeReference).node + ) { + const resolvedTypeArguments = (type as TypeReference) + .resolvedTypeArguments; + const newTypeArguments = instantiateTypes( + resolvedTypeArguments, + mapper + ); + return newTypeArguments !== resolvedTypeArguments + ? createNormalizedTypeReference( + (type as TypeReference).target, + newTypeArguments + ) + : type; } if (objectFlags & ObjectFlags.ReverseMapped) { - return instantiateReverseMappedType(type as ReverseMappedType, mapper); + return instantiateReverseMappedType( + type as ReverseMappedType, + mapper + ); } - return getObjectTypeInstantiation(type as TypeReference | AnonymousType | MappedType, mapper, aliasSymbol, aliasTypeArguments); + return getObjectTypeInstantiation( + type as TypeReference | AnonymousType | MappedType, + mapper, + aliasSymbol, + aliasTypeArguments + ); } return type; } if (flags & TypeFlags.UnionOrIntersection) { - const origin = type.flags & TypeFlags.Union ? (type as UnionType).origin : undefined; - const types = origin && origin.flags & TypeFlags.UnionOrIntersection ? (origin as UnionOrIntersectionType).types : (type as UnionOrIntersectionType).types; + const origin = + type.flags & TypeFlags.Union + ? (type as UnionType).origin + : undefined; + const types = + origin && origin.flags & TypeFlags.UnionOrIntersection + ? (origin as UnionOrIntersectionType).types + : (type as UnionOrIntersectionType).types; const newTypes = instantiateTypes(types, mapper); if (newTypes === types && aliasSymbol === type.aliasSymbol) { return type; } const newAliasSymbol = aliasSymbol || type.aliasSymbol; - const newAliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(type.aliasTypeArguments, mapper); - return flags & TypeFlags.Intersection || origin && origin.flags & TypeFlags.Intersection ? - getIntersectionType(newTypes, IntersectionFlags.None, newAliasSymbol, newAliasTypeArguments) : - getUnionType(newTypes, UnionReduction.Literal, newAliasSymbol, newAliasTypeArguments); + const newAliasTypeArguments = aliasSymbol + ? aliasTypeArguments + : instantiateTypes(type.aliasTypeArguments, mapper); + return flags & TypeFlags.Intersection || + (origin && origin.flags & TypeFlags.Intersection) + ? getIntersectionType( + newTypes, + IntersectionFlags.None, + newAliasSymbol, + newAliasTypeArguments + ) + : getUnionType( + newTypes, + UnionReduction.Literal, + newAliasSymbol, + newAliasTypeArguments + ); } if (flags & TypeFlags.Index) { - return getIndexType(instantiateType((type as IndexType).type, mapper)); + return getIndexType( + instantiateType((type as IndexType).type, mapper) + ); } if (flags & TypeFlags.TemplateLiteral) { - return getTemplateLiteralType((type as TemplateLiteralType).texts, instantiateTypes((type as TemplateLiteralType).types, mapper)); + return getTemplateLiteralType( + (type as TemplateLiteralType).texts, + instantiateTypes((type as TemplateLiteralType).types, mapper) + ); } if (flags & TypeFlags.StringMapping) { - return getStringMappingType((type as StringMappingType).symbol, instantiateType((type as StringMappingType).type, mapper)); + return getStringMappingType( + (type as StringMappingType).symbol, + instantiateType((type as StringMappingType).type, mapper) + ); } if (flags & TypeFlags.IndexedAccess) { const newAliasSymbol = aliasSymbol || type.aliasSymbol; - const newAliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(type.aliasTypeArguments, mapper); - return getIndexedAccessType(instantiateType((type as IndexedAccessType).objectType, mapper), instantiateType((type as IndexedAccessType).indexType, mapper), (type as IndexedAccessType).accessFlags, /*accessNode*/ undefined, newAliasSymbol, newAliasTypeArguments); + const newAliasTypeArguments = aliasSymbol + ? aliasTypeArguments + : instantiateTypes(type.aliasTypeArguments, mapper); + return getIndexedAccessType( + instantiateType((type as IndexedAccessType).objectType, mapper), + instantiateType((type as IndexedAccessType).indexType, mapper), + (type as IndexedAccessType).accessFlags, + /*accessNode*/ undefined, + newAliasSymbol, + newAliasTypeArguments + ); } if (flags & TypeFlags.Conditional) { return getConditionalTypeInstantiation( @@ -20973,30 +36901,50 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { combineTypeMappers((type as ConditionalType).mapper, mapper), /*forConstraint*/ false, aliasSymbol, - aliasTypeArguments, + aliasTypeArguments ); } if (flags & TypeFlags.Substitution) { - const newBaseType = instantiateType((type as SubstitutionType).baseType, mapper); + const newBaseType = instantiateType( + (type as SubstitutionType).baseType, + mapper + ); if (isNoInferType(type)) { return getNoInferType(newBaseType); } - const newConstraint = instantiateType((type as SubstitutionType).constraint, mapper); + const newConstraint = instantiateType( + (type as SubstitutionType).constraint, + mapper + ); // A substitution type originates in the true branch of a conditional type and can be resolved // to just the base type in the same cases as the conditional type resolves to its true branch // (because the base type is then known to satisfy the constraint). - if (newBaseType.flags & TypeFlags.TypeVariable && isGenericType(newConstraint)) { + if ( + newBaseType.flags & TypeFlags.TypeVariable && + isGenericType(newConstraint) + ) { return getSubstitutionType(newBaseType, newConstraint); } - if (newConstraint.flags & TypeFlags.AnyOrUnknown || isTypeAssignableTo(getRestrictiveInstantiation(newBaseType), getRestrictiveInstantiation(newConstraint))) { + if ( + newConstraint.flags & TypeFlags.AnyOrUnknown || + isTypeAssignableTo( + getRestrictiveInstantiation(newBaseType), + getRestrictiveInstantiation(newConstraint) + ) + ) { return newBaseType; } - return newBaseType.flags & TypeFlags.TypeVariable ? getSubstitutionType(newBaseType, newConstraint) : getIntersectionType([newConstraint, newBaseType]); + return newBaseType.flags & TypeFlags.TypeVariable + ? getSubstitutionType(newBaseType, newConstraint) + : getIntersectionType([newConstraint, newBaseType]); } return type; } - function instantiateReverseMappedType(type: ReverseMappedType, mapper: TypeMapper) { + function instantiateReverseMappedType( + type: ReverseMappedType, + mapper: TypeMapper + ) { const innerMappedType = instantiateType(type.mappedType, mapper); if (!(getObjectFlags(innerMappedType) & ObjectFlags.Mapped)) { return type; @@ -21008,7 +36956,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const instantiated = inferTypeForHomomorphicMappedType( instantiateType(type.source, mapper), innerMappedType as MappedType, - innerIndexType as IndexType, + innerIndexType as IndexType ); if (instantiated) { return instantiated; @@ -21017,57 +36965,120 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getPermissiveInstantiation(type: Type) { - return type.flags & (TypeFlags.Primitive | TypeFlags.AnyOrUnknown | TypeFlags.Never) ? type : - type.permissiveInstantiation || (type.permissiveInstantiation = instantiateType(type, permissiveMapper)); + return type.flags & + (TypeFlags.Primitive | TypeFlags.AnyOrUnknown | TypeFlags.Never) + ? type + : type.permissiveInstantiation || + (type.permissiveInstantiation = instantiateType( + type, + permissiveMapper + )); } function getRestrictiveInstantiation(type: Type) { - if (type.flags & (TypeFlags.Primitive | TypeFlags.AnyOrUnknown | TypeFlags.Never)) { + if ( + type.flags & + (TypeFlags.Primitive | TypeFlags.AnyOrUnknown | TypeFlags.Never) + ) { return type; } if (type.restrictiveInstantiation) { return type.restrictiveInstantiation; } - type.restrictiveInstantiation = instantiateType(type, restrictiveMapper); + type.restrictiveInstantiation = instantiateType( + type, + restrictiveMapper + ); // We set the following so we don't attempt to set the restrictive instance of a restrictive instance // which is redundant - we'll produce new type identities, but all type params have already been mapped. // This also gives us a way to detect restrictive instances upon comparisons and _disable_ the "distributeive constraint" // assignability check for them, which is distinctly unsafe, as once you have a restrctive instance, all the type parameters // are constrained to `unknown` and produce tons of false positives/negatives! - type.restrictiveInstantiation.restrictiveInstantiation = type.restrictiveInstantiation; + type.restrictiveInstantiation.restrictiveInstantiation = + type.restrictiveInstantiation; return type.restrictiveInstantiation; } function instantiateIndexInfo(info: IndexInfo, mapper: TypeMapper) { - return createIndexInfo(info.keyType, instantiateType(info.type, mapper), info.isReadonly, info.declaration, info.components); + return createIndexInfo( + info.keyType, + instantiateType(info.type, mapper), + info.isReadonly, + info.declaration, + info.components + ); } // Returns true if the given expression contains (at any level of nesting) a function or arrow expression // that is subject to contextual typing. - function isContextSensitive(node: Expression | MethodDeclaration | ObjectLiteralElementLike | JsxAttributeLike | JsxChild): boolean { - Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); + function isContextSensitive( + node: + | Expression + | MethodDeclaration + | ObjectLiteralElementLike + | JsxAttributeLike + | JsxChild + ): boolean { + Debug.assert( + node.kind !== SyntaxKind.MethodDeclaration || + isObjectLiteralMethod(node) + ); switch (node.kind) { case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: case SyntaxKind.MethodDeclaration: case SyntaxKind.FunctionDeclaration: // Function declarations can have context when annotated with a jsdoc @type - return isContextSensitiveFunctionLikeDeclaration(node as FunctionExpression | ArrowFunction | MethodDeclaration); + return isContextSensitiveFunctionLikeDeclaration( + node as + | FunctionExpression + | ArrowFunction + | MethodDeclaration + ); case SyntaxKind.ObjectLiteralExpression: - return some((node as ObjectLiteralExpression).properties, isContextSensitive); + return some( + (node as ObjectLiteralExpression).properties, + isContextSensitive + ); case SyntaxKind.ArrayLiteralExpression: - return some((node as ArrayLiteralExpression).elements, isContextSensitive); + return some( + (node as ArrayLiteralExpression).elements, + isContextSensitive + ); case SyntaxKind.ConditionalExpression: - return isContextSensitive((node as ConditionalExpression).whenTrue) || - isContextSensitive((node as ConditionalExpression).whenFalse); + return ( + isContextSensitive( + (node as ConditionalExpression).whenTrue + ) || + isContextSensitive( + (node as ConditionalExpression).whenFalse + ) + ); case SyntaxKind.BinaryExpression: - return ((node as BinaryExpression).operatorToken.kind === SyntaxKind.BarBarToken || (node as BinaryExpression).operatorToken.kind === SyntaxKind.QuestionQuestionToken) && - (isContextSensitive((node as BinaryExpression).left) || isContextSensitive((node as BinaryExpression).right)); + return ( + ((node as BinaryExpression).operatorToken.kind === + SyntaxKind.BarBarToken || + (node as BinaryExpression).operatorToken.kind === + SyntaxKind.QuestionQuestionToken) && + (isContextSensitive((node as BinaryExpression).left) || + isContextSensitive((node as BinaryExpression).right)) + ); case SyntaxKind.PropertyAssignment: - return isContextSensitive((node as PropertyAssignment).initializer); + return isContextSensitive( + (node as PropertyAssignment).initializer + ); case SyntaxKind.ParenthesizedExpression: - return isContextSensitive((node as ParenthesizedExpression).expression); + return isContextSensitive( + (node as ParenthesizedExpression).expression + ); case SyntaxKind.JsxAttributes: - return some((node as JsxAttributes).properties, isContextSensitive) || isJsxOpeningElement(node.parent) && some(node.parent.parent.children, isContextSensitive); + return ( + some( + (node as JsxAttributes).properties, + isContextSensitive + ) || + (isJsxOpeningElement(node.parent) && + some(node.parent.parent.children, isContextSensitive)) + ); case SyntaxKind.JsxAttribute: { // If there is no initializer, JSX attribute has a boolean value of true which is not context sensitive. const { initializer } = node as JsxAttribute; @@ -21083,30 +37094,57 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function isContextSensitiveFunctionLikeDeclaration(node: FunctionLikeDeclaration): boolean { - return hasContextSensitiveParameters(node) || hasContextSensitiveReturnExpression(node); + function isContextSensitiveFunctionLikeDeclaration( + node: FunctionLikeDeclaration + ): boolean { + return ( + hasContextSensitiveParameters(node) || + hasContextSensitiveReturnExpression(node) + ); } - function hasContextSensitiveReturnExpression(node: FunctionLikeDeclaration) { - if (node.typeParameters || getEffectiveReturnTypeNode(node) || !node.body) { + function hasContextSensitiveReturnExpression( + node: FunctionLikeDeclaration + ) { + if ( + node.typeParameters || + getEffectiveReturnTypeNode(node) || + !node.body + ) { return false; } if (node.body.kind !== SyntaxKind.Block) { return isContextSensitive(node.body); } - return !!forEachReturnStatement(node.body as Block, statement => !!statement.expression && isContextSensitive(statement.expression)); + return !!forEachReturnStatement( + node.body as Block, + (statement) => + !!statement.expression && + isContextSensitive(statement.expression) + ); } - function isContextSensitiveFunctionOrObjectLiteralMethod(func: Node): func is FunctionExpression | ArrowFunction | MethodDeclaration { - return (isFunctionExpressionOrArrowFunction(func) || isObjectLiteralMethod(func)) && - isContextSensitiveFunctionLikeDeclaration(func); + function isContextSensitiveFunctionOrObjectLiteralMethod( + func: Node + ): func is FunctionExpression | ArrowFunction | MethodDeclaration { + return ( + (isFunctionExpressionOrArrowFunction(func) || + isObjectLiteralMethod(func)) && + isContextSensitiveFunctionLikeDeclaration(func) + ); } function getTypeWithoutSignatures(type: Type): Type { if (type.flags & TypeFlags.Object) { const resolved = resolveStructuredTypeMembers(type as ObjectType); - if (resolved.constructSignatures.length || resolved.callSignatures.length) { - const result = createObjectType(ObjectFlags.Anonymous, type.symbol); + if ( + resolved.constructSignatures.length || + resolved.callSignatures.length + ) { + const result = createObjectType( + ObjectFlags.Anonymous, + type.symbol + ); result.members = resolved.members; result.properties = resolved.properties; result.callSignatures = emptyArray; @@ -21114,9 +37152,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { result.indexInfos = emptyArray; return result; } - } - else if (type.flags & TypeFlags.Intersection) { - return getIntersectionType(map((type as IntersectionType).types, getTypeWithoutSignatures)); + } else if (type.flags & TypeFlags.Intersection) { + return getIntersectionType( + map((type as IntersectionType).types, getTypeWithoutSignatures) + ); } return type; } @@ -21128,15 +37167,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function compareTypesIdentical(source: Type, target: Type): Ternary { - return isTypeRelatedTo(source, target, identityRelation) ? Ternary.True : Ternary.False; + return isTypeRelatedTo(source, target, identityRelation) + ? Ternary.True + : Ternary.False; } function compareTypesAssignable(source: Type, target: Type): Ternary { - return isTypeRelatedTo(source, target, assignableRelation) ? Ternary.True : Ternary.False; + return isTypeRelatedTo(source, target, assignableRelation) + ? Ternary.True + : Ternary.False; } function compareTypesSubtypeOf(source: Type, target: Type): Ternary { - return isTypeRelatedTo(source, target, subtypeRelation) ? Ternary.True : Ternary.False; + return isTypeRelatedTo(source, target, subtypeRelation) + ? Ternary.True + : Ternary.False; } function isTypeSubtypeOf(source: Type, target: Type): boolean { @@ -21162,14 +37207,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Note that this check ignores type parameters and only considers the // inheritance hierarchy. function isTypeDerivedFrom(source: Type, target: Type): boolean { - return source.flags & TypeFlags.Union ? every((source as UnionType).types, t => isTypeDerivedFrom(t, target)) : - target.flags & TypeFlags.Union ? some((target as UnionType).types, t => isTypeDerivedFrom(source, t)) : - source.flags & TypeFlags.Intersection ? some((source as IntersectionType).types, t => isTypeDerivedFrom(t, target)) : - source.flags & TypeFlags.InstantiableNonPrimitive ? isTypeDerivedFrom(getBaseConstraintOfType(source) || unknownType, target) : - isEmptyAnonymousObjectType(target) ? !!(source.flags & (TypeFlags.Object | TypeFlags.NonPrimitive)) : - target === globalObjectType ? !!(source.flags & (TypeFlags.Object | TypeFlags.NonPrimitive)) && !isEmptyAnonymousObjectType(source) : - target === globalFunctionType ? !!(source.flags & TypeFlags.Object) && isFunctionObjectType(source as ObjectType) : - hasBaseType(source, getTargetType(target)) || (isArrayType(target) && !isReadonlyArrayType(target) && isTypeDerivedFrom(source, globalReadonlyArrayType)); + return source.flags & TypeFlags.Union + ? every((source as UnionType).types, (t) => + isTypeDerivedFrom(t, target) + ) + : target.flags & TypeFlags.Union + ? some((target as UnionType).types, (t) => + isTypeDerivedFrom(source, t) + ) + : source.flags & TypeFlags.Intersection + ? some((source as IntersectionType).types, (t) => + isTypeDerivedFrom(t, target) + ) + : source.flags & TypeFlags.InstantiableNonPrimitive + ? isTypeDerivedFrom( + getBaseConstraintOfType(source) || unknownType, + target + ) + : isEmptyAnonymousObjectType(target) + ? !!(source.flags & (TypeFlags.Object | TypeFlags.NonPrimitive)) + : target === globalObjectType + ? !!(source.flags & (TypeFlags.Object | TypeFlags.NonPrimitive)) && + !isEmptyAnonymousObjectType(source) + : target === globalFunctionType + ? !!(source.flags & TypeFlags.Object) && + isFunctionObjectType(source as ObjectType) + : hasBaseType(source, getTargetType(target)) || + (isArrayType(target) && + !isReadonlyArrayType(target) && + isTypeDerivedFrom(source, globalReadonlyArrayType)); } /** @@ -21187,19 +37253,52 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function areTypesComparable(type1: Type, type2: Type): boolean { - return isTypeComparableTo(type1, type2) || isTypeComparableTo(type2, type1); + return ( + isTypeComparableTo(type1, type2) || isTypeComparableTo(type2, type1) + ); } - function checkTypeAssignableTo(source: Type, target: Type, errorNode: Node | undefined, headMessage?: DiagnosticMessage, containingMessageChain?: () => DiagnosticMessageChain | undefined, errorOutputObject?: { errors?: Diagnostic[]; }): boolean { - return checkTypeRelatedTo(source, target, assignableRelation, errorNode, headMessage, containingMessageChain, errorOutputObject); + function checkTypeAssignableTo( + source: Type, + target: Type, + errorNode: Node | undefined, + headMessage?: DiagnosticMessage, + containingMessageChain?: () => DiagnosticMessageChain | undefined, + errorOutputObject?: { errors?: Diagnostic[] } + ): boolean { + return checkTypeRelatedTo( + source, + target, + assignableRelation, + errorNode, + headMessage, + containingMessageChain, + errorOutputObject + ); } /** * Like `checkTypeAssignableTo`, but if it would issue an error, instead performs structural comparisons of the types using the given expression node to * attempt to issue more specific errors on, for example, specific object literal properties or tuple members. */ - function checkTypeAssignableToAndOptionallyElaborate(source: Type, target: Type, errorNode: Node | undefined, expr: Expression | undefined, headMessage?: DiagnosticMessage, containingMessageChain?: () => DiagnosticMessageChain | undefined): boolean { - return checkTypeRelatedToAndOptionallyElaborate(source, target, assignableRelation, errorNode, expr, headMessage, containingMessageChain, /*errorOutputContainer*/ undefined); + function checkTypeAssignableToAndOptionallyElaborate( + source: Type, + target: Type, + errorNode: Node | undefined, + expr: Expression | undefined, + headMessage?: DiagnosticMessage, + containingMessageChain?: () => DiagnosticMessageChain | undefined + ): boolean { + return checkTypeRelatedToAndOptionallyElaborate( + source, + target, + assignableRelation, + errorNode, + expr, + headMessage, + containingMessageChain, + /*errorOutputContainer*/ undefined + ); } function checkTypeRelatedToAndOptionallyElaborate( @@ -21209,18 +37308,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { errorNode: Node | undefined, expr: Expression | undefined, headMessage: DiagnosticMessage | undefined, - containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, - errorOutputContainer: ErrorOutputContainer | undefined, + containingMessageChain: + | (() => DiagnosticMessageChain | undefined) + | undefined, + errorOutputContainer: ErrorOutputContainer | undefined ): boolean { if (isTypeRelatedTo(source, target, relation)) return true; - if (!errorNode || !elaborateError(expr, source, target, relation, headMessage, containingMessageChain, errorOutputContainer)) { - return checkTypeRelatedTo(source, target, relation, errorNode, headMessage, containingMessageChain, errorOutputContainer); + if ( + !errorNode || + !elaborateError( + expr, + source, + target, + relation, + headMessage, + containingMessageChain, + errorOutputContainer + ) + ) { + return checkTypeRelatedTo( + source, + target, + relation, + errorNode, + headMessage, + containingMessageChain, + errorOutputContainer + ); } return false; } function isOrHasGenericConditional(type: Type): boolean { - return !!(type.flags & TypeFlags.Conditional || (type.flags & TypeFlags.Intersection && some((type as IntersectionType).types, isOrHasGenericConditional))); + return !!( + type.flags & TypeFlags.Conditional || + (type.flags & TypeFlags.Intersection && + some( + (type as IntersectionType).types, + isOrHasGenericConditional + )) + ); } function elaborateError( @@ -21229,13 +37356,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { target: Type, relation: Map, headMessage: DiagnosticMessage | undefined, - containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, - errorOutputContainer: ErrorOutputContainer | undefined, + containingMessageChain: + | (() => DiagnosticMessageChain | undefined) + | undefined, + errorOutputContainer: ErrorOutputContainer | undefined ): boolean { if (!node || isOrHasGenericConditional(target)) return false; if ( - !checkTypeRelatedTo(source, target, relation, /*errorNode*/ undefined) - && elaborateDidYouMeanToCallOrConstruct(node, source, target, relation, headMessage, containingMessageChain, errorOutputContainer) + !checkTypeRelatedTo( + source, + target, + relation, + /*errorNode*/ undefined + ) && + elaborateDidYouMeanToCallOrConstruct( + node, + source, + target, + relation, + headMessage, + containingMessageChain, + errorOutputContainer + ) ) { return true; } @@ -21244,25 +37386,74 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!isConstAssertion(node)) { break; } - // fallthrough + // fallthrough case SyntaxKind.JsxExpression: case SyntaxKind.ParenthesizedExpression: - return elaborateError((node as AsExpression | ParenthesizedExpression | JsxExpression).expression, source, target, relation, headMessage, containingMessageChain, errorOutputContainer); + return elaborateError( + ( + node as + | AsExpression + | ParenthesizedExpression + | JsxExpression + ).expression, + source, + target, + relation, + headMessage, + containingMessageChain, + errorOutputContainer + ); case SyntaxKind.BinaryExpression: switch ((node as BinaryExpression).operatorToken.kind) { case SyntaxKind.EqualsToken: case SyntaxKind.CommaToken: - return elaborateError((node as BinaryExpression).right, source, target, relation, headMessage, containingMessageChain, errorOutputContainer); + return elaborateError( + (node as BinaryExpression).right, + source, + target, + relation, + headMessage, + containingMessageChain, + errorOutputContainer + ); } break; case SyntaxKind.ObjectLiteralExpression: - return elaborateObjectLiteral(node as ObjectLiteralExpression, source, target, relation, containingMessageChain, errorOutputContainer); + return elaborateObjectLiteral( + node as ObjectLiteralExpression, + source, + target, + relation, + containingMessageChain, + errorOutputContainer + ); case SyntaxKind.ArrayLiteralExpression: - return elaborateArrayLiteral(node as ArrayLiteralExpression, source, target, relation, containingMessageChain, errorOutputContainer); + return elaborateArrayLiteral( + node as ArrayLiteralExpression, + source, + target, + relation, + containingMessageChain, + errorOutputContainer + ); case SyntaxKind.JsxAttributes: - return elaborateJsxComponents(node as JsxAttributes, source, target, relation, containingMessageChain, errorOutputContainer); + return elaborateJsxComponents( + node as JsxAttributes, + source, + target, + relation, + containingMessageChain, + errorOutputContainer + ); case SyntaxKind.ArrowFunction: - return elaborateArrowFunction(node as ArrowFunction, source, target, relation, containingMessageChain, errorOutputContainer); + return elaborateArrowFunction( + node as ArrowFunction, + source, + target, + relation, + containingMessageChain, + errorOutputContainer + ); } return false; } @@ -21273,27 +37464,54 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { target: Type, relation: Map, headMessage: DiagnosticMessage | undefined, - containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, - errorOutputContainer: ErrorOutputContainer | undefined, + containingMessageChain: + | (() => DiagnosticMessageChain | undefined) + | undefined, + errorOutputContainer: ErrorOutputContainer | undefined ): boolean { const callSignatures = getSignaturesOfType(source, SignatureKind.Call); - const constructSignatures = getSignaturesOfType(source, SignatureKind.Construct); + const constructSignatures = getSignaturesOfType( + source, + SignatureKind.Construct + ); for (const signatures of [constructSignatures, callSignatures]) { if ( - some(signatures, s => { + some(signatures, (s) => { const returnType = getReturnTypeOfSignature(s); - return !(returnType.flags & (TypeFlags.Any | TypeFlags.Never)) && checkTypeRelatedTo(returnType, target, relation, /*errorNode*/ undefined); + return ( + !( + returnType.flags & + (TypeFlags.Any | TypeFlags.Never) + ) && + checkTypeRelatedTo( + returnType, + target, + relation, + /*errorNode*/ undefined + ) + ); }) ) { - const resultObj: { errors?: Diagnostic[]; } = errorOutputContainer || {}; - checkTypeAssignableTo(source, target, node, headMessage, containingMessageChain, resultObj); - const diagnostic = resultObj.errors![resultObj.errors!.length - 1]; + const resultObj: { errors?: Diagnostic[] } = + errorOutputContainer || {}; + checkTypeAssignableTo( + source, + target, + node, + headMessage, + containingMessageChain, + resultObj + ); + const diagnostic = + resultObj.errors![resultObj.errors!.length - 1]; addRelatedInfo( diagnostic, createDiagnosticForNode( node, - signatures === constructSignatures ? Diagnostics.Did_you_mean_to_use_new_with_this_expression : Diagnostics.Did_you_mean_to_call_this_expression, - ), + signatures === constructSignatures + ? Diagnostics.Did_you_mean_to_use_new_with_this_expression + : Diagnostics.Did_you_mean_to_call_this_expression + ) ); return true; } @@ -21306,8 +37524,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { source: Type, target: Type, relation: Map, - containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, - errorOutputContainer: ErrorOutputContainer | undefined, + containingMessageChain: + | (() => DiagnosticMessageChain | undefined) + | undefined, + errorOutputContainer: ErrorOutputContainer | undefined ): boolean { // Don't elaborate blocks if (isBlock(node.body)) { @@ -21321,43 +37541,82 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!sourceSig) { return false; } - const targetSignatures = getSignaturesOfType(target, SignatureKind.Call); + const targetSignatures = getSignaturesOfType( + target, + SignatureKind.Call + ); if (!length(targetSignatures)) { return false; } const returnExpression = node.body; const sourceReturn = getReturnTypeOfSignature(sourceSig); - const targetReturn = getUnionType(map(targetSignatures, getReturnTypeOfSignature)); - if (!checkTypeRelatedTo(sourceReturn, targetReturn, relation, /*errorNode*/ undefined)) { - const elaborated = returnExpression && elaborateError(returnExpression, sourceReturn, targetReturn, relation, /*headMessage*/ undefined, containingMessageChain, errorOutputContainer); + const targetReturn = getUnionType( + map(targetSignatures, getReturnTypeOfSignature) + ); + if ( + !checkTypeRelatedTo( + sourceReturn, + targetReturn, + relation, + /*errorNode*/ undefined + ) + ) { + const elaborated = + returnExpression && + elaborateError( + returnExpression, + sourceReturn, + targetReturn, + relation, + /*headMessage*/ undefined, + containingMessageChain, + errorOutputContainer + ); if (elaborated) { return elaborated; } - const resultObj: { errors?: Diagnostic[]; } = errorOutputContainer || {}; - checkTypeRelatedTo(sourceReturn, targetReturn, relation, returnExpression, /*headMessage*/ undefined, containingMessageChain, resultObj); + const resultObj: { errors?: Diagnostic[] } = + errorOutputContainer || {}; + checkTypeRelatedTo( + sourceReturn, + targetReturn, + relation, + returnExpression, + /*headMessage*/ undefined, + containingMessageChain, + resultObj + ); if (resultObj.errors) { if (target.symbol && length(target.symbol.declarations)) { addRelatedInfo( resultObj.errors[resultObj.errors.length - 1], createDiagnosticForNode( target.symbol.declarations![0], - Diagnostics.The_expected_type_comes_from_the_return_type_of_this_signature, - ), + Diagnostics.The_expected_type_comes_from_the_return_type_of_this_signature + ) ); } if ( - (getFunctionFlags(node) & FunctionFlags.Async) === 0 + (getFunctionFlags(node) & FunctionFlags.Async) === 0 && // exclude cases where source itself is promisy - this way we don't make a suggestion when relating // an IPromise and a Promise that are slightly different - && !getTypeOfPropertyOfType(sourceReturn, "then" as __String) - && checkTypeRelatedTo(createPromiseType(sourceReturn), targetReturn, relation, /*errorNode*/ undefined) + !getTypeOfPropertyOfType( + sourceReturn, + "then" as __String + ) && + checkTypeRelatedTo( + createPromiseType(sourceReturn), + targetReturn, + relation, + /*errorNode*/ undefined + ) ) { addRelatedInfo( resultObj.errors[resultObj.errors.length - 1], createDiagnosticForNode( node, - Diagnostics.Did_you_mean_to_mark_this_function_as_async, - ), + Diagnostics.Did_you_mean_to_mark_this_function_as_async + ) ); } return true; @@ -21366,7 +37625,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function getBestMatchIndexedAccessTypeOrUndefined(source: Type, target: Type, nameType: Type) { + function getBestMatchIndexedAccessTypeOrUndefined( + source: Type, + target: Type, + nameType: Type + ) { const idx = getIndexedAccessTypeOrUndefined(target, nameType); if (idx) { return idx; @@ -21379,14 +37642,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function checkExpressionForMutableLocationWithContextualType(next: Expression, sourcePropType: Type) { + function checkExpressionForMutableLocationWithContextualType( + next: Expression, + sourcePropType: Type + ) { pushContextualType(next, sourcePropType, /*isCache*/ false); - const result = checkExpressionForMutableLocation(next, CheckMode.Contextual); + const result = checkExpressionForMutableLocation( + next, + CheckMode.Contextual + ); popContextualType(); return result; } - type ElaborationIterator = IterableIterator<{ errorNode: Node; innerExpression: Expression | undefined; nameType: Type; errorMessage?: DiagnosticMessage | undefined; }>; + type ElaborationIterator = IterableIterator<{ + errorNode: Node; + innerExpression: Expression | undefined; + nameType: Type; + errorMessage?: DiagnosticMessage | undefined; + }>; /** * For every element returned from the iterator, checks that element to issue an error on a property of that element's type * 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` @@ -21397,67 +37671,195 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { source: Type, target: Type, relation: Map, - containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, - errorOutputContainer: ErrorOutputContainer | undefined, + containingMessageChain: + | (() => DiagnosticMessageChain | undefined) + | undefined, + errorOutputContainer: ErrorOutputContainer | undefined ) { // Assignability failure - check each prop individually, and if that fails, fall back on the bad error span let reportedError = false; for (const value of iterator) { - const { errorNode: prop, innerExpression: next, nameType, errorMessage } = value; - let targetPropType = getBestMatchIndexedAccessTypeOrUndefined(source, target, nameType); - if (!targetPropType || targetPropType.flags & TypeFlags.IndexedAccess) continue; // Don't elaborate on indexes on generic variables - let sourcePropType = getIndexedAccessTypeOrUndefined(source, nameType); + const { + errorNode: prop, + innerExpression: next, + nameType, + errorMessage, + } = value; + let targetPropType = getBestMatchIndexedAccessTypeOrUndefined( + source, + target, + nameType + ); + if ( + !targetPropType || + targetPropType.flags & TypeFlags.IndexedAccess + ) + continue; // Don't elaborate on indexes on generic variables + let sourcePropType = getIndexedAccessTypeOrUndefined( + source, + nameType + ); if (!sourcePropType) continue; - const propName = getPropertyNameFromIndex(nameType, /*accessNode*/ undefined); - if (!checkTypeRelatedTo(sourcePropType, targetPropType, relation, /*errorNode*/ undefined)) { - const elaborated = next && elaborateError(next, sourcePropType, targetPropType, relation, /*headMessage*/ undefined, containingMessageChain, errorOutputContainer); + const propName = getPropertyNameFromIndex( + nameType, + /*accessNode*/ undefined + ); + if ( + !checkTypeRelatedTo( + sourcePropType, + targetPropType, + relation, + /*errorNode*/ undefined + ) + ) { + const elaborated = + next && + elaborateError( + next, + sourcePropType, + targetPropType, + relation, + /*headMessage*/ undefined, + containingMessageChain, + errorOutputContainer + ); reportedError = true; if (!elaborated) { // Issue error on the prop itself, since the prop couldn't elaborate the error - const resultObj: { errors?: Diagnostic[]; } = errorOutputContainer || {}; + const resultObj: { errors?: Diagnostic[] } = + errorOutputContainer || {}; // Use the expression type, if available - const specificSource = next ? checkExpressionForMutableLocationWithContextualType(next, sourcePropType) : sourcePropType; - if (exactOptionalPropertyTypes && isExactOptionalPropertyMismatch(specificSource, targetPropType)) { - 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)); + const specificSource = next + ? checkExpressionForMutableLocationWithContextualType( + next, + sourcePropType + ) + : sourcePropType; + if ( + exactOptionalPropertyTypes && + isExactOptionalPropertyMismatch( + specificSource, + targetPropType + ) + ) { + 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) + ); diagnostics.add(diag); resultObj.errors = [diag]; - } - else { - const targetIsOptional = !!(propName && (getPropertyOfType(target, propName) || unknownSymbol).flags & SymbolFlags.Optional); - const sourceIsOptional = !!(propName && (getPropertyOfType(source, propName) || unknownSymbol).flags & SymbolFlags.Optional); - targetPropType = removeMissingType(targetPropType, targetIsOptional); - sourcePropType = removeMissingType(sourcePropType, targetIsOptional && sourceIsOptional); - const result = checkTypeRelatedTo(specificSource, targetPropType, relation, prop, errorMessage, containingMessageChain, resultObj); + } else { + const targetIsOptional = !!( + propName && + ( + getPropertyOfType(target, propName) || + unknownSymbol + ).flags & SymbolFlags.Optional + ); + const sourceIsOptional = !!( + propName && + ( + getPropertyOfType(source, propName) || + unknownSymbol + ).flags & SymbolFlags.Optional + ); + targetPropType = removeMissingType( + targetPropType, + targetIsOptional + ); + sourcePropType = removeMissingType( + sourcePropType, + targetIsOptional && sourceIsOptional + ); + const result = checkTypeRelatedTo( + specificSource, + targetPropType, + relation, + prop, + errorMessage, + containingMessageChain, + resultObj + ); if (result && specificSource !== sourcePropType) { // If for whatever reason the expression type doesn't yield an error, make sure we still issue an error on the sourcePropType - checkTypeRelatedTo(sourcePropType, targetPropType, relation, prop, errorMessage, containingMessageChain, resultObj); + checkTypeRelatedTo( + sourcePropType, + targetPropType, + relation, + prop, + errorMessage, + containingMessageChain, + resultObj + ); } } if (resultObj.errors) { - const reportedDiag = resultObj.errors[resultObj.errors.length - 1]; - const propertyName = isTypeUsableAsPropertyName(nameType) ? getPropertyNameFromType(nameType) : undefined; - const targetProp = propertyName !== undefined ? getPropertyOfType(target, propertyName) : undefined; + const reportedDiag = + resultObj.errors[resultObj.errors.length - 1]; + const propertyName = isTypeUsableAsPropertyName( + nameType + ) + ? getPropertyNameFromType(nameType) + : undefined; + const targetProp = + propertyName !== undefined + ? getPropertyOfType(target, propertyName) + : undefined; let issuedElaboration = false; if (!targetProp) { - const indexInfo = getApplicableIndexInfo(target, nameType); - if (indexInfo && indexInfo.declaration && !getSourceFileOfNode(indexInfo.declaration).hasNoDefaultLib) { + const indexInfo = getApplicableIndexInfo( + target, + nameType + ); + if ( + indexInfo && + indexInfo.declaration && + !getSourceFileOfNode(indexInfo.declaration) + .hasNoDefaultLib + ) { issuedElaboration = true; - addRelatedInfo(reportedDiag, createDiagnosticForNode(indexInfo.declaration, Diagnostics.The_expected_type_comes_from_this_index_signature)); + addRelatedInfo( + reportedDiag, + createDiagnosticForNode( + indexInfo.declaration, + Diagnostics.The_expected_type_comes_from_this_index_signature + ) + ); } } - if (!issuedElaboration && (targetProp && length(targetProp.declarations) || target.symbol && length(target.symbol.declarations))) { - const targetNode = targetProp && length(targetProp.declarations) ? targetProp.declarations![0] : target.symbol.declarations![0]; - if (!getSourceFileOfNode(targetNode).hasNoDefaultLib) { + if ( + !issuedElaboration && + ((targetProp && length(targetProp.declarations)) || + (target.symbol && + length(target.symbol.declarations))) + ) { + const targetNode = + targetProp && length(targetProp.declarations) + ? targetProp.declarations![0] + : target.symbol.declarations![0]; + if ( + !getSourceFileOfNode(targetNode).hasNoDefaultLib + ) { addRelatedInfo( reportedDiag, createDiagnosticForNode( targetNode, Diagnostics.The_expected_type_comes_from_property_0_which_is_declared_here_on_type_1, - propertyName && !(nameType.flags & TypeFlags.UniqueESSymbol) ? unescapeLeadingUnderscores(propertyName) : typeToString(nameType), - typeToString(target), - ), + propertyName && + !( + nameType.flags & + TypeFlags.UniqueESSymbol + ) + ? unescapeLeadingUnderscores( + propertyName + ) + : typeToString(nameType), + typeToString(target) + ) ); } } @@ -21477,50 +37879,161 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { source: Type, target: Type, relation: Map, - containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, - errorOutputContainer: ErrorOutputContainer | undefined, + containingMessageChain: + | (() => DiagnosticMessageChain | undefined) + | undefined, + errorOutputContainer: ErrorOutputContainer | undefined ) { - const tupleOrArrayLikeTargetParts = filterType(target, isArrayOrTupleLikeType); - const nonTupleOrArrayLikeTargetParts = filterType(target, t => !isArrayOrTupleLikeType(t)); + const tupleOrArrayLikeTargetParts = filterType( + target, + isArrayOrTupleLikeType + ); + const nonTupleOrArrayLikeTargetParts = filterType( + target, + (t) => !isArrayOrTupleLikeType(t) + ); // If `nonTupleOrArrayLikeTargetParts` is not `never`, then that should mean `Iterable` is defined. - const iterationType = nonTupleOrArrayLikeTargetParts !== neverType - ? getIterationTypeOfIterable(IterationUse.ForOf, IterationTypeKind.Yield, nonTupleOrArrayLikeTargetParts, /*errorNode*/ undefined) - : undefined; + const iterationType = + nonTupleOrArrayLikeTargetParts !== neverType + ? getIterationTypeOfIterable( + IterationUse.ForOf, + IterationTypeKind.Yield, + nonTupleOrArrayLikeTargetParts, + /*errorNode*/ undefined + ) + : undefined; let reportedError = false; - for (let status = iterator.next(); !status.done; status = iterator.next()) { - const { errorNode: prop, innerExpression: next, nameType, errorMessage } = status.value; + for ( + let status = iterator.next(); + !status.done; + status = iterator.next() + ) { + const { + errorNode: prop, + innerExpression: next, + nameType, + errorMessage, + } = status.value; let targetPropType = iterationType; - const targetIndexedPropType = tupleOrArrayLikeTargetParts !== neverType ? getBestMatchIndexedAccessTypeOrUndefined(source, tupleOrArrayLikeTargetParts, nameType) : undefined; - if (targetIndexedPropType && !(targetIndexedPropType.flags & TypeFlags.IndexedAccess)) { // Don't elaborate on indexes on generic variables - targetPropType = iterationType ? getUnionType([iterationType, targetIndexedPropType]) : targetIndexedPropType; + const targetIndexedPropType = + tupleOrArrayLikeTargetParts !== neverType + ? getBestMatchIndexedAccessTypeOrUndefined( + source, + tupleOrArrayLikeTargetParts, + nameType + ) + : undefined; + if ( + targetIndexedPropType && + !(targetIndexedPropType.flags & TypeFlags.IndexedAccess) + ) { + // Don't elaborate on indexes on generic variables + targetPropType = iterationType + ? getUnionType([iterationType, targetIndexedPropType]) + : targetIndexedPropType; } if (!targetPropType) continue; - let sourcePropType = getIndexedAccessTypeOrUndefined(source, nameType); + let sourcePropType = getIndexedAccessTypeOrUndefined( + source, + nameType + ); if (!sourcePropType) continue; - const propName = getPropertyNameFromIndex(nameType, /*accessNode*/ undefined); - if (!checkTypeRelatedTo(sourcePropType, targetPropType, relation, /*errorNode*/ undefined)) { - const elaborated = next && elaborateError(next, sourcePropType, targetPropType, relation, /*headMessage*/ undefined, containingMessageChain, errorOutputContainer); + const propName = getPropertyNameFromIndex( + nameType, + /*accessNode*/ undefined + ); + if ( + !checkTypeRelatedTo( + sourcePropType, + targetPropType, + relation, + /*errorNode*/ undefined + ) + ) { + const elaborated = + next && + elaborateError( + next, + sourcePropType, + targetPropType, + relation, + /*headMessage*/ undefined, + containingMessageChain, + errorOutputContainer + ); reportedError = true; if (!elaborated) { // Issue error on the prop itself, since the prop couldn't elaborate the error - const resultObj: { errors?: Diagnostic[]; } = errorOutputContainer || {}; + const resultObj: { errors?: Diagnostic[] } = + errorOutputContainer || {}; // Use the expression type, if available - const specificSource = next ? checkExpressionForMutableLocationWithContextualType(next, sourcePropType) : sourcePropType; - if (exactOptionalPropertyTypes && isExactOptionalPropertyMismatch(specificSource, targetPropType)) { - 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)); + const specificSource = next + ? checkExpressionForMutableLocationWithContextualType( + next, + sourcePropType + ) + : sourcePropType; + if ( + exactOptionalPropertyTypes && + isExactOptionalPropertyMismatch( + specificSource, + targetPropType + ) + ) { + 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) + ); diagnostics.add(diag); resultObj.errors = [diag]; - } - else { - const targetIsOptional = !!(propName && (getPropertyOfType(tupleOrArrayLikeTargetParts, propName) || unknownSymbol).flags & SymbolFlags.Optional); - const sourceIsOptional = !!(propName && (getPropertyOfType(source, propName) || unknownSymbol).flags & SymbolFlags.Optional); - targetPropType = removeMissingType(targetPropType, targetIsOptional); - sourcePropType = removeMissingType(sourcePropType, targetIsOptional && sourceIsOptional); - const result = checkTypeRelatedTo(specificSource, targetPropType, relation, prop, errorMessage, containingMessageChain, resultObj); + } else { + const targetIsOptional = !!( + propName && + ( + getPropertyOfType( + tupleOrArrayLikeTargetParts, + propName + ) || unknownSymbol + ).flags & SymbolFlags.Optional + ); + const sourceIsOptional = !!( + propName && + ( + getPropertyOfType(source, propName) || + unknownSymbol + ).flags & SymbolFlags.Optional + ); + targetPropType = removeMissingType( + targetPropType, + targetIsOptional + ); + sourcePropType = removeMissingType( + sourcePropType, + targetIsOptional && sourceIsOptional + ); + const result = checkTypeRelatedTo( + specificSource, + targetPropType, + relation, + prop, + errorMessage, + containingMessageChain, + resultObj + ); if (result && specificSource !== sourcePropType) { // If for whatever reason the expression type doesn't yield an error, make sure we still issue an error on the sourcePropType - checkTypeRelatedTo(sourcePropType, targetPropType, relation, prop, errorMessage, containingMessageChain, resultObj); + checkTypeRelatedTo( + sourcePropType, + targetPropType, + relation, + prop, + errorMessage, + containingMessageChain, + resultObj + ); } } } @@ -21532,38 +38045,67 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function* generateJsxAttributes(node: JsxAttributes): ElaborationIterator { if (!length(node.properties)) return; for (const prop of node.properties) { - if (isJsxSpreadAttribute(prop) || isHyphenatedJsxName(getTextOfJsxAttributeName(prop.name))) continue; - yield { errorNode: prop.name, innerExpression: prop.initializer, nameType: getStringLiteralType(getTextOfJsxAttributeName(prop.name)) }; + if ( + isJsxSpreadAttribute(prop) || + isHyphenatedJsxName(getTextOfJsxAttributeName(prop.name)) + ) + continue; + yield { + errorNode: prop.name, + innerExpression: prop.initializer, + nameType: getStringLiteralType( + getTextOfJsxAttributeName(prop.name) + ), + }; } } - function* generateJsxChildren(node: JsxElement, getInvalidTextDiagnostic: () => DiagnosticMessage): ElaborationIterator { + function* generateJsxChildren( + node: JsxElement, + getInvalidTextDiagnostic: () => DiagnosticMessage + ): ElaborationIterator { if (!length(node.children)) return; let memberOffset = 0; for (let i = 0; i < node.children.length; i++) { const child = node.children[i]; const nameType = getNumberLiteralType(i - memberOffset); - const elem = getElaborationElementForJsxChild(child, nameType, getInvalidTextDiagnostic); + const elem = getElaborationElementForJsxChild( + child, + nameType, + getInvalidTextDiagnostic + ); if (elem) { yield elem; - } - else { + } else { memberOffset++; } } } - function getElaborationElementForJsxChild(child: JsxChild, nameType: LiteralType, getInvalidTextDiagnostic: () => DiagnosticMessage) { + function getElaborationElementForJsxChild( + child: JsxChild, + nameType: LiteralType, + getInvalidTextDiagnostic: () => DiagnosticMessage + ) { switch (child.kind) { case SyntaxKind.JsxExpression: // child is of the type of the expression - return { errorNode: child, innerExpression: child.expression, nameType }; + return { + errorNode: child, + innerExpression: child.expression, + nameType, + }; case SyntaxKind.JsxText: if (child.containsOnlyTriviaWhiteSpaces) { break; // Whitespace only jsx text isn't real jsx text } // child is a string - return { errorNode: child, innerExpression: undefined, nameType, errorMessage: getInvalidTextDiagnostic() }; + return { + errorNode: child, + innerExpression: undefined, + nameType, + errorMessage: getInvalidTextDiagnostic(), + }; case SyntaxKind.JsxElement: case SyntaxKind.JsxSelfClosingElement: case SyntaxKind.JsxFragment: @@ -21579,18 +38121,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { source: Type, target: Type, relation: Map, - containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, - errorOutputContainer: ErrorOutputContainer | undefined, + containingMessageChain: + | (() => DiagnosticMessageChain | undefined) + | undefined, + errorOutputContainer: ErrorOutputContainer | undefined ) { - let result = elaborateElementwise(generateJsxAttributes(node), source, target, relation, containingMessageChain, errorOutputContainer); + let result = elaborateElementwise( + generateJsxAttributes(node), + source, + target, + relation, + containingMessageChain, + errorOutputContainer + ); let invalidTextDiagnostic: DiagnosticMessage | undefined; - if (isJsxOpeningElement(node.parent) && isJsxElement(node.parent.parent)) { + if ( + isJsxOpeningElement(node.parent) && + isJsxElement(node.parent.parent) + ) { const containingElement = node.parent.parent; - const childPropName = getJsxElementChildrenPropertyName(getJsxNamespaceAt(node)); - const childrenPropName = childPropName === undefined ? "children" : unescapeLeadingUnderscores(childPropName); + const childPropName = getJsxElementChildrenPropertyName( + getJsxNamespaceAt(node) + ); + const childrenPropName = + childPropName === undefined + ? "children" + : unescapeLeadingUnderscores(childPropName); const childrenNameType = getStringLiteralType(childrenPropName); - const childrenTargetType = getIndexedAccessType(target, childrenNameType); - const validChildren = getSemanticJsxChildren(containingElement.children); + const childrenTargetType = getIndexedAccessType( + target, + childrenNameType + ); + const validChildren = getSemanticJsxChildren( + containingElement.children + ); if (!length(validChildren)) { return result; } @@ -21600,61 +38164,110 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const iterableType = getGlobalIterableType(/*reportErrors*/ false); if (iterableType !== emptyGenericType) { const anyIterable = createIterableType(anyType); - arrayLikeTargetParts = filterType(childrenTargetType, t => isTypeAssignableTo(t, anyIterable)); - nonArrayLikeTargetParts = filterType(childrenTargetType, t => !isTypeAssignableTo(t, anyIterable)); - } - else { - arrayLikeTargetParts = filterType(childrenTargetType, isArrayOrTupleLikeType); - nonArrayLikeTargetParts = filterType(childrenTargetType, t => !isArrayOrTupleLikeType(t)); + arrayLikeTargetParts = filterType(childrenTargetType, (t) => + isTypeAssignableTo(t, anyIterable) + ); + nonArrayLikeTargetParts = filterType( + childrenTargetType, + (t) => !isTypeAssignableTo(t, anyIterable) + ); + } else { + arrayLikeTargetParts = filterType( + childrenTargetType, + isArrayOrTupleLikeType + ); + nonArrayLikeTargetParts = filterType( + childrenTargetType, + (t) => !isArrayOrTupleLikeType(t) + ); } if (moreThanOneRealChildren) { if (arrayLikeTargetParts !== neverType) { - const realSource = createTupleType(checkJsxChildren(containingElement, CheckMode.Normal)); - const children = generateJsxChildren(containingElement, getInvalidTextualChildDiagnostic); - result = elaborateIterableOrArrayLikeTargetElementwise(children, realSource, arrayLikeTargetParts, relation, containingMessageChain, errorOutputContainer) || result; - } - else if (!isTypeRelatedTo(getIndexedAccessType(source, childrenNameType), childrenTargetType, relation)) { + const realSource = createTupleType( + checkJsxChildren(containingElement, CheckMode.Normal) + ); + const children = generateJsxChildren( + containingElement, + getInvalidTextualChildDiagnostic + ); + result = + elaborateIterableOrArrayLikeTargetElementwise( + children, + realSource, + arrayLikeTargetParts, + relation, + containingMessageChain, + errorOutputContainer + ) || result; + } else if ( + !isTypeRelatedTo( + getIndexedAccessType(source, childrenNameType), + childrenTargetType, + relation + ) + ) { // arity mismatch result = true; const diag = error( containingElement.openingElement.tagName, Diagnostics.This_JSX_tag_s_0_prop_expects_a_single_child_of_type_1_but_multiple_children_were_provided, childrenPropName, - typeToString(childrenTargetType), + typeToString(childrenTargetType) ); - if (errorOutputContainer && errorOutputContainer.skipLogging) { - (errorOutputContainer.errors || (errorOutputContainer.errors = [])).push(diag); + if ( + errorOutputContainer && + errorOutputContainer.skipLogging + ) { + ( + errorOutputContainer.errors || + (errorOutputContainer.errors = []) + ).push(diag); } } - } - else { + } else { if (nonArrayLikeTargetParts !== neverType) { const child = validChildren[0]; - const elem = getElaborationElementForJsxChild(child, childrenNameType, getInvalidTextualChildDiagnostic); + const elem = getElaborationElementForJsxChild( + child, + childrenNameType, + getInvalidTextualChildDiagnostic + ); if (elem) { - result = elaborateElementwise( - (function* () { - yield elem; - })(), - source, - target, - relation, - containingMessageChain, - errorOutputContainer, - ) || result; - } - } - else if (!isTypeRelatedTo(getIndexedAccessType(source, childrenNameType), childrenTargetType, relation)) { + result = + elaborateElementwise( + (function* () { + yield elem; + })(), + source, + target, + relation, + containingMessageChain, + errorOutputContainer + ) || result; + } + } else if ( + !isTypeRelatedTo( + getIndexedAccessType(source, childrenNameType), + childrenTargetType, + relation + ) + ) { // arity mismatch result = true; const diag = error( containingElement.openingElement.tagName, Diagnostics.This_JSX_tag_s_0_prop_expects_type_1_which_requires_multiple_children_but_only_a_single_child_was_provided, childrenPropName, - typeToString(childrenTargetType), + typeToString(childrenTargetType) ); - if (errorOutputContainer && errorOutputContainer.skipLogging) { - (errorOutputContainer.errors || (errorOutputContainer.errors = [])).push(diag); + if ( + errorOutputContainer && + errorOutputContainer.skipLogging + ) { + ( + errorOutputContainer.errors || + (errorOutputContainer.errors = []) + ).push(diag); } } } @@ -21664,27 +38277,56 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getInvalidTextualChildDiagnostic() { if (!invalidTextDiagnostic) { const tagNameText = getTextOfNode(node.parent.tagName); - const childPropName = getJsxElementChildrenPropertyName(getJsxNamespaceAt(node)); - const childrenPropName = childPropName === undefined ? "children" : unescapeLeadingUnderscores(childPropName); - const childrenTargetType = getIndexedAccessType(target, getStringLiteralType(childrenPropName)); - 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; - invalidTextDiagnostic = { ...diagnostic, key: "!!ALREADY FORMATTED!!", message: formatMessage(diagnostic, tagNameText, childrenPropName, typeToString(childrenTargetType)) }; + const childPropName = getJsxElementChildrenPropertyName( + getJsxNamespaceAt(node) + ); + const childrenPropName = + childPropName === undefined + ? "children" + : unescapeLeadingUnderscores(childPropName); + const childrenTargetType = getIndexedAccessType( + target, + getStringLiteralType(childrenPropName) + ); + 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; + invalidTextDiagnostic = { + ...diagnostic, + key: "!!ALREADY FORMATTED!!", + message: formatMessage( + diagnostic, + tagNameText, + childrenPropName, + typeToString(childrenTargetType) + ), + }; } return invalidTextDiagnostic; } } - function* generateLimitedTupleElements(node: ArrayLiteralExpression, target: Type): ElaborationIterator { + function* generateLimitedTupleElements( + node: ArrayLiteralExpression, + target: Type + ): ElaborationIterator { const len = length(node.elements); if (!len) return; for (let i = 0; i < len; i++) { // 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 - if (isTupleLikeType(target) && !getPropertyOfType(target, ("" + i) as __String)) continue; + if ( + isTupleLikeType(target) && + !getPropertyOfType(target, ("" + i) as __String) + ) + continue; const elem = node.elements[i]; if (isOmittedExpression(elem)) continue; const nameType = getNumberLiteralType(i); const checkNode = getEffectiveCheckNode(elem); - yield { errorNode: checkNode, innerExpression: checkNode, nameType }; + yield { + errorNode: checkNode, + innerExpression: checkNode, + nameType, + }; } } @@ -21693,30 +38335,56 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { source: Type, target: Type, relation: Map, - containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, - errorOutputContainer: ErrorOutputContainer | undefined, + containingMessageChain: + | (() => DiagnosticMessageChain | undefined) + | undefined, + errorOutputContainer: ErrorOutputContainer | undefined ) { - if (target.flags & (TypeFlags.Primitive | TypeFlags.Never)) return false; + if (target.flags & (TypeFlags.Primitive | TypeFlags.Never)) + return false; if (isTupleLikeType(source)) { - return elaborateElementwise(generateLimitedTupleElements(node, target), source, target, relation, containingMessageChain, errorOutputContainer); + return elaborateElementwise( + generateLimitedTupleElements(node, target), + source, + target, + relation, + containingMessageChain, + errorOutputContainer + ); } // recreate a tuple from the elements, if possible // Since we're re-doing the expression type, we need to reapply the contextual type pushContextualType(node, target, /*isCache*/ false); - const tupleizedType = checkArrayLiteral(node, CheckMode.Contextual, /*forceTuple*/ true); + const tupleizedType = checkArrayLiteral( + node, + CheckMode.Contextual, + /*forceTuple*/ true + ); popContextualType(); if (isTupleLikeType(tupleizedType)) { - return elaborateElementwise(generateLimitedTupleElements(node, target), tupleizedType, target, relation, containingMessageChain, errorOutputContainer); + return elaborateElementwise( + generateLimitedTupleElements(node, target), + tupleizedType, + target, + relation, + containingMessageChain, + errorOutputContainer + ); } return false; } - function* generateObjectLiteralElements(node: ObjectLiteralExpression): ElaborationIterator { + function* generateObjectLiteralElements( + node: ObjectLiteralExpression + ): ElaborationIterator { if (!length(node.properties)) return; for (const prop of node.properties) { if (isSpreadAssignment(prop)) continue; - const type = getLiteralTypeFromProperty(getSymbolOfDeclaration(prop), TypeFlags.StringOrNumberLiteralOrUnique); - if (!type || (type.flags & TypeFlags.Never)) { + const type = getLiteralTypeFromProperty( + getSymbolOfDeclaration(prop), + TypeFlags.StringOrNumberLiteralOrUnique + ); + if (!type || type.flags & TypeFlags.Never) { continue; } switch (prop.kind) { @@ -21724,10 +38392,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.GetAccessor: case SyntaxKind.MethodDeclaration: case SyntaxKind.ShorthandPropertyAssignment: - yield { errorNode: prop.name, innerExpression: undefined, nameType: type }; + yield { + errorNode: prop.name, + innerExpression: undefined, + nameType: type, + }; break; case SyntaxKind.PropertyAssignment: - 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 }; + 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, + }; break; default: Debug.assertNever(prop); @@ -21740,35 +38419,89 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { source: Type, target: Type, relation: Map, - containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, - errorOutputContainer: ErrorOutputContainer | undefined, + containingMessageChain: + | (() => DiagnosticMessageChain | undefined) + | undefined, + errorOutputContainer: ErrorOutputContainer | undefined ) { - if (target.flags & (TypeFlags.Primitive | TypeFlags.Never)) return false; - return elaborateElementwise(generateObjectLiteralElements(node), source, target, relation, containingMessageChain, errorOutputContainer); + if (target.flags & (TypeFlags.Primitive | TypeFlags.Never)) + return false; + return elaborateElementwise( + generateObjectLiteralElements(node), + source, + target, + relation, + containingMessageChain, + errorOutputContainer + ); } /** * This is *not* a bi-directional relationship. * If one needs to check both directions for comparability, use a second call to this function or 'isTypeComparableTo'. */ - function checkTypeComparableTo(source: Type, target: Type, errorNode: Node, headMessage?: DiagnosticMessage, containingMessageChain?: () => DiagnosticMessageChain | undefined): boolean { - return checkTypeRelatedTo(source, target, comparableRelation, errorNode, headMessage, containingMessageChain); + function checkTypeComparableTo( + source: Type, + target: Type, + errorNode: Node, + headMessage?: DiagnosticMessage, + containingMessageChain?: () => DiagnosticMessageChain | undefined + ): boolean { + return checkTypeRelatedTo( + source, + target, + comparableRelation, + errorNode, + headMessage, + containingMessageChain + ); } - function isSignatureAssignableTo(source: Signature, target: Signature, ignoreReturnTypes: boolean): boolean { - return compareSignaturesRelated(source, target, ignoreReturnTypes ? SignatureCheckMode.IgnoreReturnTypes : SignatureCheckMode.None, /*reportErrors*/ false, /*errorReporter*/ undefined, /*incompatibleErrorReporter*/ undefined, compareTypesAssignable, /*reportUnreliableMarkers*/ undefined) !== Ternary.False; + function isSignatureAssignableTo( + source: Signature, + target: Signature, + ignoreReturnTypes: boolean + ): boolean { + return ( + compareSignaturesRelated( + source, + target, + ignoreReturnTypes + ? SignatureCheckMode.IgnoreReturnTypes + : SignatureCheckMode.None, + /*reportErrors*/ false, + /*errorReporter*/ undefined, + /*incompatibleErrorReporter*/ undefined, + compareTypesAssignable, + /*reportUnreliableMarkers*/ undefined + ) !== Ternary.False + ); } - type ErrorReporter = (message: DiagnosticMessage, ...args: DiagnosticArguments) => void; + type ErrorReporter = ( + message: DiagnosticMessage, + ...args: DiagnosticArguments + ) => void; /** * Returns true if `s` is `(...args: A) => R` where `A` is `any`, `any[]`, `never`, or `never[]`, and `R` is `any` or `unknown`. */ function isTopSignature(s: Signature) { - if (!s.typeParameters && (!s.thisParameter || isTypeAny(getTypeOfParameter(s.thisParameter))) && s.parameters.length === 1 && signatureHasRestParameter(s)) { + if ( + !s.typeParameters && + (!s.thisParameter || + isTypeAny(getTypeOfParameter(s.thisParameter))) && + s.parameters.length === 1 && + signatureHasRestParameter(s) + ) { const paramType = getTypeOfParameter(s.parameters[0]); - const restType = isArrayType(paramType) ? getTypeArguments(paramType)[0] : paramType; - return !!(restType.flags & (TypeFlags.Any | TypeFlags.Never) && getReturnTypeOfSignature(s).flags & TypeFlags.AnyOrUnknown); + const restType = isArrayType(paramType) + ? getTypeArguments(paramType)[0] + : paramType; + return !!( + restType.flags & (TypeFlags.Any | TypeFlags.Never) && + getReturnTypeOfSignature(s).flags & TypeFlags.AnyOrUnknown + ); } return false; } @@ -21776,46 +38509,92 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** * See signatureRelatedTo, compareSignaturesIdentical */ - function compareSignaturesRelated(source: Signature, target: Signature, checkMode: SignatureCheckMode, reportErrors: boolean, errorReporter: ErrorReporter | undefined, incompatibleErrorReporter: ((source: Type, target: Type) => void) | undefined, compareTypes: TypeComparer, reportUnreliableMarkers: TypeMapper | undefined): Ternary { + function compareSignaturesRelated( + source: Signature, + target: Signature, + checkMode: SignatureCheckMode, + reportErrors: boolean, + errorReporter: ErrorReporter | undefined, + incompatibleErrorReporter: + | ((source: Type, target: Type) => void) + | undefined, + compareTypes: TypeComparer, + reportUnreliableMarkers: TypeMapper | undefined + ): Ternary { // TODO (drosen): De-duplicate code between related functions. if (source === target) { return Ternary.True; } - if (!(checkMode & SignatureCheckMode.StrictTopSignature && isTopSignature(source)) && isTopSignature(target)) { + if ( + !( + checkMode & SignatureCheckMode.StrictTopSignature && + isTopSignature(source) + ) && + isTopSignature(target) + ) { return Ternary.True; } - if (checkMode & SignatureCheckMode.StrictTopSignature && isTopSignature(source) && !isTopSignature(target)) { + if ( + checkMode & SignatureCheckMode.StrictTopSignature && + isTopSignature(source) && + !isTopSignature(target) + ) { return Ternary.False; } const targetCount = getParameterCount(target); - const sourceHasMoreParameters = !hasEffectiveRestParameter(target) && - (checkMode & SignatureCheckMode.StrictArity ? hasEffectiveRestParameter(source) || getParameterCount(source) > targetCount : getMinArgumentCount(source) > targetCount); + const sourceHasMoreParameters = + !hasEffectiveRestParameter(target) && + (checkMode & SignatureCheckMode.StrictArity + ? hasEffectiveRestParameter(source) || + getParameterCount(source) > targetCount + : getMinArgumentCount(source) > targetCount); if (sourceHasMoreParameters) { if (reportErrors && !(checkMode & SignatureCheckMode.StrictArity)) { // the second condition should be redundant, because there is no error reporting when comparing signatures by strict arity // since it is only done for subtype reduction - errorReporter!(Diagnostics.Target_signature_provides_too_few_arguments_Expected_0_or_more_but_got_1, getMinArgumentCount(source), targetCount); + errorReporter!( + Diagnostics.Target_signature_provides_too_few_arguments_Expected_0_or_more_but_got_1, + getMinArgumentCount(source), + targetCount + ); } return Ternary.False; } - if (source.typeParameters && source.typeParameters !== target.typeParameters) { + if ( + source.typeParameters && + source.typeParameters !== target.typeParameters + ) { target = getCanonicalSignature(target); - source = instantiateSignatureInContextOf(source, target, /*inferenceContext*/ undefined, compareTypes); + source = instantiateSignatureInContextOf( + source, + target, + /*inferenceContext*/ undefined, + compareTypes + ); } const sourceCount = getParameterCount(source); const sourceRestType = getNonArrayRestType(source); const targetRestType = getNonArrayRestType(target); if (sourceRestType || targetRestType) { - void instantiateType(sourceRestType || targetRestType, reportUnreliableMarkers); + void instantiateType( + sourceRestType || targetRestType, + reportUnreliableMarkers + ); } - const kind = target.declaration ? target.declaration.kind : SyntaxKind.Unknown; - const strictVariance = !(checkMode & SignatureCheckMode.Callback) && strictFunctionTypes && kind !== SyntaxKind.MethodDeclaration && - kind !== SyntaxKind.MethodSignature && kind !== SyntaxKind.Constructor; + const kind = target.declaration + ? target.declaration.kind + : SyntaxKind.Unknown; + const strictVariance = + !(checkMode & SignatureCheckMode.Callback) && + strictFunctionTypes && + kind !== SyntaxKind.MethodDeclaration && + kind !== SyntaxKind.MethodSignature && + kind !== SyntaxKind.Constructor; let result = Ternary.True; const sourceThisType = getThisTypeOfSignature(source); @@ -21823,11 +38602,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const targetThisType = getThisTypeOfSignature(target); if (targetThisType) { // void sources are assignable to anything. - const related = !strictVariance && compareTypes(sourceThisType, targetThisType, /*reportErrors*/ false) - || compareTypes(targetThisType, sourceThisType, reportErrors); + const related = + (!strictVariance && + compareTypes( + sourceThisType, + targetThisType, + /*reportErrors*/ false + )) || + compareTypes(targetThisType, sourceThisType, reportErrors); if (!related) { if (reportErrors) { - errorReporter!(Diagnostics.The_this_types_of_each_signature_are_incompatible); + errorReporter!( + Diagnostics.The_this_types_of_each_signature_are_incompatible + ); } return Ternary.False; } @@ -21835,13 +38622,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - const paramCount = sourceRestType || targetRestType ? Math.min(sourceCount, targetCount) : Math.max(sourceCount, targetCount); - const restIndex = sourceRestType || targetRestType ? paramCount - 1 : -1; + const paramCount = + sourceRestType || targetRestType + ? Math.min(sourceCount, targetCount) + : Math.max(sourceCount, targetCount); + const restIndex = + sourceRestType || targetRestType ? paramCount - 1 : -1; for (let i = 0; i < paramCount; i++) { - const sourceType = i === restIndex ? getRestOrAnyTypeAtPosition(source, i) : tryGetTypeAtPosition(source, i); - const targetType = i === restIndex ? getRestOrAnyTypeAtPosition(target, i) : tryGetTypeAtPosition(target, i); - if (sourceType && targetType && (sourceType !== targetType || checkMode & SignatureCheckMode.StrictArity)) { + const sourceType = + i === restIndex + ? getRestOrAnyTypeAtPosition(source, i) + : tryGetTypeAtPosition(source, i); + const targetType = + i === restIndex + ? getRestOrAnyTypeAtPosition(target, i) + : tryGetTypeAtPosition(target, i); + if ( + sourceType && + targetType && + (sourceType !== targetType || + checkMode & SignatureCheckMode.StrictArity) + ) { // In order to ensure that any generic type Foo is at least co-variant with respect to T no matter // how Foo uses T, we need to relate parameters bi-variantly (given that parameters are input positions, // they naturally relate only contra-variantly). However, if the source and target parameters both have @@ -21850,20 +38652,70 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // similar to return values, callback parameters are output positions. This means that a Promise, // where T is used only in callback parameter positions, will be co-variant (as opposed to bi-variant) // with respect to T. - const sourceSig = checkMode & SignatureCheckMode.Callback || isInstantiatedGenericParameter(source, i) ? undefined : getSingleCallSignature(getNonNullableType(sourceType)); - const targetSig = checkMode & SignatureCheckMode.Callback || isInstantiatedGenericParameter(target, i) ? undefined : getSingleCallSignature(getNonNullableType(targetType)); - const callbacks = sourceSig && targetSig && !getTypePredicateOfSignature(sourceSig) && !getTypePredicateOfSignature(targetSig) && - getTypeFacts(sourceType, TypeFacts.IsUndefinedOrNull) === getTypeFacts(targetType, TypeFacts.IsUndefinedOrNull); - let related = callbacks ? - compareSignaturesRelated(targetSig, sourceSig, (checkMode & SignatureCheckMode.StrictArity) | (strictVariance ? SignatureCheckMode.StrictCallback : SignatureCheckMode.BivariantCallback), reportErrors, errorReporter, incompatibleErrorReporter, compareTypes, reportUnreliableMarkers) : - !(checkMode & SignatureCheckMode.Callback) && !strictVariance && compareTypes(sourceType, targetType, /*reportErrors*/ false) || compareTypes(targetType, sourceType, reportErrors); + const sourceSig = + checkMode & SignatureCheckMode.Callback || + isInstantiatedGenericParameter(source, i) + ? undefined + : getSingleCallSignature( + getNonNullableType(sourceType) + ); + const targetSig = + checkMode & SignatureCheckMode.Callback || + isInstantiatedGenericParameter(target, i) + ? undefined + : getSingleCallSignature( + getNonNullableType(targetType) + ); + const callbacks = + sourceSig && + targetSig && + !getTypePredicateOfSignature(sourceSig) && + !getTypePredicateOfSignature(targetSig) && + getTypeFacts(sourceType, TypeFacts.IsUndefinedOrNull) === + getTypeFacts(targetType, TypeFacts.IsUndefinedOrNull); + let related = callbacks + ? compareSignaturesRelated( + targetSig, + sourceSig, + (checkMode & SignatureCheckMode.StrictArity) | + (strictVariance + ? SignatureCheckMode.StrictCallback + : SignatureCheckMode.BivariantCallback), + reportErrors, + errorReporter, + incompatibleErrorReporter, + compareTypes, + reportUnreliableMarkers + ) + : (!(checkMode & SignatureCheckMode.Callback) && + !strictVariance && + compareTypes( + sourceType, + targetType, + /*reportErrors*/ false + )) || + compareTypes(targetType, sourceType, reportErrors); // With strict arity, (x: number | undefined) => void is a subtype of (x?: number | undefined) => void - if (related && checkMode & SignatureCheckMode.StrictArity && i >= getMinArgumentCount(source) && i < getMinArgumentCount(target) && compareTypes(sourceType, targetType, /*reportErrors*/ false)) { + if ( + related && + checkMode & SignatureCheckMode.StrictArity && + i >= getMinArgumentCount(source) && + i < getMinArgumentCount(target) && + compareTypes(sourceType, targetType, /*reportErrors*/ false) + ) { related = Ternary.False; } if (!related) { if (reportErrors) { - errorReporter!(Diagnostics.Types_of_parameters_0_and_1_are_incompatible, unescapeLeadingUnderscores(getParameterNameAtPosition(source, i)), unescapeLeadingUnderscores(getParameterNameAtPosition(target, i))); + errorReporter!( + Diagnostics.Types_of_parameters_0_and_1_are_incompatible, + unescapeLeadingUnderscores( + getParameterNameAtPosition(source, i) + ), + unescapeLeadingUnderscores( + getParameterNameAtPosition(target, i) + ) + ); } return Ternary.False; } @@ -21874,14 +38726,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!(checkMode & SignatureCheckMode.IgnoreReturnTypes)) { // If a signature resolution is already in-flight, skip issuing a circularity error // here and just use the `any` type directly - const targetReturnType = isResolvingReturnTypeOfSignature(target) ? anyType - : target.declaration && isJSConstructor(target.declaration) ? getDeclaredTypeOfClassOrInterface(getMergedSymbol(target.declaration.symbol)) + const targetReturnType = isResolvingReturnTypeOfSignature(target) + ? anyType + : target.declaration && isJSConstructor(target.declaration) + ? getDeclaredTypeOfClassOrInterface( + getMergedSymbol(target.declaration.symbol) + ) : getReturnTypeOfSignature(target); if (targetReturnType === voidType || targetReturnType === anyType) { return result; } - const sourceReturnType = isResolvingReturnTypeOfSignature(source) ? anyType - : source.declaration && isJSConstructor(source.declaration) ? getDeclaredTypeOfClassOrInterface(getMergedSymbol(source.declaration.symbol)) + const sourceReturnType = isResolvingReturnTypeOfSignature(source) + ? anyType + : source.declaration && isJSConstructor(source.declaration) + ? getDeclaredTypeOfClassOrInterface( + getMergedSymbol(source.declaration.symbol) + ) : getReturnTypeOfSignature(source); // The following block preserves behavior forbidding boolean returning functions from being assignable to type guard returning functions @@ -21889,23 +38749,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (targetTypePredicate) { const sourceTypePredicate = getTypePredicateOfSignature(source); if (sourceTypePredicate) { - result &= compareTypePredicateRelatedTo(sourceTypePredicate, targetTypePredicate, reportErrors, errorReporter, compareTypes); - } - else if (isIdentifierTypePredicate(targetTypePredicate) || isThisTypePredicate(targetTypePredicate)) { + result &= compareTypePredicateRelatedTo( + sourceTypePredicate, + targetTypePredicate, + reportErrors, + errorReporter, + compareTypes + ); + } else if ( + isIdentifierTypePredicate(targetTypePredicate) || + isThisTypePredicate(targetTypePredicate) + ) { if (reportErrors) { - errorReporter!(Diagnostics.Signature_0_must_be_a_type_predicate, signatureToString(source)); + errorReporter!( + Diagnostics.Signature_0_must_be_a_type_predicate, + signatureToString(source) + ); } return Ternary.False; } - } - else { + } else { // When relating callback signatures, we still need to relate return types bi-variantly as otherwise // the containing type wouldn't be co-variant. For example, interface Foo { add(cb: () => T): void } // wouldn't be co-variant for T without this rule. - result &= checkMode & SignatureCheckMode.BivariantCallback && compareTypes(targetReturnType, sourceReturnType, /*reportErrors*/ false) || - compareTypes(sourceReturnType, targetReturnType, reportErrors); + result &= + (checkMode & SignatureCheckMode.BivariantCallback && + compareTypes( + targetReturnType, + sourceReturnType, + /*reportErrors*/ false + )) || + compareTypes( + sourceReturnType, + targetReturnType, + reportErrors + ); if (!result && reportErrors && incompatibleErrorReporter) { - incompatibleErrorReporter(sourceReturnType, targetReturnType); + incompatibleErrorReporter( + sourceReturnType, + targetReturnType + ); } } } @@ -21918,36 +38801,66 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { target: TypePredicate, reportErrors: boolean, errorReporter: ErrorReporter | undefined, - compareTypes: (s: Type, t: Type, reportErrors?: boolean) => Ternary, + compareTypes: (s: Type, t: Type, reportErrors?: boolean) => Ternary ): Ternary { if (source.kind !== target.kind) { if (reportErrors) { - errorReporter!(Diagnostics.A_this_based_type_guard_is_not_compatible_with_a_parameter_based_type_guard); - errorReporter!(Diagnostics.Type_predicate_0_is_not_assignable_to_1, typePredicateToString(source), typePredicateToString(target)); + errorReporter!( + Diagnostics.A_this_based_type_guard_is_not_compatible_with_a_parameter_based_type_guard + ); + errorReporter!( + Diagnostics.Type_predicate_0_is_not_assignable_to_1, + typePredicateToString(source), + typePredicateToString(target) + ); } return Ternary.False; } - if (source.kind === TypePredicateKind.Identifier || source.kind === TypePredicateKind.AssertsIdentifier) { - if (source.parameterIndex !== (target as IdentifierTypePredicate).parameterIndex) { + if ( + source.kind === TypePredicateKind.Identifier || + source.kind === TypePredicateKind.AssertsIdentifier + ) { + if ( + source.parameterIndex !== + (target as IdentifierTypePredicate).parameterIndex + ) { if (reportErrors) { - errorReporter!(Diagnostics.Parameter_0_is_not_in_the_same_position_as_parameter_1, source.parameterName, (target as IdentifierTypePredicate).parameterName); - errorReporter!(Diagnostics.Type_predicate_0_is_not_assignable_to_1, typePredicateToString(source), typePredicateToString(target)); + errorReporter!( + Diagnostics.Parameter_0_is_not_in_the_same_position_as_parameter_1, + source.parameterName, + (target as IdentifierTypePredicate).parameterName + ); + errorReporter!( + Diagnostics.Type_predicate_0_is_not_assignable_to_1, + typePredicateToString(source), + typePredicateToString(target) + ); } return Ternary.False; } } - const related = source.type === target.type ? Ternary.True : - source.type && target.type ? compareTypes(source.type, target.type, reportErrors) : - Ternary.False; + const related = + source.type === target.type + ? Ternary.True + : source.type && target.type + ? compareTypes(source.type, target.type, reportErrors) + : Ternary.False; if (related === Ternary.False && reportErrors) { - errorReporter!(Diagnostics.Type_predicate_0_is_not_assignable_to_1, typePredicateToString(source), typePredicateToString(target)); + errorReporter!( + Diagnostics.Type_predicate_0_is_not_assignable_to_1, + typePredicateToString(source), + typePredicateToString(target) + ); } return related; } - function isImplementationCompatibleWithOverload(implementation: Signature, overload: Signature): boolean { + function isImplementationCompatibleWithOverload( + implementation: Signature, + overload: Signature + ): boolean { const erasedSource = getErasedSignature(implementation); const erasedTarget = getErasedSignature(overload); @@ -21955,103 +38868,208 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const sourceReturnType = getReturnTypeOfSignature(erasedSource); const targetReturnType = getReturnTypeOfSignature(erasedTarget); if ( - targetReturnType === voidType - || isTypeRelatedTo(targetReturnType, sourceReturnType, assignableRelation) - || isTypeRelatedTo(sourceReturnType, targetReturnType, assignableRelation) + targetReturnType === voidType || + isTypeRelatedTo( + targetReturnType, + sourceReturnType, + assignableRelation + ) || + isTypeRelatedTo( + sourceReturnType, + targetReturnType, + assignableRelation + ) ) { - return isSignatureAssignableTo(erasedSource, erasedTarget, /*ignoreReturnTypes*/ true); + return isSignatureAssignableTo( + erasedSource, + erasedTarget, + /*ignoreReturnTypes*/ true + ); } return false; } function isEmptyResolvedType(t: ResolvedType) { - return t !== anyFunctionType && + return ( + t !== anyFunctionType && t.properties.length === 0 && t.callSignatures.length === 0 && t.constructSignatures.length === 0 && - t.indexInfos.length === 0; + t.indexInfos.length === 0 + ); } function isEmptyObjectType(type: Type): boolean { - return type.flags & TypeFlags.Object ? !isGenericMappedType(type) && isEmptyResolvedType(resolveStructuredTypeMembers(type as ObjectType)) : - type.flags & TypeFlags.NonPrimitive ? true : - type.flags & TypeFlags.Union ? some((type as UnionType).types, isEmptyObjectType) : - type.flags & TypeFlags.Intersection ? every((type as UnionType).types, isEmptyObjectType) : - false; + return type.flags & TypeFlags.Object + ? !isGenericMappedType(type) && + isEmptyResolvedType( + resolveStructuredTypeMembers(type as ObjectType) + ) + : type.flags & TypeFlags.NonPrimitive + ? true + : type.flags & TypeFlags.Union + ? some((type as UnionType).types, isEmptyObjectType) + : type.flags & TypeFlags.Intersection + ? every((type as UnionType).types, isEmptyObjectType) + : false; } function isEmptyAnonymousObjectType(type: Type) { - return !!(getObjectFlags(type) & ObjectFlags.Anonymous && ( - (type as ResolvedType).members && isEmptyResolvedType(type as ResolvedType) || - type.symbol && type.symbol.flags & SymbolFlags.TypeLiteral && getMembersOfSymbol(type.symbol).size === 0 - )); + return !!( + getObjectFlags(type) & ObjectFlags.Anonymous && + (((type as ResolvedType).members && + isEmptyResolvedType(type as ResolvedType)) || + (type.symbol && + type.symbol.flags & SymbolFlags.TypeLiteral && + getMembersOfSymbol(type.symbol).size === 0)) + ); } function isUnknownLikeUnionType(type: Type) { if (strictNullChecks && type.flags & TypeFlags.Union) { - if (!((type as UnionType).objectFlags & ObjectFlags.IsUnknownLikeUnionComputed)) { + if ( + !( + (type as UnionType).objectFlags & + ObjectFlags.IsUnknownLikeUnionComputed + ) + ) { const types = (type as UnionType).types; - (type as UnionType).objectFlags |= ObjectFlags.IsUnknownLikeUnionComputed | (types.length >= 3 && types[0].flags & TypeFlags.Undefined && - types[1].flags & TypeFlags.Null && some(types, isEmptyAnonymousObjectType) ? ObjectFlags.IsUnknownLikeUnion : 0); - } - return !!((type as UnionType).objectFlags & ObjectFlags.IsUnknownLikeUnion); + (type as UnionType).objectFlags |= + ObjectFlags.IsUnknownLikeUnionComputed | + (types.length >= 3 && + types[0].flags & TypeFlags.Undefined && + types[1].flags & TypeFlags.Null && + some(types, isEmptyAnonymousObjectType) + ? ObjectFlags.IsUnknownLikeUnion + : 0); + } + return !!( + (type as UnionType).objectFlags & ObjectFlags.IsUnknownLikeUnion + ); } return false; } function containsUndefinedType(type: Type) { - return !!((type.flags & TypeFlags.Union ? (type as UnionType).types[0] : type).flags & TypeFlags.Undefined); + return !!( + (type.flags & TypeFlags.Union ? (type as UnionType).types[0] : type) + .flags & TypeFlags.Undefined + ); } function containsNonMissingUndefinedType(type: Type) { - const candidate = type.flags & TypeFlags.Union ? (type as UnionType).types[0] : type; - return !!(candidate.flags & TypeFlags.Undefined) && candidate !== missingType; + const candidate = + type.flags & TypeFlags.Union ? (type as UnionType).types[0] : type; + return ( + !!(candidate.flags & TypeFlags.Undefined) && + candidate !== missingType + ); } function isStringIndexSignatureOnlyType(type: Type): boolean { - return type.flags & TypeFlags.Object && !isGenericMappedType(type) && getPropertiesOfType(type).length === 0 && getIndexInfosOfType(type).length === 1 && !!getIndexInfoOfType(type, stringType) || - type.flags & TypeFlags.UnionOrIntersection && every((type as UnionOrIntersectionType).types, isStringIndexSignatureOnlyType) || - false; + return ( + (type.flags & TypeFlags.Object && + !isGenericMappedType(type) && + getPropertiesOfType(type).length === 0 && + getIndexInfosOfType(type).length === 1 && + !!getIndexInfoOfType(type, stringType)) || + (type.flags & TypeFlags.UnionOrIntersection && + every( + (type as UnionOrIntersectionType).types, + isStringIndexSignatureOnlyType + )) || + false + ); } - function isEnumTypeRelatedTo(source: Symbol, target: Symbol, errorReporter?: ErrorReporter) { - const sourceSymbol = source.flags & SymbolFlags.EnumMember ? getParentOfSymbol(source)! : source; - const targetSymbol = target.flags & SymbolFlags.EnumMember ? getParentOfSymbol(target)! : target; + function isEnumTypeRelatedTo( + source: Symbol, + target: Symbol, + errorReporter?: ErrorReporter + ) { + const sourceSymbol = + source.flags & SymbolFlags.EnumMember + ? getParentOfSymbol(source)! + : source; + const targetSymbol = + target.flags & SymbolFlags.EnumMember + ? getParentOfSymbol(target)! + : target; if (sourceSymbol === targetSymbol) { return true; } - if (sourceSymbol.escapedName !== targetSymbol.escapedName || !(sourceSymbol.flags & SymbolFlags.RegularEnum) || !(targetSymbol.flags & SymbolFlags.RegularEnum)) { + if ( + sourceSymbol.escapedName !== targetSymbol.escapedName || + !(sourceSymbol.flags & SymbolFlags.RegularEnum) || + !(targetSymbol.flags & SymbolFlags.RegularEnum) + ) { return false; } const id = getSymbolId(sourceSymbol) + "," + getSymbolId(targetSymbol); const entry = enumRelation.get(id); - if (entry !== undefined && !(entry & RelationComparisonResult.Failed && errorReporter)) { + if ( + entry !== undefined && + !(entry & RelationComparisonResult.Failed && errorReporter) + ) { return !!(entry & RelationComparisonResult.Succeeded); } const targetEnumType = getTypeOfSymbol(targetSymbol); - for (const sourceProperty of getPropertiesOfType(getTypeOfSymbol(sourceSymbol))) { + for (const sourceProperty of getPropertiesOfType( + getTypeOfSymbol(sourceSymbol) + )) { if (sourceProperty.flags & SymbolFlags.EnumMember) { - const targetProperty = getPropertyOfType(targetEnumType, sourceProperty.escapedName); - if (!targetProperty || !(targetProperty.flags & SymbolFlags.EnumMember)) { + const targetProperty = getPropertyOfType( + targetEnumType, + sourceProperty.escapedName + ); + if ( + !targetProperty || + !(targetProperty.flags & SymbolFlags.EnumMember) + ) { if (errorReporter) { - errorReporter(Diagnostics.Property_0_is_missing_in_type_1, symbolName(sourceProperty), typeToString(getDeclaredTypeOfSymbol(targetSymbol), /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType)); + errorReporter( + Diagnostics.Property_0_is_missing_in_type_1, + symbolName(sourceProperty), + typeToString( + getDeclaredTypeOfSymbol(targetSymbol), + /*enclosingDeclaration*/ undefined, + TypeFormatFlags.UseFullyQualifiedType + ) + ); } enumRelation.set(id, RelationComparisonResult.Failed); return false; } - const sourceValue = getEnumMemberValue(getDeclarationOfKind(sourceProperty, SyntaxKind.EnumMember)!).value; - const targetValue = getEnumMemberValue(getDeclarationOfKind(targetProperty, SyntaxKind.EnumMember)!).value; + const sourceValue = getEnumMemberValue( + getDeclarationOfKind(sourceProperty, SyntaxKind.EnumMember)! + ).value; + const targetValue = getEnumMemberValue( + getDeclarationOfKind(targetProperty, SyntaxKind.EnumMember)! + ).value; if (sourceValue !== targetValue) { const sourceIsString = typeof sourceValue === "string"; const targetIsString = typeof targetValue === "string"; // If we have 2 enums with *known* values that differ, they are incompatible. - if (sourceValue !== undefined && targetValue !== undefined) { + if ( + sourceValue !== undefined && + targetValue !== undefined + ) { if (errorReporter) { - const escapedSource = sourceIsString ? `"${escapeString(sourceValue)}"` : sourceValue; - const escapedTarget = targetIsString ? `"${escapeString(targetValue)}"` : targetValue; - errorReporter(Diagnostics.Each_declaration_of_0_1_differs_in_its_value_where_2_was_expected_but_3_was_given, symbolName(targetSymbol), symbolName(targetProperty), escapedTarget, escapedSource); + const escapedSource = sourceIsString + ? `"${escapeString(sourceValue)}"` + : sourceValue; + const escapedTarget = targetIsString + ? `"${escapeString(targetValue)}"` + : targetValue; + errorReporter( + Diagnostics.Each_declaration_of_0_1_differs_in_its_value_where_2_was_expected_but_3_was_given, + symbolName(targetSymbol), + symbolName(targetProperty), + escapedTarget, + escapedSource + ); } enumRelation.set(id, RelationComparisonResult.Failed); return false; @@ -22067,8 +39085,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (errorReporter) { const knownStringValue = sourceValue ?? targetValue; Debug.assert(typeof knownStringValue === "string"); - const escapedValue = `"${escapeString(knownStringValue)}"`; - errorReporter(Diagnostics.One_value_of_0_1_is_the_string_2_and_the_other_is_assumed_to_be_an_unknown_numeric_value, symbolName(targetSymbol), symbolName(targetProperty), escapedValue); + const escapedValue = `"${escapeString( + knownStringValue + )}"`; + errorReporter( + Diagnostics.One_value_of_0_1_is_the_string_2_and_the_other_is_assumed_to_be_an_unknown_numeric_value, + symbolName(targetSymbol), + symbolName(targetProperty), + escapedValue + ); } enumRelation.set(id, RelationComparisonResult.Failed); return false; @@ -22080,61 +39105,127 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; } - function isSimpleTypeRelatedTo(source: Type, target: Type, relation: Map, errorReporter?: ErrorReporter) { + function isSimpleTypeRelatedTo( + source: Type, + target: Type, + relation: Map, + errorReporter?: ErrorReporter + ) { const s = source.flags; const t = target.flags; - if (t & TypeFlags.Any || s & TypeFlags.Never || source === wildcardType) return true; - if (t & TypeFlags.Unknown && !(relation === strictSubtypeRelation && s & TypeFlags.Any)) return true; + if (t & TypeFlags.Any || s & TypeFlags.Never || source === wildcardType) + return true; + if ( + t & TypeFlags.Unknown && + !(relation === strictSubtypeRelation && s & TypeFlags.Any) + ) + return true; if (t & TypeFlags.Never) return false; if (s & TypeFlags.StringLike && t & TypeFlags.String) return true; if ( - s & TypeFlags.StringLiteral && s & TypeFlags.EnumLiteral && - t & TypeFlags.StringLiteral && !(t & TypeFlags.EnumLiteral) && - (source as StringLiteralType).value === (target as StringLiteralType).value - ) return true; + s & TypeFlags.StringLiteral && + s & TypeFlags.EnumLiteral && + t & TypeFlags.StringLiteral && + !(t & TypeFlags.EnumLiteral) && + (source as StringLiteralType).value === + (target as StringLiteralType).value + ) + return true; if (s & TypeFlags.NumberLike && t & TypeFlags.Number) return true; if ( - s & TypeFlags.NumberLiteral && s & TypeFlags.EnumLiteral && - t & TypeFlags.NumberLiteral && !(t & TypeFlags.EnumLiteral) && - (source as NumberLiteralType).value === (target as NumberLiteralType).value - ) return true; + s & TypeFlags.NumberLiteral && + s & TypeFlags.EnumLiteral && + t & TypeFlags.NumberLiteral && + !(t & TypeFlags.EnumLiteral) && + (source as NumberLiteralType).value === + (target as NumberLiteralType).value + ) + return true; if (s & TypeFlags.BigIntLike && t & TypeFlags.BigInt) return true; if (s & TypeFlags.BooleanLike && t & TypeFlags.Boolean) return true; if (s & TypeFlags.ESSymbolLike && t & TypeFlags.ESSymbol) return true; if ( - s & TypeFlags.Enum && t & TypeFlags.Enum && source.symbol.escapedName === target.symbol.escapedName && + s & TypeFlags.Enum && + t & TypeFlags.Enum && + source.symbol.escapedName === target.symbol.escapedName && isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter) - ) return true; + ) + return true; if (s & TypeFlags.EnumLiteral && t & TypeFlags.EnumLiteral) { - if (s & TypeFlags.Union && t & TypeFlags.Union && isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter)) return true; if ( - s & TypeFlags.Literal && t & TypeFlags.Literal && (source as LiteralType).value === (target as LiteralType).value && + s & TypeFlags.Union && + t & TypeFlags.Union && + isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter) + ) + return true; + if ( + s & TypeFlags.Literal && + t & TypeFlags.Literal && + (source as LiteralType).value === + (target as LiteralType).value && isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter) - ) return true; + ) + return true; } // In non-strictNullChecks mode, `undefined` and `null` are assignable to anything except `never`. // Since unions and intersections may reduce to `never`, we exclude them here. - if (s & TypeFlags.Undefined && (!strictNullChecks && !(t & TypeFlags.UnionOrIntersection) || t & (TypeFlags.Undefined | TypeFlags.Void))) return true; - if (s & TypeFlags.Null && (!strictNullChecks && !(t & TypeFlags.UnionOrIntersection) || t & TypeFlags.Null)) return true; - if (s & TypeFlags.Object && t & TypeFlags.NonPrimitive && !(relation === strictSubtypeRelation && isEmptyAnonymousObjectType(source) && !(getObjectFlags(source) & ObjectFlags.FreshLiteral))) return true; - if (relation === assignableRelation || relation === comparableRelation) { + if ( + s & TypeFlags.Undefined && + ((!strictNullChecks && !(t & TypeFlags.UnionOrIntersection)) || + t & (TypeFlags.Undefined | TypeFlags.Void)) + ) + return true; + if ( + s & TypeFlags.Null && + ((!strictNullChecks && !(t & TypeFlags.UnionOrIntersection)) || + t & TypeFlags.Null) + ) + return true; + if ( + s & TypeFlags.Object && + t & TypeFlags.NonPrimitive && + !( + relation === strictSubtypeRelation && + isEmptyAnonymousObjectType(source) && + !(getObjectFlags(source) & ObjectFlags.FreshLiteral) + ) + ) + return true; + if ( + relation === assignableRelation || + relation === comparableRelation + ) { if (s & TypeFlags.Any) return true; // Type number is assignable to any computed numeric enum type or any numeric enum literal type, and // a numeric literal type is assignable any computed numeric enum type or any numeric enum literal type // with a matching value. These rules exist such that enums can be used for bit-flag purposes. - if (s & TypeFlags.Number && (t & TypeFlags.Enum || t & TypeFlags.NumberLiteral && t & TypeFlags.EnumLiteral)) return true; if ( - s & TypeFlags.NumberLiteral && !(s & TypeFlags.EnumLiteral) && (t & TypeFlags.Enum || - t & TypeFlags.NumberLiteral && t & TypeFlags.EnumLiteral && - (source as NumberLiteralType).value === (target as NumberLiteralType).value) - ) return true; + s & TypeFlags.Number && + (t & TypeFlags.Enum || + (t & TypeFlags.NumberLiteral && t & TypeFlags.EnumLiteral)) + ) + return true; + if ( + s & TypeFlags.NumberLiteral && + !(s & TypeFlags.EnumLiteral) && + (t & TypeFlags.Enum || + (t & TypeFlags.NumberLiteral && + t & TypeFlags.EnumLiteral && + (source as NumberLiteralType).value === + (target as NumberLiteralType).value)) + ) + return true; // Anything is assignable to a union containing undefined, null, and {} if (isUnknownLikeUnionType(target)) return true; } return false; } - function isTypeRelatedTo(source: Type, target: Type, relation: Map) { + function isTypeRelatedTo( + source: Type, + target: Type, + relation: Map + ) { if (isFreshLiteralType(source)) { source = (source as FreshableType).regularType; } @@ -22145,58 +39236,116 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; } if (relation !== identityRelation) { - if (relation === comparableRelation && !(target.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(target, source, relation) || isSimpleTypeRelatedTo(source, target, relation)) { + if ( + (relation === comparableRelation && + !(target.flags & TypeFlags.Never) && + isSimpleTypeRelatedTo(target, source, relation)) || + isSimpleTypeRelatedTo(source, target, relation) + ) { return true; } - } - else if (!((source.flags | target.flags) & (TypeFlags.UnionOrIntersection | TypeFlags.IndexedAccess | TypeFlags.Conditional | TypeFlags.Substitution))) { + } else if ( + !( + (source.flags | target.flags) & + (TypeFlags.UnionOrIntersection | + TypeFlags.IndexedAccess | + TypeFlags.Conditional | + TypeFlags.Substitution) + ) + ) { // We have excluded types that may simplify to other forms, so types must have identical flags if (source.flags !== target.flags) return false; if (source.flags & TypeFlags.Singleton) return true; } - if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) { - const related = relation.get(getRelationKey(source, target, IntersectionState.None, relation, /*ignoreConstraints*/ false)); + if ( + source.flags & TypeFlags.Object && + target.flags & TypeFlags.Object + ) { + const related = relation.get( + getRelationKey( + source, + target, + IntersectionState.None, + relation, + /*ignoreConstraints*/ false + ) + ); if (related !== undefined) { return !!(related & RelationComparisonResult.Succeeded); } } - if (source.flags & TypeFlags.StructuredOrInstantiable || target.flags & TypeFlags.StructuredOrInstantiable) { - return checkTypeRelatedTo(source, target, relation, /*errorNode*/ undefined); + if ( + source.flags & TypeFlags.StructuredOrInstantiable || + target.flags & TypeFlags.StructuredOrInstantiable + ) { + return checkTypeRelatedTo( + source, + target, + relation, + /*errorNode*/ undefined + ); } return false; } function isIgnoredJsxProperty(source: Type, sourceProp: Symbol) { - return getObjectFlags(source) & ObjectFlags.JsxAttributes && isHyphenatedJsxName(sourceProp.escapedName); + return ( + getObjectFlags(source) & ObjectFlags.JsxAttributes && + isHyphenatedJsxName(sourceProp.escapedName) + ); } function getNormalizedType(type: Type, writing: boolean): Type { while (true) { - const t = isFreshLiteralType(type) ? (type as FreshableType).regularType : - isGenericTupleType(type) ? getNormalizedTupleType(type, writing) : - getObjectFlags(type) & ObjectFlags.Reference ? (type as TypeReference).node ? createTypeReference((type as TypeReference).target, getTypeArguments(type as TypeReference)) : getSingleBaseForNonAugmentingSubtype(type) || type : - type.flags & TypeFlags.UnionOrIntersection ? getNormalizedUnionOrIntersectionType(type as UnionOrIntersectionType, writing) : - type.flags & TypeFlags.Substitution ? writing ? (type as SubstitutionType).baseType : getSubstitutionIntersection(type as SubstitutionType) : - type.flags & TypeFlags.Simplifiable ? getSimplifiedType(type, writing) : - type; + const t = isFreshLiteralType(type) + ? (type as FreshableType).regularType + : isGenericTupleType(type) + ? getNormalizedTupleType(type, writing) + : getObjectFlags(type) & ObjectFlags.Reference + ? (type as TypeReference).node + ? createTypeReference( + (type as TypeReference).target, + getTypeArguments(type as TypeReference) + ) + : getSingleBaseForNonAugmentingSubtype(type) || type + : type.flags & TypeFlags.UnionOrIntersection + ? getNormalizedUnionOrIntersectionType( + type as UnionOrIntersectionType, + writing + ) + : type.flags & TypeFlags.Substitution + ? writing + ? (type as SubstitutionType).baseType + : getSubstitutionIntersection(type as SubstitutionType) + : type.flags & TypeFlags.Simplifiable + ? getSimplifiedType(type, writing) + : type; if (t === type) return t; type = t; } } - function getNormalizedUnionOrIntersectionType(type: UnionOrIntersectionType, writing: boolean) { + function getNormalizedUnionOrIntersectionType( + type: UnionOrIntersectionType, + writing: boolean + ) { const reduced = getReducedType(type); if (reduced !== type) { return reduced; } - if (type.flags & TypeFlags.Intersection && shouldNormalizeIntersection(type as IntersectionType)) { + if ( + type.flags & TypeFlags.Intersection && + shouldNormalizeIntersection(type as IntersectionType) + ) { // Normalization handles cases like // Partial[K] & ({} | null) ==> // Partial[K] & {} | Partial[K] & null ==> // (T[K] | undefined) & {} | (T[K] | undefined) & null ==> // T[K] & {} | undefined & {} | T[K] & null | undefined & null ==> // T[K] & {} | T[K] & null - const normalizedTypes = sameMap(type.types, t => getNormalizedType(t, writing)); + const normalizedTypes = sameMap(type.types, (t) => + getNormalizedType(t, writing) + ); if (normalizedTypes !== type.types) { return getIntersectionType(normalizedTypes); } @@ -22209,16 +39358,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let hasNullableOrEmpty = false; for (const t of type.types) { hasInstantiable ||= !!(t.flags & TypeFlags.Instantiable); - hasNullableOrEmpty ||= !!(t.flags & TypeFlags.Nullable) || isEmptyAnonymousObjectType(t); + hasNullableOrEmpty ||= + !!(t.flags & TypeFlags.Nullable) || + isEmptyAnonymousObjectType(t); if (hasInstantiable && hasNullableOrEmpty) return true; } return false; } - function getNormalizedTupleType(type: TupleTypeReference, writing: boolean): Type { + function getNormalizedTupleType( + type: TupleTypeReference, + writing: boolean + ): Type { const elements = getElementTypes(type); - const normalizedElements = sameMap(elements, t => t.flags & TypeFlags.Simplifiable ? getSimplifiedType(t, writing) : t); - return elements !== normalizedElements ? createNormalizedTupleType(type.target, normalizedElements) : type; + const normalizedElements = sameMap(elements, (t) => + t.flags & TypeFlags.Simplifiable ? getSimplifiedType(t, writing) : t + ); + return elements !== normalizedElements + ? createNormalizedTupleType(type.target, normalizedElements) + : type; } /** @@ -22239,10 +39397,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { errorNode: Node | undefined, headMessage?: DiagnosticMessage, containingMessageChain?: () => DiagnosticMessageChain | undefined, - errorOutputContainer?: ErrorOutputContainer, + errorOutputContainer?: ErrorOutputContainer ): boolean { let errorInfo: DiagnosticMessageChain | undefined; - let relatedInfo: [DiagnosticRelatedInformation, ...DiagnosticRelatedInformation[]] | undefined; + let relatedInfo: + | [DiagnosticRelatedInformation, ...DiagnosticRelatedInformation[]] + | undefined; let maybeKeys: string[]; let maybeKeysSet: Set; let sourceStack: Type[]; @@ -22260,26 +39420,64 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // of checkTypeRelatedTo can add to a relation to 1/8th of its remaining capacity. let relationCount = (16_000_000 - relation.size) >> 3; - Debug.assert(relation !== identityRelation || !errorNode, "no error reporting in identity checking"); + Debug.assert( + relation !== identityRelation || !errorNode, + "no error reporting in identity checking" + ); - const result = isRelatedTo(source, target, RecursionFlags.Both, /*reportErrors*/ !!errorNode, headMessage); + const result = isRelatedTo( + source, + target, + RecursionFlags.Both, + /*reportErrors*/ !!errorNode, + headMessage + ); if (incompatibleStack) { reportIncompatibleStack(); } if (overflow) { // Record this relation as having failed such that we don't attempt the overflowing operation again. - const id = getRelationKey(source, target, /*intersectionState*/ IntersectionState.None, relation, /*ignoreConstraints*/ false); - relation.set(id, RelationComparisonResult.Failed | (relationCount <= 0 ? RelationComparisonResult.ComplexityOverflow : RelationComparisonResult.StackDepthOverflow)); - tracing?.instant(tracing.Phase.CheckTypes, "checkTypeRelatedTo_DepthLimit", { sourceId: source.id, targetId: target.id, depth: sourceDepth, targetDepth }); - const message = relationCount <= 0 ? - Diagnostics.Excessive_complexity_comparing_types_0_and_1 : - Diagnostics.Excessive_stack_depth_comparing_types_0_and_1; - const diag = error(errorNode || currentNode, message, typeToString(source), typeToString(target)); + const id = getRelationKey( + source, + target, + /*intersectionState*/ IntersectionState.None, + relation, + /*ignoreConstraints*/ false + ); + relation.set( + id, + RelationComparisonResult.Failed | + (relationCount <= 0 + ? RelationComparisonResult.ComplexityOverflow + : RelationComparisonResult.StackDepthOverflow) + ); + tracing?.instant( + tracing.Phase.CheckTypes, + "checkTypeRelatedTo_DepthLimit", + { + sourceId: source.id, + targetId: target.id, + depth: sourceDepth, + targetDepth, + } + ); + const message = + relationCount <= 0 + ? Diagnostics.Excessive_complexity_comparing_types_0_and_1 + : Diagnostics.Excessive_stack_depth_comparing_types_0_and_1; + const diag = error( + errorNode || currentNode, + message, + typeToString(source), + typeToString(target) + ); if (errorOutputContainer) { - (errorOutputContainer.errors || (errorOutputContainer.errors = [])).push(diag); + ( + errorOutputContainer.errors || + (errorOutputContainer.errors = []) + ).push(diag); } - } - else if (errorInfo) { + } else if (errorInfo) { if (containingMessageChain) { const chain = containingMessageChain(); if (chain) { @@ -22292,33 +39490,62 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Check if we should issue an extra diagnostic to produce a quickfix for a slightly incorrect import statement if (headMessage && errorNode && !result && source.symbol) { const links = getSymbolLinks(source.symbol); - if (links.originatingImport && !isImportCall(links.originatingImport)) { - const helpfulRetry = checkTypeRelatedTo(getTypeOfSymbol(links.target!), target, relation, /*errorNode*/ undefined); + if ( + links.originatingImport && + !isImportCall(links.originatingImport) + ) { + const helpfulRetry = checkTypeRelatedTo( + getTypeOfSymbol(links.target!), + target, + relation, + /*errorNode*/ undefined + ); if (helpfulRetry) { // Likely an incorrect import. Issue a helpful diagnostic to produce a quickfix to change the import - 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); + 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 + ); relatedInformation = append(relatedInformation, diag); // Cause the error to appear with the error that triggered it } } } - const diag = createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(errorNode!), errorNode!, errorInfo, relatedInformation); + const diag = createDiagnosticForNodeFromMessageChain( + getSourceFileOfNode(errorNode!), + errorNode!, + errorInfo, + relatedInformation + ); if (relatedInfo) { addRelatedInfo(diag, ...relatedInfo); } if (errorOutputContainer) { - (errorOutputContainer.errors || (errorOutputContainer.errors = [])).push(diag); + ( + errorOutputContainer.errors || + (errorOutputContainer.errors = []) + ).push(diag); } if (!errorOutputContainer || !errorOutputContainer.skipLogging) { diagnostics.add(diag); } } - if (errorNode && errorOutputContainer && errorOutputContainer.skipLogging && result === Ternary.False) { - Debug.assert(!!errorOutputContainer.errors, "missed opportunity to interact with error."); + if ( + errorNode && + errorOutputContainer && + errorOutputContainer.skipLogging && + result === Ternary.False + ) { + Debug.assert( + !!errorOutputContainer.errors, + "missed opportunity to interact with error." + ); } return result !== Ternary.False; - function resetErrorInfo(saved: ReturnType) { + function resetErrorInfo( + saved: ReturnType + ) { errorInfo = saved.errorInfo; lastSkippedInfo = saved.lastSkippedInfo; incompatibleStack = saved.incompatibleStack; @@ -22334,11 +39561,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { incompatibleStack: incompatibleStack?.slice(), overrideNextErrorInfo, skipParentCounter, - relatedInfo: relatedInfo?.slice() as [DiagnosticRelatedInformation, ...DiagnosticRelatedInformation[]] | undefined, + relatedInfo: relatedInfo?.slice() as + | [ + DiagnosticRelatedInformation, + ...DiagnosticRelatedInformation[] + ] + | undefined, }; } - function reportIncompatibleError(message: DiagnosticMessage, ...args: DiagnosticArguments) { + function reportIncompatibleError( + message: DiagnosticMessage, + ...args: DiagnosticArguments + ) { overrideNextErrorInfo++; // Suppress the next relation error lastSkippedInfo = undefined; // Reset skipped info cache (incompatibleStack ||= []).push([message, ...args]); @@ -22364,7 +39599,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { while (stack.length) { const [msg, ...args] = stack.pop()!; switch (msg.code) { - case Diagnostics.Types_of_property_0_are_incompatible.code: { + case Diagnostics.Types_of_property_0_are_incompatible + .code: { // Parenthesize a `new` if there is one if (path.indexOf("new ") === 0) { path = `(${path})`; @@ -22375,11 +39611,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { path = `${str}`; } // Otherwise write a dotted name if possible - else if (isIdentifierText(str, getEmitScriptTarget(compilerOptions))) { + else if ( + isIdentifierText( + str, + getEmitScriptTarget(compilerOptions) + ) + ) { path = `${path}.${str}`; } // Failing that, check if the name is already a computed name - else if (str[0] === "[" && str[str.length - 1] === "]") { + else if ( + str[0] === "[" && + str[str.length - 1] === "]" + ) { path = `${path}${str}`; } // And finally write out a computed name as a last resort @@ -22388,41 +39632,90 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } break; } - case Diagnostics.Call_signature_return_types_0_and_1_are_incompatible.code: - case Diagnostics.Construct_signature_return_types_0_and_1_are_incompatible.code: - case Diagnostics.Call_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code: - case Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code: { + case Diagnostics + .Call_signature_return_types_0_and_1_are_incompatible + .code: + case Diagnostics + .Construct_signature_return_types_0_and_1_are_incompatible + .code: + case Diagnostics + .Call_signatures_with_no_arguments_have_incompatible_return_types_0_and_1 + .code: + case Diagnostics + .Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1 + .code: { if (path.length === 0) { // Don't flatten signature compatability errors at the start of a chain - instead prefer // to unify (the with no arguments bit is excessive for printback) and print them back let mappedMsg = msg; - if (msg.code === Diagnostics.Call_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code) { - mappedMsg = Diagnostics.Call_signature_return_types_0_and_1_are_incompatible; - } - else if (msg.code === Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code) { - mappedMsg = Diagnostics.Construct_signature_return_types_0_and_1_are_incompatible; + if ( + msg.code === + Diagnostics + .Call_signatures_with_no_arguments_have_incompatible_return_types_0_and_1 + .code + ) { + mappedMsg = + Diagnostics.Call_signature_return_types_0_and_1_are_incompatible; + } else if ( + msg.code === + Diagnostics + .Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1 + .code + ) { + mappedMsg = + Diagnostics.Construct_signature_return_types_0_and_1_are_incompatible; } - secondaryRootErrors.unshift([mappedMsg, args[0], args[1]]); - } - else { - const prefix = (msg.code === Diagnostics.Construct_signature_return_types_0_and_1_are_incompatible.code || - msg.code === Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code) - ? "new " - : ""; - const params = (msg.code === Diagnostics.Call_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code || - msg.code === Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code) - ? "" - : "..."; + secondaryRootErrors.unshift([ + mappedMsg, + args[0], + args[1], + ]); + } else { + const prefix = + msg.code === + Diagnostics + .Construct_signature_return_types_0_and_1_are_incompatible + .code || + msg.code === + Diagnostics + .Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1 + .code + ? "new " + : ""; + const params = + msg.code === + Diagnostics + .Call_signatures_with_no_arguments_have_incompatible_return_types_0_and_1 + .code || + msg.code === + Diagnostics + .Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1 + .code + ? "" + : "..."; path = `${prefix}${path}(${params})`; } break; } - case Diagnostics.Type_at_position_0_in_source_is_not_compatible_with_type_at_position_1_in_target.code: { - secondaryRootErrors.unshift([Diagnostics.Type_at_position_0_in_source_is_not_compatible_with_type_at_position_1_in_target, args[0], args[1]]); + case Diagnostics + .Type_at_position_0_in_source_is_not_compatible_with_type_at_position_1_in_target + .code: { + secondaryRootErrors.unshift([ + Diagnostics.Type_at_position_0_in_source_is_not_compatible_with_type_at_position_1_in_target, + args[0], + args[1], + ]); break; } - case Diagnostics.Type_at_positions_0_through_1_in_source_is_not_compatible_with_type_at_position_2_in_target.code: { - 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]]); + case Diagnostics + .Type_at_positions_0_through_1_in_source_is_not_compatible_with_type_at_position_2_in_target + .code: { + 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], + ]); break; } default: @@ -22434,10 +39727,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { path[path.length - 1] === ")" ? Diagnostics.The_types_returned_by_0_are_incompatible_between_these_types : Diagnostics.The_types_of_0_are_incompatible_between_these_types, - path, + path ); - } - else { + } else { // Remove the innermost secondary error as it will duplicate the error already reported by `reportRelationError` on entry secondaryRootErrors.shift(); } @@ -22453,19 +39745,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function reportError(message: DiagnosticMessage, ...args: DiagnosticArguments): void { + function reportError( + message: DiagnosticMessage, + ...args: DiagnosticArguments + ): void { Debug.assert(!!errorNode); if (incompatibleStack) reportIncompatibleStack(); if (message.elidedInCompatabilityPyramid) return; if (skipParentCounter === 0) { - errorInfo = chainDiagnosticMessages(errorInfo, message, ...args); - } - else { + errorInfo = chainDiagnosticMessages( + errorInfo, + message, + ...args + ); + } else { skipParentCounter--; } } - function reportParentSkippedError(message: DiagnosticMessage, ...args: DiagnosticArguments): void { + function reportParentSkippedError( + message: DiagnosticMessage, + ...args: DiagnosticArguments + ): void { reportError(message, ...args); skipParentCounter++; } @@ -22474,48 +39775,76 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { Debug.assert(!!errorInfo); if (!relatedInfo) { relatedInfo = [info]; - } - else { + } else { relatedInfo.push(info); } } - function reportRelationError(message: DiagnosticMessage | undefined, source: Type, target: Type) { + function reportRelationError( + message: DiagnosticMessage | undefined, + source: Type, + target: Type + ) { if (incompatibleStack) reportIncompatibleStack(); - const [sourceType, targetType] = getTypeNamesForErrorDisplay(source, target); + const [sourceType, targetType] = getTypeNamesForErrorDisplay( + source, + target + ); let generalizedSource = source; let generalizedSourceType = sourceType; // Don't generalize on 'never' - we really want the original type // to be displayed for use-cases like 'assertNever'. - if (!(target.flags & TypeFlags.Never) && isLiteralType(source) && !typeCouldHaveTopLevelSingletonTypes(target)) { + if ( + !(target.flags & TypeFlags.Never) && + isLiteralType(source) && + !typeCouldHaveTopLevelSingletonTypes(target) + ) { generalizedSource = getBaseTypeOfLiteralType(source); - Debug.assert(!isTypeAssignableTo(generalizedSource, target), "generalized source shouldn't be assignable"); - generalizedSourceType = getTypeNameForErrorDisplay(generalizedSource); + Debug.assert( + !isTypeAssignableTo(generalizedSource, target), + "generalized source shouldn't be assignable" + ); + generalizedSourceType = + getTypeNameForErrorDisplay(generalizedSource); } // If `target` is of indexed access type (And `source` it is not), we use the object type of `target` for better error reporting - const targetFlags = target.flags & TypeFlags.IndexedAccess && !(source.flags & TypeFlags.IndexedAccess) ? - (target as IndexedAccessType).objectType.flags : - target.flags; + const targetFlags = + target.flags & TypeFlags.IndexedAccess && + !(source.flags & TypeFlags.IndexedAccess) + ? (target as IndexedAccessType).objectType.flags + : target.flags; - if (targetFlags & TypeFlags.TypeParameter && target !== markerSuperTypeForCheck && target !== markerSubTypeForCheck) { + if ( + targetFlags & TypeFlags.TypeParameter && + target !== markerSuperTypeForCheck && + target !== markerSubTypeForCheck + ) { const constraint = getBaseConstraintOfType(target); let needsOriginalSource; - if (constraint && (isTypeAssignableTo(generalizedSource, constraint) || (needsOriginalSource = isTypeAssignableTo(source, constraint)))) { + if ( + constraint && + (isTypeAssignableTo(generalizedSource, constraint) || + (needsOriginalSource = isTypeAssignableTo( + source, + constraint + ))) + ) { reportError( Diagnostics._0_is_assignable_to_the_constraint_of_type_1_but_1_could_be_instantiated_with_a_different_subtype_of_constraint_2, - needsOriginalSource ? sourceType : generalizedSourceType, + needsOriginalSource + ? sourceType + : generalizedSourceType, targetType, - typeToString(constraint), + typeToString(constraint) ); - } - else { + } else { errorInfo = undefined; reportError( Diagnostics._0_could_be_instantiated_with_an_arbitrary_type_which_could_be_unrelated_to_1, targetType, - generalizedSourceType, + generalizedSourceType ); } } @@ -22523,38 +39852,65 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!message) { if (relation === comparableRelation) { message = Diagnostics.Type_0_is_not_comparable_to_type_1; - } - else if (sourceType === targetType) { - message = Diagnostics.Type_0_is_not_assignable_to_type_1_Two_different_types_with_this_name_exist_but_they_are_unrelated; - } - else if (exactOptionalPropertyTypes && getExactOptionalUnassignableProperties(source, target).length) { - 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; - } - else { - if (source.flags & TypeFlags.StringLiteral && target.flags & TypeFlags.Union) { - const suggestedType = getSuggestedTypeForNonexistentStringLiteralType(source as StringLiteralType, target as UnionType); + } else if (sourceType === targetType) { + message = + Diagnostics.Type_0_is_not_assignable_to_type_1_Two_different_types_with_this_name_exist_but_they_are_unrelated; + } else if ( + exactOptionalPropertyTypes && + getExactOptionalUnassignableProperties(source, target) + .length + ) { + 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; + } else { + if ( + source.flags & TypeFlags.StringLiteral && + target.flags & TypeFlags.Union + ) { + const suggestedType = + getSuggestedTypeForNonexistentStringLiteralType( + source as StringLiteralType, + target as UnionType + ); if (suggestedType) { - reportError(Diagnostics.Type_0_is_not_assignable_to_type_1_Did_you_mean_2, generalizedSourceType, targetType, typeToString(suggestedType)); + reportError( + Diagnostics.Type_0_is_not_assignable_to_type_1_Did_you_mean_2, + generalizedSourceType, + targetType, + typeToString(suggestedType) + ); return; } } message = Diagnostics.Type_0_is_not_assignable_to_type_1; } - } - else if ( - message === Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1 - && exactOptionalPropertyTypes - && getExactOptionalUnassignableProperties(source, target).length + } else if ( + message === + Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1 && + exactOptionalPropertyTypes && + getExactOptionalUnassignableProperties(source, target).length ) { - 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; + 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; } reportError(message, generalizedSourceType, targetType); } - function tryElaborateErrorsForPrimitivesAndObjects(source: Type, target: Type) { - const sourceType = symbolValueDeclarationIsContextSensitive(source.symbol) ? typeToString(source, source.symbol.valueDeclaration) : typeToString(source); - const targetType = symbolValueDeclarationIsContextSensitive(target.symbol) ? typeToString(target, target.symbol.valueDeclaration) : typeToString(target); + function tryElaborateErrorsForPrimitivesAndObjects( + source: Type, + target: Type + ) { + const sourceType = symbolValueDeclarationIsContextSensitive( + source.symbol + ) + ? typeToString(source, source.symbol.valueDeclaration) + : typeToString(source); + const targetType = symbolValueDeclarationIsContextSensitive( + target.symbol + ) + ? typeToString(target, target.symbol.valueDeclaration) + : typeToString(target); if ( (globalStringType === source && stringType === target) || @@ -22562,7 +39918,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { (globalBooleanType === source && booleanType === target) || (getGlobalESSymbolType() === source && esSymbolType === target) ) { - reportError(Diagnostics._0_is_a_primitive_but_1_is_a_wrapper_object_Prefer_using_0_when_possible, targetType, sourceType); + reportError( + Diagnostics._0_is_a_primitive_but_1_is_a_wrapper_object_Prefer_using_0_when_possible, + targetType, + sourceType + ); } } @@ -22572,7 +39932,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * any other elaborations when relating the `source` and * `target` types. */ - function tryElaborateArrayLikeErrors(source: Type, target: Type, reportErrors: boolean): boolean { + function tryElaborateArrayLikeErrors( + source: Type, + target: Type, + reportErrors: boolean + ): boolean { /** * The spec for elaboration is: * - If the source is a readonly tuple and the target is a mutable array or tuple, elaborate on mutability and skip property elaborations. @@ -22583,7 +39947,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isTupleType(source)) { if (source.target.readonly && isMutableArrayOrTuple(target)) { if (reportErrors) { - reportError(Diagnostics.The_type_0_is_readonly_and_cannot_be_assigned_to_the_mutable_type_1, typeToString(source), typeToString(target)); + reportError( + Diagnostics.The_type_0_is_readonly_and_cannot_be_assigned_to_the_mutable_type_1, + typeToString(source), + typeToString(target) + ); } return false; } @@ -22591,7 +39959,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (isReadonlyArrayType(source) && isMutableArrayOrTuple(target)) { if (reportErrors) { - reportError(Diagnostics.The_type_0_is_readonly_and_cannot_be_assigned_to_the_mutable_type_1, typeToString(source), typeToString(target)); + reportError( + Diagnostics.The_type_0_is_readonly_and_cannot_be_assigned_to_the_mutable_type_1, + typeToString(source), + typeToString(target) + ); } return false; } @@ -22601,8 +39973,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; } - function isRelatedToWorker(source: Type, target: Type, reportErrors?: boolean) { - return isRelatedTo(source, target, RecursionFlags.Both, reportErrors); + function isRelatedToWorker( + source: Type, + target: Type, + reportErrors?: boolean + ) { + return isRelatedTo( + source, + target, + RecursionFlags.Both, + reportErrors + ); } /** @@ -22611,20 +39992,47 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * * Ternary.Maybe if they are related with assumptions of other relationships, or * * Ternary.False if they are not related. */ - function isRelatedTo(originalSource: Type, originalTarget: Type, recursionFlags: RecursionFlags = RecursionFlags.Both, reportErrors = false, headMessage?: DiagnosticMessage, intersectionState = IntersectionState.None): Ternary { + function isRelatedTo( + originalSource: Type, + originalTarget: Type, + recursionFlags: RecursionFlags = RecursionFlags.Both, + reportErrors = false, + headMessage?: DiagnosticMessage, + intersectionState = IntersectionState.None + ): Ternary { if (originalSource === originalTarget) return Ternary.True; // Before normalization: if `source` is type an object type, and `target` is primitive, // skip all the checks we don't need and just return `isSimpleTypeRelatedTo` result - if (originalSource.flags & TypeFlags.Object && originalTarget.flags & TypeFlags.Primitive) { + if ( + originalSource.flags & TypeFlags.Object && + originalTarget.flags & TypeFlags.Primitive + ) { if ( - relation === comparableRelation && !(originalTarget.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(originalTarget, originalSource, relation) || - isSimpleTypeRelatedTo(originalSource, originalTarget, relation, reportErrors ? reportError : undefined) + (relation === comparableRelation && + !(originalTarget.flags & TypeFlags.Never) && + isSimpleTypeRelatedTo( + originalTarget, + originalSource, + relation + )) || + isSimpleTypeRelatedTo( + originalSource, + originalTarget, + relation, + reportErrors ? reportError : undefined + ) ) { return Ternary.True; } if (reportErrors) { - reportErrorResults(originalSource, originalTarget, originalSource, originalTarget, headMessage); + reportErrorResults( + originalSource, + originalTarget, + originalSource, + originalTarget, + headMessage + ); } return Ternary.False; } @@ -22642,7 +40050,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (source.flags !== target.flags) return Ternary.False; if (source.flags & TypeFlags.Singleton) return Ternary.True; traceUnionsOrIntersectionsTooLarge(source, target); - return recursiveTypeRelatedTo(source, target, /*reportErrors*/ false, IntersectionState.None, recursionFlags); + return recursiveTypeRelatedTo( + source, + target, + /*reportErrors*/ false, + IntersectionState.None, + recursionFlags + ); } // We fastpath comparing a type parameter to exactly its constraint, as this is _super_ common, @@ -22650,17 +40064,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // as we break down the _target_ union first, _then_ get the source constraint - so for every // member of the target, we attempt to find a match in the source. This avoids that in cases where // the target is exactly the constraint. - if (source.flags & TypeFlags.TypeParameter && getConstraintOfType(source) === target) { + if ( + source.flags & TypeFlags.TypeParameter && + getConstraintOfType(source) === target + ) { return Ternary.True; } // See if we're relating a definitely non-nullable type to a union that includes null and/or undefined // plus a single non-nullable type. If so, remove null and/or undefined from the target type. - if (source.flags & TypeFlags.DefinitelyNonNullable && target.flags & TypeFlags.Union) { + if ( + source.flags & TypeFlags.DefinitelyNonNullable && + target.flags & TypeFlags.Union + ) { const types = (target as UnionType).types; - const candidate = types.length === 2 && types[0].flags & TypeFlags.Nullable ? types[1] : - types.length === 3 && types[0].flags & TypeFlags.Nullable && types[1].flags & TypeFlags.Nullable ? types[2] : - undefined; + const candidate = + types.length === 2 && types[0].flags & TypeFlags.Nullable + ? types[1] + : types.length === 3 && + types[0].flags & TypeFlags.Nullable && + types[1].flags & TypeFlags.Nullable + ? types[2] + : undefined; if (candidate && !(candidate.flags & TypeFlags.Nullable)) { target = getNormalizedType(candidate, /*writing*/ true); if (source === target) return Ternary.True; @@ -22668,41 +40093,113 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if ( - relation === comparableRelation && !(target.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(target, source, relation) || - isSimpleTypeRelatedTo(source, target, relation, reportErrors ? reportError : undefined) - ) return Ternary.True; + (relation === comparableRelation && + !(target.flags & TypeFlags.Never) && + isSimpleTypeRelatedTo(target, source, relation)) || + isSimpleTypeRelatedTo( + source, + target, + relation, + reportErrors ? reportError : undefined + ) + ) + return Ternary.True; - if (source.flags & TypeFlags.StructuredOrInstantiable || target.flags & TypeFlags.StructuredOrInstantiable) { - const isPerformingExcessPropertyChecks = !(intersectionState & IntersectionState.Target) && (isObjectLiteralType(source) && getObjectFlags(source) & ObjectFlags.FreshLiteral); + if ( + source.flags & TypeFlags.StructuredOrInstantiable || + target.flags & TypeFlags.StructuredOrInstantiable + ) { + const isPerformingExcessPropertyChecks = + !(intersectionState & IntersectionState.Target) && + isObjectLiteralType(source) && + getObjectFlags(source) & ObjectFlags.FreshLiteral; if (isPerformingExcessPropertyChecks) { - if (hasExcessProperties(source as FreshObjectLiteralType, target, reportErrors)) { + if ( + hasExcessProperties( + source as FreshObjectLiteralType, + target, + reportErrors + ) + ) { if (reportErrors) { - reportRelationError(headMessage, source, originalTarget.aliasSymbol ? originalTarget : target); + reportRelationError( + headMessage, + source, + originalTarget.aliasSymbol + ? originalTarget + : target + ); } return Ternary.False; } } - const isPerformingCommonPropertyChecks = (relation !== comparableRelation || isUnitType(source)) && + const isPerformingCommonPropertyChecks = + (relation !== comparableRelation || isUnitType(source)) && !(intersectionState & IntersectionState.Target) && - source.flags & (TypeFlags.Primitive | TypeFlags.Object | TypeFlags.Intersection) && source !== globalObjectType && - target.flags & (TypeFlags.Object | TypeFlags.Intersection) && isWeakType(target) && - (getPropertiesOfType(source).length > 0 || typeHasCallOrConstructSignatures(source)); - const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes); - if (isPerformingCommonPropertyChecks && !hasCommonProperties(source, target, isComparingJsxAttributes)) { + source.flags & + (TypeFlags.Primitive | + TypeFlags.Object | + TypeFlags.Intersection) && + source !== globalObjectType && + target.flags & + (TypeFlags.Object | TypeFlags.Intersection) && + isWeakType(target) && + (getPropertiesOfType(source).length > 0 || + typeHasCallOrConstructSignatures(source)); + const isComparingJsxAttributes = !!( + getObjectFlags(source) & ObjectFlags.JsxAttributes + ); + if ( + isPerformingCommonPropertyChecks && + !hasCommonProperties( + source, + target, + isComparingJsxAttributes + ) + ) { if (reportErrors) { - const sourceString = typeToString(originalSource.aliasSymbol ? originalSource : source); - const targetString = typeToString(originalTarget.aliasSymbol ? originalTarget : target); - const calls = getSignaturesOfType(source, SignatureKind.Call); - const constructs = getSignaturesOfType(source, SignatureKind.Construct); + const sourceString = typeToString( + originalSource.aliasSymbol ? originalSource : source + ); + const targetString = typeToString( + originalTarget.aliasSymbol ? originalTarget : target + ); + const calls = getSignaturesOfType( + source, + SignatureKind.Call + ); + const constructs = getSignaturesOfType( + source, + SignatureKind.Construct + ); if ( - calls.length > 0 && isRelatedTo(getReturnTypeOfSignature(calls[0]), target, RecursionFlags.Source, /*reportErrors*/ false) || - constructs.length > 0 && isRelatedTo(getReturnTypeOfSignature(constructs[0]), target, RecursionFlags.Source, /*reportErrors*/ false) + (calls.length > 0 && + isRelatedTo( + getReturnTypeOfSignature(calls[0]), + target, + RecursionFlags.Source, + /*reportErrors*/ false + )) || + (constructs.length > 0 && + isRelatedTo( + getReturnTypeOfSignature(constructs[0]), + target, + RecursionFlags.Source, + /*reportErrors*/ false + )) ) { - reportError(Diagnostics.Value_of_type_0_has_no_properties_in_common_with_type_1_Did_you_mean_to_call_it, sourceString, targetString); - } - else { - reportError(Diagnostics.Type_0_has_no_properties_in_common_with_type_1, sourceString, targetString); + reportError( + Diagnostics.Value_of_type_0_has_no_properties_in_common_with_type_1_Did_you_mean_to_call_it, + sourceString, + targetString + ); + } else { + reportError( + Diagnostics.Type_0_has_no_properties_in_common_with_type_1, + sourceString, + targetString + ); } } return Ternary.False; @@ -22710,58 +40207,121 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { traceUnionsOrIntersectionsTooLarge(source, target); - const skipCaching = source.flags & TypeFlags.Union && (source as UnionType).types.length < 4 && !(target.flags & TypeFlags.Union) || - target.flags & TypeFlags.Union && (target as UnionType).types.length < 4 && !(source.flags & TypeFlags.StructuredOrInstantiable); - const result = skipCaching ? - unionOrIntersectionRelatedTo(source, target, reportErrors, intersectionState) : - recursiveTypeRelatedTo(source, target, reportErrors, intersectionState, recursionFlags); + const skipCaching = + (source.flags & TypeFlags.Union && + (source as UnionType).types.length < 4 && + !(target.flags & TypeFlags.Union)) || + (target.flags & TypeFlags.Union && + (target as UnionType).types.length < 4 && + !(source.flags & TypeFlags.StructuredOrInstantiable)); + const result = skipCaching + ? unionOrIntersectionRelatedTo( + source, + target, + reportErrors, + intersectionState + ) + : recursiveTypeRelatedTo( + source, + target, + reportErrors, + intersectionState, + recursionFlags + ); if (result) { return result; } } if (reportErrors) { - reportErrorResults(originalSource, originalTarget, source, target, headMessage); + reportErrorResults( + originalSource, + originalTarget, + source, + target, + headMessage + ); } return Ternary.False; } - function reportErrorResults(originalSource: Type, originalTarget: Type, source: Type, target: Type, headMessage: DiagnosticMessage | undefined) { - const sourceHasBase = !!getSingleBaseForNonAugmentingSubtype(originalSource); - const targetHasBase = !!getSingleBaseForNonAugmentingSubtype(originalTarget); - source = (originalSource.aliasSymbol || sourceHasBase) ? originalSource : source; - target = (originalTarget.aliasSymbol || targetHasBase) ? originalTarget : target; + function reportErrorResults( + originalSource: Type, + originalTarget: Type, + source: Type, + target: Type, + headMessage: DiagnosticMessage | undefined + ) { + const sourceHasBase = + !!getSingleBaseForNonAugmentingSubtype(originalSource); + const targetHasBase = + !!getSingleBaseForNonAugmentingSubtype(originalTarget); + source = + originalSource.aliasSymbol || sourceHasBase + ? originalSource + : source; + target = + originalTarget.aliasSymbol || targetHasBase + ? originalTarget + : target; let maybeSuppress = overrideNextErrorInfo > 0; if (maybeSuppress) { overrideNextErrorInfo--; } - if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) { + if ( + source.flags & TypeFlags.Object && + target.flags & TypeFlags.Object + ) { const currentError = errorInfo; - tryElaborateArrayLikeErrors(source, target, /*reportErrors*/ true); + tryElaborateArrayLikeErrors( + source, + target, + /*reportErrors*/ true + ); if (errorInfo !== currentError) { maybeSuppress = !!errorInfo; } } - if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Primitive) { + if ( + source.flags & TypeFlags.Object && + target.flags & TypeFlags.Primitive + ) { tryElaborateErrorsForPrimitivesAndObjects(source, target); - } - else if (source.symbol && source.flags & TypeFlags.Object && globalObjectType === source) { - reportError(Diagnostics.The_Object_type_is_assignable_to_very_few_other_types_Did_you_mean_to_use_the_any_type_instead); - } - else if (getObjectFlags(source) & ObjectFlags.JsxAttributes && target.flags & TypeFlags.Intersection) { + } else if ( + source.symbol && + source.flags & TypeFlags.Object && + globalObjectType === source + ) { + reportError( + Diagnostics.The_Object_type_is_assignable_to_very_few_other_types_Did_you_mean_to_use_the_any_type_instead + ); + } else if ( + getObjectFlags(source) & ObjectFlags.JsxAttributes && + target.flags & TypeFlags.Intersection + ) { const targetTypes = (target as IntersectionType).types; - const intrinsicAttributes = getJsxType(JsxNames.IntrinsicAttributes, errorNode); - const intrinsicClassAttributes = getJsxType(JsxNames.IntrinsicClassAttributes, errorNode); + const intrinsicAttributes = getJsxType( + JsxNames.IntrinsicAttributes, + errorNode + ); + const intrinsicClassAttributes = getJsxType( + JsxNames.IntrinsicClassAttributes, + errorNode + ); if ( - !isErrorType(intrinsicAttributes) && !isErrorType(intrinsicClassAttributes) && - (contains(targetTypes, intrinsicAttributes) || contains(targetTypes, intrinsicClassAttributes)) + !isErrorType(intrinsicAttributes) && + !isErrorType(intrinsicClassAttributes) && + (contains(targetTypes, intrinsicAttributes) || + contains(targetTypes, intrinsicClassAttributes)) ) { // do not report top error return; } - } - else { - errorInfo = elaborateNeverIntersection(errorInfo, originalTarget); + } else { + errorInfo = elaborateNeverIntersection( + errorInfo, + originalTarget + ); } // Used by, eg, missing property checking to replace the top-level message with a more informative one. if (!headMessage && maybeSuppress) { @@ -22772,7 +40332,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { reportRelationError(headMessage, source, target); let canonical; if (errorInfo && errorInfo !== savedErrorState.errorInfo) { - canonical = { code: errorInfo.code, messageText: errorInfo.messageText }; + canonical = { + code: errorInfo.code, + messageText: errorInfo.messageText, + }; } resetErrorInfo(savedErrorState); if (canonical && errorInfo) { @@ -22783,129 +40346,278 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return; } reportRelationError(headMessage, source, target); - if (source.flags & TypeFlags.TypeParameter && source.symbol?.declarations?.[0] && !getConstraintOfType(source as TypeVariable)) { - const syntheticParam = cloneTypeParameter(source as TypeParameter); - syntheticParam.constraint = instantiateType(target, makeUnaryTypeMapper(source, syntheticParam)); + if ( + source.flags & TypeFlags.TypeParameter && + source.symbol?.declarations?.[0] && + !getConstraintOfType(source as TypeVariable) + ) { + const syntheticParam = cloneTypeParameter( + source as TypeParameter + ); + syntheticParam.constraint = instantiateType( + target, + makeUnaryTypeMapper(source, syntheticParam) + ); if (hasNonCircularBaseConstraint(syntheticParam)) { - const targetConstraintString = typeToString(target, source.symbol.declarations[0]); - associateRelatedInfo(createDiagnosticForNode(source.symbol.declarations[0], Diagnostics.This_type_parameter_might_need_an_extends_0_constraint, targetConstraintString)); + const targetConstraintString = typeToString( + target, + source.symbol.declarations[0] + ); + associateRelatedInfo( + createDiagnosticForNode( + source.symbol.declarations[0], + Diagnostics.This_type_parameter_might_need_an_extends_0_constraint, + targetConstraintString + ) + ); } } } - function traceUnionsOrIntersectionsTooLarge(source: Type, target: Type): void { + function traceUnionsOrIntersectionsTooLarge( + source: Type, + target: Type + ): void { if (!tracing) { return; } - if ((source.flags & TypeFlags.UnionOrIntersection) && (target.flags & TypeFlags.UnionOrIntersection)) { - const sourceUnionOrIntersection = source as UnionOrIntersectionType; - const targetUnionOrIntersection = target as UnionOrIntersectionType; + if ( + source.flags & TypeFlags.UnionOrIntersection && + target.flags & TypeFlags.UnionOrIntersection + ) { + const sourceUnionOrIntersection = + source as UnionOrIntersectionType; + const targetUnionOrIntersection = + target as UnionOrIntersectionType; - if (sourceUnionOrIntersection.objectFlags & targetUnionOrIntersection.objectFlags & ObjectFlags.PrimitiveUnion) { + if ( + sourceUnionOrIntersection.objectFlags & + targetUnionOrIntersection.objectFlags & + ObjectFlags.PrimitiveUnion + ) { // There's a fast path for comparing primitive unions return; } const sourceSize = sourceUnionOrIntersection.types.length; const targetSize = targetUnionOrIntersection.types.length; - if (sourceSize * targetSize > 1E6) { - tracing.instant(tracing.Phase.CheckTypes, "traceUnionsOrIntersectionsTooLarge_DepthLimit", { - sourceId: source.id, - sourceSize, - targetId: target.id, - targetSize, - pos: errorNode?.pos, - end: errorNode?.end, - }); + if (sourceSize * targetSize > 1e6) { + tracing.instant( + tracing.Phase.CheckTypes, + "traceUnionsOrIntersectionsTooLarge_DepthLimit", + { + sourceId: source.id, + sourceSize, + targetId: target.id, + targetSize, + pos: errorNode?.pos, + end: errorNode?.end, + } + ); } } } function getTypeOfPropertyInTypes(types: Type[], name: __String) { - const appendPropType = (propTypes: Type[] | undefined, type: Type) => { + const appendPropType = ( + propTypes: Type[] | undefined, + type: Type + ) => { type = getApparentType(type); - const prop = type.flags & TypeFlags.UnionOrIntersection ? getPropertyOfUnionOrIntersectionType(type as UnionOrIntersectionType, name) : getPropertyOfObjectType(type, name); - const propType = prop && getTypeOfSymbol(prop) || getApplicableIndexInfoForName(type, name)?.type || undefinedType; + const prop = + type.flags & TypeFlags.UnionOrIntersection + ? getPropertyOfUnionOrIntersectionType( + type as UnionOrIntersectionType, + name + ) + : getPropertyOfObjectType(type, name); + const propType = + (prop && getTypeOfSymbol(prop)) || + getApplicableIndexInfoForName(type, name)?.type || + undefinedType; return append(propTypes, propType); }; - return getUnionType(reduceLeft(types, appendPropType, /*initial*/ undefined) || emptyArray); + return getUnionType( + reduceLeft(types, appendPropType, /*initial*/ undefined) || + emptyArray + ); } - function hasExcessProperties(source: FreshObjectLiteralType, target: Type, reportErrors: boolean): boolean { - if (!isExcessPropertyCheckTarget(target) || !noImplicitAny && getObjectFlags(target) & ObjectFlags.JSLiteral) { + function hasExcessProperties( + source: FreshObjectLiteralType, + target: Type, + reportErrors: boolean + ): boolean { + if ( + !isExcessPropertyCheckTarget(target) || + (!noImplicitAny && + getObjectFlags(target) & ObjectFlags.JSLiteral) + ) { return false; // Disable excess property checks on JS literals to simulate having an implicit "index signature" - but only outside of noImplicitAny } - const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes); + const isComparingJsxAttributes = !!( + getObjectFlags(source) & ObjectFlags.JsxAttributes + ); if ( - (relation === assignableRelation || relation === comparableRelation) && - (isTypeSubsetOf(globalObjectType, target) || (!isComparingJsxAttributes && isEmptyObjectType(target))) + (relation === assignableRelation || + relation === comparableRelation) && + (isTypeSubsetOf(globalObjectType, target) || + (!isComparingJsxAttributes && isEmptyObjectType(target))) ) { return false; } let reducedTarget = target; let checkTypes: Type[] | undefined; if (target.flags & TypeFlags.Union) { - reducedTarget = findMatchingDiscriminantType(source, target as UnionType, isRelatedTo) || filterPrimitivesIfContainsNonPrimitive(target as UnionType); - checkTypes = reducedTarget.flags & TypeFlags.Union ? (reducedTarget as UnionType).types : [reducedTarget]; + reducedTarget = + findMatchingDiscriminantType( + source, + target as UnionType, + isRelatedTo + ) || + filterPrimitivesIfContainsNonPrimitive(target as UnionType); + checkTypes = + reducedTarget.flags & TypeFlags.Union + ? (reducedTarget as UnionType).types + : [reducedTarget]; } for (const prop of getPropertiesOfType(source)) { - if (shouldCheckAsExcessProperty(prop, source.symbol) && !isIgnoredJsxProperty(source, prop)) { - if (!isKnownProperty(reducedTarget, prop.escapedName, isComparingJsxAttributes)) { + if ( + shouldCheckAsExcessProperty(prop, source.symbol) && + !isIgnoredJsxProperty(source, prop) + ) { + if ( + !isKnownProperty( + reducedTarget, + prop.escapedName, + isComparingJsxAttributes + ) + ) { if (reportErrors) { // Report error in terms of object types in the target as those are the only ones // we check in isKnownProperty. - const errorTarget = filterType(reducedTarget, isExcessPropertyCheckTarget); + const errorTarget = filterType( + reducedTarget, + isExcessPropertyCheckTarget + ); // We know *exactly* where things went wrong when comparing the types. // Use this property as the error node as this will be more helpful in // reasoning about what went wrong. if (!errorNode) return Debug.fail(); - if (isJsxAttributes(errorNode) || isJsxOpeningLikeElement(errorNode) || isJsxOpeningLikeElement(errorNode.parent)) { + if ( + isJsxAttributes(errorNode) || + isJsxOpeningLikeElement(errorNode) || + isJsxOpeningLikeElement(errorNode.parent) + ) { // JsxAttributes has an object-literal flag and undergo same type-assignablity check as normal object-literal. // However, using an object-literal error message will be very confusing to the users so we give different a message. - if (prop.valueDeclaration && isJsxAttribute(prop.valueDeclaration) && getSourceFileOfNode(errorNode) === getSourceFileOfNode(prop.valueDeclaration.name)) { + if ( + prop.valueDeclaration && + isJsxAttribute(prop.valueDeclaration) && + getSourceFileOfNode(errorNode) === + getSourceFileOfNode( + prop.valueDeclaration.name + ) + ) { // Note that extraneous children (as in `extra`) don't pass this check, // since `children` is a SyntaxKind.PropertySignature instead of a SyntaxKind.JsxAttribute. errorNode = prop.valueDeclaration.name; } const propName = symbolToString(prop); - const suggestionSymbol = getSuggestedSymbolForNonexistentJSXAttribute(propName, errorTarget); - const suggestion = suggestionSymbol ? symbolToString(suggestionSymbol) : undefined; + const suggestionSymbol = + getSuggestedSymbolForNonexistentJSXAttribute( + propName, + errorTarget + ); + const suggestion = suggestionSymbol + ? symbolToString(suggestionSymbol) + : undefined; if (suggestion) { - reportError(Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2, propName, typeToString(errorTarget), suggestion); - } - else { - reportError(Diagnostics.Property_0_does_not_exist_on_type_1, propName, typeToString(errorTarget)); + reportError( + Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2, + propName, + typeToString(errorTarget), + suggestion + ); + } else { + reportError( + Diagnostics.Property_0_does_not_exist_on_type_1, + propName, + typeToString(errorTarget) + ); } - } - else { + } else { // use the property's value declaration if the property is assigned inside the literal itself - const objectLiteralDeclaration = source.symbol?.declarations && firstOrUndefined(source.symbol.declarations); + const objectLiteralDeclaration = + source.symbol?.declarations && + firstOrUndefined( + source.symbol.declarations + ); let suggestion: string | undefined; - if (prop.valueDeclaration && findAncestor(prop.valueDeclaration, d => d === objectLiteralDeclaration) && getSourceFileOfNode(objectLiteralDeclaration) === getSourceFileOfNode(errorNode)) { - const propDeclaration = prop.valueDeclaration as ObjectLiteralElementLike; - Debug.assertNode(propDeclaration, isObjectLiteralElementLike); + if ( + prop.valueDeclaration && + findAncestor( + prop.valueDeclaration, + (d) => d === objectLiteralDeclaration + ) && + getSourceFileOfNode( + objectLiteralDeclaration + ) === getSourceFileOfNode(errorNode) + ) { + const propDeclaration = + prop.valueDeclaration as ObjectLiteralElementLike; + Debug.assertNode( + propDeclaration, + isObjectLiteralElementLike + ); const name = propDeclaration.name!; errorNode = name; if (isIdentifier(name)) { - suggestion = getSuggestionForNonexistentProperty(name, errorTarget); + suggestion = + getSuggestionForNonexistentProperty( + name, + errorTarget + ); } } if (suggestion !== undefined) { - reportParentSkippedError(Diagnostics.Object_literal_may_only_specify_known_properties_but_0_does_not_exist_in_type_1_Did_you_mean_to_write_2, symbolToString(prop), typeToString(errorTarget), suggestion); - } - else { - reportParentSkippedError(Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1, symbolToString(prop), typeToString(errorTarget)); + reportParentSkippedError( + Diagnostics.Object_literal_may_only_specify_known_properties_but_0_does_not_exist_in_type_1_Did_you_mean_to_write_2, + symbolToString(prop), + typeToString(errorTarget), + suggestion + ); + } else { + reportParentSkippedError( + Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1, + symbolToString(prop), + typeToString(errorTarget) + ); } } } return true; } - if (checkTypes && !isRelatedTo(getTypeOfSymbol(prop), getTypeOfPropertyInTypes(checkTypes, prop.escapedName), RecursionFlags.Both, reportErrors)) { + if ( + checkTypes && + !isRelatedTo( + getTypeOfSymbol(prop), + getTypeOfPropertyInTypes( + checkTypes, + prop.escapedName + ), + RecursionFlags.Both, + reportErrors + ) + ) { if (reportErrors) { - reportIncompatibleError(Diagnostics.Types_of_property_0_are_incompatible, symbolToString(prop)); + reportIncompatibleError( + Diagnostics.Types_of_property_0_are_incompatible, + symbolToString(prop) + ); } return true; } @@ -22915,10 +40627,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function shouldCheckAsExcessProperty(prop: Symbol, container: Symbol) { - return prop.valueDeclaration && container.valueDeclaration && prop.valueDeclaration.parent === container.valueDeclaration; + return ( + prop.valueDeclaration && + container.valueDeclaration && + prop.valueDeclaration.parent === container.valueDeclaration + ); } - function unionOrIntersectionRelatedTo(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function unionOrIntersectionRelatedTo( + source: Type, + target: Type, + reportErrors: boolean, + intersectionState: IntersectionState + ): Ternary { // Note that these checks are specifically ordered to produce correct results. In particular, // we need to deconstruct unions before intersections (because unions are always at the top), // and we need to handle "each" relations before "some" relations for the same kind of type. @@ -22929,41 +40650,97 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // originated in an intersection. If so, and if that intersection contains the target type, then we know // the result to be true (for any two types A and B, A & B is related to both A and B). const sourceOrigin = (source as UnionType).origin; - if (sourceOrigin && sourceOrigin.flags & TypeFlags.Intersection && target.aliasSymbol && contains((sourceOrigin as IntersectionType).types, target)) { + if ( + sourceOrigin && + sourceOrigin.flags & TypeFlags.Intersection && + target.aliasSymbol && + contains( + (sourceOrigin as IntersectionType).types, + target + ) + ) { return Ternary.True; } // Similarly, in unions of unions the we preserve the original list of unions. This original list is often // much shorter than the normalized result, so we scan it in the following fast path. const targetOrigin = (target as UnionType).origin; - if (targetOrigin && targetOrigin.flags & TypeFlags.Union && source.aliasSymbol && contains((targetOrigin as UnionType).types, source)) { + if ( + targetOrigin && + targetOrigin.flags & TypeFlags.Union && + source.aliasSymbol && + contains((targetOrigin as UnionType).types, source) + ) { return Ternary.True; } } - return relation === comparableRelation ? - someTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive), intersectionState) : - eachTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive), intersectionState); + return relation === comparableRelation + ? someTypeRelatedToType( + source as UnionType, + target, + reportErrors && !(source.flags & TypeFlags.Primitive), + intersectionState + ) + : eachTypeRelatedToType( + source as UnionType, + target, + reportErrors && !(source.flags & TypeFlags.Primitive), + intersectionState + ); } if (target.flags & TypeFlags.Union) { - return typeRelatedToSomeType(getRegularTypeOfObjectLiteral(source), target as UnionType, reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive), intersectionState); + return typeRelatedToSomeType( + getRegularTypeOfObjectLiteral(source), + target as UnionType, + reportErrors && + !(source.flags & TypeFlags.Primitive) && + !(target.flags & TypeFlags.Primitive), + intersectionState + ); } if (target.flags & TypeFlags.Intersection) { - return typeRelatedToEachType(source, target as IntersectionType, reportErrors, IntersectionState.Target); + return typeRelatedToEachType( + source, + target as IntersectionType, + reportErrors, + IntersectionState.Target + ); } // Source is an intersection. For the comparable relation, if the target is a primitive type we hoist the // constraints of all non-primitive types in the source into a new intersection. We do this because the // intersection may further constrain the constraints of the non-primitive types. For example, given a type // parameter 'T extends 1 | 2', the intersection 'T & 1' should be reduced to '1' such that it doesn't // appear to be comparable to '2'. - if (relation === comparableRelation && target.flags & TypeFlags.Primitive) { - const constraints = sameMap((source as IntersectionType).types, t => t.flags & TypeFlags.Instantiable ? getBaseConstraintOfType(t) || unknownType : t); + if ( + relation === comparableRelation && + target.flags & TypeFlags.Primitive + ) { + const constraints = sameMap( + (source as IntersectionType).types, + (t) => + t.flags & TypeFlags.Instantiable + ? getBaseConstraintOfType(t) || unknownType + : t + ); if (constraints !== (source as IntersectionType).types) { source = getIntersectionType(constraints); if (source.flags & TypeFlags.Never) { return Ternary.False; } if (!(source.flags & TypeFlags.Intersection)) { - return isRelatedTo(source, target, RecursionFlags.Source, /*reportErrors*/ false) || - isRelatedTo(target, source, RecursionFlags.Source, /*reportErrors*/ false); + return ( + isRelatedTo( + source, + target, + RecursionFlags.Source, + /*reportErrors*/ false + ) || + isRelatedTo( + target, + source, + RecursionFlags.Source, + /*reportErrors*/ false + ) + ); } } } @@ -22971,14 +40748,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Don't report errors though. Elaborating on whether a source constituent is related to the target is // not actually useful and leads to some confusing error messages. Instead, we rely on the caller // checking whether the full intersection viewed as an object is related to the target. - return someTypeRelatedToType(source as IntersectionType, target, /*reportErrors*/ false, IntersectionState.Source); + return someTypeRelatedToType( + source as IntersectionType, + target, + /*reportErrors*/ false, + IntersectionState.Source + ); } - function eachTypeRelatedToSomeType(source: UnionOrIntersectionType, target: UnionOrIntersectionType): Ternary { + function eachTypeRelatedToSomeType( + source: UnionOrIntersectionType, + target: UnionOrIntersectionType + ): Ternary { let result = Ternary.True; const sourceTypes = source.types; for (const sourceType of sourceTypes) { - const related = typeRelatedToSomeType(sourceType, target, /*reportErrors*/ false, IntersectionState.None); + const related = typeRelatedToSomeType( + sourceType, + target, + /*reportErrors*/ false, + IntersectionState.None + ); if (!related) { return Ternary.False; } @@ -22987,17 +40777,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function typeRelatedToSomeType(source: Type, target: UnionOrIntersectionType, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function typeRelatedToSomeType( + source: Type, + target: UnionOrIntersectionType, + reportErrors: boolean, + intersectionState: IntersectionState + ): Ternary { const targetTypes = target.types; if (target.flags & TypeFlags.Union) { if (containsType(targetTypes, source)) { return Ternary.True; } if ( - relation !== comparableRelation && getObjectFlags(target) & ObjectFlags.PrimitiveUnion && !(source.flags & TypeFlags.EnumLiteral) && ( - source.flags & (TypeFlags.StringLiteral | TypeFlags.BooleanLiteral | TypeFlags.BigIntLiteral) || - (relation === subtypeRelation || relation === strictSubtypeRelation) && source.flags & TypeFlags.NumberLiteral - ) + relation !== comparableRelation && + getObjectFlags(target) & ObjectFlags.PrimitiveUnion && + !(source.flags & TypeFlags.EnumLiteral) && + (source.flags & + (TypeFlags.StringLiteral | + TypeFlags.BooleanLiteral | + TypeFlags.BigIntLiteral) || + ((relation === subtypeRelation || + relation === strictSubtypeRelation) && + source.flags & TypeFlags.NumberLiteral)) ) { // When relating a literal type to a union of primitive types, we know the relation is false unless // the union contains the base primitive type or the literal type in one of its fresh/regular forms. @@ -23005,42 +40806,94 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // numeric enum literals with the same value. Similarly, we exclude enum literal types because // identically named enum types are related (see isEnumTypeRelatedTo). We exclude the comparable // relation in entirety because it needs to be checked in both directions. - const alternateForm = source === (source as StringLiteralType).regularType ? (source as StringLiteralType).freshType : (source as StringLiteralType).regularType; - const primitive = source.flags & TypeFlags.StringLiteral ? stringType : - source.flags & TypeFlags.NumberLiteral ? numberType : - source.flags & TypeFlags.BigIntLiteral ? bigintType : - undefined; - return primitive && containsType(targetTypes, primitive) || alternateForm && containsType(targetTypes, alternateForm) ? Ternary.True : Ternary.False; - } - const match = getMatchingUnionConstituentForType(target as UnionType, source); + const alternateForm = + source === (source as StringLiteralType).regularType + ? (source as StringLiteralType).freshType + : (source as StringLiteralType).regularType; + const primitive = + source.flags & TypeFlags.StringLiteral + ? stringType + : source.flags & TypeFlags.NumberLiteral + ? numberType + : source.flags & TypeFlags.BigIntLiteral + ? bigintType + : undefined; + return (primitive && + containsType(targetTypes, primitive)) || + (alternateForm && + containsType(targetTypes, alternateForm)) + ? Ternary.True + : Ternary.False; + } + const match = getMatchingUnionConstituentForType( + target as UnionType, + source + ); if (match) { - const related = isRelatedTo(source, match, RecursionFlags.Target, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState); + const related = isRelatedTo( + source, + match, + RecursionFlags.Target, + /*reportErrors*/ false, + /*headMessage*/ undefined, + intersectionState + ); if (related) { return related; } } } for (const type of targetTypes) { - const related = isRelatedTo(source, type, RecursionFlags.Target, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState); + const related = isRelatedTo( + source, + type, + RecursionFlags.Target, + /*reportErrors*/ false, + /*headMessage*/ undefined, + intersectionState + ); if (related) { return related; } } if (reportErrors) { // Elaborate only if we can find a best matching type in the target union - const bestMatchingType = getBestMatchingType(source, target, isRelatedTo); + const bestMatchingType = getBestMatchingType( + source, + target, + isRelatedTo + ); if (bestMatchingType) { - isRelatedTo(source, bestMatchingType, RecursionFlags.Target, /*reportErrors*/ true, /*headMessage*/ undefined, intersectionState); + isRelatedTo( + source, + bestMatchingType, + RecursionFlags.Target, + /*reportErrors*/ true, + /*headMessage*/ undefined, + intersectionState + ); } } return Ternary.False; } - function typeRelatedToEachType(source: Type, target: IntersectionType, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function typeRelatedToEachType( + source: Type, + target: IntersectionType, + reportErrors: boolean, + intersectionState: IntersectionState + ): Ternary { let result = Ternary.True; const targetTypes = target.types; for (const targetType of targetTypes) { - const related = isRelatedTo(source, targetType, RecursionFlags.Target, reportErrors, /*headMessage*/ undefined, intersectionState); + const related = isRelatedTo( + source, + targetType, + RecursionFlags.Target, + reportErrors, + /*headMessage*/ undefined, + intersectionState + ); if (!related) { return Ternary.False; } @@ -23049,14 +40902,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function someTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function someTypeRelatedToType( + source: UnionOrIntersectionType, + target: Type, + reportErrors: boolean, + intersectionState: IntersectionState + ): Ternary { const sourceTypes = source.types; - if (source.flags & TypeFlags.Union && containsType(sourceTypes, target)) { + if ( + source.flags & TypeFlags.Union && + containsType(sourceTypes, target) + ) { return Ternary.True; } const len = sourceTypes.length; for (let i = 0; i < len; i++) { - const related = isRelatedTo(sourceTypes[i], target, RecursionFlags.Source, reportErrors && i === len - 1, /*headMessage*/ undefined, intersectionState); + const related = isRelatedTo( + sourceTypes[i], + target, + RecursionFlags.Source, + reportErrors && i === len - 1, + /*headMessage*/ undefined, + intersectionState + ); if (related) { return related; } @@ -23064,37 +40932,75 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return Ternary.False; } - function getUndefinedStrippedTargetIfNeeded(source: Type, target: Type) { + function getUndefinedStrippedTargetIfNeeded( + source: Type, + target: Type + ) { if ( - source.flags & TypeFlags.Union && target.flags & TypeFlags.Union && - !((source as UnionType).types[0].flags & TypeFlags.Undefined) && (target as UnionType).types[0].flags & TypeFlags.Undefined + source.flags & TypeFlags.Union && + target.flags & TypeFlags.Union && + !((source as UnionType).types[0].flags & TypeFlags.Undefined) && + (target as UnionType).types[0].flags & TypeFlags.Undefined ) { return extractTypesOfKind(target, ~TypeFlags.Undefined); } return target; } - function eachTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function eachTypeRelatedToType( + source: UnionOrIntersectionType, + target: Type, + reportErrors: boolean, + intersectionState: IntersectionState + ): Ternary { let result = Ternary.True; const sourceTypes = source.types; // We strip `undefined` from the target if the `source` trivially doesn't contain it for our correspondence-checking fastpath // since `undefined` is frequently added by optionality and would otherwise spoil a potentially useful correspondence - const undefinedStrippedTarget = getUndefinedStrippedTargetIfNeeded(source, target as UnionType); + const undefinedStrippedTarget = getUndefinedStrippedTargetIfNeeded( + source, + target as UnionType + ); for (let i = 0; i < sourceTypes.length; i++) { const sourceType = sourceTypes[i]; - if (undefinedStrippedTarget.flags & TypeFlags.Union && sourceTypes.length >= (undefinedStrippedTarget as UnionType).types.length && sourceTypes.length % (undefinedStrippedTarget as UnionType).types.length === 0) { + if ( + undefinedStrippedTarget.flags & TypeFlags.Union && + sourceTypes.length >= + (undefinedStrippedTarget as UnionType).types.length && + sourceTypes.length % + (undefinedStrippedTarget as UnionType).types.length === + 0 + ) { // many unions are mappings of one another; in such cases, simply comparing members at the same index can shortcut the comparison // such unions will have identical lengths, and their corresponding elements will match up. Another common scenario is where a large // union has a union of objects intersected with it. In such cases, if the input was, eg `("a" | "b" | "c") & (string | boolean | {} | {whatever})`, // the result will have the structure `"a" | "b" | "c" | "a" & {} | "b" & {} | "c" & {} | "a" & {whatever} | "b" & {whatever} | "c" & {whatever}` // - 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 - const related = isRelatedTo(sourceType, (undefinedStrippedTarget as UnionType).types[i % (undefinedStrippedTarget as UnionType).types.length], RecursionFlags.Both, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState); + const related = isRelatedTo( + sourceType, + (undefinedStrippedTarget as UnionType).types[ + i % + (undefinedStrippedTarget as UnionType).types + .length + ], + RecursionFlags.Both, + /*reportErrors*/ false, + /*headMessage*/ undefined, + intersectionState + ); if (related) { result &= related; continue; } } - const related = isRelatedTo(sourceType, target, RecursionFlags.Source, reportErrors, /*headMessage*/ undefined, intersectionState); + const related = isRelatedTo( + sourceType, + target, + RecursionFlags.Source, + reportErrors, + /*headMessage*/ undefined, + intersectionState + ); if (!related) { return Ternary.False; } @@ -23103,17 +41009,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function typeArgumentsRelatedTo(sources: readonly Type[] = emptyArray, targets: readonly Type[] = emptyArray, variances: readonly VarianceFlags[] = emptyArray, reportErrors: boolean, intersectionState: IntersectionState): Ternary { - if (sources.length !== targets.length && relation === identityRelation) { + function typeArgumentsRelatedTo( + sources: readonly Type[] = emptyArray, + targets: readonly Type[] = emptyArray, + variances: readonly VarianceFlags[] = emptyArray, + reportErrors: boolean, + intersectionState: IntersectionState + ): Ternary { + if ( + sources.length !== targets.length && + relation === identityRelation + ) { return Ternary.False; } - const length = sources.length <= targets.length ? sources.length : targets.length; + const length = + sources.length <= targets.length + ? sources.length + : targets.length; let result = Ternary.True; for (let i = 0; i < length; i++) { // When variance information isn't available we default to covariance. This happens // in the process of computing variance information for recursive types and when // comparing 'this' type arguments. - const varianceFlags = i < variances.length ? variances[i] : VarianceFlags.Covariant; + const varianceFlags = + i < variances.length + ? variances[i] + : VarianceFlags.Covariant; const variance = varianceFlags & VarianceFlags.VarianceMask; // We ignore arguments for independent type parameters (because they're never witnessed). if (variance !== VarianceFlags.Independent) { @@ -23124,31 +41045,75 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Even an `Unmeasurable` variance works out without a structural check if the source and target are _identical_. // We can't simply assume invariance, because `Unmeasurable` marks nonlinear relations, for example, a relation tained by // the `-?` modifier in a mapped type (where, no matter how the inputs are related, the outputs still might not be) - related = relation === identityRelation ? isRelatedTo(s, t, RecursionFlags.Both, /*reportErrors*/ false) : compareTypesIdentical(s, t); - } - else if (variance === VarianceFlags.Covariant) { - related = isRelatedTo(s, t, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); - } - else if (variance === VarianceFlags.Contravariant) { - related = isRelatedTo(t, s, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); - } - else if (variance === VarianceFlags.Bivariant) { + related = + relation === identityRelation + ? isRelatedTo( + s, + t, + RecursionFlags.Both, + /*reportErrors*/ false + ) + : compareTypesIdentical(s, t); + } else if (variance === VarianceFlags.Covariant) { + related = isRelatedTo( + s, + t, + RecursionFlags.Both, + reportErrors, + /*headMessage*/ undefined, + intersectionState + ); + } else if (variance === VarianceFlags.Contravariant) { + related = isRelatedTo( + t, + s, + RecursionFlags.Both, + reportErrors, + /*headMessage*/ undefined, + intersectionState + ); + } else if (variance === VarianceFlags.Bivariant) { // In the bivariant case we first compare contravariantly without reporting // errors. Then, if that doesn't succeed, we compare covariantly with error // reporting. Thus, error elaboration will be based on the the covariant check, // which is generally easier to reason about. - related = isRelatedTo(t, s, RecursionFlags.Both, /*reportErrors*/ false); + related = isRelatedTo( + t, + s, + RecursionFlags.Both, + /*reportErrors*/ false + ); if (!related) { - related = isRelatedTo(s, t, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); + related = isRelatedTo( + s, + t, + RecursionFlags.Both, + reportErrors, + /*headMessage*/ undefined, + intersectionState + ); } - } - else { + } else { // In the invariant case we first compare covariantly, and only when that // succeeds do we proceed to compare contravariantly. Thus, error elaboration // will typically be based on the covariant check. - related = isRelatedTo(s, t, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); + related = isRelatedTo( + s, + t, + RecursionFlags.Both, + reportErrors, + /*headMessage*/ undefined, + intersectionState + ); if (related) { - related &= isRelatedTo(t, s, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); + related &= isRelatedTo( + t, + s, + RecursionFlags.Both, + reportErrors, + /*headMessage*/ undefined, + intersectionState + ); } } if (!related) { @@ -23165,36 +41130,66 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Third, check if both types are part of deeply nested chains of generic type instantiations and if so assume the types are // equal and infinitely expanding. Fourth, if we have reached a depth of 100 nested comparisons, assume we have runaway recursion // and issue an error. Otherwise, actually compare the structure of the two types. - function recursiveTypeRelatedTo(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState, recursionFlags: RecursionFlags): Ternary { + function recursiveTypeRelatedTo( + source: Type, + target: Type, + reportErrors: boolean, + intersectionState: IntersectionState, + recursionFlags: RecursionFlags + ): Ternary { if (overflow) { return Ternary.False; } - const id = getRelationKey(source, target, intersectionState, relation, /*ignoreConstraints*/ false); + const id = getRelationKey( + source, + target, + intersectionState, + relation, + /*ignoreConstraints*/ false + ); const entry = relation.get(id); if (entry !== undefined) { - if (reportErrors && entry & RelationComparisonResult.Failed && !(entry & RelationComparisonResult.Overflow)) { + if ( + reportErrors && + entry & RelationComparisonResult.Failed && + !(entry & RelationComparisonResult.Overflow) + ) { // We are elaborating errors and the cached result is a failure not due to a comparison overflow, // so we will do the comparison again to generate an error message. - } - else { + } else { if (outofbandVarianceMarkerHandler) { // We're in the middle of variance checking - integrate any unmeasurable/unreliable flags from this cached component - const saved = entry & RelationComparisonResult.ReportsMask; - if (saved & RelationComparisonResult.ReportsUnmeasurable) { + const saved = + entry & RelationComparisonResult.ReportsMask; + if ( + saved & RelationComparisonResult.ReportsUnmeasurable + ) { instantiateType(source, reportUnmeasurableMapper); } - if (saved & RelationComparisonResult.ReportsUnreliable) { + if ( + saved & RelationComparisonResult.ReportsUnreliable + ) { instantiateType(source, reportUnreliableMapper); } } - if (reportErrors && entry & RelationComparisonResult.Overflow) { - const message = entry & RelationComparisonResult.ComplexityOverflow ? - Diagnostics.Excessive_complexity_comparing_types_0_and_1 : - Diagnostics.Excessive_stack_depth_comparing_types_0_and_1; - reportError(message, typeToString(source), typeToString(target)); + if ( + reportErrors && + entry & RelationComparisonResult.Overflow + ) { + const message = + entry & RelationComparisonResult.ComplexityOverflow + ? Diagnostics.Excessive_complexity_comparing_types_0_and_1 + : Diagnostics.Excessive_stack_depth_comparing_types_0_and_1; + reportError( + message, + typeToString(source), + typeToString(target) + ); overrideNextErrorInfo++; } - return entry & RelationComparisonResult.Succeeded ? Ternary.True : Ternary.False; + return entry & RelationComparisonResult.Succeeded + ? Ternary.True + : Ternary.False; } } if (relationCount <= 0) { @@ -23206,8 +41201,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { maybeKeysSet = new Set(); sourceStack = []; targetStack = []; - } - else { + } else { // If source and target are already being compared, consider them related with assumptions if (maybeKeysSet.has(id)) { return Ternary.Maybe; @@ -23216,8 +41210,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // A key that starts with "*" is an indication that we have type references that reference constrained // type parameters. For such keys we also check against the key we would have gotten if all type parameters // were unconstrained. - const broadestEquivalentId = id.startsWith("*") ? getRelationKey(source, target, intersectionState, relation, /*ignoreConstraints*/ true) : undefined; - if (broadestEquivalentId && maybeKeysSet.has(broadestEquivalentId)) { + const broadestEquivalentId = id.startsWith("*") + ? getRelationKey( + source, + target, + intersectionState, + relation, + /*ignoreConstraints*/ true + ) + : undefined; + if ( + broadestEquivalentId && + maybeKeysSet.has(broadestEquivalentId) + ) { return Ternary.Maybe; } @@ -23234,38 +41239,60 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (recursionFlags & RecursionFlags.Source) { sourceStack[sourceDepth] = source; sourceDepth++; - if (!(expandingFlags & ExpandingFlags.Source) && isDeeplyNestedType(source, sourceStack, sourceDepth)) expandingFlags |= ExpandingFlags.Source; + if ( + !(expandingFlags & ExpandingFlags.Source) && + isDeeplyNestedType(source, sourceStack, sourceDepth) + ) + expandingFlags |= ExpandingFlags.Source; } if (recursionFlags & RecursionFlags.Target) { targetStack[targetDepth] = target; targetDepth++; - if (!(expandingFlags & ExpandingFlags.Target) && isDeeplyNestedType(target, targetStack, targetDepth)) expandingFlags |= ExpandingFlags.Target; + if ( + !(expandingFlags & ExpandingFlags.Target) && + isDeeplyNestedType(target, targetStack, targetDepth) + ) + expandingFlags |= ExpandingFlags.Target; } let originalHandler: typeof outofbandVarianceMarkerHandler; let propagatingVarianceFlags = 0 as RelationComparisonResult; if (outofbandVarianceMarkerHandler) { originalHandler = outofbandVarianceMarkerHandler; - outofbandVarianceMarkerHandler = onlyUnreliable => { - propagatingVarianceFlags |= onlyUnreliable ? RelationComparisonResult.ReportsUnreliable : RelationComparisonResult.ReportsUnmeasurable; + outofbandVarianceMarkerHandler = (onlyUnreliable) => { + propagatingVarianceFlags |= onlyUnreliable + ? RelationComparisonResult.ReportsUnreliable + : RelationComparisonResult.ReportsUnmeasurable; return originalHandler!(onlyUnreliable); }; } let result: Ternary; if (expandingFlags === ExpandingFlags.Both) { - tracing?.instant(tracing.Phase.CheckTypes, "recursiveTypeRelatedTo_DepthLimit", { - sourceId: source.id, - sourceIdStack: sourceStack.map(t => t.id), - targetId: target.id, - targetIdStack: targetStack.map(t => t.id), - depth: sourceDepth, - targetDepth, - }); + tracing?.instant( + tracing.Phase.CheckTypes, + "recursiveTypeRelatedTo_DepthLimit", + { + sourceId: source.id, + sourceIdStack: sourceStack.map((t) => t.id), + targetId: target.id, + targetIdStack: targetStack.map((t) => t.id), + depth: sourceDepth, + targetDepth, + } + ); result = Ternary.Maybe; - } - else { - tracing?.push(tracing.Phase.CheckTypes, "structuredTypeRelatedTo", { sourceId: source.id, targetId: target.id }); - result = structuredTypeRelatedTo(source, target, reportErrors, intersectionState); + } else { + tracing?.push( + tracing.Phase.CheckTypes, + "structuredTypeRelatedTo", + { sourceId: source.id, targetId: target.id } + ); + result = structuredTypeRelatedTo( + source, + target, + reportErrors, + intersectionState + ); tracing?.pop(); } @@ -23280,24 +41307,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } expandingFlags = saveExpandingFlags; if (result) { - if (result === Ternary.True || (sourceDepth === 0 && targetDepth === 0)) { + if ( + result === Ternary.True || + (sourceDepth === 0 && targetDepth === 0) + ) { if (result === Ternary.True || result === Ternary.Maybe) { // If result is definitely true, record all maybe keys as having succeeded. Also, record Ternary.Maybe // results as having succeeded once we reach depth 0, but never record Ternary.Unknown results. resetMaybeStack(/*markAllAsSucceeded*/ true); - } - else { + } else { resetMaybeStack(/*markAllAsSucceeded*/ false); } } // Note: it's intentional that we don't reset in the else case; // we leave them on the stack such that when we hit depth zero // above, we can report all of them as successful. - } - else { + } else { // A false result goes straight into global cache (when something is false under // assumptions it will also be false without assumptions) - relation.set(id, RelationComparisonResult.Failed | propagatingVarianceFlags); + relation.set( + id, + RelationComparisonResult.Failed | propagatingVarianceFlags + ); relationCount--; resetMaybeStack(/*markAllAsSucceeded*/ false); } @@ -23307,7 +41338,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (let i = maybeStart; i < maybeCount; i++) { maybeKeysSet.delete(maybeKeys[i]); if (markAllAsSucceeded) { - relation.set(maybeKeys[i], RelationComparisonResult.Succeeded | propagatingVarianceFlags); + relation.set( + maybeKeys[i], + RelationComparisonResult.Succeeded | + propagatingVarianceFlags + ); relationCount--; } } @@ -23315,9 +41350,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function structuredTypeRelatedTo(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function structuredTypeRelatedTo( + source: Type, + target: Type, + reportErrors: boolean, + intersectionState: IntersectionState + ): Ternary { const saveErrorInfo = captureErrorCalculationState(); - let result = structuredTypeRelatedToWorker(source, target, reportErrors, intersectionState, saveErrorInfo); + let result = structuredTypeRelatedToWorker( + source, + target, + reportErrors, + intersectionState, + saveErrorInfo + ); if (relation !== identityRelation) { // The combined constraint of an intersection type is the intersection of the constraints of // the constituents. When an intersection type contains instantiable types with union type @@ -23332,11 +41378,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // needs to have its constraint hoisted into an intersection with said type parameter, this way // the type param can be compared with itself in the target (with the influence of its constraint to match other parts) // For example, if `T extends 1 | 2` and `U extends 2 | 3` and we compare `T & U` to `T & U & (1 | 2 | 3)` - if (!result && (source.flags & TypeFlags.Intersection || source.flags & TypeFlags.TypeParameter && target.flags & TypeFlags.Union)) { - const constraint = getEffectiveConstraintOfIntersection(source.flags & TypeFlags.Intersection ? (source as IntersectionType).types : [source], !!(target.flags & TypeFlags.Union)); - if (constraint && everyType(constraint, c => c !== source)) { // Skip comparison if expansion contains the source itself + if ( + !result && + (source.flags & TypeFlags.Intersection || + (source.flags & TypeFlags.TypeParameter && + target.flags & TypeFlags.Union)) + ) { + const constraint = getEffectiveConstraintOfIntersection( + source.flags & TypeFlags.Intersection + ? (source as IntersectionType).types + : [source], + !!(target.flags & TypeFlags.Union) + ); + if ( + constraint && + everyType(constraint, (c) => c !== source) + ) { + // Skip comparison if expansion contains the source itself // TODO: Stack errors so we get a pyramid for the "normal" comparison above, _and_ a second for this - result = isRelatedTo(constraint, target, RecursionFlags.Source, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState); + result = isRelatedTo( + constraint, + target, + RecursionFlags.Source, + /*reportErrors*/ false, + /*headMessage*/ undefined, + intersectionState + ); } } // When the target is an intersection we need an extra property check in order to detect nested excess @@ -23349,12 +41416,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // let weak: { a?: { x?: number } } & { c?: string } = wrong; // Nested weak object type // if ( - result && !(intersectionState & IntersectionState.Target) && target.flags & TypeFlags.Intersection && - !isGenericObjectType(target) && source.flags & (TypeFlags.Object | TypeFlags.Intersection) + result && + !(intersectionState & IntersectionState.Target) && + target.flags & TypeFlags.Intersection && + !isGenericObjectType(target) && + source.flags & (TypeFlags.Object | TypeFlags.Intersection) ) { - result &= propertiesRelatedTo(source, target, reportErrors, /*excludedProperties*/ undefined, /*optionalsOnly*/ false, IntersectionState.None); - if (result && isObjectLiteralType(source) && getObjectFlags(source) & ObjectFlags.FreshLiteral) { - result &= indexSignaturesRelatedTo(source, target, /*sourceIsPrimitive*/ false, reportErrors, IntersectionState.None); + result &= propertiesRelatedTo( + source, + target, + reportErrors, + /*excludedProperties*/ undefined, + /*optionalsOnly*/ false, + IntersectionState.None + ); + if ( + result && + isObjectLiteralType(source) && + getObjectFlags(source) & ObjectFlags.FreshLiteral + ) { + result &= indexSignaturesRelatedTo( + source, + target, + /*sourceIsPrimitive*/ false, + reportErrors, + IntersectionState.None + ); } } // When the source is an intersection we need an extra check of any optional properties in the target to @@ -23365,11 +41452,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // } // else if ( - result && isNonGenericObjectType(target) && !isArrayOrTupleType(target) && - source.flags & TypeFlags.Intersection && getApparentType(source).flags & TypeFlags.StructuredType && - !some((source as IntersectionType).types, t => t === target || !!(getObjectFlags(t) & ObjectFlags.NonInferrableType)) + result && + isNonGenericObjectType(target) && + !isArrayOrTupleType(target) && + source.flags & TypeFlags.Intersection && + getApparentType(source).flags & TypeFlags.StructuredType && + !some( + (source as IntersectionType).types, + (t) => + t === target || + !!( + getObjectFlags(t) & + ObjectFlags.NonInferrableType + ) + ) ) { - result &= propertiesRelatedTo(source, target, reportErrors, /*excludedProperties*/ undefined, /*optionalsOnly*/ true, intersectionState); + result &= propertiesRelatedTo( + source, + target, + reportErrors, + /*excludedProperties*/ undefined, + /*optionalsOnly*/ true, + intersectionState + ); } } if (result) { @@ -23378,19 +41483,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function getApparentMappedTypeKeys(nameType: Type, targetType: MappedType) { - const modifiersType = getApparentType(getModifiersTypeFromMappedType(targetType)); + function getApparentMappedTypeKeys( + nameType: Type, + targetType: MappedType + ) { + const modifiersType = getApparentType( + getModifiersTypeFromMappedType(targetType) + ); const mappedKeys: Type[] = []; forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType( modifiersType, TypeFlags.StringOrNumberLiteralOrUnique, /*stringsOnly*/ false, - t => void mappedKeys.push(instantiateType(nameType, appendTypeMapping(targetType.mapper, getTypeParameterFromMappedType(targetType), t))), + (t) => + void mappedKeys.push( + instantiateType( + nameType, + appendTypeMapping( + targetType.mapper, + getTypeParameterFromMappedType(targetType), + t + ) + ) + ) ); return getUnionType(mappedKeys); } - function structuredTypeRelatedToWorker(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState, saveErrorInfo: ReturnType): Ternary { + function structuredTypeRelatedToWorker( + source: Type, + target: Type, + reportErrors: boolean, + intersectionState: IntersectionState, + saveErrorInfo: ReturnType + ): Ternary { let result: Ternary; let originalErrorInfo: DiagnosticMessageChain | undefined; let varianceCheckFailed = false; @@ -23399,28 +41525,92 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (relation === identityRelation) { // We've already checked that source.flags and target.flags are identical if (sourceFlags & TypeFlags.UnionOrIntersection) { - let result = eachTypeRelatedToSomeType(source as UnionOrIntersectionType, target as UnionOrIntersectionType); + let result = eachTypeRelatedToSomeType( + source as UnionOrIntersectionType, + target as UnionOrIntersectionType + ); if (result) { - result &= eachTypeRelatedToSomeType(target as UnionOrIntersectionType, source as UnionOrIntersectionType); + result &= eachTypeRelatedToSomeType( + target as UnionOrIntersectionType, + source as UnionOrIntersectionType + ); } return result; } if (sourceFlags & TypeFlags.Index) { - return isRelatedTo((source as IndexType).type, (target as IndexType).type, RecursionFlags.Both, /*reportErrors*/ false); + return isRelatedTo( + (source as IndexType).type, + (target as IndexType).type, + RecursionFlags.Both, + /*reportErrors*/ false + ); } if (sourceFlags & TypeFlags.IndexedAccess) { - if (result = isRelatedTo((source as IndexedAccessType).objectType, (target as IndexedAccessType).objectType, RecursionFlags.Both, /*reportErrors*/ false)) { - if (result &= isRelatedTo((source as IndexedAccessType).indexType, (target as IndexedAccessType).indexType, RecursionFlags.Both, /*reportErrors*/ false)) { + if ( + (result = isRelatedTo( + (source as IndexedAccessType).objectType, + (target as IndexedAccessType).objectType, + RecursionFlags.Both, + /*reportErrors*/ false + )) + ) { + if ( + (result &= isRelatedTo( + (source as IndexedAccessType).indexType, + (target as IndexedAccessType).indexType, + RecursionFlags.Both, + /*reportErrors*/ false + )) + ) { return result; } } } if (sourceFlags & TypeFlags.Conditional) { - if ((source as ConditionalType).root.isDistributive === (target as ConditionalType).root.isDistributive) { - if (result = isRelatedTo((source as ConditionalType).checkType, (target as ConditionalType).checkType, RecursionFlags.Both, /*reportErrors*/ false)) { - if (result &= isRelatedTo((source as ConditionalType).extendsType, (target as ConditionalType).extendsType, RecursionFlags.Both, /*reportErrors*/ false)) { - if (result &= isRelatedTo(getTrueTypeFromConditionalType(source as ConditionalType), getTrueTypeFromConditionalType(target as ConditionalType), RecursionFlags.Both, /*reportErrors*/ false)) { - if (result &= isRelatedTo(getFalseTypeFromConditionalType(source as ConditionalType), getFalseTypeFromConditionalType(target as ConditionalType), RecursionFlags.Both, /*reportErrors*/ false)) { + if ( + (source as ConditionalType).root.isDistributive === + (target as ConditionalType).root.isDistributive + ) { + if ( + (result = isRelatedTo( + (source as ConditionalType).checkType, + (target as ConditionalType).checkType, + RecursionFlags.Both, + /*reportErrors*/ false + )) + ) { + if ( + (result &= isRelatedTo( + (source as ConditionalType).extendsType, + (target as ConditionalType).extendsType, + RecursionFlags.Both, + /*reportErrors*/ false + )) + ) { + if ( + (result &= isRelatedTo( + getTrueTypeFromConditionalType( + source as ConditionalType + ), + getTrueTypeFromConditionalType( + target as ConditionalType + ), + RecursionFlags.Both, + /*reportErrors*/ false + )) + ) { + if ( + (result &= isRelatedTo( + getFalseTypeFromConditionalType( + source as ConditionalType + ), + getFalseTypeFromConditionalType( + target as ConditionalType + ), + RecursionFlags.Both, + /*reportErrors*/ false + )) + ) { return result; } } @@ -23429,19 +41619,47 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } if (sourceFlags & TypeFlags.Substitution) { - if (result = isRelatedTo((source as SubstitutionType).baseType, (target as SubstitutionType).baseType, RecursionFlags.Both, /*reportErrors*/ false)) { - if (result &= isRelatedTo((source as SubstitutionType).constraint, (target as SubstitutionType).constraint, RecursionFlags.Both, /*reportErrors*/ false)) { + if ( + (result = isRelatedTo( + (source as SubstitutionType).baseType, + (target as SubstitutionType).baseType, + RecursionFlags.Both, + /*reportErrors*/ false + )) + ) { + if ( + (result &= isRelatedTo( + (source as SubstitutionType).constraint, + (target as SubstitutionType).constraint, + RecursionFlags.Both, + /*reportErrors*/ false + )) + ) { return result; } } } if (sourceFlags & TypeFlags.TemplateLiteral) { - if (arrayIsEqualTo((source as TemplateLiteralType).texts, (target as TemplateLiteralType).texts)) { - const sourceTypes = (source as TemplateLiteralType).types; - const targetTypes = (target as TemplateLiteralType).types; + if ( + arrayIsEqualTo( + (source as TemplateLiteralType).texts, + (target as TemplateLiteralType).texts + ) + ) { + const sourceTypes = (source as TemplateLiteralType) + .types; + const targetTypes = (target as TemplateLiteralType) + .types; result = Ternary.True; for (let i = 0; i < sourceTypes.length; i++) { - if (!(result &= isRelatedTo(sourceTypes[i], targetTypes[i], RecursionFlags.Both, /*reportErrors*/ false))) { + if ( + !(result &= isRelatedTo( + sourceTypes[i], + targetTypes[i], + RecursionFlags.Both, + /*reportErrors*/ false + )) + ) { break; } } @@ -23449,16 +41667,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } if (sourceFlags & TypeFlags.StringMapping) { - if ((source as StringMappingType).symbol === (target as StringMappingType).symbol) { - return isRelatedTo((source as StringMappingType).type, (target as StringMappingType).type, RecursionFlags.Both, /*reportErrors*/ false); + if ( + (source as StringMappingType).symbol === + (target as StringMappingType).symbol + ) { + return isRelatedTo( + (source as StringMappingType).type, + (target as StringMappingType).type, + RecursionFlags.Both, + /*reportErrors*/ false + ); } } if (!(sourceFlags & TypeFlags.Object)) { return Ternary.False; } - } - else if (sourceFlags & TypeFlags.UnionOrIntersection || targetFlags & TypeFlags.UnionOrIntersection) { - if (result = unionOrIntersectionRelatedTo(source, target, reportErrors, intersectionState)) { + } else if ( + sourceFlags & TypeFlags.UnionOrIntersection || + targetFlags & TypeFlags.UnionOrIntersection + ) { + if ( + (result = unionOrIntersectionRelatedTo( + source, + target, + reportErrors, + intersectionState + )) + ) { return result; } // The ordered decomposition above doesn't handle all cases. Specifically, we also need to handle: @@ -23468,9 +41703,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Source is an intersection, target is a union (e.g. { a } & { b: boolean } <=> { a, b: true } | { a, b: false }). // Source is an intersection, target instantiable (e.g. string & { tag } <=> T["a"] constrained to string & { tag }). if ( - !(sourceFlags & TypeFlags.Instantiable || - sourceFlags & TypeFlags.Object && targetFlags & TypeFlags.Union || - sourceFlags & TypeFlags.Intersection && targetFlags & (TypeFlags.Object | TypeFlags.Union | TypeFlags.Instantiable)) + !( + sourceFlags & TypeFlags.Instantiable || + (sourceFlags & TypeFlags.Object && + targetFlags & TypeFlags.Union) || + (sourceFlags & TypeFlags.Intersection && + targetFlags & + (TypeFlags.Object | + TypeFlags.Union | + TypeFlags.Instantiable)) + ) ) { return Ternary.False; } @@ -23480,18 +41722,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // is more predictable than other, interned types, which may or may not have an alias depending on // the order in which things were checked. if ( - sourceFlags & (TypeFlags.Object | TypeFlags.Conditional) && source.aliasSymbol && source.aliasTypeArguments && - source.aliasSymbol === target.aliasSymbol && !(isMarkerType(source) || isMarkerType(target)) + sourceFlags & (TypeFlags.Object | TypeFlags.Conditional) && + source.aliasSymbol && + source.aliasTypeArguments && + source.aliasSymbol === target.aliasSymbol && + !(isMarkerType(source) || isMarkerType(target)) ) { const variances = getAliasVariances(source.aliasSymbol); if (variances === emptyArray) { return Ternary.Unknown; } - const params = getSymbolLinks(source.aliasSymbol).typeParameters!; + const params = getSymbolLinks(source.aliasSymbol) + .typeParameters!; const minParams = getMinTypeArgumentCount(params); - const sourceTypes = fillMissingTypeArguments(source.aliasTypeArguments, params, minParams, isInJSFile(source.aliasSymbol.valueDeclaration)); - const targetTypes = fillMissingTypeArguments(target.aliasTypeArguments, params, minParams, isInJSFile(source.aliasSymbol.valueDeclaration)); - const varianceResult = relateVariances(sourceTypes, targetTypes, variances, intersectionState); + const sourceTypes = fillMissingTypeArguments( + source.aliasTypeArguments, + params, + minParams, + isInJSFile(source.aliasSymbol.valueDeclaration) + ); + const targetTypes = fillMissingTypeArguments( + target.aliasTypeArguments, + params, + minParams, + isInJSFile(source.aliasSymbol.valueDeclaration) + ); + const varianceResult = relateVariances( + sourceTypes, + targetTypes, + variances, + intersectionState + ); if (varianceResult !== undefined) { return varianceResult; } @@ -23500,96 +41761,202 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // 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], // and U is assignable to [...T] when U is constrained to a mutable array or tuple type. if ( - isSingleElementGenericTupleType(source) && !source.target.readonly && (result = isRelatedTo(getTypeArguments(source)[0], target, RecursionFlags.Source)) || - isSingleElementGenericTupleType(target) && (target.target.readonly || isMutableArrayOrTuple(getBaseConstraintOfType(source) || source)) && (result = isRelatedTo(source, getTypeArguments(target)[0], RecursionFlags.Target)) + (isSingleElementGenericTupleType(source) && + !source.target.readonly && + (result = isRelatedTo( + getTypeArguments(source)[0], + target, + RecursionFlags.Source + ))) || + (isSingleElementGenericTupleType(target) && + (target.target.readonly || + isMutableArrayOrTuple( + getBaseConstraintOfType(source) || source + )) && + (result = isRelatedTo( + source, + getTypeArguments(target)[0], + RecursionFlags.Target + ))) ) { return result; } if (targetFlags & TypeFlags.TypeParameter) { // 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]. - if (getObjectFlags(source) & ObjectFlags.Mapped && !(source as MappedType).declaration.nameType && isRelatedTo(getIndexType(target), getConstraintTypeFromMappedType(source as MappedType), RecursionFlags.Both)) { - if (!(getMappedTypeModifiers(source as MappedType) & MappedTypeModifiers.IncludeOptional)) { - const templateType = getTemplateTypeFromMappedType(source as MappedType); - const indexedAccessType = getIndexedAccessType(target, getTypeParameterFromMappedType(source as MappedType)); - if (result = isRelatedTo(templateType, indexedAccessType, RecursionFlags.Both, reportErrors)) { + if ( + getObjectFlags(source) & ObjectFlags.Mapped && + !(source as MappedType).declaration.nameType && + isRelatedTo( + getIndexType(target), + getConstraintTypeFromMappedType(source as MappedType), + RecursionFlags.Both + ) + ) { + if ( + !( + getMappedTypeModifiers(source as MappedType) & + MappedTypeModifiers.IncludeOptional + ) + ) { + const templateType = getTemplateTypeFromMappedType( + source as MappedType + ); + const indexedAccessType = getIndexedAccessType( + target, + getTypeParameterFromMappedType(source as MappedType) + ); + if ( + (result = isRelatedTo( + templateType, + indexedAccessType, + RecursionFlags.Both, + reportErrors + )) + ) { return result; } } } - if (relation === comparableRelation && sourceFlags & TypeFlags.TypeParameter) { + if ( + relation === comparableRelation && + sourceFlags & TypeFlags.TypeParameter + ) { // This is a carve-out in comparability to essentially forbid comparing a type parameter // with another type parameter unless one extends the other. (Remember: comparability is mostly bidirectional!) let constraint = getConstraintOfTypeParameter(source); if (constraint) { - while (constraint && someType(constraint, c => !!(c.flags & TypeFlags.TypeParameter))) { - if (result = isRelatedTo(constraint, target, RecursionFlags.Source, /*reportErrors*/ false)) { + while ( + constraint && + someType( + constraint, + (c) => !!(c.flags & TypeFlags.TypeParameter) + ) + ) { + if ( + (result = isRelatedTo( + constraint, + target, + RecursionFlags.Source, + /*reportErrors*/ false + )) + ) { return result; } - constraint = getConstraintOfTypeParameter(constraint); + constraint = + getConstraintOfTypeParameter(constraint); } } return Ternary.False; } - } - else if (targetFlags & TypeFlags.Index) { + } else if (targetFlags & TypeFlags.Index) { const targetType = (target as IndexType).type; // A keyof S is related to a keyof T if T is related to S. if (sourceFlags & TypeFlags.Index) { - if (result = isRelatedTo(targetType, (source as IndexType).type, RecursionFlags.Both, /*reportErrors*/ false)) { + if ( + (result = isRelatedTo( + targetType, + (source as IndexType).type, + RecursionFlags.Both, + /*reportErrors*/ false + )) + ) { return result; } } if (isTupleType(targetType)) { // An index type can have a tuple type target when the tuple type contains variadic elements. // Check if the source is related to the known keys of the tuple type. - if (result = isRelatedTo(source, getKnownKeysOfTupleType(targetType), RecursionFlags.Target, reportErrors)) { + if ( + (result = isRelatedTo( + source, + getKnownKeysOfTupleType(targetType), + RecursionFlags.Target, + reportErrors + )) + ) { return result; } - } - else { + } else { // A type S is assignable to keyof T if S is assignable to keyof C, where C is the // simplified form of T or, if T doesn't simplify, the constraint of T. - const constraint = getSimplifiedTypeOrConstraint(targetType); + const constraint = + getSimplifiedTypeOrConstraint(targetType); if (constraint) { // We require Ternary.True here such that circular constraints don't cause // false positives. For example, given 'T extends { [K in keyof T]: string }', // 'keyof T' has itself as its constraint and produces a Ternary.Maybe when // related to other types. - if (isRelatedTo(source, getIndexType(constraint, (target as IndexType).indexFlags | IndexFlags.NoReducibleCheck), RecursionFlags.Target, reportErrors) === Ternary.True) { + if ( + isRelatedTo( + source, + getIndexType( + constraint, + (target as IndexType).indexFlags | + IndexFlags.NoReducibleCheck + ), + RecursionFlags.Target, + reportErrors + ) === Ternary.True + ) { return Ternary.True; } - } - else if (isGenericMappedType(targetType)) { + } else if (isGenericMappedType(targetType)) { // generic mapped types that don't simplify or have a constraint still have a very simple set of keys we can compare against // - their nameType or constraintType. // In many ways, this comparison is a deferred version of what `getIndexTypeForMappedType` does to actually resolve the keys for _non_-generic types const nameType = getNameTypeFromMappedType(targetType); - const constraintType = getConstraintTypeFromMappedType(targetType); + const constraintType = + getConstraintTypeFromMappedType(targetType); let targetKeys; - if (nameType && isMappedTypeWithKeyofConstraintDeclaration(targetType)) { + if ( + nameType && + isMappedTypeWithKeyofConstraintDeclaration( + targetType + ) + ) { // we need to get the apparent mappings and union them with the generic mappings, since some properties may be // missing from the `constraintType` which will otherwise be mapped in the object - const mappedKeys = getApparentMappedTypeKeys(nameType, targetType); + const mappedKeys = getApparentMappedTypeKeys( + nameType, + targetType + ); // 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) targetKeys = getUnionType([mappedKeys, nameType]); - } - else { + } else { targetKeys = nameType || constraintType; } - if (isRelatedTo(source, targetKeys, RecursionFlags.Target, reportErrors) === Ternary.True) { + if ( + isRelatedTo( + source, + targetKeys, + RecursionFlags.Target, + reportErrors + ) === Ternary.True + ) { return Ternary.True; } } } - } - else if (targetFlags & TypeFlags.IndexedAccess) { + } else if (targetFlags & TypeFlags.IndexedAccess) { if (sourceFlags & TypeFlags.IndexedAccess) { // Relate components directly before falling back to constraint relationships // A type S[K] is related to a type T[J] if S is related to T and K is related to J. - if (result = isRelatedTo((source as IndexedAccessType).objectType, (target as IndexedAccessType).objectType, RecursionFlags.Both, reportErrors)) { - result &= isRelatedTo((source as IndexedAccessType).indexType, (target as IndexedAccessType).indexType, RecursionFlags.Both, reportErrors); + if ( + (result = isRelatedTo( + (source as IndexedAccessType).objectType, + (target as IndexedAccessType).objectType, + RecursionFlags.Both, + reportErrors + )) + ) { + result &= isRelatedTo( + (source as IndexedAccessType).indexType, + (target as IndexedAccessType).indexType, + RecursionFlags.Both, + reportErrors + ); } if (result) { return result; @@ -23600,25 +41967,59 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // A type S is related to a type T[K] if S is related to C, where C is the base // constraint of T[K] for writing. - if (relation === assignableRelation || relation === comparableRelation) { + if ( + relation === assignableRelation || + relation === comparableRelation + ) { const objectType = (target as IndexedAccessType).objectType; const indexType = (target as IndexedAccessType).indexType; - const baseObjectType = getBaseConstraintOfType(objectType) || objectType; - const baseIndexType = getBaseConstraintOfType(indexType) || indexType; - if (!isGenericObjectType(baseObjectType) && !isGenericIndexType(baseIndexType)) { - const accessFlags = AccessFlags.Writing | (baseObjectType !== objectType ? AccessFlags.NoIndexSignatures : 0); - const constraint = getIndexedAccessTypeOrUndefined(baseObjectType, baseIndexType, accessFlags); + const baseObjectType = + getBaseConstraintOfType(objectType) || objectType; + const baseIndexType = + getBaseConstraintOfType(indexType) || indexType; + if ( + !isGenericObjectType(baseObjectType) && + !isGenericIndexType(baseIndexType) + ) { + const accessFlags = + AccessFlags.Writing | + (baseObjectType !== objectType + ? AccessFlags.NoIndexSignatures + : 0); + const constraint = getIndexedAccessTypeOrUndefined( + baseObjectType, + baseIndexType, + accessFlags + ); if (constraint) { if (reportErrors && originalErrorInfo) { // create a new chain for the constraint error resetErrorInfo(saveErrorInfo); } - if (result = isRelatedTo(source, constraint, RecursionFlags.Target, reportErrors, /*headMessage*/ undefined, intersectionState)) { + if ( + (result = isRelatedTo( + source, + constraint, + RecursionFlags.Target, + reportErrors, + /*headMessage*/ undefined, + intersectionState + )) + ) { return result; } // prefer the shorter chain of the constraint comparison chain, and the direct comparison chain - if (reportErrors && originalErrorInfo && errorInfo) { - errorInfo = countMessageChainBreadth([originalErrorInfo]) <= countMessageChainBreadth([errorInfo]) ? originalErrorInfo : errorInfo; + if ( + reportErrors && + originalErrorInfo && + errorInfo + ) { + errorInfo = + countMessageChainBreadth([ + originalErrorInfo, + ]) <= countMessageChainBreadth([errorInfo]) + ? originalErrorInfo + : errorInfo; } } } @@ -23626,8 +42027,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (reportErrors) { originalErrorInfo = undefined; } - } - else if (isGenericMappedType(target) && relation !== identityRelation) { + } else if ( + isGenericMappedType(target) && + relation !== identityRelation + ) { // Check if source type `S` is related to target type `{ [P in Q]: T }` or `{ [P in Q as R]: T}`. const keysRemapped = !!target.declaration.nameType; const templateType = getTemplateTypeFromMappedType(target); @@ -23636,40 +42039,77 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If the mapped type has shape `{ [P in Q]: T[P] }`, // source `S` is related to target if `T` = `S`, i.e. `S` is related to `{ [P in Q]: S[P] }`. if ( - !keysRemapped && templateType.flags & TypeFlags.IndexedAccess && (templateType as IndexedAccessType).objectType === source && - (templateType as IndexedAccessType).indexType === getTypeParameterFromMappedType(target) + !keysRemapped && + templateType.flags & TypeFlags.IndexedAccess && + (templateType as IndexedAccessType).objectType === + source && + (templateType as IndexedAccessType).indexType === + getTypeParameterFromMappedType(target) ) { return Ternary.True; } if (!isGenericMappedType(source)) { // If target has shape `{ [P in Q as R]: T}`, then its keys have type `R`. // If target has shape `{ [P in Q]: T }`, then its keys have type `Q`. - const targetKeys = keysRemapped ? getNameTypeFromMappedType(target)! : getConstraintTypeFromMappedType(target); + const targetKeys = keysRemapped + ? getNameTypeFromMappedType(target)! + : getConstraintTypeFromMappedType(target); // Type of the keys of source type `S`, i.e. `keyof S`. - const sourceKeys = getIndexType(source, IndexFlags.NoIndexSignatures); - const includeOptional = modifiers & MappedTypeModifiers.IncludeOptional; - const filteredByApplicability = includeOptional ? intersectTypes(targetKeys, sourceKeys) : undefined; + const sourceKeys = getIndexType( + source, + IndexFlags.NoIndexSignatures + ); + const includeOptional = + modifiers & MappedTypeModifiers.IncludeOptional; + const filteredByApplicability = includeOptional + ? intersectTypes(targetKeys, sourceKeys) + : undefined; // 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`. // 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. // 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`. // 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`. if ( includeOptional - ? !(filteredByApplicability!.flags & TypeFlags.Never) - : isRelatedTo(targetKeys, sourceKeys, RecursionFlags.Both) + ? !( + filteredByApplicability!.flags & + TypeFlags.Never + ) + : isRelatedTo( + targetKeys, + sourceKeys, + RecursionFlags.Both + ) ) { - const templateType = getTemplateTypeFromMappedType(target); - const typeParameter = getTypeParameterFromMappedType(target); + const templateType = + getTemplateTypeFromMappedType(target); + const typeParameter = + getTypeParameterFromMappedType(target); // Fastpath: When the template type has the form `Obj[P]` where `P` is the mapped type parameter, directly compare source `S` with `Obj` // to avoid creating the (potentially very large) number of new intermediate types made by manufacturing `S[P]`. - const nonNullComponent = extractTypesOfKind(templateType, ~TypeFlags.Nullable); - if (!keysRemapped && nonNullComponent.flags & TypeFlags.IndexedAccess && (nonNullComponent as IndexedAccessType).indexType === typeParameter) { - if (result = isRelatedTo(source, (nonNullComponent as IndexedAccessType).objectType, RecursionFlags.Target, reportErrors)) { + const nonNullComponent = extractTypesOfKind( + templateType, + ~TypeFlags.Nullable + ); + if ( + !keysRemapped && + nonNullComponent.flags & + TypeFlags.IndexedAccess && + (nonNullComponent as IndexedAccessType) + .indexType === typeParameter + ) { + if ( + (result = isRelatedTo( + source, + (nonNullComponent as IndexedAccessType) + .objectType, + RecursionFlags.Target, + reportErrors + )) + ) { return result; } - } - else { + } else { // 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, // so we need to construct an indexing type representing a property, and then use indexing type to index the source type for comparison. @@ -23680,13 +42120,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If the target type has shape `{ [P in Q as R]?: T }`, then a property of the target has type `R`, // but the property is optional, so we only want to compare properties `R` that are common between `keyof S` and `R`. const indexingType = keysRemapped - ? (filteredByApplicability || targetKeys) + ? filteredByApplicability || targetKeys : filteredByApplicability - ? getIntersectionType([filteredByApplicability, typeParameter]) + ? getIntersectionType([ + filteredByApplicability, + typeParameter, + ]) : typeParameter; - const indexedAccessType = getIndexedAccessType(source, indexingType); + const indexedAccessType = getIndexedAccessType( + source, + indexingType + ); // Compare `S[indexingType]` to `T`, where `T` is the type of a property of the target type. - if (result = isRelatedTo(indexedAccessType, templateType, RecursionFlags.Both, reportErrors)) { + if ( + (result = isRelatedTo( + indexedAccessType, + templateType, + RecursionFlags.Both, + reportErrors + )) + ) { return result; } } @@ -23695,8 +42148,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { resetErrorInfo(saveErrorInfo); } } - } - else if (targetFlags & TypeFlags.Conditional) { + } else if (targetFlags & TypeFlags.Conditional) { // If we reach 10 levels of nesting for the same conditional type, assume it is an infinitely expanding recursive // conditional type and bail out with a Ternary.Maybe result. if (isDeeplyNestedType(target, targetStack, targetDepth, 10)) { @@ -23707,33 +42159,76 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // 'infer' positions, is not distributive or is distributive but doesn't reference the check type // parameter in either of the result types, and the source isn't an instantiation of the same // conditional type (as happens when computing variance). - if (!c.root.inferTypeParameters && !isDistributionDependent(c.root) && !(source.flags & TypeFlags.Conditional && (source as ConditionalType).root === c.root)) { + if ( + !c.root.inferTypeParameters && + !isDistributionDependent(c.root) && + !( + source.flags & TypeFlags.Conditional && + (source as ConditionalType).root === c.root + ) + ) { // Check if the conditional is always true or always false but still deferred for distribution purposes. - const skipTrue = !isTypeAssignableTo(getPermissiveInstantiation(c.checkType), getPermissiveInstantiation(c.extendsType)); - const skipFalse = !skipTrue && isTypeAssignableTo(getRestrictiveInstantiation(c.checkType), getRestrictiveInstantiation(c.extendsType)); + const skipTrue = !isTypeAssignableTo( + getPermissiveInstantiation(c.checkType), + getPermissiveInstantiation(c.extendsType) + ); + const skipFalse = + !skipTrue && + isTypeAssignableTo( + getRestrictiveInstantiation(c.checkType), + getRestrictiveInstantiation(c.extendsType) + ); // TODO: Find a nice way to include potential conditional type breakdowns in error output, if they seem good (they usually don't) - if (result = skipTrue ? Ternary.True : isRelatedTo(source, getTrueTypeFromConditionalType(c), RecursionFlags.Target, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState)) { - result &= skipFalse ? Ternary.True : isRelatedTo(source, getFalseTypeFromConditionalType(c), RecursionFlags.Target, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState); + if ( + (result = skipTrue + ? Ternary.True + : isRelatedTo( + source, + getTrueTypeFromConditionalType(c), + RecursionFlags.Target, + /*reportErrors*/ false, + /*headMessage*/ undefined, + intersectionState + )) + ) { + result &= skipFalse + ? Ternary.True + : isRelatedTo( + source, + getFalseTypeFromConditionalType(c), + RecursionFlags.Target, + /*reportErrors*/ false, + /*headMessage*/ undefined, + intersectionState + ); if (result) { return result; } } } - } - else if (targetFlags & TypeFlags.TemplateLiteral) { + } else if (targetFlags & TypeFlags.TemplateLiteral) { if (sourceFlags & TypeFlags.TemplateLiteral) { if (relation === comparableRelation) { - return templateLiteralTypesDefinitelyUnrelated(source as TemplateLiteralType, target as TemplateLiteralType) ? Ternary.False : Ternary.True; + return templateLiteralTypesDefinitelyUnrelated( + source as TemplateLiteralType, + target as TemplateLiteralType + ) + ? Ternary.False + : Ternary.True; } // Report unreliable variance for type variables referenced in template literal type placeholders. // For example, `foo-${number}` is related to `foo-${string}` even though number isn't related to string. instantiateType(source, reportUnreliableMapper); } - if (isTypeMatchedByTemplateLiteralType(source, target as TemplateLiteralType)) { + if ( + isTypeMatchedByTemplateLiteralType( + source, + target as TemplateLiteralType + ) + ) { return Ternary.True; } - } - else if (target.flags & TypeFlags.StringMapping) { + } else if (target.flags & TypeFlags.StringMapping) { if (!(source.flags & TypeFlags.StringMapping)) { if (isMemberOfStringMapping(source, target)) { return Ternary.True; @@ -23743,31 +42238,87 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (sourceFlags & TypeFlags.TypeVariable) { // IndexedAccess comparisons are handled above in the `targetFlags & TypeFlage.IndexedAccess` branch - if (!(sourceFlags & TypeFlags.IndexedAccess && targetFlags & TypeFlags.IndexedAccess)) { - const constraint = getConstraintOfType(source as TypeVariable) || unknownType; + if ( + !( + sourceFlags & TypeFlags.IndexedAccess && + targetFlags & TypeFlags.IndexedAccess + ) + ) { + const constraint = + getConstraintOfType(source as TypeVariable) || + unknownType; // 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 - if (result = isRelatedTo(constraint, target, RecursionFlags.Source, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState)) { + if ( + (result = isRelatedTo( + constraint, + target, + RecursionFlags.Source, + /*reportErrors*/ false, + /*headMessage*/ undefined, + intersectionState + )) + ) { return result; } // slower, fuller, this-instantiated check (necessary when comparing raw `this` types from base classes), see `subclassWithPolymorphicThisIsAssignable.ts` test for example - else if (result = isRelatedTo(getTypeWithThisArgument(constraint, source), target, RecursionFlags.Source, reportErrors && constraint !== unknownType && !(targetFlags & sourceFlags & TypeFlags.TypeParameter), /*headMessage*/ undefined, intersectionState)) { + else if ( + (result = isRelatedTo( + getTypeWithThisArgument(constraint, source), + target, + RecursionFlags.Source, + reportErrors && + constraint !== unknownType && + !( + targetFlags & + sourceFlags & + TypeFlags.TypeParameter + ), + /*headMessage*/ undefined, + intersectionState + )) + ) { return result; } if (isMappedTypeGenericIndexedAccess(source)) { // For an indexed access type { [P in K]: E}[X], above we have already explored an instantiation of E with X // substituted for P. We also want to explore type { [P in K]: E }[C], where C is the constraint of X. - const indexConstraint = getConstraintOfType((source as IndexedAccessType).indexType); + const indexConstraint = getConstraintOfType( + (source as IndexedAccessType).indexType + ); if (indexConstraint) { - if (result = isRelatedTo(getIndexedAccessType((source as IndexedAccessType).objectType, indexConstraint), target, RecursionFlags.Source, reportErrors)) { + if ( + (result = isRelatedTo( + getIndexedAccessType( + (source as IndexedAccessType) + .objectType, + indexConstraint + ), + target, + RecursionFlags.Source, + reportErrors + )) + ) { return result; } } } } - } - else if (sourceFlags & TypeFlags.Index) { - const isDeferredMappedIndex = shouldDeferIndexType((source as IndexType).type, (source as IndexType).indexFlags) && getObjectFlags((source as IndexType).type) & ObjectFlags.Mapped; - if (result = isRelatedTo(stringNumberSymbolType, target, RecursionFlags.Source, reportErrors && !isDeferredMappedIndex)) { + } else if (sourceFlags & TypeFlags.Index) { + const isDeferredMappedIndex = + shouldDeferIndexType( + (source as IndexType).type, + (source as IndexType).indexFlags + ) && + getObjectFlags((source as IndexType).type) & + ObjectFlags.Mapped; + if ( + (result = isRelatedTo( + stringNumberSymbolType, + target, + RecursionFlags.Source, + reportErrors && !isDeferredMappedIndex + )) + ) { return result; } if (isDeferredMappedIndex) { @@ -23778,37 +42329,75 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // allow assignments of index types of identical (or similar enough) mapped types. // eg, `keyof {[X in keyof A]: Obj[X]}` should be assignable to `keyof {[Y in keyof A]: Tup[Y]}` because both map over the same set of keys (`keyof A`). // Without this source-side breakdown, a `keyof {[X in keyof A]: Obj[X]}` style type won't be assignable to anything except itself, which is much too strict. - const sourceMappedKeys = nameType && isMappedTypeWithKeyofConstraintDeclaration(mappedType) ? getApparentMappedTypeKeys(nameType, mappedType) : (nameType || getConstraintTypeFromMappedType(mappedType)); - if (result = isRelatedTo(sourceMappedKeys, target, RecursionFlags.Source, reportErrors)) { + const sourceMappedKeys = + nameType && + isMappedTypeWithKeyofConstraintDeclaration(mappedType) + ? getApparentMappedTypeKeys(nameType, mappedType) + : nameType || + getConstraintTypeFromMappedType(mappedType); + if ( + (result = isRelatedTo( + sourceMappedKeys, + target, + RecursionFlags.Source, + reportErrors + )) + ) { return result; } } - } - else if (sourceFlags & TypeFlags.TemplateLiteral && !(targetFlags & TypeFlags.Object)) { + } else if ( + sourceFlags & TypeFlags.TemplateLiteral && + !(targetFlags & TypeFlags.Object) + ) { if (!(targetFlags & TypeFlags.TemplateLiteral)) { const constraint = getBaseConstraintOfType(source); - if (constraint && constraint !== source && (result = isRelatedTo(constraint, target, RecursionFlags.Source, reportErrors))) { + if ( + constraint && + constraint !== source && + (result = isRelatedTo( + constraint, + target, + RecursionFlags.Source, + reportErrors + )) + ) { return result; } } - } - else if (sourceFlags & TypeFlags.StringMapping) { + } else if (sourceFlags & TypeFlags.StringMapping) { if (targetFlags & TypeFlags.StringMapping) { - if ((source as StringMappingType).symbol !== (target as StringMappingType).symbol) { + if ( + (source as StringMappingType).symbol !== + (target as StringMappingType).symbol + ) { return Ternary.False; } - if (result = isRelatedTo((source as StringMappingType).type, (target as StringMappingType).type, RecursionFlags.Both, reportErrors)) { + if ( + (result = isRelatedTo( + (source as StringMappingType).type, + (target as StringMappingType).type, + RecursionFlags.Both, + reportErrors + )) + ) { return result; } - } - else { + } else { const constraint = getBaseConstraintOfType(source); - if (constraint && (result = isRelatedTo(constraint, target, RecursionFlags.Source, reportErrors))) { + if ( + constraint && + (result = isRelatedTo( + constraint, + target, + RecursionFlags.Source, + reportErrors + )) + ) { return result; } } - } - else if (sourceFlags & TypeFlags.Conditional) { + } else if (sourceFlags & TypeFlags.Conditional) { // If we reach 10 levels of nesting for the same conditional type, assume it is an infinitely expanding recursive // conditional type and bail out with a Ternary.Maybe result. if (isDeeplyNestedType(source, sourceStack, sourceDepth, 10)) { @@ -23818,22 +42407,72 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Two conditional types 'T1 extends U1 ? X1 : Y1' and 'T2 extends U2 ? X2 : Y2' are related if // one of T1 and T2 is related to the other, U1 and U2 are identical types, X1 is related to X2, // and Y1 is related to Y2. - const sourceParams = (source as ConditionalType).root.inferTypeParameters; + const sourceParams = (source as ConditionalType).root + .inferTypeParameters; let sourceExtends = (source as ConditionalType).extendsType; let mapper: TypeMapper | undefined; if (sourceParams) { // If the source has infer type parameters, we instantiate them in the context of the target - const ctx = createInferenceContext(sourceParams, /*signature*/ undefined, InferenceFlags.None, isRelatedToWorker); - inferTypes(ctx.inferences, (target as ConditionalType).extendsType, sourceExtends, InferencePriority.NoConstraints | InferencePriority.AlwaysStrict); - sourceExtends = instantiateType(sourceExtends, ctx.mapper); + const ctx = createInferenceContext( + sourceParams, + /*signature*/ undefined, + InferenceFlags.None, + isRelatedToWorker + ); + inferTypes( + ctx.inferences, + (target as ConditionalType).extendsType, + sourceExtends, + InferencePriority.NoConstraints | + InferencePriority.AlwaysStrict + ); + sourceExtends = instantiateType( + sourceExtends, + ctx.mapper + ); mapper = ctx.mapper; } if ( - isTypeIdenticalTo(sourceExtends, (target as ConditionalType).extendsType) && - (isRelatedTo((source as ConditionalType).checkType, (target as ConditionalType).checkType, RecursionFlags.Both) || isRelatedTo((target as ConditionalType).checkType, (source as ConditionalType).checkType, RecursionFlags.Both)) + isTypeIdenticalTo( + sourceExtends, + (target as ConditionalType).extendsType + ) && + (isRelatedTo( + (source as ConditionalType).checkType, + (target as ConditionalType).checkType, + RecursionFlags.Both + ) || + isRelatedTo( + (target as ConditionalType).checkType, + (source as ConditionalType).checkType, + RecursionFlags.Both + )) ) { - if (result = isRelatedTo(instantiateType(getTrueTypeFromConditionalType(source as ConditionalType), mapper), getTrueTypeFromConditionalType(target as ConditionalType), RecursionFlags.Both, reportErrors)) { - result &= isRelatedTo(getFalseTypeFromConditionalType(source as ConditionalType), getFalseTypeFromConditionalType(target as ConditionalType), RecursionFlags.Both, reportErrors); + if ( + (result = isRelatedTo( + instantiateType( + getTrueTypeFromConditionalType( + source as ConditionalType + ), + mapper + ), + getTrueTypeFromConditionalType( + target as ConditionalType + ), + RecursionFlags.Both, + reportErrors + )) + ) { + result &= isRelatedTo( + getFalseTypeFromConditionalType( + source as ConditionalType + ), + getFalseTypeFromConditionalType( + target as ConditionalType + ), + RecursionFlags.Both, + reportErrors + ); } if (result) { return result; @@ -23842,30 +42481,62 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // conditionals can be related to one another via normal constraint, as, eg, `A extends B ? O : never` should be assignable to `O` // when `O` is a conditional (`never` is trivially assignable to `O`, as is `O`!). - const defaultConstraint = getDefaultConstraintOfConditionalType(source as ConditionalType); + const defaultConstraint = getDefaultConstraintOfConditionalType( + source as ConditionalType + ); if (defaultConstraint) { - if (result = isRelatedTo(defaultConstraint, target, RecursionFlags.Source, reportErrors)) { + if ( + (result = isRelatedTo( + defaultConstraint, + target, + RecursionFlags.Source, + reportErrors + )) + ) { return result; } } // conditionals aren't related to one another via distributive constraint as it is much too inaccurate and allows way // more assignments than are desirable (since it maps the source check type to its constraint, it loses information). - const distributiveConstraint = !(targetFlags & TypeFlags.Conditional) && hasNonCircularBaseConstraint(source) ? getConstraintOfDistributiveConditionalType(source as ConditionalType) : undefined; + const distributiveConstraint = + !(targetFlags & TypeFlags.Conditional) && + hasNonCircularBaseConstraint(source) + ? getConstraintOfDistributiveConditionalType( + source as ConditionalType + ) + : undefined; if (distributiveConstraint) { resetErrorInfo(saveErrorInfo); - if (result = isRelatedTo(distributiveConstraint, target, RecursionFlags.Source, reportErrors)) { + if ( + (result = isRelatedTo( + distributiveConstraint, + target, + RecursionFlags.Source, + reportErrors + )) + ) { return result; } } - } - else { + } else { // An empty object type is related to any mapped type that includes a '?' modifier. - if (relation !== subtypeRelation && relation !== strictSubtypeRelation && isPartialMappedType(target) && isEmptyObjectType(source)) { + if ( + relation !== subtypeRelation && + relation !== strictSubtypeRelation && + isPartialMappedType(target) && + isEmptyObjectType(source) + ) { return Ternary.True; } if (isGenericMappedType(target)) { if (isGenericMappedType(source)) { - if (result = mappedTypeRelatedTo(source, target, reportErrors)) { + if ( + (result = mappedTypeRelatedTo( + source, + target, + reportErrors + )) + ) { return result; } } @@ -23875,13 +42546,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (relation !== identityRelation) { source = getApparentType(source); sourceFlags = source.flags; - } - else if (isGenericMappedType(source)) { + } else if (isGenericMappedType(source)) { return Ternary.False; } if ( - getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source as TypeReference).target === (target as TypeReference).target && - !isTupleType(source) && !(isMarkerType(source) || isMarkerType(target)) + getObjectFlags(source) & ObjectFlags.Reference && + getObjectFlags(target) & ObjectFlags.Reference && + (source as TypeReference).target === + (target as TypeReference).target && + !isTupleType(source) && + !(isMarkerType(source) || isMarkerType(target)) ) { // When strictNullChecks is disabled, the element type of the empty array literal is undefinedWideningType, // and an empty array literal wouldn't be assignable to a `never[]` without this check. @@ -23891,37 +42565,69 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We have type references to the same generic type, and the type references are not marker // type references (which are intended by be compared structurally). Obtain the variance // information for the type parameters and relate the type arguments accordingly. - const variances = getVariances((source as TypeReference).target); + const variances = getVariances( + (source as TypeReference).target + ); // We return Ternary.Maybe for a recursive invocation of getVariances (signalled by emptyArray). This // effectively means we measure variance only from type parameter occurrences that aren't nested in // recursive instantiations of the generic type. if (variances === emptyArray) { return Ternary.Unknown; } - const varianceResult = relateVariances(getTypeArguments(source as TypeReference), getTypeArguments(target as TypeReference), variances, intersectionState); + const varianceResult = relateVariances( + getTypeArguments(source as TypeReference), + getTypeArguments(target as TypeReference), + variances, + intersectionState + ); if (varianceResult !== undefined) { return varianceResult; } - } - else if (isReadonlyArrayType(target) ? everyType(source, isArrayOrTupleType) : isArrayType(target) && everyType(source, t => isTupleType(t) && !t.target.readonly)) { + } else if ( + isReadonlyArrayType(target) + ? everyType(source, isArrayOrTupleType) + : isArrayType(target) && + everyType( + source, + (t) => isTupleType(t) && !t.target.readonly + ) + ) { if (relation !== identityRelation) { - return isRelatedTo(getIndexTypeOfType(source, numberType) || anyType, getIndexTypeOfType(target, numberType) || anyType, RecursionFlags.Both, reportErrors); - } - else { + return isRelatedTo( + getIndexTypeOfType(source, numberType) || anyType, + getIndexTypeOfType(target, numberType) || anyType, + RecursionFlags.Both, + reportErrors + ); + } else { // By flags alone, we know that the `target` is a readonly array while the source is a normal array or tuple // or `target` is an array and source is a tuple - in both cases the types cannot be identical, by construction return Ternary.False; } - } - else if (isGenericTupleType(source) && isTupleType(target) && !isGenericTupleType(target)) { + } else if ( + isGenericTupleType(source) && + isTupleType(target) && + !isGenericTupleType(target) + ) { const constraint = getBaseConstraintOrType(source); if (constraint !== source) { - return isRelatedTo(constraint, target, RecursionFlags.Source, reportErrors); + return isRelatedTo( + constraint, + target, + RecursionFlags.Source, + reportErrors + ); } } // A fresh empty object type is never a subtype of a non-empty object type. This ensures fresh({}) <: { [x: string]: xxx } // but not vice-versa. Without this rule, those types would be mutual subtypes. - else if ((relation === subtypeRelation || relation === strictSubtypeRelation) && isEmptyObjectType(target) && getObjectFlags(target) & ObjectFlags.FreshLiteral && !isEmptyObjectType(source)) { + else if ( + (relation === subtypeRelation || + relation === strictSubtypeRelation) && + isEmptyObjectType(target) && + getObjectFlags(target) & ObjectFlags.FreshLiteral && + !isEmptyObjectType(source) + ) { return Ternary.False; } // Even if relationship doesn't hold for unions, intersections, or generic type references, @@ -23929,23 +42635,56 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // In a check of the form X = A & B, we will have previously checked if A relates to X or B relates // to X. Failing both of those we want to check if the aggregation of A and B's members structurally // relates to X. Thus, we include intersection types on the source side here. - if (sourceFlags & (TypeFlags.Object | TypeFlags.Intersection) && targetFlags & TypeFlags.Object) { + if ( + sourceFlags & (TypeFlags.Object | TypeFlags.Intersection) && + targetFlags & TypeFlags.Object + ) { // Report structural errors only if we haven't reported any errors yet - const reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo.errorInfo && !sourceIsPrimitive; - result = propertiesRelatedTo(source, target, reportStructuralErrors, /*excludedProperties*/ undefined, /*optionalsOnly*/ false, intersectionState); + const reportStructuralErrors = + reportErrors && + errorInfo === saveErrorInfo.errorInfo && + !sourceIsPrimitive; + result = propertiesRelatedTo( + source, + target, + reportStructuralErrors, + /*excludedProperties*/ undefined, + /*optionalsOnly*/ false, + intersectionState + ); if (result) { - result &= signaturesRelatedTo(source, target, SignatureKind.Call, reportStructuralErrors, intersectionState); + result &= signaturesRelatedTo( + source, + target, + SignatureKind.Call, + reportStructuralErrors, + intersectionState + ); if (result) { - result &= signaturesRelatedTo(source, target, SignatureKind.Construct, reportStructuralErrors, intersectionState); + result &= signaturesRelatedTo( + source, + target, + SignatureKind.Construct, + reportStructuralErrors, + intersectionState + ); if (result) { - result &= indexSignaturesRelatedTo(source, target, sourceIsPrimitive, reportStructuralErrors, intersectionState); + result &= indexSignaturesRelatedTo( + source, + target, + sourceIsPrimitive, + reportStructuralErrors, + intersectionState + ); } } } if (varianceCheckFailed && result) { - errorInfo = originalErrorInfo || errorInfo || saveErrorInfo.errorInfo; // Use variance error (there is no structural one) and return false - } - else if (result) { + errorInfo = + originalErrorInfo || + errorInfo || + saveErrorInfo.errorInfo; // Use variance error (there is no structural one) and return false + } else if (result) { return result; } } @@ -23953,10 +42692,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // there exists a constituent of T for every combination of the discriminants of S // with respect to T. We do not report errors here, as we will use the existing // error result from checking each constituent of the union. - if (sourceFlags & (TypeFlags.Object | TypeFlags.Intersection) && targetFlags & TypeFlags.Union) { - const objectOnlyTarget = extractTypesOfKind(target, TypeFlags.Object | TypeFlags.Intersection | TypeFlags.Substitution); + if ( + sourceFlags & (TypeFlags.Object | TypeFlags.Intersection) && + targetFlags & TypeFlags.Union + ) { + const objectOnlyTarget = extractTypesOfKind( + target, + TypeFlags.Object | + TypeFlags.Intersection | + TypeFlags.Substitution + ); if (objectOnlyTarget.flags & TypeFlags.Union) { - const result = typeRelatedToDiscriminatedType(source, objectOnlyTarget as UnionType); + const result = typeRelatedToDiscriminatedType( + source, + objectOnlyTarget as UnionType + ); if (result) { return result; } @@ -23965,16 +42715,41 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } return Ternary.False; - function countMessageChainBreadth(info: DiagnosticMessageChain[] | undefined): number { + function countMessageChainBreadth( + info: DiagnosticMessageChain[] | undefined + ): number { if (!info) return 0; - return reduceLeft(info, (value, chain) => value + 1 + countMessageChainBreadth(chain.next), 0); + return reduceLeft( + info, + (value, chain) => + value + 1 + countMessageChainBreadth(chain.next), + 0 + ); } - function relateVariances(sourceTypeArguments: readonly Type[] | undefined, targetTypeArguments: readonly Type[] | undefined, variances: VarianceFlags[], intersectionState: IntersectionState) { - if (result = typeArgumentsRelatedTo(sourceTypeArguments, targetTypeArguments, variances, reportErrors, intersectionState)) { + function relateVariances( + sourceTypeArguments: readonly Type[] | undefined, + targetTypeArguments: readonly Type[] | undefined, + variances: VarianceFlags[], + intersectionState: IntersectionState + ) { + if ( + (result = typeArgumentsRelatedTo( + sourceTypeArguments, + targetTypeArguments, + variances, + reportErrors, + intersectionState + )) + ) { return result; } - if (some(variances, v => !!(v & VarianceFlags.AllowsStructuralFallback))) { + if ( + some( + variances, + (v) => !!(v & VarianceFlags.AllowsStructuralFallback) + ) + ) { // If some type parameter was `Unmeasurable` or `Unreliable`, and we couldn't pass by assuming it was identical, then we // have to allow a structural fallback check // We elide the variance-based error elaborations, since those might not be too helpful, since we'll potentially @@ -23983,7 +42758,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { resetErrorInfo(saveErrorInfo); return undefined; } - const allowStructuralFallback = targetTypeArguments && hasCovariantVoidArgument(targetTypeArguments, variances); + const allowStructuralFallback = + targetTypeArguments && + hasCovariantVoidArgument(targetTypeArguments, variances); varianceCheckFailed = !allowStructuralFallback; // The type arguments did not relate appropriately, but it may be because we have no variance // information (in which case typeArgumentsRelatedTo defaulted to covariance for all type @@ -24001,7 +42778,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // reveal the reason). // We can switch on `reportErrors` here, since varianceCheckFailed guarantees we return `False`, // we can return `False` early here to skip calculating the structural error message we don't need. - if (varianceCheckFailed && !(reportErrors && some(variances, v => (v & VarianceFlags.VarianceMask) === VarianceFlags.Invariant))) { + if ( + varianceCheckFailed && + !( + reportErrors && + some( + variances, + (v) => + (v & VarianceFlags.VarianceMask) === + VarianceFlags.Invariant + ) + ) + ) { return Ternary.False; } // We remember the original error information so we can restore it in case the structural @@ -24016,24 +42804,72 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // A type [P in S]: X is related to a type [Q in T]: Y if T is related to S and X' is // related to Y, where X' is an instantiation of X in which P is replaced with Q. Notice // that S and T are contra-variant whereas X and Y are co-variant. - function mappedTypeRelatedTo(source: MappedType, target: MappedType, reportErrors: boolean): Ternary { - const modifiersRelated = relation === comparableRelation || (relation === identityRelation ? getMappedTypeModifiers(source) === getMappedTypeModifiers(target) : - getCombinedMappedTypeOptionality(source) <= getCombinedMappedTypeOptionality(target)); + function mappedTypeRelatedTo( + source: MappedType, + target: MappedType, + reportErrors: boolean + ): Ternary { + const modifiersRelated = + relation === comparableRelation || + (relation === identityRelation + ? getMappedTypeModifiers(source) === + getMappedTypeModifiers(target) + : getCombinedMappedTypeOptionality(source) <= + getCombinedMappedTypeOptionality(target)); if (modifiersRelated) { let result: Ternary; - const targetConstraint = getConstraintTypeFromMappedType(target); - const sourceConstraint = instantiateType(getConstraintTypeFromMappedType(source), getCombinedMappedTypeOptionality(source) < 0 ? reportUnmeasurableMapper : reportUnreliableMapper); - if (result = isRelatedTo(targetConstraint, sourceConstraint, RecursionFlags.Both, reportErrors)) { - const mapper = createTypeMapper([getTypeParameterFromMappedType(source)], [getTypeParameterFromMappedType(target)]); - if (instantiateType(getNameTypeFromMappedType(source), mapper) === instantiateType(getNameTypeFromMappedType(target), mapper)) { - return result & isRelatedTo(instantiateType(getTemplateTypeFromMappedType(source), mapper), getTemplateTypeFromMappedType(target), RecursionFlags.Both, reportErrors); + const targetConstraint = + getConstraintTypeFromMappedType(target); + const sourceConstraint = instantiateType( + getConstraintTypeFromMappedType(source), + getCombinedMappedTypeOptionality(source) < 0 + ? reportUnmeasurableMapper + : reportUnreliableMapper + ); + if ( + (result = isRelatedTo( + targetConstraint, + sourceConstraint, + RecursionFlags.Both, + reportErrors + )) + ) { + const mapper = createTypeMapper( + [getTypeParameterFromMappedType(source)], + [getTypeParameterFromMappedType(target)] + ); + if ( + instantiateType( + getNameTypeFromMappedType(source), + mapper + ) === + instantiateType( + getNameTypeFromMappedType(target), + mapper + ) + ) { + return ( + result & + isRelatedTo( + instantiateType( + getTemplateTypeFromMappedType(source), + mapper + ), + getTemplateTypeFromMappedType(target), + RecursionFlags.Both, + reportErrors + ) + ); } } } return Ternary.False; } - function typeRelatedToDiscriminatedType(source: Type, target: UnionType) { + function typeRelatedToDiscriminatedType( + source: Type, + target: UnionType + ) { // 1. Generate the combinations of discriminant properties & types 'source' can satisfy. // a. If the number of combinations is above a set limit, the comparison is too complex. // 2. Filter 'target' to the subset of types whose discriminants exist in the matrix. @@ -24045,7 +42881,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // for examples. const sourceProperties = getPropertiesOfType(source); - const sourcePropertiesFiltered = findDiscriminantProperties(sourceProperties, target); + const sourcePropertiesFiltered = findDiscriminantProperties( + sourceProperties, + target + ); if (!sourcePropertiesFiltered) return Ternary.False; // Though we could compute the number of combinations as we generate @@ -24055,41 +42894,69 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // fixed limit before incurring the cost of any allocations: let numCombinations = 1; for (const sourceProperty of sourcePropertiesFiltered) { - numCombinations *= countTypes(getNonMissingTypeOfSymbol(sourceProperty)); + numCombinations *= countTypes( + getNonMissingTypeOfSymbol(sourceProperty) + ); if (numCombinations > 25) { // We've reached the complexity limit. - tracing?.instant(tracing.Phase.CheckTypes, "typeRelatedToDiscriminatedType_DepthLimit", { sourceId: source.id, targetId: target.id, numCombinations }); + tracing?.instant( + tracing.Phase.CheckTypes, + "typeRelatedToDiscriminatedType_DepthLimit", + { + sourceId: source.id, + targetId: target.id, + numCombinations, + } + ); return Ternary.False; } } // Compute the set of types for each discriminant property. - const sourceDiscriminantTypes: Type[][] = new Array(sourcePropertiesFiltered.length); + const sourceDiscriminantTypes: Type[][] = new Array( + sourcePropertiesFiltered.length + ); const excludedProperties = new Set<__String>(); for (let i = 0; i < sourcePropertiesFiltered.length; i++) { const sourceProperty = sourcePropertiesFiltered[i]; - const sourcePropertyType = getNonMissingTypeOfSymbol(sourceProperty); - sourceDiscriminantTypes[i] = sourcePropertyType.flags & TypeFlags.Union - ? (sourcePropertyType as UnionType).types - : [sourcePropertyType]; + const sourcePropertyType = + getNonMissingTypeOfSymbol(sourceProperty); + sourceDiscriminantTypes[i] = + sourcePropertyType.flags & TypeFlags.Union + ? (sourcePropertyType as UnionType).types + : [sourcePropertyType]; excludedProperties.add(sourceProperty.escapedName); } // Match each combination of the cartesian product of discriminant properties to one or more // constituents of 'target'. If any combination does not have a match then 'source' is not relatable. - const discriminantCombinations = cartesianProduct(sourceDiscriminantTypes); + const discriminantCombinations = cartesianProduct( + sourceDiscriminantTypes + ); const matchingTypes: Type[] = []; for (const combination of discriminantCombinations) { let hasMatch = false; - outer: - for (const type of target.types) { + outer: for (const type of target.types) { for (let i = 0; i < sourcePropertiesFiltered.length; i++) { const sourceProperty = sourcePropertiesFiltered[i]; - const targetProperty = getPropertyOfType(type, sourceProperty.escapedName); + const targetProperty = getPropertyOfType( + type, + sourceProperty.escapedName + ); if (!targetProperty) continue outer; if (sourceProperty === targetProperty) continue; // We compare the source property to the target in the context of a single discriminant type. - const related = propertyRelatedTo(source, target, sourceProperty, targetProperty, _ => combination[i], /*reportErrors*/ false, IntersectionState.None, /*skipOptional*/ strictNullChecks || relation === comparableRelation); + const related = propertyRelatedTo( + source, + target, + sourceProperty, + targetProperty, + (_) => combination[i], + /*reportErrors*/ false, + IntersectionState.None, + /*skipOptional*/ strictNullChecks || + relation === comparableRelation + ); // If the target property could not be found, or if the properties were not related, // then this constituent is not a match. if (!related) { @@ -24108,17 +42975,45 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Compare the remaining non-discriminant properties of each match. let result = Ternary.True; for (const type of matchingTypes) { - result &= propertiesRelatedTo(source, type, /*reportErrors*/ false, excludedProperties, /*optionalsOnly*/ false, IntersectionState.None); + result &= propertiesRelatedTo( + source, + type, + /*reportErrors*/ false, + excludedProperties, + /*optionalsOnly*/ false, + IntersectionState.None + ); if (result) { - result &= signaturesRelatedTo(source, type, SignatureKind.Call, /*reportErrors*/ false, IntersectionState.None); + result &= signaturesRelatedTo( + source, + type, + SignatureKind.Call, + /*reportErrors*/ false, + IntersectionState.None + ); if (result) { - result &= signaturesRelatedTo(source, type, SignatureKind.Construct, /*reportErrors*/ false, IntersectionState.None); - if (result && !(isTupleType(source) && isTupleType(type))) { + result &= signaturesRelatedTo( + source, + type, + SignatureKind.Construct, + /*reportErrors*/ false, + IntersectionState.None + ); + if ( + result && + !(isTupleType(source) && isTupleType(type)) + ) { // Comparing numeric index types when both `source` and `type` are tuples is unnecessary as the // element types should be sufficiently covered by `propertiesRelatedTo`. It also causes problems // with index type assignability as the types for the excluded discriminants are still included // in the index type. - result &= indexSignaturesRelatedTo(source, type, /*sourceIsPrimitive*/ false, /*reportErrors*/ false, IntersectionState.None); + result &= indexSignaturesRelatedTo( + source, + type, + /*sourceIsPrimitive*/ false, + /*reportErrors*/ false, + IntersectionState.None + ); } } } @@ -24129,60 +43024,133 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function excludeProperties(properties: Symbol[], excludedProperties: Set<__String> | undefined) { - if (!excludedProperties || properties.length === 0) return properties; + function excludeProperties( + properties: Symbol[], + excludedProperties: Set<__String> | undefined + ) { + if (!excludedProperties || properties.length === 0) + return properties; let result: Symbol[] | undefined; for (let i = 0; i < properties.length; i++) { if (!excludedProperties.has(properties[i].escapedName)) { if (result) { result.push(properties[i]); } - } - else if (!result) { + } else if (!result) { result = properties.slice(0, i); } } return result || properties; } - function isPropertySymbolTypeRelated(sourceProp: Symbol, targetProp: Symbol, getTypeOfSourceProperty: (sym: Symbol) => Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary { - const targetIsOptional = strictNullChecks && !!(getCheckFlags(targetProp) & CheckFlags.Partial); - const effectiveTarget = addOptionality(getNonMissingTypeOfSymbol(targetProp), /*isProperty*/ false, targetIsOptional); + function isPropertySymbolTypeRelated( + sourceProp: Symbol, + targetProp: Symbol, + getTypeOfSourceProperty: (sym: Symbol) => Type, + reportErrors: boolean, + intersectionState: IntersectionState + ): Ternary { + const targetIsOptional = + strictNullChecks && + !!(getCheckFlags(targetProp) & CheckFlags.Partial); + const effectiveTarget = addOptionality( + getNonMissingTypeOfSymbol(targetProp), + /*isProperty*/ false, + targetIsOptional + ); // source could resolve to `any` and that's not related to `unknown` target under strict subtype relation - if (effectiveTarget.flags & (relation === strictSubtypeRelation ? TypeFlags.Any : TypeFlags.AnyOrUnknown)) { + if ( + effectiveTarget.flags & + (relation === strictSubtypeRelation + ? TypeFlags.Any + : TypeFlags.AnyOrUnknown) + ) { return Ternary.True; } const effectiveSource = getTypeOfSourceProperty(sourceProp); - return isRelatedTo(effectiveSource, effectiveTarget, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); + return isRelatedTo( + effectiveSource, + effectiveTarget, + RecursionFlags.Both, + reportErrors, + /*headMessage*/ undefined, + intersectionState + ); } - function propertyRelatedTo(source: Type, target: Type, sourceProp: Symbol, targetProp: Symbol, getTypeOfSourceProperty: (sym: Symbol) => Type, reportErrors: boolean, intersectionState: IntersectionState, skipOptional: boolean): Ternary { - const sourcePropFlags = getDeclarationModifierFlagsFromSymbol(sourceProp); - const targetPropFlags = getDeclarationModifierFlagsFromSymbol(targetProp); - if (sourcePropFlags & ModifierFlags.Private || targetPropFlags & ModifierFlags.Private) { - if (sourceProp.valueDeclaration !== targetProp.valueDeclaration) { + function propertyRelatedTo( + source: Type, + target: Type, + sourceProp: Symbol, + targetProp: Symbol, + getTypeOfSourceProperty: (sym: Symbol) => Type, + reportErrors: boolean, + intersectionState: IntersectionState, + skipOptional: boolean + ): Ternary { + const sourcePropFlags = + getDeclarationModifierFlagsFromSymbol(sourceProp); + const targetPropFlags = + getDeclarationModifierFlagsFromSymbol(targetProp); + if ( + sourcePropFlags & ModifierFlags.Private || + targetPropFlags & ModifierFlags.Private + ) { + if ( + sourceProp.valueDeclaration !== targetProp.valueDeclaration + ) { if (reportErrors) { - if (sourcePropFlags & ModifierFlags.Private && targetPropFlags & ModifierFlags.Private) { - reportError(Diagnostics.Types_have_separate_declarations_of_a_private_property_0, symbolToString(targetProp)); - } - else { - reportError(Diagnostics.Property_0_is_private_in_type_1_but_not_in_type_2, symbolToString(targetProp), typeToString(sourcePropFlags & ModifierFlags.Private ? source : target), typeToString(sourcePropFlags & ModifierFlags.Private ? target : source)); + if ( + sourcePropFlags & ModifierFlags.Private && + targetPropFlags & ModifierFlags.Private + ) { + reportError( + Diagnostics.Types_have_separate_declarations_of_a_private_property_0, + symbolToString(targetProp) + ); + } else { + reportError( + Diagnostics.Property_0_is_private_in_type_1_but_not_in_type_2, + symbolToString(targetProp), + typeToString( + sourcePropFlags & ModifierFlags.Private + ? source + : target + ), + typeToString( + sourcePropFlags & ModifierFlags.Private + ? target + : source + ) + ); } } return Ternary.False; } - } - else if (targetPropFlags & ModifierFlags.Protected) { + } else if (targetPropFlags & ModifierFlags.Protected) { if (!isValidOverrideOf(sourceProp, targetProp)) { if (reportErrors) { - reportError(Diagnostics.Property_0_is_protected_but_type_1_is_not_a_class_derived_from_2, symbolToString(targetProp), typeToString(getDeclaringClass(sourceProp) || source), typeToString(getDeclaringClass(targetProp) || target)); + reportError( + Diagnostics.Property_0_is_protected_but_type_1_is_not_a_class_derived_from_2, + symbolToString(targetProp), + typeToString( + getDeclaringClass(sourceProp) || source + ), + typeToString( + getDeclaringClass(targetProp) || target + ) + ); } return Ternary.False; } - } - else if (sourcePropFlags & ModifierFlags.Protected) { + } else if (sourcePropFlags & ModifierFlags.Protected) { if (reportErrors) { - reportError(Diagnostics.Property_0_is_protected_in_type_1_but_public_in_type_2, symbolToString(targetProp), typeToString(source), typeToString(target)); + reportError( + Diagnostics.Property_0_is_protected_in_type_1_but_public_in_type_2, + symbolToString(targetProp), + typeToString(source), + typeToString(target) + ); } return Ternary.False; } @@ -24195,20 +43163,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // This is only applied during the strictSubtypeRelation -- currently used in subtype reduction if ( relation === strictSubtypeRelation && - isReadonlySymbol(sourceProp) && !isReadonlySymbol(targetProp) + isReadonlySymbol(sourceProp) && + !isReadonlySymbol(targetProp) ) { return Ternary.False; } // If the target comes from a partial union prop, allow `undefined` in the target type - const related = isPropertySymbolTypeRelated(sourceProp, targetProp, getTypeOfSourceProperty, reportErrors, intersectionState); + const related = isPropertySymbolTypeRelated( + sourceProp, + targetProp, + getTypeOfSourceProperty, + reportErrors, + intersectionState + ); if (!related) { if (reportErrors) { - reportIncompatibleError(Diagnostics.Types_of_property_0_are_incompatible, symbolToString(targetProp)); + reportIncompatibleError( + Diagnostics.Types_of_property_0_are_incompatible, + symbolToString(targetProp) + ); } return Ternary.False; } // When checking for comparability, be more lenient with optional properties. - if (!skipOptional && sourceProp.flags & SymbolFlags.Optional && targetProp.flags & SymbolFlags.ClassMember && !(targetProp.flags & SymbolFlags.Optional)) { + if ( + !skipOptional && + sourceProp.flags & SymbolFlags.Optional && + targetProp.flags & SymbolFlags.ClassMember && + !(targetProp.flags & SymbolFlags.Optional) + ) { // TypeScript 1.0 spec (April 2014): 3.8.3 // S is a subtype of a type T, and T is a supertype of S if ... // S' and T are object types and, for each member M in T.. @@ -24217,60 +43200,132 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // (M - property in T) // (N - property in S) if (reportErrors) { - reportError(Diagnostics.Property_0_is_optional_in_type_1_but_required_in_type_2, symbolToString(targetProp), typeToString(source), typeToString(target)); + reportError( + Diagnostics.Property_0_is_optional_in_type_1_but_required_in_type_2, + symbolToString(targetProp), + typeToString(source), + typeToString(target) + ); } return Ternary.False; } return related; } - function reportUnmatchedProperty(source: Type, target: Type, unmatchedProperty: Symbol, requireOptionalProperties: boolean) { + function reportUnmatchedProperty( + source: Type, + target: Type, + unmatchedProperty: Symbol, + requireOptionalProperties: boolean + ) { let shouldSkipElaboration = false; // give specific error in case where private names have the same description if ( - unmatchedProperty.valueDeclaration - && isNamedDeclaration(unmatchedProperty.valueDeclaration) - && isPrivateIdentifier(unmatchedProperty.valueDeclaration.name) - && source.symbol - && source.symbol.flags & SymbolFlags.Class - ) { - const privateIdentifierDescription = unmatchedProperty.valueDeclaration.name.escapedText; - const symbolTableKey = getSymbolNameForPrivateIdentifier(source.symbol, privateIdentifierDescription); - if (symbolTableKey && getPropertyOfType(source, symbolTableKey)) { - const sourceName = factory.getDeclarationName(source.symbol.valueDeclaration); - const targetName = factory.getDeclarationName(target.symbol.valueDeclaration); + unmatchedProperty.valueDeclaration && + isNamedDeclaration(unmatchedProperty.valueDeclaration) && + isPrivateIdentifier(unmatchedProperty.valueDeclaration.name) && + source.symbol && + source.symbol.flags & SymbolFlags.Class + ) { + const privateIdentifierDescription = + unmatchedProperty.valueDeclaration.name.escapedText; + const symbolTableKey = getSymbolNameForPrivateIdentifier( + source.symbol, + privateIdentifierDescription + ); + if ( + symbolTableKey && + getPropertyOfType(source, symbolTableKey) + ) { + const sourceName = factory.getDeclarationName( + source.symbol.valueDeclaration + ); + const targetName = factory.getDeclarationName( + target.symbol.valueDeclaration + ); reportError( Diagnostics.Property_0_in_type_1_refers_to_a_different_member_that_cannot_be_accessed_from_within_type_2, diagnosticName(privateIdentifierDescription), - diagnosticName(sourceName.escapedText === "" ? anon : sourceName), - diagnosticName(targetName.escapedText === "" ? anon : targetName), + diagnosticName( + sourceName.escapedText === "" ? anon : sourceName + ), + diagnosticName( + targetName.escapedText === "" ? anon : targetName + ) ); return; } } - const props = arrayFrom(getUnmatchedProperties(source, target, requireOptionalProperties, /*matchDiscriminantProperties*/ false)); + const props = arrayFrom( + getUnmatchedProperties( + source, + target, + requireOptionalProperties, + /*matchDiscriminantProperties*/ false + ) + ); if ( - !headMessage || (headMessage.code !== Diagnostics.Class_0_incorrectly_implements_interface_1.code && - headMessage.code !== Diagnostics.Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass.code) + !headMessage || + (headMessage.code !== + Diagnostics.Class_0_incorrectly_implements_interface_1 + .code && + headMessage.code !== + Diagnostics + .Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass + .code) ) { shouldSkipElaboration = true; // Retain top-level error for interface implementing issues, otherwise omit it } if (props.length === 1) { - const propName = symbolToString(unmatchedProperty, /*enclosingDeclaration*/ undefined, SymbolFlags.None, SymbolFormatFlags.AllowAnyNodeKind | SymbolFormatFlags.WriteComputedProps); - reportError(Diagnostics.Property_0_is_missing_in_type_1_but_required_in_type_2, propName, ...getTypeNamesForErrorDisplay(source, target)); + const propName = symbolToString( + unmatchedProperty, + /*enclosingDeclaration*/ undefined, + SymbolFlags.None, + SymbolFormatFlags.AllowAnyNodeKind | + SymbolFormatFlags.WriteComputedProps + ); + reportError( + Diagnostics.Property_0_is_missing_in_type_1_but_required_in_type_2, + propName, + ...getTypeNamesForErrorDisplay(source, target) + ); if (length(unmatchedProperty.declarations)) { - associateRelatedInfo(createDiagnosticForNode(unmatchedProperty.declarations![0], Diagnostics._0_is_declared_here, propName)); + associateRelatedInfo( + createDiagnosticForNode( + unmatchedProperty.declarations![0], + Diagnostics._0_is_declared_here, + propName + ) + ); } if (shouldSkipElaboration && errorInfo) { overrideNextErrorInfo++; } - } - else if (tryElaborateArrayLikeErrors(source, target, /*reportErrors*/ false)) { - if (props.length > 5) { // arbitrary cutoff for too-long list form - 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); - } - else { - reportError(Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2, typeToString(source), typeToString(target), map(props, p => symbolToString(p)).join(", ")); + } else if ( + tryElaborateArrayLikeErrors( + source, + target, + /*reportErrors*/ false + ) + ) { + if (props.length > 5) { + // arbitrary cutoff for too-long list form + 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 + ); + } else { + reportError( + Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2, + typeToString(source), + typeToString(target), + map(props, (p) => symbolToString(p)).join(", ") + ); } if (shouldSkipElaboration && errorInfo) { overrideNextErrorInfo++; @@ -24279,101 +43334,226 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // No array like or unmatched property error - just issue top level error (errorInfo = undefined) } - function propertiesRelatedTo(source: Type, target: Type, reportErrors: boolean, excludedProperties: Set<__String> | undefined, optionalsOnly: boolean, intersectionState: IntersectionState): Ternary { + function propertiesRelatedTo( + source: Type, + target: Type, + reportErrors: boolean, + excludedProperties: Set<__String> | undefined, + optionalsOnly: boolean, + intersectionState: IntersectionState + ): Ternary { if (relation === identityRelation) { - return propertiesIdenticalTo(source, target, excludedProperties); + return propertiesIdenticalTo( + source, + target, + excludedProperties + ); } let result = Ternary.True; if (isTupleType(target)) { if (isArrayOrTupleType(source)) { - if (!target.target.readonly && (isReadonlyArrayType(source) || isTupleType(source) && source.target.readonly)) { + if ( + !target.target.readonly && + (isReadonlyArrayType(source) || + (isTupleType(source) && source.target.readonly)) + ) { return Ternary.False; } const sourceArity = getTypeReferenceArity(source); const targetArity = getTypeReferenceArity(target); - const sourceRestFlag = isTupleType(source) ? source.target.combinedFlags & ElementFlags.Rest : ElementFlags.Rest; - const targetHasRestElement = !!(target.target.combinedFlags & ElementFlags.Variable); - const sourceMinLength = isTupleType(source) ? source.target.minLength : 0; + const sourceRestFlag = isTupleType(source) + ? source.target.combinedFlags & ElementFlags.Rest + : ElementFlags.Rest; + const targetHasRestElement = !!( + target.target.combinedFlags & ElementFlags.Variable + ); + const sourceMinLength = isTupleType(source) + ? source.target.minLength + : 0; const targetMinLength = target.target.minLength; if (!sourceRestFlag && sourceArity < targetMinLength) { if (reportErrors) { - reportError(Diagnostics.Source_has_0_element_s_but_target_requires_1, sourceArity, targetMinLength); + reportError( + Diagnostics.Source_has_0_element_s_but_target_requires_1, + sourceArity, + targetMinLength + ); } return Ternary.False; } - if (!targetHasRestElement && targetArity < sourceMinLength) { + if ( + !targetHasRestElement && + targetArity < sourceMinLength + ) { if (reportErrors) { - reportError(Diagnostics.Source_has_0_element_s_but_target_allows_only_1, sourceMinLength, targetArity); + reportError( + Diagnostics.Source_has_0_element_s_but_target_allows_only_1, + sourceMinLength, + targetArity + ); } return Ternary.False; } - if (!targetHasRestElement && (sourceRestFlag || targetArity < sourceArity)) { + if ( + !targetHasRestElement && + (sourceRestFlag || targetArity < sourceArity) + ) { if (reportErrors) { if (sourceMinLength < targetMinLength) { - reportError(Diagnostics.Target_requires_0_element_s_but_source_may_have_fewer, targetMinLength); - } - else { - reportError(Diagnostics.Target_allows_only_0_element_s_but_source_may_have_more, targetArity); + reportError( + Diagnostics.Target_requires_0_element_s_but_source_may_have_fewer, + targetMinLength + ); + } else { + reportError( + Diagnostics.Target_allows_only_0_element_s_but_source_may_have_more, + targetArity + ); } } return Ternary.False; } const sourceTypeArguments = getTypeArguments(source); const targetTypeArguments = getTypeArguments(target); - const targetStartCount = getStartElementCount(target.target, ElementFlags.NonRest); - const targetEndCount = getEndElementCount(target.target, ElementFlags.NonRest); + const targetStartCount = getStartElementCount( + target.target, + ElementFlags.NonRest + ); + const targetEndCount = getEndElementCount( + target.target, + ElementFlags.NonRest + ); let canExcludeDiscriminants = !!excludedProperties; - for (let sourcePosition = 0; sourcePosition < sourceArity; sourcePosition++) { - const sourceFlags = isTupleType(source) ? source.target.elementFlags[sourcePosition] : ElementFlags.Rest; - const sourcePositionFromEnd = sourceArity - 1 - sourcePosition; - - const targetPosition = targetHasRestElement && sourcePosition >= targetStartCount - ? targetArity - 1 - Math.min(sourcePositionFromEnd, targetEndCount) - : sourcePosition; - - const targetFlags = target.target.elementFlags[targetPosition]; + for ( + let sourcePosition = 0; + sourcePosition < sourceArity; + sourcePosition++ + ) { + const sourceFlags = isTupleType(source) + ? source.target.elementFlags[sourcePosition] + : ElementFlags.Rest; + const sourcePositionFromEnd = + sourceArity - 1 - sourcePosition; + + const targetPosition = + targetHasRestElement && + sourcePosition >= targetStartCount + ? targetArity - + 1 - + Math.min( + sourcePositionFromEnd, + targetEndCount + ) + : sourcePosition; + + const targetFlags = + target.target.elementFlags[targetPosition]; - if (targetFlags & ElementFlags.Variadic && !(sourceFlags & ElementFlags.Variadic)) { + if ( + targetFlags & ElementFlags.Variadic && + !(sourceFlags & ElementFlags.Variadic) + ) { if (reportErrors) { - reportError(Diagnostics.Source_provides_no_match_for_variadic_element_at_position_0_in_target, targetPosition); + reportError( + Diagnostics.Source_provides_no_match_for_variadic_element_at_position_0_in_target, + targetPosition + ); } return Ternary.False; } - if (sourceFlags & ElementFlags.Variadic && !(targetFlags & ElementFlags.Variable)) { + if ( + sourceFlags & ElementFlags.Variadic && + !(targetFlags & ElementFlags.Variable) + ) { if (reportErrors) { - reportError(Diagnostics.Variadic_element_at_position_0_in_source_does_not_match_element_at_position_1_in_target, sourcePosition, targetPosition); + reportError( + Diagnostics.Variadic_element_at_position_0_in_source_does_not_match_element_at_position_1_in_target, + sourcePosition, + targetPosition + ); } return Ternary.False; } - if (targetFlags & ElementFlags.Required && !(sourceFlags & ElementFlags.Required)) { + if ( + targetFlags & ElementFlags.Required && + !(sourceFlags & ElementFlags.Required) + ) { if (reportErrors) { - reportError(Diagnostics.Source_provides_no_match_for_required_element_at_position_0_in_target, targetPosition); + reportError( + Diagnostics.Source_provides_no_match_for_required_element_at_position_0_in_target, + targetPosition + ); } return Ternary.False; } // We can only exclude discriminant properties if we have not yet encountered a variable-length element. if (canExcludeDiscriminants) { - if (sourceFlags & ElementFlags.Variable || targetFlags & ElementFlags.Variable) { + if ( + sourceFlags & ElementFlags.Variable || + targetFlags & ElementFlags.Variable + ) { canExcludeDiscriminants = false; } - if (canExcludeDiscriminants && excludedProperties?.has(("" + sourcePosition) as __String)) { + if ( + canExcludeDiscriminants && + excludedProperties?.has( + ("" + sourcePosition) as __String + ) + ) { continue; } } - const sourceType = removeMissingType(sourceTypeArguments[sourcePosition], !!(sourceFlags & targetFlags & ElementFlags.Optional)); + const sourceType = removeMissingType( + sourceTypeArguments[sourcePosition], + !!( + sourceFlags & + targetFlags & + ElementFlags.Optional + ) + ); const targetType = targetTypeArguments[targetPosition]; - const targetCheckType = sourceFlags & ElementFlags.Variadic && targetFlags & ElementFlags.Rest ? createArrayType(targetType) : - removeMissingType(targetType, !!(targetFlags & ElementFlags.Optional)); - const related = isRelatedTo(sourceType, targetCheckType, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); + const targetCheckType = + sourceFlags & ElementFlags.Variadic && + targetFlags & ElementFlags.Rest + ? createArrayType(targetType) + : removeMissingType( + targetType, + !!(targetFlags & ElementFlags.Optional) + ); + const related = isRelatedTo( + sourceType, + targetCheckType, + RecursionFlags.Both, + reportErrors, + /*headMessage*/ undefined, + intersectionState + ); if (!related) { - if (reportErrors && (targetArity > 1 || sourceArity > 1)) { - if (targetHasRestElement && sourcePosition >= targetStartCount && sourcePositionFromEnd >= targetEndCount && targetStartCount !== sourceArity - targetEndCount - 1) { - reportIncompatibleError(Diagnostics.Type_at_positions_0_through_1_in_source_is_not_compatible_with_type_at_position_2_in_target, targetStartCount, sourceArity - targetEndCount - 1, targetPosition); - } - else { - reportIncompatibleError(Diagnostics.Type_at_position_0_in_source_is_not_compatible_with_type_at_position_1_in_target, sourcePosition, targetPosition); + if ( + reportErrors && + (targetArity > 1 || sourceArity > 1) + ) { + if ( + targetHasRestElement && + sourcePosition >= targetStartCount && + sourcePositionFromEnd >= targetEndCount && + targetStartCount !== + sourceArity - targetEndCount - 1 + ) { + reportIncompatibleError( + Diagnostics.Type_at_positions_0_through_1_in_source_is_not_compatible_with_type_at_position_2_in_target, + targetStartCount, + sourceArity - targetEndCount - 1, + targetPosition + ); + } else { + reportIncompatibleError( + Diagnostics.Type_at_position_0_in_source_is_not_compatible_with_type_at_position_1_in_target, + sourcePosition, + targetPosition + ); } } return Ternary.False; @@ -24386,21 +43566,48 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return Ternary.False; } } - const requireOptionalProperties = (relation === subtypeRelation || relation === strictSubtypeRelation) && !isObjectLiteralType(source) && !isEmptyArrayLiteralType(source) && !isTupleType(source); - const unmatchedProperty = getUnmatchedProperty(source, target, requireOptionalProperties, /*matchDiscriminantProperties*/ false); + const requireOptionalProperties = + (relation === subtypeRelation || + relation === strictSubtypeRelation) && + !isObjectLiteralType(source) && + !isEmptyArrayLiteralType(source) && + !isTupleType(source); + const unmatchedProperty = getUnmatchedProperty( + source, + target, + requireOptionalProperties, + /*matchDiscriminantProperties*/ false + ); if (unmatchedProperty) { - if (reportErrors && shouldReportUnmatchedPropertyError(source, target)) { - reportUnmatchedProperty(source, target, unmatchedProperty, requireOptionalProperties); + if ( + reportErrors && + shouldReportUnmatchedPropertyError(source, target) + ) { + reportUnmatchedProperty( + source, + target, + unmatchedProperty, + requireOptionalProperties + ); } return Ternary.False; } if (isObjectLiteralType(target)) { - for (const sourceProp of excludeProperties(getPropertiesOfType(source), excludedProperties)) { - if (!getPropertyOfObjectType(target, sourceProp.escapedName)) { + for (const sourceProp of excludeProperties( + getPropertiesOfType(source), + excludedProperties + )) { + if ( + !getPropertyOfObjectType(target, sourceProp.escapedName) + ) { const sourceType = getTypeOfSymbol(sourceProp); if (!(sourceType.flags & TypeFlags.Undefined)) { if (reportErrors) { - reportError(Diagnostics.Property_0_does_not_exist_on_type_1, symbolToString(sourceProp), typeToString(target)); + reportError( + Diagnostics.Property_0_does_not_exist_on_type_1, + symbolToString(sourceProp), + typeToString(target) + ); } return Ternary.False; } @@ -24411,12 +43618,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // from the target union, across all members const properties = getPropertiesOfType(target); const numericNamesOnly = isTupleType(source) && isTupleType(target); - for (const targetProp of excludeProperties(properties, excludedProperties)) { + for (const targetProp of excludeProperties( + properties, + excludedProperties + )) { const name = targetProp.escapedName; - if (!(targetProp.flags & SymbolFlags.Prototype) && (!numericNamesOnly || isNumericLiteralName(name) || name === "length") && (!optionalsOnly || targetProp.flags & SymbolFlags.Optional)) { + if ( + !(targetProp.flags & SymbolFlags.Prototype) && + (!numericNamesOnly || + isNumericLiteralName(name) || + name === "length") && + (!optionalsOnly || targetProp.flags & SymbolFlags.Optional) + ) { const sourceProp = getPropertyOfType(source, name); if (sourceProp && sourceProp !== targetProp) { - const related = propertyRelatedTo(source, target, sourceProp, targetProp, getNonMissingTypeOfSymbol, reportErrors, intersectionState, relation === comparableRelation); + const related = propertyRelatedTo( + source, + target, + sourceProp, + targetProp, + getNonMissingTypeOfSymbol, + reportErrors, + intersectionState, + relation === comparableRelation + ); if (!related) { return Ternary.False; } @@ -24427,22 +43652,44 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function propertiesIdenticalTo(source: Type, target: Type, excludedProperties: Set<__String> | undefined): Ternary { - if (!(source.flags & TypeFlags.Object && target.flags & TypeFlags.Object)) { + function propertiesIdenticalTo( + source: Type, + target: Type, + excludedProperties: Set<__String> | undefined + ): Ternary { + if ( + !( + source.flags & TypeFlags.Object && + target.flags & TypeFlags.Object + ) + ) { return Ternary.False; } - const sourceProperties = excludeProperties(getPropertiesOfObjectType(source), excludedProperties); - const targetProperties = excludeProperties(getPropertiesOfObjectType(target), excludedProperties); + const sourceProperties = excludeProperties( + getPropertiesOfObjectType(source), + excludedProperties + ); + const targetProperties = excludeProperties( + getPropertiesOfObjectType(target), + excludedProperties + ); if (sourceProperties.length !== targetProperties.length) { return Ternary.False; } let result = Ternary.True; for (const sourceProp of sourceProperties) { - const targetProp = getPropertyOfObjectType(target, sourceProp.escapedName); + const targetProp = getPropertyOfObjectType( + target, + sourceProp.escapedName + ); if (!targetProp) { return Ternary.False; } - const related = compareProperties(sourceProp, targetProp, isRelatedTo); + const related = compareProperties( + sourceProp, + targetProp, + isRelatedTo + ); if (!related) { return Ternary.False; } @@ -24451,7 +43698,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function signaturesRelatedTo(source: Type, target: Type, kind: SignatureKind, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function signaturesRelatedTo( + source: Type, + target: Type, + kind: SignatureKind, + reportErrors: boolean, + intersectionState: IntersectionState + ): Ternary { if (relation === identityRelation) { return signaturesIdenticalTo(source, target, kind); } @@ -24459,60 +43712,105 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return Ternary.True; } - const sourceIsJSConstructor = source.symbol && isJSConstructor(source.symbol.valueDeclaration); - const targetIsJSConstructor = target.symbol && isJSConstructor(target.symbol.valueDeclaration); + const sourceIsJSConstructor = + source.symbol && + isJSConstructor(source.symbol.valueDeclaration); + const targetIsJSConstructor = + target.symbol && + isJSConstructor(target.symbol.valueDeclaration); const sourceSignatures = getSignaturesOfType( source, - (sourceIsJSConstructor && kind === SignatureKind.Construct) ? - SignatureKind.Call : kind, + sourceIsJSConstructor && kind === SignatureKind.Construct + ? SignatureKind.Call + : kind ); const targetSignatures = getSignaturesOfType( target, - (targetIsJSConstructor && kind === SignatureKind.Construct) ? - SignatureKind.Call : kind, + targetIsJSConstructor && kind === SignatureKind.Construct + ? SignatureKind.Call + : kind ); - if (kind === SignatureKind.Construct && sourceSignatures.length && targetSignatures.length) { - const sourceIsAbstract = !!(sourceSignatures[0].flags & SignatureFlags.Abstract); - const targetIsAbstract = !!(targetSignatures[0].flags & SignatureFlags.Abstract); + if ( + kind === SignatureKind.Construct && + sourceSignatures.length && + targetSignatures.length + ) { + const sourceIsAbstract = !!( + sourceSignatures[0].flags & SignatureFlags.Abstract + ); + const targetIsAbstract = !!( + targetSignatures[0].flags & SignatureFlags.Abstract + ); if (sourceIsAbstract && !targetIsAbstract) { // An abstract constructor type is not assignable to a non-abstract constructor type // as it would otherwise be possible to new an abstract class. Note that the assignability // check we perform for an extends clause excludes construct signatures from the target, // so this check never proceeds. if (reportErrors) { - reportError(Diagnostics.Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type); + reportError( + Diagnostics.Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type + ); } return Ternary.False; } - if (!constructorVisibilitiesAreCompatible(sourceSignatures[0], targetSignatures[0], reportErrors)) { + if ( + !constructorVisibilitiesAreCompatible( + sourceSignatures[0], + targetSignatures[0], + reportErrors + ) + ) { return Ternary.False; } } let result = Ternary.True; - const incompatibleReporter = kind === SignatureKind.Construct ? reportIncompatibleConstructSignatureReturn : reportIncompatibleCallSignatureReturn; + const incompatibleReporter = + kind === SignatureKind.Construct + ? reportIncompatibleConstructSignatureReturn + : reportIncompatibleCallSignatureReturn; const sourceObjectFlags = getObjectFlags(source); const targetObjectFlags = getObjectFlags(target); if ( - sourceObjectFlags & ObjectFlags.Instantiated && targetObjectFlags & ObjectFlags.Instantiated && source.symbol === target.symbol || - sourceObjectFlags & ObjectFlags.Reference && targetObjectFlags & ObjectFlags.Reference && (source as TypeReference).target === (target as TypeReference).target + (sourceObjectFlags & ObjectFlags.Instantiated && + targetObjectFlags & ObjectFlags.Instantiated && + source.symbol === target.symbol) || + (sourceObjectFlags & ObjectFlags.Reference && + targetObjectFlags & ObjectFlags.Reference && + (source as TypeReference).target === + (target as TypeReference).target) ) { // We have instantiations of the same anonymous type (which typically will be the type of a // method). Simply do a pairwise comparison of the signatures in the two signature lists instead // of the much more expensive N * M comparison matrix we explore below. We erase type parameters // as they are known to always be the same. - Debug.assertEqual(sourceSignatures.length, targetSignatures.length); + Debug.assertEqual( + sourceSignatures.length, + targetSignatures.length + ); for (let i = 0; i < targetSignatures.length; i++) { - const related = signatureRelatedTo(sourceSignatures[i], targetSignatures[i], /*erase*/ true, reportErrors, intersectionState, incompatibleReporter(sourceSignatures[i], targetSignatures[i])); + const related = signatureRelatedTo( + sourceSignatures[i], + targetSignatures[i], + /*erase*/ true, + reportErrors, + intersectionState, + incompatibleReporter( + sourceSignatures[i], + targetSignatures[i] + ) + ); if (!related) { return Ternary.False; } result &= related; } - } - else if (sourceSignatures.length === 1 && targetSignatures.length === 1) { + } else if ( + sourceSignatures.length === 1 && + targetSignatures.length === 1 + ) { // For simple functions (functions with a single signature) we only erase type parameters for // the comparable relation. Otherwise, if the source signature is generic, we instantiate it // in the context of the target signature before checking the relationship. Ideally we'd do @@ -24521,25 +43819,55 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const eraseGenerics = relation === comparableRelation; const sourceSignature = first(sourceSignatures); const targetSignature = first(targetSignatures); - result = signatureRelatedTo(sourceSignature, targetSignature, eraseGenerics, reportErrors, intersectionState, incompatibleReporter(sourceSignature, targetSignature)); + result = signatureRelatedTo( + sourceSignature, + targetSignature, + eraseGenerics, + reportErrors, + intersectionState, + incompatibleReporter(sourceSignature, targetSignature) + ); if ( - !result && reportErrors && kind === SignatureKind.Construct && (sourceObjectFlags & targetObjectFlags) && - (targetSignature.declaration?.kind === SyntaxKind.Constructor || sourceSignature.declaration?.kind === SyntaxKind.Constructor) + !result && + reportErrors && + kind === SignatureKind.Construct && + sourceObjectFlags & targetObjectFlags && + (targetSignature.declaration?.kind === + SyntaxKind.Constructor || + sourceSignature.declaration?.kind === + SyntaxKind.Constructor) ) { - const constructSignatureToString = (signature: Signature) => signatureToString(signature, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrowStyleSignature, kind); - reportError(Diagnostics.Type_0_is_not_assignable_to_type_1, constructSignatureToString(sourceSignature), constructSignatureToString(targetSignature)); - reportError(Diagnostics.Types_of_construct_signatures_are_incompatible); + const constructSignatureToString = (signature: Signature) => + signatureToString( + signature, + /*enclosingDeclaration*/ undefined, + TypeFormatFlags.WriteArrowStyleSignature, + kind + ); + reportError( + Diagnostics.Type_0_is_not_assignable_to_type_1, + constructSignatureToString(sourceSignature), + constructSignatureToString(targetSignature) + ); + reportError( + Diagnostics.Types_of_construct_signatures_are_incompatible + ); return result; } - } - else { - outer: - for (const t of targetSignatures) { + } else { + outer: for (const t of targetSignatures) { const saveErrorInfo = captureErrorCalculationState(); // Only elaborate errors from the first failure let shouldElaborateErrors = reportErrors; for (const s of sourceSignatures) { - const related = signatureRelatedTo(s, t, /*erase*/ true, shouldElaborateErrors, intersectionState, incompatibleReporter(s, t)); + const related = signatureRelatedTo( + s, + t, + /*erase*/ true, + shouldElaborateErrors, + intersectionState, + incompatibleReporter(s, t) + ); if (related) { result &= related; resetErrorInfo(saveErrorInfo); @@ -24548,7 +43876,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { shouldElaborateErrors = false; } if (shouldElaborateErrors) { - reportError(Diagnostics.Type_0_provides_no_match_for_the_signature_1, typeToString(source), signatureToString(t, /*enclosingDeclaration*/ undefined, /*flags*/ undefined, kind)); + reportError( + Diagnostics.Type_0_provides_no_match_for_the_signature_1, + typeToString(source), + signatureToString( + t, + /*enclosingDeclaration*/ undefined, + /*flags*/ undefined, + kind + ) + ); } return Ternary.False; } @@ -24556,14 +43893,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function shouldReportUnmatchedPropertyError(source: Type, target: Type): boolean { - const typeCallSignatures = getSignaturesOfStructuredType(source, SignatureKind.Call); - const typeConstructSignatures = getSignaturesOfStructuredType(source, SignatureKind.Construct); + function shouldReportUnmatchedPropertyError( + source: Type, + target: Type + ): boolean { + const typeCallSignatures = getSignaturesOfStructuredType( + source, + SignatureKind.Call + ); + const typeConstructSignatures = getSignaturesOfStructuredType( + source, + SignatureKind.Construct + ); const typeProperties = getPropertiesOfObjectType(source); - if ((typeCallSignatures.length || typeConstructSignatures.length) && !typeProperties.length) { + if ( + (typeCallSignatures.length || typeConstructSignatures.length) && + !typeProperties.length + ) { if ( - (getSignaturesOfType(target, SignatureKind.Call).length && typeCallSignatures.length) || - (getSignaturesOfType(target, SignatureKind.Construct).length && typeConstructSignatures.length) + (getSignaturesOfType(target, SignatureKind.Call).length && + typeCallSignatures.length) || + (getSignaturesOfType(target, SignatureKind.Construct) + .length && + typeConstructSignatures.length) ) { return true; // target has similar signature kinds to source, still focus on the unmatched property } @@ -24572,34 +43924,95 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; } - function reportIncompatibleCallSignatureReturn(siga: Signature, sigb: Signature) { + function reportIncompatibleCallSignatureReturn( + siga: Signature, + sigb: Signature + ) { if (siga.parameters.length === 0 && sigb.parameters.length === 0) { - return (source: Type, target: Type) => reportIncompatibleError(Diagnostics.Call_signatures_with_no_arguments_have_incompatible_return_types_0_and_1, typeToString(source), typeToString(target)); + return (source: Type, target: Type) => + reportIncompatibleError( + Diagnostics.Call_signatures_with_no_arguments_have_incompatible_return_types_0_and_1, + typeToString(source), + typeToString(target) + ); } - return (source: Type, target: Type) => reportIncompatibleError(Diagnostics.Call_signature_return_types_0_and_1_are_incompatible, typeToString(source), typeToString(target)); + return (source: Type, target: Type) => + reportIncompatibleError( + Diagnostics.Call_signature_return_types_0_and_1_are_incompatible, + typeToString(source), + typeToString(target) + ); } - function reportIncompatibleConstructSignatureReturn(siga: Signature, sigb: Signature) { + function reportIncompatibleConstructSignatureReturn( + siga: Signature, + sigb: Signature + ) { if (siga.parameters.length === 0 && sigb.parameters.length === 0) { - return (source: Type, target: Type) => reportIncompatibleError(Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1, typeToString(source), typeToString(target)); + return (source: Type, target: Type) => + reportIncompatibleError( + Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1, + typeToString(source), + typeToString(target) + ); } - return (source: Type, target: Type) => reportIncompatibleError(Diagnostics.Construct_signature_return_types_0_and_1_are_incompatible, typeToString(source), typeToString(target)); + return (source: Type, target: Type) => + reportIncompatibleError( + Diagnostics.Construct_signature_return_types_0_and_1_are_incompatible, + typeToString(source), + typeToString(target) + ); } /** * See signatureAssignableTo, compareSignaturesIdentical */ - function signatureRelatedTo(source: Signature, target: Signature, erase: boolean, reportErrors: boolean, intersectionState: IntersectionState, incompatibleReporter: (source: Type, target: Type) => void): Ternary { - const checkMode = relation === subtypeRelation ? SignatureCheckMode.StrictTopSignature : - relation === strictSubtypeRelation ? SignatureCheckMode.StrictTopSignature | SignatureCheckMode.StrictArity : - SignatureCheckMode.None; - return compareSignaturesRelated(erase ? getErasedSignature(source) : source, erase ? getErasedSignature(target) : target, checkMode, reportErrors, reportError, incompatibleReporter, isRelatedToWorker, reportUnreliableMapper); - function isRelatedToWorker(source: Type, target: Type, reportErrors?: boolean) { - return isRelatedTo(source, target, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); + function signatureRelatedTo( + source: Signature, + target: Signature, + erase: boolean, + reportErrors: boolean, + intersectionState: IntersectionState, + incompatibleReporter: (source: Type, target: Type) => void + ): Ternary { + const checkMode = + relation === subtypeRelation + ? SignatureCheckMode.StrictTopSignature + : relation === strictSubtypeRelation + ? SignatureCheckMode.StrictTopSignature | + SignatureCheckMode.StrictArity + : SignatureCheckMode.None; + return compareSignaturesRelated( + erase ? getErasedSignature(source) : source, + erase ? getErasedSignature(target) : target, + checkMode, + reportErrors, + reportError, + incompatibleReporter, + isRelatedToWorker, + reportUnreliableMapper + ); + function isRelatedToWorker( + source: Type, + target: Type, + reportErrors?: boolean + ) { + return isRelatedTo( + source, + target, + RecursionFlags.Both, + reportErrors, + /*headMessage*/ undefined, + intersectionState + ); } } - function signaturesIdenticalTo(source: Type, target: Type, kind: SignatureKind): Ternary { + function signaturesIdenticalTo( + source: Type, + target: Type, + kind: SignatureKind + ): Ternary { const sourceSignatures = getSignaturesOfType(source, kind); const targetSignatures = getSignaturesOfType(target, kind); if (sourceSignatures.length !== targetSignatures.length) { @@ -24607,7 +44020,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } let result = Ternary.True; for (let i = 0; i < sourceSignatures.length; i++) { - const related = compareSignaturesIdentical(sourceSignatures[i], targetSignatures[i], /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ false, isRelatedTo); + const related = compareSignaturesIdentical( + sourceSignatures[i], + targetSignatures[i], + /*partialMatch*/ false, + /*ignoreThisTypes*/ false, + /*ignoreReturnTypes*/ false, + isRelatedTo + ); if (!related) { return Ternary.False; } @@ -24616,24 +44036,56 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function membersRelatedToIndexInfo(source: Type, targetInfo: IndexInfo, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function membersRelatedToIndexInfo( + source: Type, + targetInfo: IndexInfo, + reportErrors: boolean, + intersectionState: IntersectionState + ): Ternary { let result = Ternary.True; const keyType = targetInfo.keyType; - const props = source.flags & TypeFlags.Intersection ? getPropertiesOfUnionOrIntersectionType(source as IntersectionType) : getPropertiesOfObjectType(source); + const props = + source.flags & TypeFlags.Intersection + ? getPropertiesOfUnionOrIntersectionType( + source as IntersectionType + ) + : getPropertiesOfObjectType(source); for (const prop of props) { // Skip over ignored JSX and symbol-named members if (isIgnoredJsxProperty(source, prop)) { continue; } - if (isApplicableIndexType(getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique), keyType)) { + if ( + isApplicableIndexType( + getLiteralTypeFromProperty( + prop, + TypeFlags.StringOrNumberLiteralOrUnique + ), + keyType + ) + ) { const propType = getNonMissingTypeOfSymbol(prop); - const type = exactOptionalPropertyTypes || propType.flags & TypeFlags.Undefined || keyType === numberType || !(prop.flags & SymbolFlags.Optional) - ? propType - : getTypeWithFacts(propType, TypeFacts.NEUndefined); - const related = isRelatedTo(type, targetInfo.type, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); + const type = + exactOptionalPropertyTypes || + propType.flags & TypeFlags.Undefined || + keyType === numberType || + !(prop.flags & SymbolFlags.Optional) + ? propType + : getTypeWithFacts(propType, TypeFacts.NEUndefined); + const related = isRelatedTo( + type, + targetInfo.type, + RecursionFlags.Both, + reportErrors, + /*headMessage*/ undefined, + intersectionState + ); if (!related) { if (reportErrors) { - reportError(Diagnostics.Property_0_is_incompatible_with_index_signature, symbolToString(prop)); + reportError( + Diagnostics.Property_0_is_incompatible_with_index_signature, + symbolToString(prop) + ); } return Ternary.False; } @@ -24642,7 +44094,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } for (const info of getIndexInfosOfType(source)) { if (isApplicableIndexType(info.keyType, keyType)) { - const related = indexInfoRelatedTo(info, targetInfo, reportErrors, intersectionState); + const related = indexInfoRelatedTo( + info, + targetInfo, + reportErrors, + intersectionState + ); if (!related) { return Ternary.False; } @@ -24652,30 +44109,73 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function indexInfoRelatedTo(sourceInfo: IndexInfo, targetInfo: IndexInfo, reportErrors: boolean, intersectionState: IntersectionState) { - const related = isRelatedTo(sourceInfo.type, targetInfo.type, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); + function indexInfoRelatedTo( + sourceInfo: IndexInfo, + targetInfo: IndexInfo, + reportErrors: boolean, + intersectionState: IntersectionState + ) { + const related = isRelatedTo( + sourceInfo.type, + targetInfo.type, + RecursionFlags.Both, + reportErrors, + /*headMessage*/ undefined, + intersectionState + ); if (!related && reportErrors) { if (sourceInfo.keyType === targetInfo.keyType) { - reportError(Diagnostics._0_index_signatures_are_incompatible, typeToString(sourceInfo.keyType)); - } - else { - reportError(Diagnostics._0_and_1_index_signatures_are_incompatible, typeToString(sourceInfo.keyType), typeToString(targetInfo.keyType)); + reportError( + Diagnostics._0_index_signatures_are_incompatible, + typeToString(sourceInfo.keyType) + ); + } else { + reportError( + Diagnostics._0_and_1_index_signatures_are_incompatible, + typeToString(sourceInfo.keyType), + typeToString(targetInfo.keyType) + ); } } return related; } - function indexSignaturesRelatedTo(source: Type, target: Type, sourceIsPrimitive: boolean, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function indexSignaturesRelatedTo( + source: Type, + target: Type, + sourceIsPrimitive: boolean, + reportErrors: boolean, + intersectionState: IntersectionState + ): Ternary { if (relation === identityRelation) { return indexSignaturesIdenticalTo(source, target); } const indexInfos = getIndexInfosOfType(target); - const targetHasStringIndex = some(indexInfos, info => info.keyType === stringType); + const targetHasStringIndex = some( + indexInfos, + (info) => info.keyType === stringType + ); let result = Ternary.True; for (const targetInfo of indexInfos) { - const related = relation !== strictSubtypeRelation && !sourceIsPrimitive && targetHasStringIndex && targetInfo.type.flags & TypeFlags.Any ? Ternary.True : - isGenericMappedType(source) && targetHasStringIndex ? isRelatedTo(getTemplateTypeFromMappedType(source), targetInfo.type, RecursionFlags.Both, reportErrors) : - typeRelatedToIndexInfo(source, targetInfo, reportErrors, intersectionState); + const related = + relation !== strictSubtypeRelation && + !sourceIsPrimitive && + targetHasStringIndex && + targetInfo.type.flags & TypeFlags.Any + ? Ternary.True + : isGenericMappedType(source) && targetHasStringIndex + ? isRelatedTo( + getTemplateTypeFromMappedType(source), + targetInfo.type, + RecursionFlags.Both, + reportErrors + ) + : typeRelatedToIndexInfo( + source, + targetInfo, + reportErrors, + intersectionState + ); if (!related) { return Ternary.False; } @@ -24684,45 +44184,98 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function typeRelatedToIndexInfo(source: Type, targetInfo: IndexInfo, reportErrors: boolean, intersectionState: IntersectionState): Ternary { - const sourceInfo = getApplicableIndexInfo(source, targetInfo.keyType); + function typeRelatedToIndexInfo( + source: Type, + targetInfo: IndexInfo, + reportErrors: boolean, + intersectionState: IntersectionState + ): Ternary { + const sourceInfo = getApplicableIndexInfo( + source, + targetInfo.keyType + ); if (sourceInfo) { - return indexInfoRelatedTo(sourceInfo, targetInfo, reportErrors, intersectionState); + return indexInfoRelatedTo( + sourceInfo, + targetInfo, + reportErrors, + intersectionState + ); } // Intersection constituents are never considered to have an inferred index signature. Also, in the strict subtype relation, // only fresh object literals are considered to have inferred index signatures. This ensures { [x: string]: xxx } <: {} but // not vice-versa. Without this rule, those types would be mutual strict subtypes. - if (!(intersectionState & IntersectionState.Source) && (relation !== strictSubtypeRelation || getObjectFlags(source) & ObjectFlags.FreshLiteral) && isObjectTypeWithInferableIndex(source)) { - return membersRelatedToIndexInfo(source, targetInfo, reportErrors, intersectionState); + if ( + !(intersectionState & IntersectionState.Source) && + (relation !== strictSubtypeRelation || + getObjectFlags(source) & ObjectFlags.FreshLiteral) && + isObjectTypeWithInferableIndex(source) + ) { + return membersRelatedToIndexInfo( + source, + targetInfo, + reportErrors, + intersectionState + ); } if (reportErrors) { - reportError(Diagnostics.Index_signature_for_type_0_is_missing_in_type_1, typeToString(targetInfo.keyType), typeToString(source)); + reportError( + Diagnostics.Index_signature_for_type_0_is_missing_in_type_1, + typeToString(targetInfo.keyType), + typeToString(source) + ); } return Ternary.False; } - function indexSignaturesIdenticalTo(source: Type, target: Type): Ternary { + function indexSignaturesIdenticalTo( + source: Type, + target: Type + ): Ternary { const sourceInfos = getIndexInfosOfType(source); const targetInfos = getIndexInfosOfType(target); if (sourceInfos.length !== targetInfos.length) { return Ternary.False; } for (const targetInfo of targetInfos) { - const sourceInfo = getIndexInfoOfType(source, targetInfo.keyType); - if (!(sourceInfo && isRelatedTo(sourceInfo.type, targetInfo.type, RecursionFlags.Both) && sourceInfo.isReadonly === targetInfo.isReadonly)) { + const sourceInfo = getIndexInfoOfType( + source, + targetInfo.keyType + ); + if ( + !( + sourceInfo && + isRelatedTo( + sourceInfo.type, + targetInfo.type, + RecursionFlags.Both + ) && + sourceInfo.isReadonly === targetInfo.isReadonly + ) + ) { return Ternary.False; } } return Ternary.True; } - function constructorVisibilitiesAreCompatible(sourceSignature: Signature, targetSignature: Signature, reportErrors: boolean) { + function constructorVisibilitiesAreCompatible( + sourceSignature: Signature, + targetSignature: Signature, + reportErrors: boolean + ) { if (!sourceSignature.declaration || !targetSignature.declaration) { return true; } - const sourceAccessibility = getSelectedEffectiveModifierFlags(sourceSignature.declaration, ModifierFlags.NonPublicAccessibilityModifier); - const targetAccessibility = getSelectedEffectiveModifierFlags(targetSignature.declaration, ModifierFlags.NonPublicAccessibilityModifier); + const sourceAccessibility = getSelectedEffectiveModifierFlags( + sourceSignature.declaration, + ModifierFlags.NonPublicAccessibilityModifier + ); + const targetAccessibility = getSelectedEffectiveModifierFlags( + targetSignature.declaration, + ModifierFlags.NonPublicAccessibilityModifier + ); // A public, protected and private signature is assignable to a private signature. if (targetAccessibility === ModifierFlags.Private) { @@ -24730,17 +44283,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // A public and protected signature is assignable to a protected signature. - if (targetAccessibility === ModifierFlags.Protected && sourceAccessibility !== ModifierFlags.Private) { + if ( + targetAccessibility === ModifierFlags.Protected && + sourceAccessibility !== ModifierFlags.Private + ) { return true; } // Only a public signature is assignable to public signature. - if (targetAccessibility !== ModifierFlags.Protected && !sourceAccessibility) { + if ( + targetAccessibility !== ModifierFlags.Protected && + !sourceAccessibility + ) { return true; } if (reportErrors) { - reportError(Diagnostics.Cannot_assign_a_0_constructor_type_to_a_1_constructor_type, visibilityToString(sourceAccessibility), visibilityToString(targetAccessibility)); + reportError( + Diagnostics.Cannot_assign_a_0_constructor_type_to_a_1_constructor_type, + visibilityToString(sourceAccessibility), + visibilityToString(targetAccessibility) + ); } return false; @@ -24756,7 +44319,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (type.flags & TypeFlags.UnionOrIntersection) { - return !!forEach((type as IntersectionType).types, typeCouldHaveTopLevelSingletonTypes); + return !!forEach( + (type as IntersectionType).types, + typeCouldHaveTopLevelSingletonTypes + ); } if (type.flags & TypeFlags.Instantiable) { @@ -24766,34 +44332,67 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - return isUnitType(type) || !!(type.flags & TypeFlags.TemplateLiteral) || !!(type.flags & TypeFlags.StringMapping); + return ( + isUnitType(type) || + !!(type.flags & TypeFlags.TemplateLiteral) || + !!(type.flags & TypeFlags.StringMapping) + ); } - function getExactOptionalUnassignableProperties(source: Type, target: Type) { + function getExactOptionalUnassignableProperties( + source: Type, + target: Type + ) { if (isTupleType(source) && isTupleType(target)) return emptyArray; - return getPropertiesOfType(target) - .filter(targetProp => isExactOptionalPropertyMismatch(getTypeOfPropertyOfType(source, targetProp.escapedName), getTypeOfSymbol(targetProp))); + return getPropertiesOfType(target).filter((targetProp) => + isExactOptionalPropertyMismatch( + getTypeOfPropertyOfType(source, targetProp.escapedName), + getTypeOfSymbol(targetProp) + ) + ); } - function isExactOptionalPropertyMismatch(source: Type | undefined, target: Type | undefined) { - return !!source && !!target && maybeTypeOfKind(source, TypeFlags.Undefined) && !!containsMissingType(target); + function isExactOptionalPropertyMismatch( + source: Type | undefined, + target: Type | undefined + ) { + return ( + !!source && + !!target && + maybeTypeOfKind(source, TypeFlags.Undefined) && + !!containsMissingType(target) + ); } function getExactOptionalProperties(type: Type) { - return getPropertiesOfType(type).filter(targetProp => containsMissingType(getTypeOfSymbol(targetProp))); + return getPropertiesOfType(type).filter((targetProp) => + containsMissingType(getTypeOfSymbol(targetProp)) + ); } - function getBestMatchingType(source: Type, target: UnionOrIntersectionType, isRelatedTo = compareTypesAssignable) { - return findMatchingDiscriminantType(source, target, isRelatedTo) || + function getBestMatchingType( + source: Type, + target: UnionOrIntersectionType, + isRelatedTo = compareTypesAssignable + ) { + return ( + findMatchingDiscriminantType(source, target, isRelatedTo) || findMatchingTypeReferenceOrTypeAliasReference(source, target) || findBestTypeForObjectLiteral(source, target) || findBestTypeForInvokable(source, target) || - findMostOverlappyType(source, target); + findMostOverlappyType(source, target) + ); } - function discriminateTypeByDiscriminableItems(target: UnionType, discriminators: (readonly [() => Type, __String])[], related: (source: Type, target: Type) => boolean | Ternary) { + function discriminateTypeByDiscriminableItems( + target: UnionType, + discriminators: (readonly [() => Type, __String])[], + related: (source: Type, target: Type) => boolean | Ternary + ) { const types = target.types; - const include: Ternary[] = types.map(t => t.flags & TypeFlags.Primitive ? Ternary.False : Ternary.True); + const include: Ternary[] = types.map((t) => + t.flags & TypeFlags.Primitive ? Ternary.False : Ternary.True + ); for (const [getDiscriminatingType, propertyName] of discriminators) { // If the remaining target types include at least one with a matching discriminant, eliminate those that // have non-matching discriminants. This ensures that we ignore erroneous discriminators and gradually @@ -24801,12 +44400,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let matched = false; for (let i = 0; i < types.length; i++) { if (include[i]) { - const targetType = getTypeOfPropertyOrIndexSignatureOfType(types[i], propertyName); + const targetType = getTypeOfPropertyOrIndexSignatureOfType( + types[i], + propertyName + ); if (targetType) { - if (someType(getDiscriminatingType(), t => !!related(t, targetType))) { + if ( + someType( + getDiscriminatingType(), + (t) => !!related(t, targetType) + ) + ) { matched = true; - } - else { + } else { include[i] = Ternary.Maybe; } } @@ -24819,7 +44425,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } } - const filtered = contains(include, Ternary.False) ? getUnionType(types.filter((_, i) => include[i]), UnionReduction.None) : target; + const filtered = contains(include, Ternary.False) + ? getUnionType( + types.filter((_, i) => include[i]), + UnionReduction.None + ) + : target; return filtered.flags & TypeFlags.Never ? target : filtered; } @@ -24830,8 +44441,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isWeakType(type: Type): boolean { if (type.flags & TypeFlags.Object) { const resolved = resolveStructuredTypeMembers(type as ObjectType); - return resolved.callSignatures.length === 0 && resolved.constructSignatures.length === 0 && resolved.indexInfos.length === 0 && - resolved.properties.length > 0 && every(resolved.properties, p => !!(p.flags & SymbolFlags.Optional)); + return ( + resolved.callSignatures.length === 0 && + resolved.constructSignatures.length === 0 && + resolved.indexInfos.length === 0 && + resolved.properties.length > 0 && + every( + resolved.properties, + (p) => !!(p.flags & SymbolFlags.Optional) + ) + ); } if (type.flags & TypeFlags.Substitution) { return isWeakType((type as SubstitutionType).baseType); @@ -24842,9 +44461,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function hasCommonProperties(source: Type, target: Type, isComparingJsxAttributes: boolean) { + function hasCommonProperties( + source: Type, + target: Type, + isComparingJsxAttributes: boolean + ) { for (const prop of getPropertiesOfType(source)) { - if (isKnownProperty(target, prop.escapedName, isComparingJsxAttributes)) { + if ( + isKnownProperty( + target, + prop.escapedName, + isComparingJsxAttributes + ) + ) { return true; } } @@ -24853,13 +44482,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getVariances(type: GenericType): VarianceFlags[] { // Arrays and tuples are known to be covariant, no need to spend time computing this. - return type === globalArrayType || type === globalReadonlyArrayType || type.objectFlags & ObjectFlags.Tuple ? - arrayVariances : - getVariancesWorker(type.symbol, type.typeParameters); + return type === globalArrayType || + type === globalReadonlyArrayType || + type.objectFlags & ObjectFlags.Tuple + ? arrayVariances + : getVariancesWorker(type.symbol, type.typeParameters); } function getAliasVariances(symbol: Symbol) { - return getVariancesWorker(symbol, getSymbolLinks(symbol).typeParameters); + return getVariancesWorker( + symbol, + getSymbolLinks(symbol).typeParameters + ); } // Return an array containing the variance of each type parameter. The variance is effectively @@ -24867,10 +44501,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // generic type are structurally compared. We infer the variance information by comparing // instantiations of the generic type for type arguments with known relations. The function // returns the emptyArray singleton when invoked recursively for the given generic type. - function getVariancesWorker(symbol: Symbol, typeParameters: readonly TypeParameter[] = emptyArray): VarianceFlags[] { + function getVariancesWorker( + symbol: Symbol, + typeParameters: readonly TypeParameter[] = emptyArray + ): VarianceFlags[] { const links = getSymbolLinks(symbol); if (!links.variances) { - tracing?.push(tracing.Phase.CheckTypes, "getVariancesWorker", { arity: typeParameters.length, id: getTypeId(getDeclaredTypeOfSymbol(symbol)) }); + tracing?.push(tracing.Phase.CheckTypes, "getVariancesWorker", { + arity: typeParameters.length, + id: getTypeId(getDeclaredTypeOfSymbol(symbol)), + }); const oldVarianceComputation = inVarianceComputation; const saveResolutionStart = resolutionStart; if (!inVarianceComputation) { @@ -24881,26 +44521,53 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const variances = []; for (const tp of typeParameters) { const modifiers = getTypeParameterModifiers(tp); - let variance = modifiers & ModifierFlags.Out ? - modifiers & ModifierFlags.In ? VarianceFlags.Invariant : VarianceFlags.Covariant : - modifiers & ModifierFlags.In ? VarianceFlags.Contravariant : undefined; + let variance = + modifiers & ModifierFlags.Out + ? modifiers & ModifierFlags.In + ? VarianceFlags.Invariant + : VarianceFlags.Covariant + : modifiers & ModifierFlags.In + ? VarianceFlags.Contravariant + : undefined; if (variance === undefined) { let unmeasurable = false; let unreliable = false; const oldHandler = outofbandVarianceMarkerHandler; - outofbandVarianceMarkerHandler = onlyUnreliable => onlyUnreliable ? unreliable = true : unmeasurable = true; + outofbandVarianceMarkerHandler = (onlyUnreliable) => + onlyUnreliable + ? (unreliable = true) + : (unmeasurable = true); // We first compare instantiations where the type parameter is replaced with // marker types that have a known subtype relationship. From this we can infer // invariance, covariance, contravariance or bivariance. - const typeWithSuper = createMarkerType(symbol, tp, markerSuperType); - const typeWithSub = createMarkerType(symbol, tp, markerSubType); - variance = (isTypeAssignableTo(typeWithSub, typeWithSuper) ? VarianceFlags.Covariant : 0) | - (isTypeAssignableTo(typeWithSuper, typeWithSub) ? VarianceFlags.Contravariant : 0); + const typeWithSuper = createMarkerType( + symbol, + tp, + markerSuperType + ); + const typeWithSub = createMarkerType( + symbol, + tp, + markerSubType + ); + variance = + (isTypeAssignableTo(typeWithSub, typeWithSuper) + ? VarianceFlags.Covariant + : 0) | + (isTypeAssignableTo(typeWithSuper, typeWithSub) + ? VarianceFlags.Contravariant + : 0); // If the instantiations appear to be related bivariantly it may be because the // type parameter is independent (i.e. it isn't witnessed anywhere in the generic // type). To determine this we compare instantiations where the type parameter is // replaced with marker types that are known to be unrelated. - if (variance === VarianceFlags.Bivariant && isTypeAssignableTo(createMarkerType(symbol, tp, markerOtherType), typeWithSuper)) { + if ( + variance === VarianceFlags.Bivariant && + isTypeAssignableTo( + createMarkerType(symbol, tp, markerOtherType), + typeWithSuper + ) + ) { variance = VarianceFlags.Independent; } outofbandVarianceMarkerHandler = oldHandler; @@ -24925,15 +44592,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return links.variances; } - function createMarkerType(symbol: Symbol, source: TypeParameter, target: Type) { + function createMarkerType( + symbol: Symbol, + source: TypeParameter, + target: Type + ) { const mapper = makeUnaryTypeMapper(source, target); const type = getDeclaredTypeOfSymbol(symbol); if (isErrorType(type)) { return type; } - const result = symbol.flags & SymbolFlags.TypeAlias ? - getTypeAliasInstantiation(symbol, instantiateTypes(getSymbolLinks(symbol).typeParameters!, mapper)) : - createTypeReference(type as GenericType, instantiateTypes((type as GenericType).typeParameters, mapper)); + const result = + symbol.flags & SymbolFlags.TypeAlias + ? getTypeAliasInstantiation( + symbol, + instantiateTypes( + getSymbolLinks(symbol).typeParameters!, + mapper + ) + ) + : createTypeReference( + type as GenericType, + instantiateTypes( + (type as GenericType).typeParameters, + mapper + ) + ); markerTypes.add(getTypeId(result)); return result; } @@ -24943,14 +44627,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getTypeParameterModifiers(tp: TypeParameter): ModifierFlags { - return reduceLeft(tp.symbol?.declarations, (modifiers, d) => modifiers | getEffectiveModifierFlags(d), ModifierFlags.None) & (ModifierFlags.In | ModifierFlags.Out | ModifierFlags.Const); + return ( + reduceLeft( + tp.symbol?.declarations, + (modifiers, d) => modifiers | getEffectiveModifierFlags(d), + ModifierFlags.None + ) & + (ModifierFlags.In | ModifierFlags.Out | ModifierFlags.Const) + ); } // Return true if the given type reference has a 'void' type argument for a covariant type parameter. // See comment at call in recursiveTypeRelatedTo for when this case matters. - function hasCovariantVoidArgument(typeArguments: readonly Type[], variances: VarianceFlags[]): boolean { + function hasCovariantVoidArgument( + typeArguments: readonly Type[], + variances: VarianceFlags[] + ): boolean { for (let i = 0; i < variances.length; i++) { - if ((variances[i] & VarianceFlags.VarianceMask) === VarianceFlags.Covariant && typeArguments[i].flags & TypeFlags.Void) { + if ( + (variances[i] & VarianceFlags.VarianceMask) === + VarianceFlags.Covariant && + typeArguments[i].flags & TypeFlags.Void + ) { return true; } } @@ -24958,18 +44656,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isUnconstrainedTypeParameter(type: Type) { - return type.flags & TypeFlags.TypeParameter && !getConstraintOfTypeParameter(type as TypeParameter); + return ( + type.flags & TypeFlags.TypeParameter && + !getConstraintOfTypeParameter(type as TypeParameter) + ); } function isNonDeferredTypeReference(type: Type): type is TypeReference { - return !!(getObjectFlags(type) & ObjectFlags.Reference) && !(type as TypeReference).node; + return ( + !!(getObjectFlags(type) & ObjectFlags.Reference) && + !(type as TypeReference).node + ); } function isTypeReferenceWithGenericArguments(type: Type): boolean { - return isNonDeferredTypeReference(type) && some(getTypeArguments(type), t => !!(t.flags & TypeFlags.TypeParameter) || isTypeReferenceWithGenericArguments(t)); + return ( + isNonDeferredTypeReference(type) && + some( + getTypeArguments(type), + (t) => + !!(t.flags & TypeFlags.TypeParameter) || + isTypeReferenceWithGenericArguments(t) + ) + ); } - function getGenericTypeReferenceRelationKey(source: TypeReference, target: TypeReference, postFix: string, ignoreConstraints: boolean) { + function getGenericTypeReferenceRelationKey( + source: TypeReference, + target: TypeReference, + postFix: string, + ignoreConstraints: boolean + ) { const typeParameters: Type[] = []; let constraintMarker = ""; const sourceId = getTypeReferenceId(source, 0); @@ -24993,9 +44710,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We mark type references that reference constrained type parameters such that we know to obtain // and look for a "broadest equivalent key" in the cache. constraintMarker = "*"; - } - else if (depth < 4 && isTypeReferenceWithGenericArguments(t)) { - result += "<" + getTypeReferenceId(t as TypeReference, depth + 1) + ">"; + } else if ( + depth < 4 && + isTypeReferenceWithGenericArguments(t) + ) { + result += + "<" + + getTypeReferenceId(t as TypeReference, depth + 1) + + ">"; continue; } result += "-" + t.id; @@ -25008,24 +44730,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * To improve caching, the relation key for two generic types uses the target's id plus ids of the type parameters. * For other cases, the types ids are used. */ - function getRelationKey(source: Type, target: Type, intersectionState: IntersectionState, relation: Map, ignoreConstraints: boolean) { + function getRelationKey( + source: Type, + target: Type, + intersectionState: IntersectionState, + relation: Map, + ignoreConstraints: boolean + ) { if (relation === identityRelation && source.id > target.id) { const temp = source; source = target; target = temp; } const postFix = intersectionState ? ":" + intersectionState : ""; - return isTypeReferenceWithGenericArguments(source) && isTypeReferenceWithGenericArguments(target) ? - getGenericTypeReferenceRelationKey(source as TypeReference, target as TypeReference, postFix, ignoreConstraints) : - `${source.id},${target.id}${postFix}`; + return isTypeReferenceWithGenericArguments(source) && + isTypeReferenceWithGenericArguments(target) + ? getGenericTypeReferenceRelationKey( + source as TypeReference, + target as TypeReference, + postFix, + ignoreConstraints + ) + : `${source.id},${target.id}${postFix}`; } // Invoke the callback for each underlying property symbol of the given symbol and return the first // value that isn't undefined. - function forEachProperty(prop: Symbol, callback: (p: Symbol) => T): T | undefined { + function forEachProperty( + prop: Symbol, + callback: (p: Symbol) => T + ): T | undefined { if (getCheckFlags(prop) & CheckFlags.Synthetic) { // NOTE: cast to TransientSymbol should be safe because only TransientSymbols can have CheckFlags.Synthetic - for (const t of (prop as TransientSymbol).links.containingType!.types) { + for (const t of (prop as TransientSymbol).links.containingType! + .types) { const p = getPropertyOfType(t, prop.escapedName); const result = p && forEachProperty(p, callback); if (result) { @@ -25039,20 +44777,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Return the declaring class type of a property or undefined if property not declared in class function getDeclaringClass(prop: Symbol) { - return prop.parent && prop.parent.flags & SymbolFlags.Class ? getDeclaredTypeOfSymbol(getParentOfSymbol(prop)!) as InterfaceType : undefined; + return prop.parent && prop.parent.flags & SymbolFlags.Class + ? (getDeclaredTypeOfSymbol( + getParentOfSymbol(prop)! + ) as InterfaceType) + : undefined; } // Return the inherited type of the given property or undefined if property doesn't exist in a base class. function getTypeOfPropertyInBaseClass(property: Symbol) { const classType = getDeclaringClass(property); const baseClassType = classType && getBaseTypes(classType)[0]; - return baseClassType && getTypeOfPropertyOfType(baseClassType, property.escapedName); + return ( + baseClassType && + getTypeOfPropertyOfType(baseClassType, property.escapedName) + ); } // Return true if some underlying source property is declared in a class that derives // from the given base class. - function isPropertyInClassDerivedFrom(prop: Symbol, baseClass: Type | undefined) { - return forEachProperty(prop, sp => { + function isPropertyInClassDerivedFrom( + prop: Symbol, + baseClass: Type | undefined + ) { + return forEachProperty(prop, (sp) => { const sourceClass = getDeclaringClass(sp); return sourceClass ? hasBaseType(sourceClass, baseClass) : false; }); @@ -25060,17 +44808,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Return true if source property is a valid override of protected parts of target property. function isValidOverrideOf(sourceProp: Symbol, targetProp: Symbol) { - return !forEachProperty(targetProp, tp => - getDeclarationModifierFlagsFromSymbol(tp) & ModifierFlags.Protected ? - !isPropertyInClassDerivedFrom(sourceProp, getDeclaringClass(tp)) : false); + return !forEachProperty(targetProp, (tp) => + getDeclarationModifierFlagsFromSymbol(tp) & ModifierFlags.Protected + ? !isPropertyInClassDerivedFrom( + sourceProp, + getDeclaringClass(tp) + ) + : false + ); } // Return true if the given class derives from each of the declaring classes of the protected // constituents of the given property. - function isClassDerivedFromDeclaringClasses(checkClass: T, prop: Symbol, writing: boolean) { - return forEachProperty(prop, p => - getDeclarationModifierFlagsFromSymbol(p, writing) & ModifierFlags.Protected ? - !hasBaseType(checkClass, getDeclaringClass(p)) : false) ? undefined : checkClass; + function isClassDerivedFromDeclaringClasses( + checkClass: T, + prop: Symbol, + writing: boolean + ) { + return forEachProperty(prop, (p) => + getDeclarationModifierFlagsFromSymbol(p, writing) & + ModifierFlags.Protected + ? !hasBaseType(checkClass, getDeclaringClass(p)) + : false + ) + ? undefined + : checkClass; } // Return true if the given type is deeply nested. We consider this to be the case when the given stack contains @@ -25084,13 +44846,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // It is possible, though highly unlikely, for the deeply nested check to be true in a situation where a chain of // instantiations is not infinitely expanding. Effectively, we will generate a false positive when two types are // structurally equal to at least maxDepth levels, but unequal at some level beyond that. - function isDeeplyNestedType(type: Type, stack: Type[], depth: number, maxDepth = 3): boolean { + function isDeeplyNestedType( + type: Type, + stack: Type[], + depth: number, + maxDepth = 3 + ): boolean { if (depth >= maxDepth) { - if ((getObjectFlags(type) & ObjectFlags.InstantiatedMapped) === ObjectFlags.InstantiatedMapped) { + if ( + (getObjectFlags(type) & ObjectFlags.InstantiatedMapped) === + ObjectFlags.InstantiatedMapped + ) { type = getMappedTargetWithSymbol(type); } if (type.flags & TypeFlags.Intersection) { - return some((type as IntersectionType).types, t => isDeeplyNestedType(t, stack, depth, maxDepth)); + return some((type as IntersectionType).types, (t) => + isDeeplyNestedType(t, stack, depth, maxDepth) + ); } const identity = getRecursionIdentity(type); let count = 0; @@ -25120,21 +44892,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getMappedTargetWithSymbol(type: Type) { let target; while ( - (getObjectFlags(type) & ObjectFlags.InstantiatedMapped) === ObjectFlags.InstantiatedMapped && + (getObjectFlags(type) & ObjectFlags.InstantiatedMapped) === + ObjectFlags.InstantiatedMapped && (target = getModifiersTypeFromMappedType(type as MappedType)) && - (target.symbol || target.flags & TypeFlags.Intersection && some((target as IntersectionType).types, t => !!t.symbol)) + (target.symbol || + (target.flags & TypeFlags.Intersection && + some( + (target as IntersectionType).types, + (t) => !!t.symbol + ))) ) { type = target; } return type; } - function hasMatchingRecursionIdentity(type: Type, identity: object): boolean { - if ((getObjectFlags(type) & ObjectFlags.InstantiatedMapped) === ObjectFlags.InstantiatedMapped) { + function hasMatchingRecursionIdentity( + type: Type, + identity: object + ): boolean { + if ( + (getObjectFlags(type) & ObjectFlags.InstantiatedMapped) === + ObjectFlags.InstantiatedMapped + ) { type = getMappedTargetWithSymbol(type); } if (type.flags & TypeFlags.Intersection) { - return some((type as IntersectionType).types, t => hasMatchingRecursionIdentity(t, identity)); + return some((type as IntersectionType).types, (t) => + hasMatchingRecursionIdentity(t, identity) + ); } return getRecursionIdentity(type) === identity; } @@ -25147,14 +44933,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // reference the type have a recursion identity that differs from the object identity. function getRecursionIdentity(type: Type): object { // Object and array literals are known not to contain recursive references and don't need a recursion identity. - if (type.flags & TypeFlags.Object && !isObjectOrArrayLiteralType(type)) { - if (getObjectFlags(type) & ObjectFlags.Reference && (type as TypeReference).node) { + if ( + type.flags & TypeFlags.Object && + !isObjectOrArrayLiteralType(type) + ) { + if ( + getObjectFlags(type) & ObjectFlags.Reference && + (type as TypeReference).node + ) { // Deferred type references are tracked through their associated AST node. This gives us finer // granularity than using their associated target because each manifest type reference has a // unique AST node. return (type as TypeReference).node!; } - if (type.symbol && !(getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol.flags & SymbolFlags.Class)) { + if ( + type.symbol && + !( + getObjectFlags(type) & ObjectFlags.Anonymous && + type.symbol.flags & SymbolFlags.Class + ) + ) { // We track object types that have a symbol by that symbol (representing the origin of the type), but // exclude the static side of a class since it shares its symbol with the instance side. return type.symbol; @@ -25172,8 +44970,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Identity is the leftmost object type in a chain of indexed accesses, eg, in A[P1][P2][P3] it is A. do { type = (type as IndexedAccessType).objectType; - } - while (type.flags & TypeFlags.IndexedAccess); + } while (type.flags & TypeFlags.IndexedAccess); return type; } if (type.flags & TypeFlags.Conditional) { @@ -25183,19 +44980,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return type; } - function isPropertyIdenticalTo(sourceProp: Symbol, targetProp: Symbol): boolean { - return compareProperties(sourceProp, targetProp, compareTypesIdentical) !== Ternary.False; + function isPropertyIdenticalTo( + sourceProp: Symbol, + targetProp: Symbol + ): boolean { + return ( + compareProperties(sourceProp, targetProp, compareTypesIdentical) !== + Ternary.False + ); } - function compareProperties(sourceProp: Symbol, targetProp: Symbol, compareTypes: (source: Type, target: Type) => Ternary): Ternary { + function compareProperties( + sourceProp: Symbol, + targetProp: Symbol, + compareTypes: (source: Type, target: Type) => Ternary + ): Ternary { // Two members are considered identical when // - they are public properties with identical names, optionality, and types, // - they are private or protected properties originating in the same declaration and having identical types if (sourceProp === targetProp) { return Ternary.True; } - const sourcePropAccessibility = getDeclarationModifierFlagsFromSymbol(sourceProp) & ModifierFlags.NonPublicAccessibilityModifier; - const targetPropAccessibility = getDeclarationModifierFlagsFromSymbol(targetProp) & ModifierFlags.NonPublicAccessibilityModifier; + const sourcePropAccessibility = + getDeclarationModifierFlagsFromSymbol(sourceProp) & + ModifierFlags.NonPublicAccessibilityModifier; + const targetPropAccessibility = + getDeclarationModifierFlagsFromSymbol(targetProp) & + ModifierFlags.NonPublicAccessibilityModifier; if (sourcePropAccessibility !== targetPropAccessibility) { return Ternary.False; } @@ -25203,19 +45014,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (getTargetSymbol(sourceProp) !== getTargetSymbol(targetProp)) { return Ternary.False; } - } - else { - if ((sourceProp.flags & SymbolFlags.Optional) !== (targetProp.flags & SymbolFlags.Optional)) { + } else { + if ( + (sourceProp.flags & SymbolFlags.Optional) !== + (targetProp.flags & SymbolFlags.Optional) + ) { return Ternary.False; } } if (isReadonlySymbol(sourceProp) !== isReadonlySymbol(targetProp)) { return Ternary.False; } - return compareTypes(getTypeOfSymbol(sourceProp), getTypeOfSymbol(targetProp)); + return compareTypes( + getTypeOfSymbol(sourceProp), + getTypeOfSymbol(targetProp) + ); } - function isMatchingSignature(source: Signature, target: Signature, partialMatch: boolean) { + function isMatchingSignature( + source: Signature, + target: Signature, + partialMatch: boolean + ) { const sourceParameterCount = getParameterCount(source); const targetParameterCount = getParameterCount(target); const sourceMinArgumentCount = getMinArgumentCount(source); @@ -25242,12 +45062,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** * See signatureRelatedTo, compareSignaturesIdentical */ - function compareSignaturesIdentical(source: Signature, target: Signature, partialMatch: boolean, ignoreThisTypes: boolean, ignoreReturnTypes: boolean, compareTypes: (s: Type, t: Type) => Ternary): Ternary { + function compareSignaturesIdentical( + source: Signature, + target: Signature, + partialMatch: boolean, + ignoreThisTypes: boolean, + ignoreReturnTypes: boolean, + compareTypes: (s: Type, t: Type) => Ternary + ): Ternary { // TODO (drosen): De-duplicate code between related functions. if (source === target) { return Ternary.True; } - if (!(isMatchingSignature(source, target, partialMatch))) { + if (!isMatchingSignature(source, target, partialMatch)) { return Ternary.False; } // Check that the two signatures have the same number of type parameters. @@ -25257,18 +45084,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Check that type parameter constraints and defaults match. If they do, instantiate the source // signature with the type parameters of the target signature and continue the comparison. if (target.typeParameters) { - const mapper = createTypeMapper(source.typeParameters!, target.typeParameters); + const mapper = createTypeMapper( + source.typeParameters!, + target.typeParameters + ); for (let i = 0; i < target.typeParameters.length; i++) { const s = source.typeParameters![i]; const t = target.typeParameters[i]; if ( - !(s === t || compareTypes(instantiateType(getConstraintFromTypeParameter(s), mapper) || unknownType, getConstraintFromTypeParameter(t) || unknownType) && - compareTypes(instantiateType(getDefaultFromTypeParameter(s), mapper) || unknownType, getDefaultFromTypeParameter(t) || unknownType)) + !( + s === t || + (compareTypes( + instantiateType( + getConstraintFromTypeParameter(s), + mapper + ) || unknownType, + getConstraintFromTypeParameter(t) || unknownType + ) && + compareTypes( + instantiateType( + getDefaultFromTypeParameter(s), + mapper + ) || unknownType, + getDefaultFromTypeParameter(t) || unknownType + )) + ) ) { return Ternary.False; } } - source = instantiateSignature(source, mapper, /*eraseTypeParameters*/ true); + source = instantiateSignature( + source, + mapper, + /*eraseTypeParameters*/ true + ); } let result = Ternary.True; if (!ignoreThisTypes) { @@ -25276,7 +45125,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (sourceThisType) { const targetThisType = getThisTypeOfSignature(target); if (targetThisType) { - const related = compareTypes(sourceThisType, targetThisType); + const related = compareTypes( + sourceThisType, + targetThisType + ); if (!related) { return Ternary.False; } @@ -25297,18 +45149,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!ignoreReturnTypes) { const sourceTypePredicate = getTypePredicateOfSignature(source); const targetTypePredicate = getTypePredicateOfSignature(target); - result &= sourceTypePredicate || targetTypePredicate ? - compareTypePredicatesIdentical(sourceTypePredicate, targetTypePredicate, compareTypes) : - compareTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target)); + result &= + sourceTypePredicate || targetTypePredicate + ? compareTypePredicatesIdentical( + sourceTypePredicate, + targetTypePredicate, + compareTypes + ) + : compareTypes( + getReturnTypeOfSignature(source), + getReturnTypeOfSignature(target) + ); } return result; } - function compareTypePredicatesIdentical(source: TypePredicate | undefined, target: TypePredicate | undefined, compareTypes: (s: Type, t: Type) => Ternary): Ternary { - return !(source && target && typePredicateKindsMatch(source, target)) ? Ternary.False : - source.type === target.type ? Ternary.True : - source.type && target.type ? compareTypes(source.type, target.type) : - Ternary.False; + function compareTypePredicatesIdentical( + source: TypePredicate | undefined, + target: TypePredicate | undefined, + compareTypes: (s: Type, t: Type) => Ternary + ): Ternary { + return !(source && target && typePredicateKindsMatch(source, target)) + ? Ternary.False + : source.type === target.type + ? Ternary.True + : source.type && target.type + ? compareTypes(source.type, target.type) + : Ternary.False; } function literalTypesWithSameBaseType(types: Type[]): boolean { @@ -25326,7 +45193,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getCombinedTypeFlags(types: Type[]): TypeFlags { - return reduceLeft(types, (flags, t) => flags | (t.flags & TypeFlags.Union ? getCombinedTypeFlags((t as UnionType).types) : t.flags), 0 as TypeFlags); + return reduceLeft( + types, + (flags, t) => + flags | + (t.flags & TypeFlags.Union + ? getCombinedTypeFlags((t as UnionType).types) + : t.flags), + 0 as TypeFlags + ); } function getCommonSupertype(types: Type[]): Type { @@ -25334,28 +45209,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return types[0]; } // Remove nullable types from each of the candidates. - const primaryTypes = strictNullChecks ? sameMap(types, t => filterType(t, u => !(u.flags & TypeFlags.Nullable))) : types; + const primaryTypes = strictNullChecks + ? sameMap(types, (t) => + filterType(t, (u) => !(u.flags & TypeFlags.Nullable)) + ) + : types; // When the candidate types are all literal types with the same base type, return a union // of those literal types. Otherwise, return the leftmost type for which no type to the // right is a supertype. - const superTypeOrUnion = literalTypesWithSameBaseType(primaryTypes) ? - getUnionType(primaryTypes) : - reduceLeft(primaryTypes, (s, t) => isTypeSubtypeOf(s, t) ? t : s)!; + const superTypeOrUnion = literalTypesWithSameBaseType(primaryTypes) + ? getUnionType(primaryTypes) + : reduceLeft(primaryTypes, (s, t) => + isTypeSubtypeOf(s, t) ? t : s + )!; // Add any nullable types that occurred in the candidates back to the result. - return primaryTypes === types ? superTypeOrUnion : getNullableType(superTypeOrUnion, getCombinedTypeFlags(types) & TypeFlags.Nullable); + return primaryTypes === types + ? superTypeOrUnion + : getNullableType( + superTypeOrUnion, + getCombinedTypeFlags(types) & TypeFlags.Nullable + ); } // Return the leftmost type for which no type to the right is a subtype. function getCommonSubtype(types: Type[]) { - return reduceLeft(types, (s, t) => isTypeSubtypeOf(t, s) ? t : s)!; + return reduceLeft(types, (s, t) => (isTypeSubtypeOf(t, s) ? t : s))!; } function isArrayType(type: Type): type is TypeReference { - return !!(getObjectFlags(type) & ObjectFlags.Reference) && ((type as TypeReference).target === globalArrayType || (type as TypeReference).target === globalReadonlyArrayType); + return ( + !!(getObjectFlags(type) & ObjectFlags.Reference) && + ((type as TypeReference).target === globalArrayType || + (type as TypeReference).target === globalReadonlyArrayType) + ); } function isReadonlyArrayType(type: Type): boolean { - return !!(getObjectFlags(type) & ObjectFlags.Reference) && (type as TypeReference).target === globalReadonlyArrayType; + return ( + !!(getObjectFlags(type) & ObjectFlags.Reference) && + (type as TypeReference).target === globalReadonlyArrayType + ); } function isArrayOrTupleType(type: Type): type is TypeReference { @@ -25363,7 +45256,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isMutableArrayOrTuple(type: Type): boolean { - return isArrayType(type) && !isReadonlyArrayType(type) || isTupleType(type) && !type.target.readonly; + return ( + (isArrayType(type) && !isReadonlyArrayType(type)) || + (isTupleType(type) && !type.target.readonly) + ); } function getElementTypeOfArrayType(type: Type): Type | undefined { @@ -25373,29 +45269,51 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isArrayLikeType(type: Type): boolean { // A type is array-like if it is a reference to the global Array or global ReadonlyArray type, // or if it is not the undefined or null type and if it is assignable to ReadonlyArray - return isArrayType(type) || !(type.flags & TypeFlags.Nullable) && isTypeAssignableTo(type, anyReadonlyArrayType); + return ( + isArrayType(type) || + (!(type.flags & TypeFlags.Nullable) && + isTypeAssignableTo(type, anyReadonlyArrayType)) + ); } function isMutableArrayLikeType(type: Type): boolean { // A type is mutable-array-like if it is a reference to the global Array type, or if it is not the // any, undefined or null type and if it is assignable to Array - return isMutableArrayOrTuple(type) || !(type.flags & (TypeFlags.Any | TypeFlags.Nullable)) && isTypeAssignableTo(type, anyArrayType); + return ( + isMutableArrayOrTuple(type) || + (!(type.flags & (TypeFlags.Any | TypeFlags.Nullable)) && + isTypeAssignableTo(type, anyArrayType)) + ); } function getSingleBaseForNonAugmentingSubtype(type: Type) { - if (!(getObjectFlags(type) & ObjectFlags.Reference) || !(getObjectFlags((type as TypeReference).target) & ObjectFlags.ClassOrInterface)) { + if ( + !(getObjectFlags(type) & ObjectFlags.Reference) || + !( + getObjectFlags((type as TypeReference).target) & + ObjectFlags.ClassOrInterface + ) + ) { return undefined; } if (getObjectFlags(type) & ObjectFlags.IdenticalBaseTypeCalculated) { - return getObjectFlags(type) & ObjectFlags.IdenticalBaseTypeExists ? (type as TypeReference).cachedEquivalentBaseType : undefined; + return getObjectFlags(type) & ObjectFlags.IdenticalBaseTypeExists + ? (type as TypeReference).cachedEquivalentBaseType + : undefined; } - (type as TypeReference).objectFlags |= ObjectFlags.IdenticalBaseTypeCalculated; + (type as TypeReference).objectFlags |= + ObjectFlags.IdenticalBaseTypeCalculated; const target = (type as TypeReference).target as InterfaceType; if (getObjectFlags(target) & ObjectFlags.Class) { const baseTypeNode = getBaseTypeNodeOfClass(target); // A base type expression may circularly reference the class itself (e.g. as an argument to function call), so we only // check for base types specified as simple qualified names. - if (baseTypeNode && baseTypeNode.expression.kind !== SyntaxKind.Identifier && baseTypeNode.expression.kind !== SyntaxKind.PropertyAccessExpression) { + if ( + baseTypeNode && + baseTypeNode.expression.kind !== SyntaxKind.Identifier && + baseTypeNode.expression.kind !== + SyntaxKind.PropertyAccessExpression + ) { return undefined; } } @@ -25406,16 +45324,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (getMembersOfSymbol(type.symbol).size) { return undefined; // If the interface has any members, they may subtype members in the base, so we should do a full structural comparison } - let instantiatedBase = !length(target.typeParameters) ? bases[0] : instantiateType(bases[0], createTypeMapper(target.typeParameters!, getTypeArguments(type as TypeReference).slice(0, target.typeParameters!.length))); - if (length(getTypeArguments(type as TypeReference)) > length(target.typeParameters)) { - instantiatedBase = getTypeWithThisArgument(instantiatedBase, last(getTypeArguments(type as TypeReference))); + let instantiatedBase = !length(target.typeParameters) + ? bases[0] + : instantiateType( + bases[0], + createTypeMapper( + target.typeParameters!, + getTypeArguments(type as TypeReference).slice( + 0, + target.typeParameters!.length + ) + ) + ); + if ( + length(getTypeArguments(type as TypeReference)) > + length(target.typeParameters) + ) { + instantiatedBase = getTypeWithThisArgument( + instantiatedBase, + last(getTypeArguments(type as TypeReference)) + ); } - (type as TypeReference).objectFlags |= ObjectFlags.IdenticalBaseTypeExists; - return (type as TypeReference).cachedEquivalentBaseType = instantiatedBase; + (type as TypeReference).objectFlags |= + ObjectFlags.IdenticalBaseTypeExists; + return ((type as TypeReference).cachedEquivalentBaseType = + instantiatedBase); } function isEmptyLiteralType(type: Type): boolean { - return strictNullChecks ? type === implicitNeverType : type === undefinedWideningType; + return strictNullChecks + ? type === implicitNeverType + : type === undefinedWideningType; } function isEmptyArrayLiteralType(type: Type): boolean { @@ -25425,9 +45364,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isTupleLikeType(type: Type): boolean { let lengthType; - return isTupleType(type) || + return ( + isTupleType(type) || !!getPropertyOfType(type, "0" as __String) || - isArrayLikeType(type) && !!(lengthType = getTypeOfPropertyOfType(type, "length" as __String)) && everyType(lengthType, t => !!(t.flags & TypeFlags.NumberLiteral)); + (isArrayLikeType(type) && + !!(lengthType = getTypeOfPropertyOfType( + type, + "length" as __String + )) && + everyType( + lengthType, + (t) => !!(t.flags & TypeFlags.NumberLiteral) + )) + ); } function isArrayOrTupleLikeType(type: Type): boolean { @@ -25435,12 +45384,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getTupleElementType(type: Type, index: number) { - const propType = getTypeOfPropertyOfType(type, "" + index as __String); + const propType = getTypeOfPropertyOfType( + type, + ("" + index) as __String + ); if (propType) { return propType; } if (everyType(type, isTupleType)) { - return getTupleElementTypeOutOfStartCount(type, index, compilerOptions.noUncheckedIndexedAccess ? undefinedType : undefined); + return getTupleElementTypeOutOfStartCount( + type, + index, + compilerOptions.noUncheckedIndexedAccess + ? undefinedType + : undefined + ); } return undefined; } @@ -25457,83 +45415,144 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Intersections that reduce to 'never' (e.g. 'T & null' where 'T extends {}') are not unit types. const t = getBaseConstraintOrType(type); // Scan intersections such that tagged literal types are considered unit types. - return t.flags & TypeFlags.Intersection ? some((t as IntersectionType).types, isUnitType) : isUnitType(t); + return t.flags & TypeFlags.Intersection + ? some((t as IntersectionType).types, isUnitType) + : isUnitType(t); } function extractUnitType(type: Type) { - return type.flags & TypeFlags.Intersection ? find((type as IntersectionType).types, isUnitType) || type : type; + return type.flags & TypeFlags.Intersection + ? find((type as IntersectionType).types, isUnitType) || type + : type; } function isLiteralType(type: Type): boolean { - return type.flags & TypeFlags.Boolean ? true : - type.flags & TypeFlags.Union ? type.flags & TypeFlags.EnumLiteral ? true : every((type as UnionType).types, isUnitType) : - isUnitType(type); + return type.flags & TypeFlags.Boolean + ? true + : type.flags & TypeFlags.Union + ? type.flags & TypeFlags.EnumLiteral + ? true + : every((type as UnionType).types, isUnitType) + : isUnitType(type); } function getBaseTypeOfLiteralType(type: Type): Type { - return type.flags & TypeFlags.EnumLike ? getBaseTypeOfEnumLikeType(type as LiteralType) : - type.flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) ? stringType : - type.flags & TypeFlags.NumberLiteral ? numberType : - type.flags & TypeFlags.BigIntLiteral ? bigintType : - type.flags & TypeFlags.BooleanLiteral ? booleanType : - type.flags & TypeFlags.Union ? getBaseTypeOfLiteralTypeUnion(type as UnionType) : - type; + return type.flags & TypeFlags.EnumLike + ? getBaseTypeOfEnumLikeType(type as LiteralType) + : type.flags & + (TypeFlags.StringLiteral | + TypeFlags.TemplateLiteral | + TypeFlags.StringMapping) + ? stringType + : type.flags & TypeFlags.NumberLiteral + ? numberType + : type.flags & TypeFlags.BigIntLiteral + ? bigintType + : type.flags & TypeFlags.BooleanLiteral + ? booleanType + : type.flags & TypeFlags.Union + ? getBaseTypeOfLiteralTypeUnion(type as UnionType) + : type; } function getBaseTypeOfLiteralTypeUnion(type: UnionType) { const key = `B${getTypeId(type)}`; - return getCachedType(key) ?? setCachedType(key, mapType(type, getBaseTypeOfLiteralType)); + return ( + getCachedType(key) ?? + setCachedType(key, mapType(type, getBaseTypeOfLiteralType)) + ); } // This like getBaseTypeOfLiteralType, but instead treats enum literals as strings/numbers instead // of returning their enum base type (which depends on the types of other literals in the enum). function getBaseTypeOfLiteralTypeForComparison(type: Type): Type { - return type.flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) ? stringType : - type.flags & (TypeFlags.NumberLiteral | TypeFlags.Enum) ? numberType : - type.flags & TypeFlags.BigIntLiteral ? bigintType : - type.flags & TypeFlags.BooleanLiteral ? booleanType : - type.flags & TypeFlags.Union ? mapType(type, getBaseTypeOfLiteralTypeForComparison) : - type; + return type.flags & + (TypeFlags.StringLiteral | + TypeFlags.TemplateLiteral | + TypeFlags.StringMapping) + ? stringType + : type.flags & (TypeFlags.NumberLiteral | TypeFlags.Enum) + ? numberType + : type.flags & TypeFlags.BigIntLiteral + ? bigintType + : type.flags & TypeFlags.BooleanLiteral + ? booleanType + : type.flags & TypeFlags.Union + ? mapType(type, getBaseTypeOfLiteralTypeForComparison) + : type; } function getWidenedLiteralType(type: Type): Type { - return type.flags & TypeFlags.EnumLike && isFreshLiteralType(type) ? getBaseTypeOfEnumLikeType(type as LiteralType) : - type.flags & TypeFlags.StringLiteral && isFreshLiteralType(type) ? stringType : - type.flags & TypeFlags.NumberLiteral && isFreshLiteralType(type) ? numberType : - type.flags & TypeFlags.BigIntLiteral && isFreshLiteralType(type) ? bigintType : - type.flags & TypeFlags.BooleanLiteral && isFreshLiteralType(type) ? booleanType : - type.flags & TypeFlags.Union ? mapType(type as UnionType, getWidenedLiteralType) : - type; + return type.flags & TypeFlags.EnumLike && isFreshLiteralType(type) + ? getBaseTypeOfEnumLikeType(type as LiteralType) + : type.flags & TypeFlags.StringLiteral && isFreshLiteralType(type) + ? stringType + : type.flags & TypeFlags.NumberLiteral && isFreshLiteralType(type) + ? numberType + : type.flags & TypeFlags.BigIntLiteral && isFreshLiteralType(type) + ? bigintType + : type.flags & TypeFlags.BooleanLiteral && isFreshLiteralType(type) + ? booleanType + : type.flags & TypeFlags.Union + ? mapType(type as UnionType, getWidenedLiteralType) + : type; } function getWidenedUniqueESSymbolType(type: Type): Type { - return type.flags & TypeFlags.UniqueESSymbol ? esSymbolType : - type.flags & TypeFlags.Union ? mapType(type as UnionType, getWidenedUniqueESSymbolType) : - type; + return type.flags & TypeFlags.UniqueESSymbol + ? esSymbolType + : type.flags & TypeFlags.Union + ? mapType(type as UnionType, getWidenedUniqueESSymbolType) + : type; } - function getWidenedLiteralLikeTypeForContextualType(type: Type, contextualType: Type | undefined) { + function getWidenedLiteralLikeTypeForContextualType( + type: Type, + contextualType: Type | undefined + ) { if (!isLiteralOfContextualType(type, contextualType)) { type = getWidenedUniqueESSymbolType(getWidenedLiteralType(type)); } return getRegularTypeOfLiteralType(type); } - function getWidenedLiteralLikeTypeForContextualReturnTypeIfNeeded(type: Type | undefined, contextualSignatureReturnType: Type | undefined, isAsync: boolean) { + function getWidenedLiteralLikeTypeForContextualReturnTypeIfNeeded( + type: Type | undefined, + contextualSignatureReturnType: Type | undefined, + isAsync: boolean + ) { if (type && isUnitType(type)) { - const contextualType = !contextualSignatureReturnType ? undefined : - isAsync ? getPromisedTypeOfPromise(contextualSignatureReturnType) : - contextualSignatureReturnType; - type = getWidenedLiteralLikeTypeForContextualType(type, contextualType); + const contextualType = !contextualSignatureReturnType + ? undefined + : isAsync + ? getPromisedTypeOfPromise(contextualSignatureReturnType) + : contextualSignatureReturnType; + type = getWidenedLiteralLikeTypeForContextualType( + type, + contextualType + ); } return type; } - function getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded(type: Type | undefined, contextualSignatureReturnType: Type | undefined, kind: IterationTypeKind, isAsyncGenerator: boolean) { + function getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded( + type: Type | undefined, + contextualSignatureReturnType: Type | undefined, + kind: IterationTypeKind, + isAsyncGenerator: boolean + ) { if (type && isUnitType(type)) { - const contextualType = !contextualSignatureReturnType ? undefined : - getIterationTypeOfGeneratorFunctionReturnType(kind, contextualSignatureReturnType, isAsyncGenerator); - type = getWidenedLiteralLikeTypeForContextualType(type, contextualType); + const contextualType = !contextualSignatureReturnType + ? undefined + : getIterationTypeOfGeneratorFunctionReturnType( + kind, + contextualSignatureReturnType, + isAsyncGenerator + ); + type = getWidenedLiteralLikeTypeForContextualType( + type, + contextualType + ); } return type; } @@ -25543,29 +45562,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Prefer using isTupleLikeType() unless the use of `elementTypes`/`getTypeArguments` is required. */ function isTupleType(type: Type): type is TupleTypeReference { - return !!(getObjectFlags(type) & ObjectFlags.Reference && (type as TypeReference).target.objectFlags & ObjectFlags.Tuple); + return !!( + getObjectFlags(type) & ObjectFlags.Reference && + (type as TypeReference).target.objectFlags & ObjectFlags.Tuple + ); } function isGenericTupleType(type: Type): type is TupleTypeReference { - return isTupleType(type) && !!(type.target.combinedFlags & ElementFlags.Variadic); + return ( + isTupleType(type) && + !!(type.target.combinedFlags & ElementFlags.Variadic) + ); } - function isSingleElementGenericTupleType(type: Type): type is TupleTypeReference { - return isGenericTupleType(type) && type.target.elementFlags.length === 1; + function isSingleElementGenericTupleType( + type: Type + ): type is TupleTypeReference { + return ( + isGenericTupleType(type) && type.target.elementFlags.length === 1 + ); } function getRestTypeOfTupleType(type: TupleTypeReference) { return getElementTypeOfSliceOfTupleType(type, type.target.fixedLength); } - function getTupleElementTypeOutOfStartCount(type: Type, index: number, undefinedOrMissingType: Type | undefined) { - return mapType(type, t => { + function getTupleElementTypeOutOfStartCount( + type: Type, + index: number, + undefinedOrMissingType: Type | undefined + ) { + return mapType(type, (t) => { const tupleType = t as TupleTypeReference; const restType = getRestTypeOfTupleType(tupleType); if (!restType) { return undefinedType; } - if (undefinedOrMissingType && index >= getTotalFixedElementCount(tupleType.target)) { + if ( + undefinedOrMissingType && + index >= getTotalFixedElementCount(tupleType.target) + ) { return getUnionType([restType, undefinedOrMissingType]); } return restType; @@ -25577,23 +45613,50 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return restType && createArrayType(restType); } - function getElementTypeOfSliceOfTupleType(type: TupleTypeReference, index: number, endSkipCount = 0, writing = false, noReductions = false) { + function getElementTypeOfSliceOfTupleType( + type: TupleTypeReference, + index: number, + endSkipCount = 0, + writing = false, + noReductions = false + ) { const length = getTypeReferenceArity(type) - endSkipCount; if (index < length) { const typeArguments = getTypeArguments(type); const elementTypes: Type[] = []; for (let i = index; i < length; i++) { const t = typeArguments[i]; - elementTypes.push(type.target.elementFlags[i] & ElementFlags.Variadic ? getIndexedAccessType(t, numberType) : t); + elementTypes.push( + type.target.elementFlags[i] & ElementFlags.Variadic + ? getIndexedAccessType(t, numberType) + : t + ); } - return writing ? getIntersectionType(elementTypes) : getUnionType(elementTypes, noReductions ? UnionReduction.None : UnionReduction.Literal); + return writing + ? getIntersectionType(elementTypes) + : getUnionType( + elementTypes, + noReductions + ? UnionReduction.None + : UnionReduction.Literal + ); } return undefined; } - function isTupleTypeStructureMatching(t1: TupleTypeReference, t2: TupleTypeReference) { - return getTypeReferenceArity(t1) === getTypeReferenceArity(t2) && - every(t1.target.elementFlags, (f, i) => (f & ElementFlags.Variable) === (t2.target.elementFlags[i] & ElementFlags.Variable)); + function isTupleTypeStructureMatching( + t1: TupleTypeReference, + t2: TupleTypeReference + ) { + return ( + getTypeReferenceArity(t1) === getTypeReferenceArity(t2) && + every( + t1.target.elementFlags, + (f, i) => + (f & ElementFlags.Variable) === + (t2.target.elementFlags[i] & ElementFlags.Variable) + ) + ); } function isZeroBigInt({ value }: BigIntLiteralType) { @@ -25601,7 +45664,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function removeDefinitelyFalsyTypes(type: Type): Type { - return filterType(type, t => hasTypeFacts(t, TypeFacts.Truthy)); + return filterType(type, (t) => hasTypeFacts(t, TypeFacts.Truthy)); } function extractDefinitelyFalsyTypes(type: Type): Type { @@ -25609,16 +45672,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getDefinitelyFalsyPartOfType(type: Type): Type { - return type.flags & TypeFlags.String ? emptyStringType : - type.flags & TypeFlags.Number ? zeroType : - type.flags & TypeFlags.BigInt ? zeroBigIntType : - type === regularFalseType || - type === falseType || - type.flags & (TypeFlags.Void | TypeFlags.Undefined | TypeFlags.Null | TypeFlags.AnyOrUnknown) || - type.flags & TypeFlags.StringLiteral && (type as StringLiteralType).value === "" || - type.flags & TypeFlags.NumberLiteral && (type as NumberLiteralType).value === 0 || - type.flags & TypeFlags.BigIntLiteral && isZeroBigInt(type as BigIntLiteralType) ? type : - neverType; + return type.flags & TypeFlags.String + ? emptyStringType + : type.flags & TypeFlags.Number + ? zeroType + : type.flags & TypeFlags.BigInt + ? zeroBigIntType + : type === regularFalseType || + type === falseType || + type.flags & + (TypeFlags.Void | + TypeFlags.Undefined | + TypeFlags.Null | + TypeFlags.AnyOrUnknown) || + (type.flags & TypeFlags.StringLiteral && + (type as StringLiteralType).value === "") || + (type.flags & TypeFlags.NumberLiteral && + (type as NumberLiteralType).value === 0) || + (type.flags & TypeFlags.BigIntLiteral && + isZeroBigInt(type as BigIntLiteralType)) + ? type + : neverType; } /** @@ -25627,30 +45701,49 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param flags - Either TypeFlags.Undefined or TypeFlags.Null, or both */ function getNullableType(type: Type, flags: TypeFlags): Type { - const missing = (flags & ~type.flags) & (TypeFlags.Undefined | TypeFlags.Null); - return missing === 0 ? type : - missing === TypeFlags.Undefined ? getUnionType([type, undefinedType]) : - missing === TypeFlags.Null ? getUnionType([type, nullType]) : - getUnionType([type, undefinedType, nullType]); + const missing = + flags & ~type.flags & (TypeFlags.Undefined | TypeFlags.Null); + return missing === 0 + ? type + : missing === TypeFlags.Undefined + ? getUnionType([type, undefinedType]) + : missing === TypeFlags.Null + ? getUnionType([type, nullType]) + : getUnionType([type, undefinedType, nullType]); } function getOptionalType(type: Type, isProperty = false): Type { Debug.assert(strictNullChecks); - const missingOrUndefined = isProperty ? undefinedOrMissingType : undefinedType; - return type === missingOrUndefined || type.flags & TypeFlags.Union && (type as UnionType).types[0] === missingOrUndefined ? type : getUnionType([type, missingOrUndefined]); + const missingOrUndefined = isProperty + ? undefinedOrMissingType + : undefinedType; + return type === missingOrUndefined || + (type.flags & TypeFlags.Union && + (type as UnionType).types[0] === missingOrUndefined) + ? type + : getUnionType([type, missingOrUndefined]); } function getGlobalNonNullableTypeInstantiation(type: Type) { if (!deferredGlobalNonNullableTypeAlias) { - deferredGlobalNonNullableTypeAlias = getGlobalSymbol("NonNullable" as __String, SymbolFlags.TypeAlias, /*diagnostic*/ undefined) || unknownSymbol; + deferredGlobalNonNullableTypeAlias = + getGlobalSymbol( + "NonNullable" as __String, + SymbolFlags.TypeAlias, + /*diagnostic*/ undefined + ) || unknownSymbol; } - return deferredGlobalNonNullableTypeAlias !== unknownSymbol ? - getTypeAliasInstantiation(deferredGlobalNonNullableTypeAlias, [type]) : - getIntersectionType([type, emptyObjectType]); + return deferredGlobalNonNullableTypeAlias !== unknownSymbol + ? getTypeAliasInstantiation(deferredGlobalNonNullableTypeAlias, [ + type, + ]) + : getIntersectionType([type, emptyObjectType]); } function getNonNullableType(type: Type): Type { - return strictNullChecks ? getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type; + return strictNullChecks + ? getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) + : type; } function addOptionalTypeMarker(type: Type) { @@ -25661,26 +45754,44 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return strictNullChecks ? removeType(type, optionalType) : type; } - function propagateOptionalTypeMarker(type: Type, node: OptionalChain, wasOptional: boolean) { - return wasOptional ? isOutermostOptionalChain(node) ? getOptionalType(type) : addOptionalTypeMarker(type) : type; + function propagateOptionalTypeMarker( + type: Type, + node: OptionalChain, + wasOptional: boolean + ) { + return wasOptional + ? isOutermostOptionalChain(node) + ? getOptionalType(type) + : addOptionalTypeMarker(type) + : type; } function getOptionalExpressionType(exprType: Type, expression: Expression) { - return isExpressionOfOptionalChainRoot(expression) ? getNonNullableType(exprType) : - isOptionalChain(expression) ? removeOptionalTypeMarker(exprType) : - exprType; + return isExpressionOfOptionalChainRoot(expression) + ? getNonNullableType(exprType) + : isOptionalChain(expression) + ? removeOptionalTypeMarker(exprType) + : exprType; } function removeMissingType(type: Type, isOptional: boolean) { - return exactOptionalPropertyTypes && isOptional ? removeType(type, missingType) : type; + return exactOptionalPropertyTypes && isOptional + ? removeType(type, missingType) + : type; } function containsMissingType(type: Type) { - return type === missingType || !!(type.flags & TypeFlags.Union) && (type as UnionType).types[0] === missingType; + return ( + type === missingType || + (!!(type.flags & TypeFlags.Union) && + (type as UnionType).types[0] === missingType) + ); } function removeMissingOrUndefinedType(type: Type): Type { - return exactOptionalPropertyTypes ? removeType(type, missingType) : getTypeWithFacts(type, TypeFacts.NEUndefined); + return exactOptionalPropertyTypes + ? removeType(type, missingType) + : getTypeWithFacts(type, TypeFacts.NEUndefined); } /** @@ -25704,8 +45815,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param target */ function isCoercibleUnderDoubleEquals(source: Type, target: Type): boolean { - return ((source.flags & (TypeFlags.Number | TypeFlags.String | TypeFlags.BooleanLiteral)) !== 0) - && ((target.flags & (TypeFlags.Number | TypeFlags.String | TypeFlags.Boolean)) !== 0); + return ( + (source.flags & + (TypeFlags.Number | + TypeFlags.String | + TypeFlags.BooleanLiteral)) !== + 0 && + (target.flags & + (TypeFlags.Number | TypeFlags.String | TypeFlags.Boolean)) !== + 0 + ); } /** @@ -25715,19 +45834,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isObjectTypeWithInferableIndex(type: Type): boolean { const objectFlags = getObjectFlags(type); return type.flags & TypeFlags.Intersection - ? every((type as IntersectionType).types, isObjectTypeWithInferableIndex) + ? every( + (type as IntersectionType).types, + isObjectTypeWithInferableIndex + ) : !!( - type.symbol - && (type.symbol.flags & (SymbolFlags.ObjectLiteral | SymbolFlags.TypeLiteral | SymbolFlags.Enum | SymbolFlags.ValueModule)) !== 0 - && !(type.symbol.flags & SymbolFlags.Class) - && !typeHasCallOrConstructSignatures(type) - ) || !!( - objectFlags & ObjectFlags.ObjectRestType - ) || !!(objectFlags & ObjectFlags.ReverseMapped && isObjectTypeWithInferableIndex((type as ReverseMappedType).source)); + type.symbol && + (type.symbol.flags & + (SymbolFlags.ObjectLiteral | + SymbolFlags.TypeLiteral | + SymbolFlags.Enum | + SymbolFlags.ValueModule)) !== + 0 && + !(type.symbol.flags & SymbolFlags.Class) && + !typeHasCallOrConstructSignatures(type) + ) || + !!(objectFlags & ObjectFlags.ObjectRestType) || + !!( + objectFlags & ObjectFlags.ReverseMapped && + isObjectTypeWithInferableIndex( + (type as ReverseMappedType).source + ) + ); } function createSymbolWithType(source: Symbol, type: Type | undefined) { - const symbol = createSymbol(source.flags, source.escapedName, getCheckFlags(source) & CheckFlags.Readonly); + const symbol = createSymbol( + source.flags, + source.escapedName, + getCheckFlags(source) & CheckFlags.Readonly + ); symbol.declarations = source.declarations; symbol.parent = source.parent; symbol.links.type = type; @@ -25742,12 +45878,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return symbol; } - function transformTypeOfMembers(type: Type, f: (propertyType: Type) => Type) { + function transformTypeOfMembers( + type: Type, + f: (propertyType: Type) => Type + ) { const members = createSymbolTable(); for (const property of getPropertiesOfObjectType(type)) { const original = getTypeOfSymbol(property); const updated = f(original); - members.set(property.escapedName, updated === original ? property : createSymbolWithType(property, updated)); + members.set( + property.escapedName, + updated === original + ? property + : createSymbolWithType(property, updated) + ); } return members; } @@ -25758,7 +45902,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Leave signatures alone since they are not subject to the check. */ function getRegularTypeOfObjectLiteral(type: Type): Type { - if (!(isObjectLiteralType(type) && getObjectFlags(type) & ObjectFlags.FreshLiteral)) { + if ( + !( + isObjectLiteralType(type) && + getObjectFlags(type) & ObjectFlags.FreshLiteral + ) + ) { return type; } const regularType = (type as FreshObjectLiteralType).regularType; @@ -25767,16 +45916,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const resolved = type as ResolvedType; - const members = transformTypeOfMembers(type, getRegularTypeOfObjectLiteral); - const regularNew = createAnonymousType(resolved.symbol, members, resolved.callSignatures, resolved.constructSignatures, resolved.indexInfos); + const members = transformTypeOfMembers( + type, + getRegularTypeOfObjectLiteral + ); + const regularNew = createAnonymousType( + resolved.symbol, + members, + resolved.callSignatures, + resolved.constructSignatures, + resolved.indexInfos + ); regularNew.flags = resolved.flags; - regularNew.objectFlags |= resolved.objectFlags & ~ObjectFlags.FreshLiteral; + regularNew.objectFlags |= + resolved.objectFlags & ~ObjectFlags.FreshLiteral; (type as FreshObjectLiteralType).regularType = regularNew; return regularNew; } - function createWideningContext(parent: WideningContext | undefined, propertyName: __String | undefined, siblings: Type[] | undefined): WideningContext { - return { parent, propertyName, siblings, resolvedProperties: undefined }; + function createWideningContext( + parent: WideningContext | undefined, + propertyName: __String | undefined, + siblings: Type[] | undefined + ): WideningContext { + return { + parent, + propertyName, + siblings, + resolvedProperties: undefined, + }; } function getSiblingsOfContext(context: WideningContext): Type[] { @@ -25784,9 +45952,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const siblings: Type[] = []; for (const type of getSiblingsOfContext(context.parent!)) { if (isObjectLiteralType(type)) { - const prop = getPropertyOfObjectType(type, context.propertyName!); + const prop = getPropertyOfObjectType( + type, + context.propertyName! + ); if (prop) { - forEachType(getTypeOfSymbol(prop), t => { + forEachType(getTypeOfSymbol(prop), (t) => { siblings.push(t); }); } @@ -25801,7 +45972,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!context.resolvedProperties) { const names = new Map<__String, Symbol>(); for (const t of getSiblingsOfContext(context)) { - if (isObjectLiteralType(t) && !(getObjectFlags(t) & ObjectFlags.ContainsSpread)) { + if ( + isObjectLiteralType(t) && + !(getObjectFlags(t) & ObjectFlags.ContainsSpread) + ) { for (const prop of getPropertiesOfType(t)) { names.set(prop.escapedName, prop); } @@ -25812,16 +45986,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return context.resolvedProperties; } - function getWidenedProperty(prop: Symbol, context: WideningContext | undefined): Symbol { + function getWidenedProperty( + prop: Symbol, + context: WideningContext | undefined + ): Symbol { if (!(prop.flags & SymbolFlags.Property)) { // Since get accessors already widen their return value there is no need to // widen accessor based properties here. return prop; } const original = getTypeOfSymbol(prop); - const propContext = context && createWideningContext(context, prop.escapedName, /*siblings*/ undefined); + const propContext = + context && + createWideningContext( + context, + prop.escapedName, + /*siblings*/ undefined + ); const widened = getWidenedTypeWithContext(original, propContext); - return widened === original ? prop : createSymbolWithType(prop, widened); + return widened === original + ? prop + : createSymbolWithType(prop, widened); } function getUndefinedProperty(prop: Symbol) { @@ -25835,7 +46020,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function getWidenedTypeOfObjectLiteral(type: Type, context: WideningContext | undefined): Type { + function getWidenedTypeOfObjectLiteral( + type: Type, + context: WideningContext | undefined + ): Type { const members = createSymbolTable(); for (const prop of getPropertiesOfObjectType(type)) { members.set(prop.escapedName, getWidenedProperty(prop, context)); @@ -25847,8 +46035,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } } - const result = createAnonymousType(type.symbol, members, emptyArray, emptyArray, sameMap(getIndexInfosOfType(type), info => createIndexInfo(info.keyType, getWidenedType(info.type), info.isReadonly, info.declaration, info.components))); - result.objectFlags |= getObjectFlags(type) & (ObjectFlags.JSLiteral | ObjectFlags.NonInferrableType); // Retain js literal flag through widening + const result = createAnonymousType( + type.symbol, + members, + emptyArray, + emptyArray, + sameMap(getIndexInfosOfType(type), (info) => + createIndexInfo( + info.keyType, + getWidenedType(info.type), + info.isReadonly, + info.declaration, + info.components + ) + ) + ); + result.objectFlags |= + getObjectFlags(type) & + (ObjectFlags.JSLiteral | ObjectFlags.NonInferrableType); // Retain js literal flag through widening return result; } @@ -25856,7 +46060,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getWidenedTypeWithContext(type, /*context*/ undefined); } - function getWidenedTypeWithContext(type: Type, context: WideningContext | undefined): Type { + function getWidenedTypeWithContext( + type: Type, + context: WideningContext | undefined + ): Type { if (getObjectFlags(type) & ObjectFlags.RequiresWidening) { if (context === undefined && type.widened) { return type.widened; @@ -25864,23 +46071,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let result: Type | undefined; if (type.flags & (TypeFlags.Any | TypeFlags.Nullable)) { result = anyType; - } - else if (isObjectLiteralType(type)) { + } else if (isObjectLiteralType(type)) { result = getWidenedTypeOfObjectLiteral(type, context); - } - else if (type.flags & TypeFlags.Union) { - const unionContext = context || createWideningContext(/*parent*/ undefined, /*propertyName*/ undefined, (type as UnionType).types); - const widenedTypes = sameMap((type as UnionType).types, t => t.flags & TypeFlags.Nullable ? t : getWidenedTypeWithContext(t, unionContext)); + } else if (type.flags & TypeFlags.Union) { + const unionContext = + context || + createWideningContext( + /*parent*/ undefined, + /*propertyName*/ undefined, + (type as UnionType).types + ); + const widenedTypes = sameMap((type as UnionType).types, (t) => + t.flags & TypeFlags.Nullable + ? t + : getWidenedTypeWithContext(t, unionContext) + ); // Widening an empty object literal transitions from a highly restrictive type to // a highly inclusive one. For that reason we perform subtype reduction here if the // union includes empty object types (e.g. reducing {} | string to just {}). - result = getUnionType(widenedTypes, some(widenedTypes, isEmptyObjectType) ? UnionReduction.Subtype : UnionReduction.Literal); - } - else if (type.flags & TypeFlags.Intersection) { - result = getIntersectionType(sameMap((type as IntersectionType).types, getWidenedType)); - } - else if (isArrayOrTupleType(type)) { - result = createTypeReference(type.target, sameMap(getTypeArguments(type), getWidenedType)); + result = getUnionType( + widenedTypes, + some(widenedTypes, isEmptyObjectType) + ? UnionReduction.Subtype + : UnionReduction.Literal + ); + } else if (type.flags & TypeFlags.Intersection) { + result = getIntersectionType( + sameMap((type as IntersectionType).types, getWidenedType) + ); + } else if (isArrayOrTupleType(type)) { + result = createTypeReference( + type.target, + sameMap(getTypeArguments(type), getWidenedType) + ); } if (result && context === undefined) { type.widened = result; @@ -25907,28 +46130,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (type.flags & TypeFlags.Union) { if (some((type as UnionType).types, isEmptyObjectType)) { errorReported = true; - } - else { + } else { for (const t of (type as UnionType).types) { errorReported ||= reportWideningErrorsInType(t); } } - } - else if (isArrayOrTupleType(type)) { + } else if (isArrayOrTupleType(type)) { for (const t of getTypeArguments(type)) { errorReported ||= reportWideningErrorsInType(t); } - } - else if (isObjectLiteralType(type)) { + } else if (isObjectLiteralType(type)) { for (const p of getPropertiesOfObjectType(type)) { const t = getTypeOfSymbol(p); if (getObjectFlags(t) & ObjectFlags.ContainsWideningType) { errorReported = reportWideningErrorsInType(t); if (!errorReported) { // we need to account for property types coming from object literal type normalization in unions - const valueDeclaration = p.declarations?.find(d => d.symbol.valueDeclaration?.parent === type.symbol.valueDeclaration); + const valueDeclaration = p.declarations?.find( + (d) => + d.symbol.valueDeclaration?.parent === + type.symbol.valueDeclaration + ); if (valueDeclaration) { - error(valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, symbolToString(p), typeToString(getWidenedType(t))); + error( + valueDeclaration, + Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, + symbolToString(p), + typeToString(getWidenedType(t)) + ); errorReported = true; } } @@ -25939,9 +46168,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return errorReported; } - function reportImplicitAny(declaration: Declaration, type: Type, wideningKind?: WideningKind) { + function reportImplicitAny( + declaration: Declaration, + type: Type, + wideningKind?: WideningKind + ) { const typeAsString = typeToString(getWidenedType(type)); - if (isInJSFile(declaration) && !isCheckJsEnabledForFile(getSourceFileOfNode(declaration), compilerOptions)) { + if ( + isInJSFile(declaration) && + !isCheckJsEnabledForFile( + getSourceFileOfNode(declaration), + compilerOptions + ) + ) { // Only report implicit any errors/suggestions in TS and ts-check JS files return; } @@ -25950,41 +46189,77 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.BinaryExpression: case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: - 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; + 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; break; case SyntaxKind.Parameter: const param = declaration as ParameterDeclaration; if (isIdentifier(param.name)) { - const originalKeywordKind = identifierToKeywordKind(param.name); + const originalKeywordKind = identifierToKeywordKind( + param.name + ); if ( - (isCallSignatureDeclaration(param.parent) || isMethodSignature(param.parent) || isFunctionTypeNode(param.parent)) && + (isCallSignatureDeclaration(param.parent) || + isMethodSignature(param.parent) || + isFunctionTypeNode(param.parent)) && param.parent.parameters.includes(param) && - (resolveName(param, param.name.escapedText, SymbolFlags.Type, /*nameNotFoundMessage*/ undefined, /*isUse*/ true) || - originalKeywordKind && isTypeNodeKind(originalKeywordKind)) + (resolveName( + param, + param.name.escapedText, + SymbolFlags.Type, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ true + ) || + (originalKeywordKind && + isTypeNodeKind(originalKeywordKind))) ) { - const newName = "arg" + param.parent.parameters.indexOf(param); - const typeName = declarationNameToString(param.name) + (param.dotDotDotToken ? "[]" : ""); - errorOrSuggestion(noImplicitAny, declaration, Diagnostics.Parameter_has_a_name_but_no_type_Did_you_mean_0_Colon_1, newName, typeName); + const newName = + "arg" + param.parent.parameters.indexOf(param); + const typeName = + declarationNameToString(param.name) + + (param.dotDotDotToken ? "[]" : ""); + errorOrSuggestion( + noImplicitAny, + declaration, + Diagnostics.Parameter_has_a_name_but_no_type_Did_you_mean_0_Colon_1, + newName, + typeName + ); return; } } - diagnostic = (declaration as ParameterDeclaration).dotDotDotToken ? - 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 : - 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; + diagnostic = (declaration as ParameterDeclaration) + .dotDotDotToken + ? 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 + : 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; break; case SyntaxKind.BindingElement: - diagnostic = Diagnostics.Binding_element_0_implicitly_has_an_1_type; + diagnostic = + Diagnostics.Binding_element_0_implicitly_has_an_1_type; if (!noImplicitAny) { // Don't issue a suggestion for binding elements since the codefix doesn't yet support them. return; } break; case SyntaxKind.JSDocFunctionType: - error(declaration, Diagnostics.Function_type_which_lacks_return_type_annotation_implicitly_has_an_0_return_type, typeAsString); + error( + declaration, + Diagnostics.Function_type_which_lacks_return_type_annotation_implicitly_has_an_0_return_type, + typeAsString + ); return; case SyntaxKind.JSDocSignature: if (noImplicitAny && isJSDocOverloadTag(declaration.parent)) { - error(declaration.parent.tagName, Diagnostics.This_overload_implicitly_returns_the_type_0_because_it_lacks_a_return_type_annotation, typeAsString); + error( + declaration.parent.tagName, + Diagnostics.This_overload_implicitly_returns_the_type_0_because_it_lacks_a_return_type_annotation, + typeAsString + ); } return; case SyntaxKind.FunctionDeclaration: @@ -25996,30 +46271,54 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ArrowFunction: if (noImplicitAny && !(declaration as NamedDeclaration).name) { if (wideningKind === WideningKind.GeneratorYield) { - error(declaration, Diagnostics.Generator_implicitly_has_yield_type_0_Consider_supplying_a_return_type_annotation, typeAsString); - } - else { - error(declaration, Diagnostics.Function_expression_which_lacks_return_type_annotation_implicitly_has_an_0_return_type, typeAsString); + error( + declaration, + Diagnostics.Generator_implicitly_has_yield_type_0_Consider_supplying_a_return_type_annotation, + typeAsString + ); + } else { + error( + declaration, + Diagnostics.Function_expression_which_lacks_return_type_annotation_implicitly_has_an_0_return_type, + typeAsString + ); } return; } - diagnostic = !noImplicitAny ? Diagnostics._0_implicitly_has_an_1_return_type_but_a_better_type_may_be_inferred_from_usage : - wideningKind === WideningKind.GeneratorYield ? Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_yield_type : - Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type; + diagnostic = !noImplicitAny + ? Diagnostics._0_implicitly_has_an_1_return_type_but_a_better_type_may_be_inferred_from_usage + : wideningKind === WideningKind.GeneratorYield + ? Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_yield_type + : Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type; break; case SyntaxKind.MappedType: if (noImplicitAny) { - error(declaration, Diagnostics.Mapped_object_type_implicitly_has_an_any_template_type); + error( + declaration, + Diagnostics.Mapped_object_type_implicitly_has_an_any_template_type + ); } return; default: - 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; + 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; } - errorOrSuggestion(noImplicitAny, declaration, diagnostic, declarationNameToString(getNameOfDeclaration(declaration)), typeAsString); + errorOrSuggestion( + noImplicitAny, + declaration, + diagnostic, + declarationNameToString(getNameOfDeclaration(declaration)), + typeAsString + ); } - function shouldReportErrorsFromWideningWithContextualSignature(declaration: FunctionLikeDeclaration, wideningKind: WideningKind) { - const signature = getContextualSignatureForFunctionLikeDeclaration(declaration); + function shouldReportErrorsFromWideningWithContextualSignature( + declaration: FunctionLikeDeclaration, + wideningKind: WideningKind + ) { + const signature = + getContextualSignatureForFunctionLikeDeclaration(declaration); if (!signature) { return true; } @@ -26028,26 +46327,53 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { switch (wideningKind) { case WideningKind.FunctionReturn: if (flags & FunctionFlags.Generator) { - returnType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, returnType, !!(flags & FunctionFlags.Async)) ?? returnType; - } - else if (flags & FunctionFlags.Async) { - returnType = getAwaitedTypeNoAlias(returnType) ?? returnType; + returnType = + getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Return, + returnType, + !!(flags & FunctionFlags.Async) + ) ?? returnType; + } else if (flags & FunctionFlags.Async) { + returnType = + getAwaitedTypeNoAlias(returnType) ?? returnType; } return isGenericType(returnType); case WideningKind.GeneratorYield: - const yieldType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Yield, returnType, !!(flags & FunctionFlags.Async)); + const yieldType = getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Yield, + returnType, + !!(flags & FunctionFlags.Async) + ); return !!yieldType && isGenericType(yieldType); case WideningKind.GeneratorNext: - const nextType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Next, returnType, !!(flags & FunctionFlags.Async)); + const nextType = getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Next, + returnType, + !!(flags & FunctionFlags.Async) + ); return !!nextType && isGenericType(nextType); } return false; } - function reportErrorsFromWidening(declaration: Declaration, type: Type, wideningKind?: WideningKind) { + function reportErrorsFromWidening( + declaration: Declaration, + type: Type, + wideningKind?: WideningKind + ) { addLazyDiagnostic(() => { - if (noImplicitAny && getObjectFlags(type) & ObjectFlags.ContainsWideningType) { - if (!wideningKind || isFunctionLikeDeclaration(declaration) && shouldReportErrorsFromWideningWithContextualSignature(declaration, wideningKind)) { + if ( + noImplicitAny && + getObjectFlags(type) & ObjectFlags.ContainsWideningType + ) { + if ( + !wideningKind || + (isFunctionLikeDeclaration(declaration) && + shouldReportErrorsFromWideningWithContextualSignature( + declaration, + wideningKind + )) + ) { // Report implicit any error within type if possible, otherwise report error on declaration if (!reportWideningErrorsInType(type)) { reportImplicitAny(declaration, type, wideningKind); @@ -26057,13 +46383,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { }); } - function applyToParameterTypes(source: Signature, target: Signature, callback: (s: Type, t: Type) => void) { + function applyToParameterTypes( + source: Signature, + target: Signature, + callback: (s: Type, t: Type) => void + ) { const sourceCount = getParameterCount(source); const targetCount = getParameterCount(target); const sourceRestType = getEffectiveRestType(source); const targetRestType = getEffectiveRestType(target); - const targetNonRestCount = targetRestType ? targetCount - 1 : targetCount; - const paramCount = sourceRestType ? targetNonRestCount : Math.min(sourceCount, targetNonRestCount); + const targetNonRestCount = targetRestType + ? targetCount - 1 + : targetCount; + const paramCount = sourceRestType + ? targetNonRestCount + : Math.min(sourceCount, targetNonRestCount); const sourceThisType = getThisTypeOfSignature(source); if (sourceThisType) { const targetThisType = getThisTypeOfSignature(target); @@ -26072,18 +46406,41 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } for (let i = 0; i < paramCount; i++) { - callback(getTypeAtPosition(source, i), getTypeAtPosition(target, i)); + callback( + getTypeAtPosition(source, i), + getTypeAtPosition(target, i) + ); } if (targetRestType) { - callback(getRestTypeAtPosition(source, paramCount, /*readonly*/ isConstTypeVariable(targetRestType) && !someType(targetRestType, isMutableArrayLikeType)), targetRestType); + callback( + getRestTypeAtPosition( + source, + paramCount, + /*readonly*/ isConstTypeVariable(targetRestType) && + !someType(targetRestType, isMutableArrayLikeType) + ), + targetRestType + ); } } - function applyToReturnTypes(source: Signature, target: Signature, callback: (s: Type, t: Type) => void) { + function applyToReturnTypes( + source: Signature, + target: Signature, + callback: (s: Type, t: Type) => void + ) { const targetTypePredicate = getTypePredicateOfSignature(target); if (targetTypePredicate) { const sourceTypePredicate = getTypePredicateOfSignature(source); - if (sourceTypePredicate && typePredicateKindsMatch(sourceTypePredicate, targetTypePredicate) && sourceTypePredicate.type && targetTypePredicate.type) { + if ( + sourceTypePredicate && + typePredicateKindsMatch( + sourceTypePredicate, + targetTypePredicate + ) && + sourceTypePredicate.type && + targetTypePredicate.type + ) { callback(sourceTypePredicate.type, targetTypePredicate.type); return; } @@ -26094,15 +46451,41 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function createInferenceContext(typeParameters: readonly TypeParameter[], signature: Signature | undefined, flags: InferenceFlags, compareTypes?: TypeComparer): InferenceContext { - return createInferenceContextWorker(typeParameters.map(createInferenceInfo), signature, flags, compareTypes || compareTypesAssignable); + function createInferenceContext( + typeParameters: readonly TypeParameter[], + signature: Signature | undefined, + flags: InferenceFlags, + compareTypes?: TypeComparer + ): InferenceContext { + return createInferenceContextWorker( + typeParameters.map(createInferenceInfo), + signature, + flags, + compareTypes || compareTypesAssignable + ); } - function cloneInferenceContext(context: T, extraFlags: InferenceFlags = 0): InferenceContext | T & undefined { - return context && createInferenceContextWorker(map(context.inferences, cloneInferenceInfo), context.signature, context.flags | extraFlags, context.compareTypes); + function cloneInferenceContext( + context: T, + extraFlags: InferenceFlags = 0 + ): InferenceContext | (T & undefined) { + return ( + context && + createInferenceContextWorker( + map(context.inferences, cloneInferenceInfo), + context.signature, + context.flags | extraFlags, + context.compareTypes + ) + ); } - function createInferenceContextWorker(inferences: InferenceInfo[], signature: Signature | undefined, flags: InferenceFlags, compareTypes: TypeComparer): InferenceContext { + function createInferenceContextWorker( + inferences: InferenceInfo[], + signature: Signature | undefined, + flags: InferenceFlags, + compareTypes: TypeComparer + ): InferenceContext { const context: InferenceContext = { inferences, signature, @@ -26118,7 +46501,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function makeFixingMapperForContext(context: InferenceContext) { return makeDeferredTypeMapper( - map(context.inferences, i => i.typeParameter), + map(context.inferences, (i) => i.typeParameter), map(context.inferences, (inference, i) => () => { if (!inference.isFixed) { // Before we commit to a particular inference (and thus lock out any further inferences), @@ -26128,16 +46511,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { inference.isFixed = true; } return getInferredType(context, i); - }), + }) ); } function makeNonFixingMapperForContext(context: InferenceContext) { return makeDeferredTypeMapper( - map(context.inferences, i => i.typeParameter), + map(context.inferences, (i) => i.typeParameter), map(context.inferences, (_, i) => () => { return getInferredType(context, i); - }), + }) ); } @@ -26149,7 +46532,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function addIntraExpressionInferenceSite(context: InferenceContext, node: Expression | MethodDeclaration, type: Type) { + function addIntraExpressionInferenceSite( + context: InferenceContext, + node: Expression | MethodDeclaration, + type: Type + ) { (context.intraExpressionInferenceSites ??= []).push({ node, type }); } @@ -26168,10 +46555,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // object or array literal, we need to perform intra-expression inferences early. function inferFromIntraExpressionSites(context: InferenceContext) { if (context.intraExpressionInferenceSites) { - for (const { node, type } of context.intraExpressionInferenceSites) { - const contextualType = node.kind === SyntaxKind.MethodDeclaration ? - getContextualTypeForObjectLiteralMethod(node as MethodDeclaration, ContextFlags.NoConstraints) : - getContextualType(node, ContextFlags.NoConstraints); + for (const { + node, + type, + } of context.intraExpressionInferenceSites) { + const contextualType = + node.kind === SyntaxKind.MethodDeclaration + ? getContextualTypeForObjectLiteralMethod( + node as MethodDeclaration, + ContextFlags.NoConstraints + ) + : getContextualType(node, ContextFlags.NoConstraints); if (contextualType) { inferTypes(context.inferences, type, contextualType); } @@ -26197,7 +46591,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return { typeParameter: inference.typeParameter, candidates: inference.candidates && inference.candidates.slice(), - contraCandidates: inference.contraCandidates && inference.contraCandidates.slice(), + contraCandidates: + inference.contraCandidates && + inference.contraCandidates.slice(), inferredType: inference.inferredType, priority: inference.priority, topLevel: inference.topLevel, @@ -26206,14 +46602,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { }; } - function cloneInferredPartOfContext(context: InferenceContext): InferenceContext | undefined { + function cloneInferredPartOfContext( + context: InferenceContext + ): InferenceContext | undefined { const inferences = filter(context.inferences, hasInferenceCandidates); - return inferences.length ? - createInferenceContextWorker(map(inferences, cloneInferenceInfo), context.signature, context.flags, context.compareTypes) : - undefined; + return inferences.length + ? createInferenceContextWorker( + map(inferences, cloneInferenceInfo), + context.signature, + context.flags, + context.compareTypes + ) + : undefined; } - function getMapperFromContext(context: T): TypeMapper | T & undefined { + function getMapperFromContext( + context: T + ): TypeMapper | (T & undefined) { return context && context.mapper; } @@ -26225,50 +46630,118 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (objectFlags & ObjectFlags.CouldContainTypeVariablesComputed) { return !!(objectFlags & ObjectFlags.CouldContainTypeVariables); } - const result = !!(type.flags & TypeFlags.Instantiable || - type.flags & TypeFlags.Object && !isNonGenericTopLevelType(type) && ( - objectFlags & ObjectFlags.Reference && ((type as TypeReference).node || some(getTypeArguments(type as TypeReference), couldContainTypeVariables)) || - objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && type.symbol.declarations || - objectFlags & (ObjectFlags.Mapped | ObjectFlags.ReverseMapped | ObjectFlags.ObjectRestType | ObjectFlags.InstantiationExpressionType) - ) || - type.flags & TypeFlags.UnionOrIntersection && !(type.flags & TypeFlags.EnumLiteral) && !isNonGenericTopLevelType(type) && some((type as UnionOrIntersectionType).types, couldContainTypeVariables)); + const result = !!( + type.flags & TypeFlags.Instantiable || + (type.flags & TypeFlags.Object && + !isNonGenericTopLevelType(type) && + ((objectFlags & ObjectFlags.Reference && + ((type as TypeReference).node || + some( + getTypeArguments(type as TypeReference), + couldContainTypeVariables + ))) || + (objectFlags & ObjectFlags.Anonymous && + type.symbol && + type.symbol.flags & + (SymbolFlags.Function | + SymbolFlags.Method | + SymbolFlags.Class | + SymbolFlags.TypeLiteral | + SymbolFlags.ObjectLiteral) && + type.symbol.declarations) || + objectFlags & + (ObjectFlags.Mapped | + ObjectFlags.ReverseMapped | + ObjectFlags.ObjectRestType | + ObjectFlags.InstantiationExpressionType))) || + (type.flags & TypeFlags.UnionOrIntersection && + !(type.flags & TypeFlags.EnumLiteral) && + !isNonGenericTopLevelType(type) && + some( + (type as UnionOrIntersectionType).types, + couldContainTypeVariables + )) + ); if (type.flags & TypeFlags.ObjectFlagsType) { - (type as ObjectFlagsType).objectFlags |= ObjectFlags.CouldContainTypeVariablesComputed | (result ? ObjectFlags.CouldContainTypeVariables : 0); + (type as ObjectFlagsType).objectFlags |= + ObjectFlags.CouldContainTypeVariablesComputed | + (result ? ObjectFlags.CouldContainTypeVariables : 0); } return result; } function isNonGenericTopLevelType(type: Type) { if (type.aliasSymbol && !type.aliasTypeArguments) { - const declaration = getDeclarationOfKind(type.aliasSymbol, SyntaxKind.TypeAliasDeclaration); - return !!(declaration && findAncestor(declaration.parent, n => n.kind === SyntaxKind.SourceFile ? true : n.kind === SyntaxKind.ModuleDeclaration ? false : "quit")); + const declaration = getDeclarationOfKind( + type.aliasSymbol, + SyntaxKind.TypeAliasDeclaration + ); + return !!( + declaration && + findAncestor(declaration.parent, (n) => + n.kind === SyntaxKind.SourceFile + ? true + : n.kind === SyntaxKind.ModuleDeclaration + ? false + : "quit" + ) + ); } return false; } - function isTypeParameterAtTopLevel(type: Type, tp: TypeParameter, depth = 0): boolean { - return !!(type === tp || - type.flags & TypeFlags.UnionOrIntersection && some((type as UnionOrIntersectionType).types, t => isTypeParameterAtTopLevel(t, tp, depth)) || - depth < 3 && type.flags & TypeFlags.Conditional && ( - isTypeParameterAtTopLevel(getTrueTypeFromConditionalType(type as ConditionalType), tp, depth + 1) || - isTypeParameterAtTopLevel(getFalseTypeFromConditionalType(type as ConditionalType), tp, depth + 1) - )); + function isTypeParameterAtTopLevel( + type: Type, + tp: TypeParameter, + depth = 0 + ): boolean { + return !!( + type === tp || + (type.flags & TypeFlags.UnionOrIntersection && + some((type as UnionOrIntersectionType).types, (t) => + isTypeParameterAtTopLevel(t, tp, depth) + )) || + (depth < 3 && + type.flags & TypeFlags.Conditional && + (isTypeParameterAtTopLevel( + getTrueTypeFromConditionalType(type as ConditionalType), + tp, + depth + 1 + ) || + isTypeParameterAtTopLevel( + getFalseTypeFromConditionalType( + type as ConditionalType + ), + tp, + depth + 1 + ))) + ); } - function isTypeParameterAtTopLevelInReturnType(signature: Signature, typeParameter: TypeParameter) { + function isTypeParameterAtTopLevelInReturnType( + signature: Signature, + typeParameter: TypeParameter + ) { const typePredicate = getTypePredicateOfSignature(signature); - return typePredicate ? !!typePredicate.type && isTypeParameterAtTopLevel(typePredicate.type, typeParameter) : - isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), typeParameter); + return typePredicate + ? !!typePredicate.type && + isTypeParameterAtTopLevel(typePredicate.type, typeParameter) + : isTypeParameterAtTopLevel( + getReturnTypeOfSignature(signature), + typeParameter + ); } /** Create an object with properties named in the string literal type. Every property has type `any` */ function createEmptyObjectTypeFromStringLiteral(type: Type) { const members = createSymbolTable(); - forEachType(type, t => { + forEachType(type, (t) => { if (!(t.flags & TypeFlags.StringLiteral)) { return; } - const name = escapeLeadingUnderscores((t as StringLiteralType).value); + const name = escapeLeadingUnderscores( + (t as StringLiteralType).value + ); const literalProp = createSymbol(SymbolFlags.Property, name); literalProp.links.type = anyType; if (t.symbol) { @@ -26277,8 +46750,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } members.set(name, literalProp); }); - const indexInfos = type.flags & TypeFlags.String ? [createIndexInfo(stringType, emptyObjectType, /*isReadonly*/ false)] : emptyArray; - return createAnonymousType(/*symbol*/ undefined, members, emptyArray, emptyArray, indexInfos); + const indexInfos = + type.flags & TypeFlags.String + ? [ + createIndexInfo( + stringType, + emptyObjectType, + /*isReadonly*/ false + ), + ] + : emptyArray; + return createAnonymousType( + /*symbol*/ undefined, + members, + emptyArray, + emptyArray, + indexInfos + ); } /** @@ -26287,7 +46775,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * property is computed by inferring from the source property type to X for the type * variable T[P] (i.e. we treat the type T[P] as the type variable we're inferring for). */ - function inferTypeForHomomorphicMappedType(source: Type, target: MappedType, constraint: IndexType): Type | undefined { + function inferTypeForHomomorphicMappedType( + source: Type, + target: MappedType, + constraint: IndexType + ): Type | undefined { const cacheKey = source.id + "," + target.id + "," + constraint.id; if (reverseHomomorphicMappedCache.has(cacheKey)) { return reverseHomomorphicMappedCache.get(cacheKey); @@ -26302,39 +46794,73 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // literal { a: 123, b: x => true } is marked non-inferable because it contains a context sensitive // arrow function, but is considered partially inferable because property 'a' has an inferable type. function isPartiallyInferableType(type: Type): boolean { - return !(getObjectFlags(type) & ObjectFlags.NonInferrableType) || - isObjectLiteralType(type) && some(getPropertiesOfType(type), prop => isPartiallyInferableType(getTypeOfSymbol(prop))) || - isTupleType(type) && some(getElementTypes(type), isPartiallyInferableType); + return ( + !(getObjectFlags(type) & ObjectFlags.NonInferrableType) || + (isObjectLiteralType(type) && + some(getPropertiesOfType(type), (prop) => + isPartiallyInferableType(getTypeOfSymbol(prop)) + )) || + (isTupleType(type) && + some(getElementTypes(type), isPartiallyInferableType)) + ); } - function createReverseMappedType(source: Type, target: MappedType, constraint: IndexType) { + function createReverseMappedType( + source: Type, + target: MappedType, + constraint: IndexType + ) { // We consider a source type reverse mappable if it has a string index signature or if // it has one or more properties and is of a partially inferable type. - if (!(getIndexInfoOfType(source, stringType) || getPropertiesOfType(source).length !== 0 && isPartiallyInferableType(source))) { + if ( + !( + getIndexInfoOfType(source, stringType) || + (getPropertiesOfType(source).length !== 0 && + isPartiallyInferableType(source)) + ) + ) { return undefined; } // For arrays and tuples we infer new arrays and tuples where the reverse mapping has been // applied to the element type(s). if (isArrayType(source)) { - const elementType = inferReverseMappedType(getTypeArguments(source)[0], target, constraint); + const elementType = inferReverseMappedType( + getTypeArguments(source)[0], + target, + constraint + ); if (!elementType) { return undefined; } return createArrayType(elementType, isReadonlyArrayType(source)); } if (isTupleType(source)) { - const elementTypes = map(getElementTypes(source), t => inferReverseMappedType(t, target, constraint)); + const elementTypes = map(getElementTypes(source), (t) => + inferReverseMappedType(t, target, constraint) + ); if (!every(elementTypes, (t): t is Type => !!t)) { return undefined; } - const elementFlags = getMappedTypeModifiers(target) & MappedTypeModifiers.IncludeOptional ? - sameMap(source.target.elementFlags, f => f & ElementFlags.Optional ? ElementFlags.Required : f) : - source.target.elementFlags; - return createTupleType(elementTypes, elementFlags, source.target.readonly, source.target.labeledElementDeclarations); + const elementFlags = + getMappedTypeModifiers(target) & + MappedTypeModifiers.IncludeOptional + ? sameMap(source.target.elementFlags, (f) => + f & ElementFlags.Optional ? ElementFlags.Required : f + ) + : source.target.elementFlags; + return createTupleType( + elementTypes, + elementFlags, + source.target.readonly, + source.target.labeledElementDeclarations + ); } // For all other object types we infer a new object type where the reverse mapping has been // applied to the type of each property. - const reversed = createObjectType(ObjectFlags.ReverseMapped | ObjectFlags.Anonymous, /*symbol*/ undefined) as ReverseMappedType; + const reversed = createObjectType( + ObjectFlags.ReverseMapped | ObjectFlags.Anonymous, + /*symbol*/ undefined + ) as ReverseMappedType; reversed.source = source; reversed.mappedType = target; reversed.constraintType = constraint; @@ -26344,20 +46870,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getTypeOfReverseMappedSymbol(symbol: ReverseMappedSymbol): Type { const links = getSymbolLinks(symbol); if (!links.type) { - links.type = inferReverseMappedType(symbol.links.propertyType, symbol.links.mappedType, symbol.links.constraintType) || unknownType; + links.type = + inferReverseMappedType( + symbol.links.propertyType, + symbol.links.mappedType, + symbol.links.constraintType + ) || unknownType; } return links.type; } - function inferReverseMappedTypeWorker(sourceType: Type, target: MappedType, constraint: IndexType): Type { - const typeParameter = getIndexedAccessType(constraint.type, getTypeParameterFromMappedType(target)) as TypeParameter; + function inferReverseMappedTypeWorker( + sourceType: Type, + target: MappedType, + constraint: IndexType + ): Type { + const typeParameter = getIndexedAccessType( + constraint.type, + getTypeParameterFromMappedType(target) + ) as TypeParameter; const templateType = getTemplateTypeFromMappedType(target); const inference = createInferenceInfo(typeParameter); inferTypes([inference], sourceType, templateType); return getTypeFromInference(inference) || unknownType; } - function inferReverseMappedType(source: Type, target: MappedType, constraint: IndexType): Type | undefined { + function inferReverseMappedType( + source: Type, + target: MappedType, + constraint: IndexType + ): Type | undefined { const cacheKey = source.id + "," + target.id + "," + constraint.id; if (reverseMappedCache.has(cacheKey)) { return reverseMappedCache.get(cacheKey) || unknownType; @@ -26365,8 +46907,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { reverseMappedSourceStack.push(source); reverseMappedTargetStack.push(target); const saveExpandingFlags = reverseExpandingFlags; - if (isDeeplyNestedType(source, reverseMappedSourceStack, reverseMappedSourceStack.length, 2)) reverseExpandingFlags |= ExpandingFlags.Source; - if (isDeeplyNestedType(target, reverseMappedTargetStack, reverseMappedTargetStack.length, 2)) reverseExpandingFlags |= ExpandingFlags.Target; + if ( + isDeeplyNestedType( + source, + reverseMappedSourceStack, + reverseMappedSourceStack.length, + 2 + ) + ) + reverseExpandingFlags |= ExpandingFlags.Source; + if ( + isDeeplyNestedType( + target, + reverseMappedTargetStack, + reverseMappedTargetStack.length, + 2 + ) + ) + reverseExpandingFlags |= ExpandingFlags.Target; let type; if (reverseExpandingFlags !== ExpandingFlags.Both) { type = inferReverseMappedTypeWorker(source, target, constraint); @@ -26378,23 +46936,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return type; } - function* getUnmatchedProperties(source: Type, target: Type, requireOptionalProperties: boolean, matchDiscriminantProperties: boolean): IterableIterator { + function* getUnmatchedProperties( + source: Type, + target: Type, + requireOptionalProperties: boolean, + matchDiscriminantProperties: boolean + ): IterableIterator { const properties = getPropertiesOfType(target); for (const targetProp of properties) { // TODO: remove this when we support static private identifier fields and find other solutions to get privateNamesAndStaticFields test to pass if (isStaticPrivateIdentifierProperty(targetProp)) { continue; } - if (requireOptionalProperties || !(targetProp.flags & SymbolFlags.Optional || getCheckFlags(targetProp) & CheckFlags.Partial)) { - const sourceProp = getPropertyOfType(source, targetProp.escapedName); + if ( + requireOptionalProperties || + !( + targetProp.flags & SymbolFlags.Optional || + getCheckFlags(targetProp) & CheckFlags.Partial + ) + ) { + const sourceProp = getPropertyOfType( + source, + targetProp.escapedName + ); if (!sourceProp) { yield targetProp; - } - else if (matchDiscriminantProperties) { + } else if (matchDiscriminantProperties) { const targetType = getTypeOfSymbol(targetProp); if (targetType.flags & TypeFlags.Unit) { const sourceType = getTypeOfSymbol(sourceProp); - if (!(sourceType.flags & TypeFlags.Any || getRegularTypeOfLiteralType(sourceType) === getRegularTypeOfLiteralType(targetType))) { + if ( + !( + sourceType.flags & TypeFlags.Any || + getRegularTypeOfLiteralType(sourceType) === + getRegularTypeOfLiteralType(targetType) + ) + ) { yield targetProp; } } @@ -26403,27 +46980,60 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getUnmatchedProperty(source: Type, target: Type, requireOptionalProperties: boolean, matchDiscriminantProperties: boolean): Symbol | undefined { - return firstOrUndefinedIterator(getUnmatchedProperties(source, target, requireOptionalProperties, matchDiscriminantProperties)); + function getUnmatchedProperty( + source: Type, + target: Type, + requireOptionalProperties: boolean, + matchDiscriminantProperties: boolean + ): Symbol | undefined { + return firstOrUndefinedIterator( + getUnmatchedProperties( + source, + target, + requireOptionalProperties, + matchDiscriminantProperties + ) + ); } - function tupleTypesDefinitelyUnrelated(source: TupleTypeReference, target: TupleTypeReference) { - return !(target.target.combinedFlags & ElementFlags.Variadic) && target.target.minLength > source.target.minLength || - !(target.target.combinedFlags & ElementFlags.Variable) && (!!(source.target.combinedFlags & ElementFlags.Variable) || target.target.fixedLength < source.target.fixedLength); + function tupleTypesDefinitelyUnrelated( + source: TupleTypeReference, + target: TupleTypeReference + ) { + return ( + (!(target.target.combinedFlags & ElementFlags.Variadic) && + target.target.minLength > source.target.minLength) || + (!(target.target.combinedFlags & ElementFlags.Variable) && + (!!(source.target.combinedFlags & ElementFlags.Variable) || + target.target.fixedLength < source.target.fixedLength)) + ); } function typesDefinitelyUnrelated(source: Type, target: Type) { // Two tuple types with incompatible arities are definitely unrelated. // Two object types that each have a property that is unmatched in the other are definitely unrelated. - return isTupleType(source) && isTupleType(target) ? tupleTypesDefinitelyUnrelated(source, target) : - !!getUnmatchedProperty(source, target, /*requireOptionalProperties*/ false, /*matchDiscriminantProperties*/ true) && - !!getUnmatchedProperty(target, source, /*requireOptionalProperties*/ false, /*matchDiscriminantProperties*/ false); + return isTupleType(source) && isTupleType(target) + ? tupleTypesDefinitelyUnrelated(source, target) + : !!getUnmatchedProperty( + source, + target, + /*requireOptionalProperties*/ false, + /*matchDiscriminantProperties*/ true + ) && + !!getUnmatchedProperty( + target, + source, + /*requireOptionalProperties*/ false, + /*matchDiscriminantProperties*/ false + ); } function getTypeFromInference(inference: InferenceInfo) { - return inference.candidates ? getUnionType(inference.candidates, UnionReduction.Subtype) : - inference.contraCandidates ? getIntersectionType(inference.contraCandidates) : - undefined; + return inference.candidates + ? getUnionType(inference.candidates, UnionReduction.Subtype) + : inference.contraCandidates + ? getIntersectionType(inference.contraCandidates) + : undefined; } function hasSkipDirectInferenceFlag(node: Node) { @@ -26431,10 +47041,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isFromInferenceBlockedSource(type: Type) { - return !!(type.symbol && some(type.symbol.declarations, hasSkipDirectInferenceFlag)); + return !!( + type.symbol && + some(type.symbol.declarations, hasSkipDirectInferenceFlag) + ); } - function templateLiteralTypesDefinitelyUnrelated(source: TemplateLiteralType, target: TemplateLiteralType) { + function templateLiteralTypesDefinitelyUnrelated( + source: TemplateLiteralType, + target: TemplateLiteralType + ) { // Two template literal types with diffences in their starting or ending text spans are definitely unrelated. const sourceStart = source.texts[0]; const targetStart = target.texts[0]; @@ -26442,8 +47058,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const targetEnd = target.texts[target.texts.length - 1]; const startLen = Math.min(sourceStart.length, targetStart.length); const endLen = Math.min(sourceEnd.length, targetEnd.length); - return sourceStart.slice(0, startLen) !== targetStart.slice(0, startLen) || - sourceEnd.slice(sourceEnd.length - endLen) !== targetEnd.slice(targetEnd.length - endLen); + return ( + sourceStart.slice(0, startLen) !== targetStart.slice(0, startLen) || + sourceEnd.slice(sourceEnd.length - endLen) !== + targetEnd.slice(targetEnd.length - endLen) + ); } /** @@ -26484,51 +47103,119 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { mappingStack.unshift(target.symbol); target = (target as StringMappingType).type; } - const mappedSource = reduceLeft(mappingStack, (memo, value) => getStringMappingType(value, memo), source); - return mappedSource === source && isMemberOfStringMapping(source, target); + const mappedSource = reduceLeft( + mappingStack, + (memo, value) => getStringMappingType(value, memo), + source + ); + return ( + mappedSource === source && + isMemberOfStringMapping(source, target) + ); } return false; } - function isValidTypeForTemplateLiteralPlaceholder(source: Type, target: Type): boolean { + function isValidTypeForTemplateLiteralPlaceholder( + source: Type, + target: Type + ): boolean { if (target.flags & TypeFlags.Intersection) { - return every((target as IntersectionType).types, t => t === emptyTypeLiteralType || isValidTypeForTemplateLiteralPlaceholder(source, t)); + return every( + (target as IntersectionType).types, + (t) => + t === emptyTypeLiteralType || + isValidTypeForTemplateLiteralPlaceholder(source, t) + ); } - if (target.flags & TypeFlags.String || isTypeAssignableTo(source, target)) { + if ( + target.flags & TypeFlags.String || + isTypeAssignableTo(source, target) + ) { return true; } if (source.flags & TypeFlags.StringLiteral) { const value = (source as StringLiteralType).value; - return !!(target.flags & TypeFlags.Number && isValidNumberString(value, /*roundTripOnly*/ false) || - target.flags & TypeFlags.BigInt && isValidBigIntString(value, /*roundTripOnly*/ false) || - target.flags & (TypeFlags.BooleanLiteral | TypeFlags.Nullable) && value === (target as IntrinsicType).intrinsicName || - target.flags & TypeFlags.StringMapping && isMemberOfStringMapping(source, target) || - target.flags & TypeFlags.TemplateLiteral && isTypeMatchedByTemplateLiteralType(source, target as TemplateLiteralType)); + return !!( + (target.flags & TypeFlags.Number && + isValidNumberString(value, /*roundTripOnly*/ false)) || + (target.flags & TypeFlags.BigInt && + isValidBigIntString(value, /*roundTripOnly*/ false)) || + (target.flags & + (TypeFlags.BooleanLiteral | TypeFlags.Nullable) && + value === (target as IntrinsicType).intrinsicName) || + (target.flags & TypeFlags.StringMapping && + isMemberOfStringMapping(source, target)) || + (target.flags & TypeFlags.TemplateLiteral && + isTypeMatchedByTemplateLiteralType( + source, + target as TemplateLiteralType + )) + ); } if (source.flags & TypeFlags.TemplateLiteral) { const texts = (source as TemplateLiteralType).texts; - return texts.length === 2 && texts[0] === "" && texts[1] === "" && isTypeAssignableTo((source as TemplateLiteralType).types[0], target); + return ( + texts.length === 2 && + texts[0] === "" && + texts[1] === "" && + isTypeAssignableTo( + (source as TemplateLiteralType).types[0], + target + ) + ); } return false; } - function inferTypesFromTemplateLiteralType(source: Type, target: TemplateLiteralType): Type[] | undefined { - return source.flags & TypeFlags.StringLiteral ? inferFromLiteralPartsToTemplateLiteral([(source as StringLiteralType).value], emptyArray, target) : - source.flags & TypeFlags.TemplateLiteral ? - arrayIsEqualTo((source as TemplateLiteralType).texts, target.texts) ? map((source as TemplateLiteralType).types, (s, i) => { - return isTypeAssignableTo(getBaseConstraintOrType(s), getBaseConstraintOrType(target.types[i])) ? s : getStringLikeTypeForType(s); - }) : - inferFromLiteralPartsToTemplateLiteral((source as TemplateLiteralType).texts, (source as TemplateLiteralType).types, target) : - undefined; + function inferTypesFromTemplateLiteralType( + source: Type, + target: TemplateLiteralType + ): Type[] | undefined { + return source.flags & TypeFlags.StringLiteral + ? inferFromLiteralPartsToTemplateLiteral( + [(source as StringLiteralType).value], + emptyArray, + target + ) + : source.flags & TypeFlags.TemplateLiteral + ? arrayIsEqualTo( + (source as TemplateLiteralType).texts, + target.texts + ) + ? map((source as TemplateLiteralType).types, (s, i) => { + return isTypeAssignableTo( + getBaseConstraintOrType(s), + getBaseConstraintOrType(target.types[i]) + ) + ? s + : getStringLikeTypeForType(s); + }) + : inferFromLiteralPartsToTemplateLiteral( + (source as TemplateLiteralType).texts, + (source as TemplateLiteralType).types, + target + ) + : undefined; } - function isTypeMatchedByTemplateLiteralType(source: Type, target: TemplateLiteralType): boolean { + function isTypeMatchedByTemplateLiteralType( + source: Type, + target: TemplateLiteralType + ): boolean { const inferences = inferTypesFromTemplateLiteralType(source, target); - return !!inferences && every(inferences, (r, i) => isValidTypeForTemplateLiteralPlaceholder(r, target.types[i])); + return ( + !!inferences && + every(inferences, (r, i) => + isValidTypeForTemplateLiteralPlaceholder(r, target.types[i]) + ) + ); } function getStringLikeTypeForType(type: Type) { - return type.flags & (TypeFlags.Any | TypeFlags.StringLike) ? type : getTemplateLiteralType(["", ""], [type]); + return type.flags & (TypeFlags.Any | TypeFlags.StringLike) + ? type + : getTemplateLiteralType(["", ""], [type]); } // This function infers from the text parts and type parts of a source literal to a target template literal. The number @@ -26550,7 +47237,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // the source. The first match for the '.' in target occurs at character 1 in the source text part at index 1, and thus // the first inference is the template literal type `<${string}>`. The remainder of the source makes up the second // inference, the template literal type `<${number}-${number}>`. - function inferFromLiteralPartsToTemplateLiteral(sourceTexts: readonly string[], sourceTypes: readonly Type[], target: TemplateLiteralType): Type[] | undefined { + function inferFromLiteralPartsToTemplateLiteral( + sourceTexts: readonly string[], + sourceTypes: readonly Type[], + target: TemplateLiteralType + ): Type[] | undefined { const lastSourceIndex = sourceTexts.length - 1; const sourceStartText = sourceTexts[0]; const sourceEndText = sourceTexts[lastSourceIndex]; @@ -26559,10 +47250,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const targetStartText = targetTexts[0]; const targetEndText = targetTexts[lastTargetIndex]; if ( - lastSourceIndex === 0 && sourceStartText.length < targetStartText.length + targetEndText.length || - !sourceStartText.startsWith(targetStartText) || !sourceEndText.endsWith(targetEndText) - ) return undefined; - const remainingEndText = sourceEndText.slice(0, sourceEndText.length - targetEndText.length); + (lastSourceIndex === 0 && + sourceStartText.length < + targetStartText.length + targetEndText.length) || + !sourceStartText.startsWith(targetStartText) || + !sourceEndText.endsWith(targetEndText) + ) + return undefined; + const remainingEndText = sourceEndText.slice( + 0, + sourceEndText.length - targetEndText.length + ); const matches: Type[] = []; let seg = 0; let pos = targetStartText.length; @@ -26580,36 +47278,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } addMatch(s, p); pos += delim.length; - } - else if (pos < getSourceText(seg).length) { + } else if (pos < getSourceText(seg).length) { addMatch(seg, pos + 1); - } - else if (seg < lastSourceIndex) { + } else if (seg < lastSourceIndex) { addMatch(seg + 1, 0); - } - else { + } else { return undefined; } } addMatch(lastSourceIndex, getSourceText(lastSourceIndex).length); return matches; function getSourceText(index: number) { - return index < lastSourceIndex ? sourceTexts[index] : remainingEndText; + return index < lastSourceIndex + ? sourceTexts[index] + : remainingEndText; } function addMatch(s: number, p: number) { - const matchType = s === seg ? - getStringLiteralType(getSourceText(s).slice(pos, p)) : - getTemplateLiteralType( - [sourceTexts[seg].slice(pos), ...sourceTexts.slice(seg + 1, s), getSourceText(s).slice(0, p)], - sourceTypes.slice(seg, s), - ); + const matchType = + s === seg + ? getStringLiteralType(getSourceText(s).slice(pos, p)) + : getTemplateLiteralType( + [ + sourceTexts[seg].slice(pos), + ...sourceTexts.slice(seg + 1, s), + getSourceText(s).slice(0, p), + ], + sourceTypes.slice(seg, s) + ); matches.push(matchType); seg = s; pos = p; } } - function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type, priority = InferencePriority.None, contravariant = false) { + function inferTypes( + inferences: InferenceInfo[], + originalSource: Type, + originalTarget: Type, + priority = InferencePriority.None, + contravariant = false + ) { let bivariant = false; let propagationType: Type; let inferencePriority: number = InferencePriority.MaxValue; @@ -26633,20 +47341,41 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { propagationType = savePropagationType; return; } - if (source.aliasSymbol && source.aliasSymbol === target.aliasSymbol) { + if ( + source.aliasSymbol && + source.aliasSymbol === target.aliasSymbol + ) { if (source.aliasTypeArguments) { // Source and target are types originating in the same generic type alias declaration. // Simply infer from source type arguments to target type arguments, with defaults applied. - const params = getSymbolLinks(source.aliasSymbol).typeParameters!; + const params = getSymbolLinks(source.aliasSymbol) + .typeParameters!; const minParams = getMinTypeArgumentCount(params); - const sourceTypes = fillMissingTypeArguments(source.aliasTypeArguments, params, minParams, isInJSFile(source.aliasSymbol.valueDeclaration)); - const targetTypes = fillMissingTypeArguments(target.aliasTypeArguments, params, minParams, isInJSFile(source.aliasSymbol.valueDeclaration)); - inferFromTypeArguments(sourceTypes, targetTypes!, getAliasVariances(source.aliasSymbol)); + const sourceTypes = fillMissingTypeArguments( + source.aliasTypeArguments, + params, + minParams, + isInJSFile(source.aliasSymbol.valueDeclaration) + ); + const targetTypes = fillMissingTypeArguments( + target.aliasTypeArguments, + params, + minParams, + isInJSFile(source.aliasSymbol.valueDeclaration) + ); + inferFromTypeArguments( + sourceTypes, + targetTypes!, + getAliasVariances(source.aliasSymbol) + ); } // And if there weren't any type arguments, there's no reason to run inference as the types must be the same. return; } - if (source === target && source.flags & TypeFlags.UnionOrIntersection) { + if ( + source === target && + source.flags & TypeFlags.UnionOrIntersection + ) { // When source and target are the same union or intersection type, just relate each constituent // type to itself. for (const t of (source as UnionOrIntersectionType).types) { @@ -26657,11 +47386,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (target.flags & TypeFlags.Union) { // First, infer between identically matching source and target constituents and remove the // matching types. - const [tempSources, tempTargets] = inferFromMatchingTypes(source.flags & TypeFlags.Union ? (source as UnionType).types : [source], (target as UnionType).types, isTypeOrBaseIdenticalTo); + const [tempSources, tempTargets] = inferFromMatchingTypes( + source.flags & TypeFlags.Union + ? (source as UnionType).types + : [source], + (target as UnionType).types, + isTypeOrBaseIdenticalTo + ); // Next, infer between closely matching source and target constituents and remove // the matching types. Types closely match when they are instantiations of the same // object type or instantiations of the same type alias. - const [sources, targets] = inferFromMatchingTypes(tempSources, tempTargets, isTypeCloselyMatchedBy); + const [sources, targets] = inferFromMatchingTypes( + tempSources, + tempTargets, + isTypeCloselyMatchedBy + ); if (targets.length === 0) { return; } @@ -26672,19 +47411,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // inferring a type parameter constraint. Instead, make a lower priority inference from // the full source to whatever remains in the target. For example, when inferring from // string to 'string | T', make a lower priority inference of string for T. - inferWithPriority(source, target, InferencePriority.NakedTypeVariable); + inferWithPriority( + source, + target, + InferencePriority.NakedTypeVariable + ); return; } source = getUnionType(sources); - } - else if (target.flags & TypeFlags.Intersection && !every((target as IntersectionType).types, isNonGenericObjectType)) { + } else if ( + target.flags & TypeFlags.Intersection && + !every( + (target as IntersectionType).types, + isNonGenericObjectType + ) + ) { // We reduce intersection types unless they're simple combinations of object types. For example, // when inferring from 'string[] & { extra: any }' to 'string[] & T' we want to remove string[] and // infer { extra: any } for T. But when inferring to 'string[] & Iterable' we want to keep the // string[] on the source side and infer string for T. if (!(source.flags & TypeFlags.Union)) { // Infer between identically matching source and target constituents and remove the matching types. - const [sources, targets] = inferFromMatchingTypes(source.flags & TypeFlags.Intersection ? (source as IntersectionType).types : [source], (target as IntersectionType).types, isTypeIdenticalTo); + const [sources, targets] = inferFromMatchingTypes( + source.flags & TypeFlags.Intersection + ? (source as IntersectionType).types + : [source], + (target as IntersectionType).types, + isTypeIdenticalTo + ); if (sources.length === 0 || targets.length === 0) { return; } @@ -26692,7 +47446,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { target = getIntersectionType(targets); } } - if (target.flags & (TypeFlags.IndexedAccess | TypeFlags.Substitution)) { + if ( + target.flags & + (TypeFlags.IndexedAccess | TypeFlags.Substitution) + ) { if (isNoInferType(target)) { return; } @@ -26722,7 +47479,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // // As a special case, also ignore nonInferrableAnyType, which is a special form of the any type // used as a stand-in for binding elements when they are being inferred. - if (getObjectFlags(source) & ObjectFlags.NonInferrableType || source === nonInferrableAnyType) { + if ( + getObjectFlags(source) & + ObjectFlags.NonInferrableType || + source === nonInferrableAnyType + ) { return; } if (!inference.isFixed) { @@ -26730,7 +47491,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (candidate === blockedStringType) { return; } - if (inference.priority === undefined || priority < inference.priority) { + if ( + inference.priority === undefined || + priority < inference.priority + ) { inference.candidates = undefined; inference.contraCandidates = undefined; inference.topLevel = true; @@ -26740,17 +47504,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We make contravariant inferences only if we are in a pure contravariant position, // i.e. only if we have not descended into a bivariant position. if (contravariant && !bivariant) { - if (!contains(inference.contraCandidates, candidate)) { - inference.contraCandidates = append(inference.contraCandidates, candidate); + if ( + !contains( + inference.contraCandidates, + candidate + ) + ) { + inference.contraCandidates = append( + inference.contraCandidates, + candidate + ); clearCachedInferences(inferences); } - } - else if (!contains(inference.candidates, candidate)) { - inference.candidates = append(inference.candidates, candidate); + } else if ( + !contains(inference.candidates, candidate) + ) { + inference.candidates = append( + inference.candidates, + candidate + ); clearCachedInferences(inferences); } } - if (!(priority & InferencePriority.ReturnType) && target.flags & TypeFlags.TypeParameter && inference.topLevel && !isTypeParameterAtTopLevel(originalTarget, target as TypeParameter)) { + if ( + !(priority & InferencePriority.ReturnType) && + target.flags & TypeFlags.TypeParameter && + inference.topLevel && + !isTypeParameterAtTopLevel( + originalTarget, + target as TypeParameter + ) + ) { inference.topLevel = false; clearCachedInferences(inferences); } @@ -26762,13 +47546,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const simplified = getSimplifiedType(target, /*writing*/ false); if (simplified !== target) { inferFromTypes(source, simplified); - } - else if (target.flags & TypeFlags.IndexedAccess) { - const indexType = getSimplifiedType((target as IndexedAccessType).indexType, /*writing*/ false); + } else if (target.flags & TypeFlags.IndexedAccess) { + const indexType = getSimplifiedType( + (target as IndexedAccessType).indexType, + /*writing*/ false + ); // Generally simplifications of instantiable indexes are avoided to keep relationship checking correct, however if our target is an access, we can consider // that key of that access to be "instantiated", since we're looking to find the infernce goal in any way we can. if (indexType.flags & TypeFlags.Instantiable) { - const simplified = distributeIndexOverObjectType(getSimplifiedType((target as IndexedAccessType).objectType, /*writing*/ false), indexType, /*writing*/ false); + const simplified = distributeIndexOverObjectType( + getSimplifiedType( + (target as IndexedAccessType).objectType, + /*writing*/ false + ), + indexType, + /*writing*/ false + ); if (simplified && simplified !== target) { inferFromTypes(source, simplified); } @@ -26776,86 +47569,162 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } if ( - getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && ( - (source as TypeReference).target === (target as TypeReference).target || isArrayType(source) && isArrayType(target) - ) && - !((source as TypeReference).node && (target as TypeReference).node) + getObjectFlags(source) & ObjectFlags.Reference && + getObjectFlags(target) & ObjectFlags.Reference && + ((source as TypeReference).target === + (target as TypeReference).target || + (isArrayType(source) && isArrayType(target))) && + !( + (source as TypeReference).node && + (target as TypeReference).node + ) ) { // If source and target are references to the same generic type, infer from type arguments - inferFromTypeArguments(getTypeArguments(source as TypeReference), getTypeArguments(target as TypeReference), getVariances((source as TypeReference).target)); - } - else if (source.flags & TypeFlags.Index && target.flags & TypeFlags.Index) { - inferFromContravariantTypes((source as IndexType).type, (target as IndexType).type); - } - else if ((isLiteralType(source) || source.flags & TypeFlags.String) && target.flags & TypeFlags.Index) { + inferFromTypeArguments( + getTypeArguments(source as TypeReference), + getTypeArguments(target as TypeReference), + getVariances((source as TypeReference).target) + ); + } else if ( + source.flags & TypeFlags.Index && + target.flags & TypeFlags.Index + ) { + inferFromContravariantTypes( + (source as IndexType).type, + (target as IndexType).type + ); + } else if ( + (isLiteralType(source) || source.flags & TypeFlags.String) && + target.flags & TypeFlags.Index + ) { const empty = createEmptyObjectTypeFromStringLiteral(source); - inferFromContravariantTypesWithPriority(empty, (target as IndexType).type, InferencePriority.LiteralKeyof); - } - else if (source.flags & TypeFlags.IndexedAccess && target.flags & TypeFlags.IndexedAccess) { - inferFromTypes((source as IndexedAccessType).objectType, (target as IndexedAccessType).objectType); - inferFromTypes((source as IndexedAccessType).indexType, (target as IndexedAccessType).indexType); - } - else if (source.flags & TypeFlags.StringMapping && target.flags & TypeFlags.StringMapping) { - if ((source as StringMappingType).symbol === (target as StringMappingType).symbol) { - inferFromTypes((source as StringMappingType).type, (target as StringMappingType).type); + inferFromContravariantTypesWithPriority( + empty, + (target as IndexType).type, + InferencePriority.LiteralKeyof + ); + } else if ( + source.flags & TypeFlags.IndexedAccess && + target.flags & TypeFlags.IndexedAccess + ) { + inferFromTypes( + (source as IndexedAccessType).objectType, + (target as IndexedAccessType).objectType + ); + inferFromTypes( + (source as IndexedAccessType).indexType, + (target as IndexedAccessType).indexType + ); + } else if ( + source.flags & TypeFlags.StringMapping && + target.flags & TypeFlags.StringMapping + ) { + if ( + (source as StringMappingType).symbol === + (target as StringMappingType).symbol + ) { + inferFromTypes( + (source as StringMappingType).type, + (target as StringMappingType).type + ); } - } - else if (source.flags & TypeFlags.Substitution) { + } else if (source.flags & TypeFlags.Substitution) { inferFromTypes((source as SubstitutionType).baseType, target); - inferWithPriority(getSubstitutionIntersection(source as SubstitutionType), target, InferencePriority.SubstituteSource); // Make substitute inference at a lower priority - } - else if (target.flags & TypeFlags.Conditional) { - invokeOnce(source, target as ConditionalType, inferToConditionalType); - } - else if (target.flags & TypeFlags.UnionOrIntersection) { - inferToMultipleTypes(source, (target as UnionOrIntersectionType).types, target.flags); - } - else if (source.flags & TypeFlags.Union) { + inferWithPriority( + getSubstitutionIntersection(source as SubstitutionType), + target, + InferencePriority.SubstituteSource + ); // Make substitute inference at a lower priority + } else if (target.flags & TypeFlags.Conditional) { + invokeOnce( + source, + target as ConditionalType, + inferToConditionalType + ); + } else if (target.flags & TypeFlags.UnionOrIntersection) { + inferToMultipleTypes( + source, + (target as UnionOrIntersectionType).types, + target.flags + ); + } else if (source.flags & TypeFlags.Union) { // Source is a union or intersection type, infer from each constituent type const sourceTypes = (source as UnionOrIntersectionType).types; for (const sourceType of sourceTypes) { inferFromTypes(sourceType, target); } - } - else if (target.flags & TypeFlags.TemplateLiteral) { - inferToTemplateLiteralType(source, target as TemplateLiteralType); - } - else { + } else if (target.flags & TypeFlags.TemplateLiteral) { + inferToTemplateLiteralType( + source, + target as TemplateLiteralType + ); + } else { source = getReducedType(source); - if (isGenericMappedType(source) && isGenericMappedType(target)) { + if ( + isGenericMappedType(source) && + isGenericMappedType(target) + ) { invokeOnce(source, target, inferFromGenericMappedTypes); } - if (!(priority & InferencePriority.NoConstraints && source.flags & (TypeFlags.Intersection | TypeFlags.Instantiable))) { + if ( + !( + priority & InferencePriority.NoConstraints && + source.flags & + (TypeFlags.Intersection | TypeFlags.Instantiable) + ) + ) { const apparentSource = getApparentType(source); // getApparentType can return _any_ type, since an indexed access or conditional may simplify to any other type. // If that occurs and it doesn't simplify to an object or intersection, we'll need to restart `inferFromTypes` // with the simplified source. - if (apparentSource !== source && !(apparentSource.flags & (TypeFlags.Object | TypeFlags.Intersection))) { + if ( + apparentSource !== source && + !( + apparentSource.flags & + (TypeFlags.Object | TypeFlags.Intersection) + ) + ) { return inferFromTypes(apparentSource, target); } source = apparentSource; } - if (source.flags & (TypeFlags.Object | TypeFlags.Intersection)) { + if ( + source.flags & + (TypeFlags.Object | TypeFlags.Intersection) + ) { invokeOnce(source, target, inferFromObjectTypes); } } } - function inferWithPriority(source: Type, target: Type, newPriority: InferencePriority) { + function inferWithPriority( + source: Type, + target: Type, + newPriority: InferencePriority + ) { const savePriority = priority; priority |= newPriority; inferFromTypes(source, target); priority = savePriority; } - function inferFromContravariantTypesWithPriority(source: Type, target: Type, newPriority: InferencePriority) { + function inferFromContravariantTypesWithPriority( + source: Type, + target: Type, + newPriority: InferencePriority + ) { const savePriority = priority; priority |= newPriority; inferFromContravariantTypes(source, target); priority = savePriority; } - function inferToMultipleTypesWithPriority(source: Type, targets: Type[], targetFlags: TypeFlags, newPriority: InferencePriority) { + function inferToMultipleTypesWithPriority( + source: Type, + targets: Type[], + targetFlags: TypeFlags, + newPriority: InferencePriority + ) { const savePriority = priority; priority |= newPriority; inferToMultipleTypes(source, targets, targetFlags); @@ -26875,14 +47744,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // In particular, we would be inferring from increasingly deep instantiations of `Deep` to `Loop`, // such that we would go on inferring forever, even though we would never infer // between the same pair of types. - function invokeOnce(source: Source, target: Target, action: (source: Source, target: Target) => void) { + function invokeOnce( + source: Source, + target: Target, + action: (source: Source, target: Target) => void + ) { const key = source.id + "," + target.id; const status = visited && visited.get(key); if (status !== undefined) { inferencePriority = Math.min(inferencePriority, status); return; } - (visited || (visited = new Map())).set(key, InferencePriority.Circularity); + (visited || (visited = new Map())).set( + key, + InferencePriority.Circularity + ); const saveInferencePriority = inferencePriority; inferencePriority = InferencePriority.MaxValue; // We stop inferring and report a circularity if we encounter duplicate recursion identities on both @@ -26890,22 +47766,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const saveExpandingFlags = expandingFlags; (sourceStack ??= []).push(source); (targetStack ??= []).push(target); - if (isDeeplyNestedType(source, sourceStack, sourceStack.length, 2)) expandingFlags |= ExpandingFlags.Source; - if (isDeeplyNestedType(target, targetStack, targetStack.length, 2)) expandingFlags |= ExpandingFlags.Target; + if (isDeeplyNestedType(source, sourceStack, sourceStack.length, 2)) + expandingFlags |= ExpandingFlags.Source; + if (isDeeplyNestedType(target, targetStack, targetStack.length, 2)) + expandingFlags |= ExpandingFlags.Target; if (expandingFlags !== ExpandingFlags.Both) { action(source, target); - } - else { + } else { inferencePriority = InferencePriority.Circularity; } targetStack.pop(); sourceStack.pop(); expandingFlags = saveExpandingFlags; visited.set(key, inferencePriority); - inferencePriority = Math.min(inferencePriority, saveInferencePriority); + inferencePriority = Math.min( + inferencePriority, + saveInferencePriority + ); } - function inferFromMatchingTypes(sources: Type[], targets: Type[], matches: (s: Type, t: Type) => boolean): [Type[], Type[]] { + function inferFromMatchingTypes( + sources: Type[], + targets: Type[], + matches: (s: Type, t: Type) => boolean + ): [Type[], Type[]] { let matchedSources: Type[] | undefined; let matchedTargets: Type[] | undefined; for (const t of targets) { @@ -26918,18 +47802,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } return [ - matchedSources ? filter(sources, t => !contains(matchedSources, t)) : sources, - matchedTargets ? filter(targets, t => !contains(matchedTargets, t)) : targets, + matchedSources + ? filter(sources, (t) => !contains(matchedSources, t)) + : sources, + matchedTargets + ? filter(targets, (t) => !contains(matchedTargets, t)) + : targets, ]; } - function inferFromTypeArguments(sourceTypes: readonly Type[], targetTypes: readonly Type[], variances: readonly VarianceFlags[]) { - const count = sourceTypes.length < targetTypes.length ? sourceTypes.length : targetTypes.length; + function inferFromTypeArguments( + sourceTypes: readonly Type[], + targetTypes: readonly Type[], + variances: readonly VarianceFlags[] + ) { + const count = + sourceTypes.length < targetTypes.length + ? sourceTypes.length + : targetTypes.length; for (let i = 0; i < count; i++) { - if (i < variances.length && (variances[i] & VarianceFlags.VarianceMask) === VarianceFlags.Contravariant) { + if ( + i < variances.length && + (variances[i] & VarianceFlags.VarianceMask) === + VarianceFlags.Contravariant + ) { inferFromContravariantTypes(sourceTypes[i], targetTypes[i]); - } - else { + } else { inferFromTypes(sourceTypes[i], targetTypes[i]); } } @@ -26941,11 +47839,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { contravariant = !contravariant; } - function inferFromContravariantTypesIfStrictFunctionTypes(source: Type, target: Type) { - if (strictFunctionTypes || priority & InferencePriority.AlwaysStrict) { + function inferFromContravariantTypesIfStrictFunctionTypes( + source: Type, + target: Type + ) { + if ( + strictFunctionTypes || + priority & InferencePriority.AlwaysStrict + ) { inferFromContravariantTypes(source, target); - } - else { + } else { inferFromTypes(source, target); } } @@ -26964,8 +47867,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getSingleTypeVariableFromIntersectionTypes(types: Type[]) { let typeVariable: Type | undefined; for (const type of types) { - const t = type.flags & TypeFlags.Intersection && find((type as IntersectionType).types, t => !!getInferenceInfoForType(t)); - if (!t || typeVariable && t !== typeVariable) { + const t = + type.flags & TypeFlags.Intersection && + find( + (type as IntersectionType).types, + (t) => !!getInferenceInfoForType(t) + ); + if (!t || (typeVariable && t !== typeVariable)) { return undefined; } typeVariable = t; @@ -26973,11 +47881,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return typeVariable; } - function inferToMultipleTypes(source: Type, targets: Type[], targetFlags: TypeFlags) { + function inferToMultipleTypes( + source: Type, + targets: Type[], + targetFlags: TypeFlags + ) { let typeVariableCount = 0; if (targetFlags & TypeFlags.Union) { let nakedTypeVariable: Type | undefined; - const sources = source.flags & TypeFlags.Union ? (source as UnionType).types : [source]; + const sources = + source.flags & TypeFlags.Union + ? (source as UnionType).types + : [source]; const matched = new Array(sources.length); let inferenceCircularity = false; // First infer to types that are not naked type variables. For each source type we @@ -26988,15 +47903,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (getInferenceInfoForType(t)) { nakedTypeVariable = t; typeVariableCount++; - } - else { + } else { for (let i = 0; i < sources.length; i++) { const saveInferencePriority = inferencePriority; inferencePriority = InferencePriority.MaxValue; inferFromTypes(sources[i], t); - if (inferencePriority === priority) matched[i] = true; - inferenceCircularity = inferenceCircularity || inferencePriority === InferencePriority.Circularity; - inferencePriority = Math.min(inferencePriority, saveInferencePriority); + if (inferencePriority === priority) + matched[i] = true; + inferenceCircularity = + inferenceCircularity || + inferencePriority === + InferencePriority.Circularity; + inferencePriority = Math.min( + inferencePriority, + saveInferencePriority + ); } } } @@ -27004,9 +47925,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If every target is an intersection of types containing a single naked type variable, // make a lower priority inference to that type variable. This handles inferring from // 'A | B' to 'T & (X | Y)' where we want to infer 'A | B' for T. - const intersectionTypeVariable = getSingleTypeVariableFromIntersectionTypes(targets); + const intersectionTypeVariable = + getSingleTypeVariableFromIntersectionTypes(targets); if (intersectionTypeVariable) { - inferWithPriority(source, intersectionTypeVariable, InferencePriority.NakedTypeVariable); + inferWithPriority( + source, + intersectionTypeVariable, + InferencePriority.NakedTypeVariable + ); } return; } @@ -27015,22 +47941,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // types from which no inferences have been made so far and infer from that union to the // naked type variable. if (typeVariableCount === 1 && !inferenceCircularity) { - const unmatched = flatMap(sources, (s, i) => matched[i] ? undefined : s); + const unmatched = flatMap(sources, (s, i) => + matched[i] ? undefined : s + ); if (unmatched.length) { - inferFromTypes(getUnionType(unmatched), nakedTypeVariable!); + inferFromTypes( + getUnionType(unmatched), + nakedTypeVariable! + ); return; } } - } - else { + } else { // We infer from types that are not naked type variables first so that inferences we // make from nested naked type variables and given slightly higher priority by virtue // of being first in the candidates array. for (const t of targets) { if (getInferenceInfoForType(t)) { typeVariableCount++; - } - else { + } else { inferFromTypes(source, t); } } @@ -27039,19 +47968,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // less specific. For example, when inferring from Promise to T | Promise, // we want to infer string for T, not Promise | string. For intersection types // we only infer to single naked type variables. - if (targetFlags & TypeFlags.Intersection ? typeVariableCount === 1 : typeVariableCount > 0) { + if ( + targetFlags & TypeFlags.Intersection + ? typeVariableCount === 1 + : typeVariableCount > 0 + ) { for (const t of targets) { if (getInferenceInfoForType(t)) { - inferWithPriority(source, t, InferencePriority.NakedTypeVariable); + inferWithPriority( + source, + t, + InferencePriority.NakedTypeVariable + ); } } } } - function inferToMappedType(source: Type, target: MappedType, constraintType: Type): boolean { - if ((constraintType.flags & TypeFlags.Union) || (constraintType.flags & TypeFlags.Intersection)) { + function inferToMappedType( + source: Type, + target: MappedType, + constraintType: Type + ): boolean { + if ( + constraintType.flags & TypeFlags.Union || + constraintType.flags & TypeFlags.Intersection + ) { let result = false; - for (const type of (constraintType as (UnionType | IntersectionType)).types) { + for (const type of ( + constraintType as UnionType | IntersectionType + ).types) { result = inferToMappedType(source, target, type) || result; } return result; @@ -27061,9 +48007,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // where T is a type variable. Use inferTypeForHomomorphicMappedType to infer a suitable source // type and then make a secondary inference from that type to T. We make a secondary inference // such that direct inferences to T get priority over inferences to Partial, for example. - const inference = getInferenceInfoForType((constraintType as IndexType).type); - if (inference && !inference.isFixed && !isFromInferenceBlockedSource(source)) { - const inferredType = inferTypeForHomomorphicMappedType(source, target, constraintType as IndexType); + const inference = getInferenceInfoForType( + (constraintType as IndexType).type + ); + if ( + inference && + !inference.isFixed && + !isFromInferenceBlockedSource(source) + ) { + const inferredType = inferTypeForHomomorphicMappedType( + source, + target, + constraintType as IndexType + ); if (inferredType) { // We assign a lower priority to inferences made from types containing non-inferrable // types because we may only have a partial result (i.e. we may have failed to make @@ -27071,9 +48027,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { inferWithPriority( inferredType, inference.typeParameter, - getObjectFlags(source) & ObjectFlags.NonInferrableType ? - InferencePriority.PartialHomomorphicMappedType : - InferencePriority.HomomorphicMappedType, + getObjectFlags(source) & + ObjectFlags.NonInferrableType + ? InferencePriority.PartialHomomorphicMappedType + : InferencePriority.HomomorphicMappedType ); } } @@ -27082,20 +48039,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (constraintType.flags & TypeFlags.TypeParameter) { // We're inferring from some source type S to a mapped type { [P in K]: X }, where K is a type // parameter. First infer from 'keyof S' to K. - inferWithPriority(getIndexType(source, /*indexFlags*/ !!source.pattern ? IndexFlags.NoIndexSignatures : IndexFlags.None), constraintType, InferencePriority.MappedTypeConstraint); + inferWithPriority( + getIndexType( + source, + /*indexFlags*/ !!source.pattern + ? IndexFlags.NoIndexSignatures + : IndexFlags.None + ), + constraintType, + InferencePriority.MappedTypeConstraint + ); // If K is constrained to a type C, also infer to C. Thus, for a mapped type { [P in K]: X }, // where K extends keyof T, we make the same inferences as for a homomorphic mapped type // { [P in keyof T]: X }. This enables us to make meaningful inferences when the target is a // Pick. const extendedConstraint = getConstraintOfType(constraintType); - if (extendedConstraint && inferToMappedType(source, target, extendedConstraint)) { + if ( + extendedConstraint && + inferToMappedType(source, target, extendedConstraint) + ) { return true; } // If no inferences can be made to K's constraint, infer from a union of the property types // in the source to the template type X. - const propTypes = map(getPropertiesOfType(source), getTypeOfSymbol); - const indexTypes = map(getIndexInfosOfType(source), info => info !== enumNumberIndexInfo ? info.type : neverType); - inferFromTypes(getUnionType(concatenate(propTypes, indexTypes)), getTemplateTypeFromMappedType(target)); + const propTypes = map( + getPropertiesOfType(source), + getTypeOfSymbol + ); + const indexTypes = map(getIndexInfosOfType(source), (info) => + info !== enumNumberIndexInfo ? info.type : neverType + ); + inferFromTypes( + getUnionType(concatenate(propTypes, indexTypes)), + getTemplateTypeFromMappedType(target) + ); return true; } return false; @@ -27103,18 +48080,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function inferToConditionalType(source: Type, target: ConditionalType) { if (source.flags & TypeFlags.Conditional) { - inferFromTypes((source as ConditionalType).checkType, target.checkType); - inferFromTypes((source as ConditionalType).extendsType, target.extendsType); - inferFromTypes(getTrueTypeFromConditionalType(source as ConditionalType), getTrueTypeFromConditionalType(target)); - inferFromTypes(getFalseTypeFromConditionalType(source as ConditionalType), getFalseTypeFromConditionalType(target)); - } - else { - const targetTypes = [getTrueTypeFromConditionalType(target), getFalseTypeFromConditionalType(target)]; - inferToMultipleTypesWithPriority(source, targetTypes, target.flags, contravariant ? InferencePriority.ContravariantConditional : 0); + inferFromTypes( + (source as ConditionalType).checkType, + target.checkType + ); + inferFromTypes( + (source as ConditionalType).extendsType, + target.extendsType + ); + inferFromTypes( + getTrueTypeFromConditionalType(source as ConditionalType), + getTrueTypeFromConditionalType(target) + ); + inferFromTypes( + getFalseTypeFromConditionalType(source as ConditionalType), + getFalseTypeFromConditionalType(target) + ); + } else { + const targetTypes = [ + getTrueTypeFromConditionalType(target), + getFalseTypeFromConditionalType(target), + ]; + inferToMultipleTypesWithPriority( + source, + targetTypes, + target.flags, + contravariant + ? InferencePriority.ContravariantConditional + : 0 + ); } } - function inferToTemplateLiteralType(source: Type, target: TemplateLiteralType) { + function inferToTemplateLiteralType( + source: Type, + target: TemplateLiteralType + ) { const matches = inferTypesFromTemplateLiteralType(source, target); const types = target.types; // When the target template literal contains only placeholders (meaning that inference is intended to extract @@ -27123,51 +48124,162 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // assignment check will fail. If we make no inferences, we'll likely end up with the constraint 'string' which, // upon instantiation, would collapse all the placeholders to just 'string', and an assignment check might // succeed. That would be a pointless and confusing outcome. - if (matches || every(target.texts, s => s.length === 0)) { + if (matches || every(target.texts, (s) => s.length === 0)) { for (let i = 0; i < types.length; i++) { const source = matches ? matches[i] : neverType; const target = types[i]; // If we are inferring from a string literal type to a type variable whose constraint includes one of the // allowed template literal placeholder types, infer from a literal type corresponding to the constraint. - if (source.flags & TypeFlags.StringLiteral && target.flags & TypeFlags.TypeVariable) { - const inferenceContext = getInferenceInfoForType(target); - const constraint = inferenceContext ? getBaseConstraintOfType(inferenceContext.typeParameter) : undefined; + if ( + source.flags & TypeFlags.StringLiteral && + target.flags & TypeFlags.TypeVariable + ) { + const inferenceContext = + getInferenceInfoForType(target); + const constraint = inferenceContext + ? getBaseConstraintOfType( + inferenceContext.typeParameter + ) + : undefined; if (constraint && !isTypeAny(constraint)) { - const constraintTypes = constraint.flags & TypeFlags.Union ? (constraint as UnionType).types : [constraint]; - let allTypeFlags: TypeFlags = reduceLeft(constraintTypes, (flags, t) => flags | t.flags, 0 as TypeFlags); + const constraintTypes = + constraint.flags & TypeFlags.Union + ? (constraint as UnionType).types + : [constraint]; + let allTypeFlags: TypeFlags = reduceLeft( + constraintTypes, + (flags, t) => flags | t.flags, + 0 as TypeFlags + ); // If the constraint contains `string`, we don't need to look for a more preferred type if (!(allTypeFlags & TypeFlags.String)) { const str = (source as StringLiteralType).value; // If the type contains `number` or a number literal and the string isn't a valid number, exclude numbers - if (allTypeFlags & TypeFlags.NumberLike && !isValidNumberString(str, /*roundTripOnly*/ true)) { + if ( + allTypeFlags & TypeFlags.NumberLike && + !isValidNumberString( + str, + /*roundTripOnly*/ true + ) + ) { allTypeFlags &= ~TypeFlags.NumberLike; } // If the type contains `bigint` or a bigint literal and the string isn't a valid bigint, exclude bigints - if (allTypeFlags & TypeFlags.BigIntLike && !isValidBigIntString(str, /*roundTripOnly*/ true)) { + if ( + allTypeFlags & TypeFlags.BigIntLike && + !isValidBigIntString( + str, + /*roundTripOnly*/ true + ) + ) { allTypeFlags &= ~TypeFlags.BigIntLike; } // for each type in the constraint, find the highest priority matching type - const matchingType = reduceLeft(constraintTypes, (left, right) => - !(right.flags & allTypeFlags) ? left : - left.flags & TypeFlags.String ? left : right.flags & TypeFlags.String ? source : - left.flags & TypeFlags.TemplateLiteral ? left : right.flags & TypeFlags.TemplateLiteral && isTypeMatchedByTemplateLiteralType(source, right as TemplateLiteralType) ? source : - left.flags & TypeFlags.StringMapping ? left : right.flags & TypeFlags.StringMapping && str === applyStringMapping(right.symbol, str) ? source : - left.flags & TypeFlags.StringLiteral ? left : right.flags & TypeFlags.StringLiteral && (right as StringLiteralType).value === str ? right : - left.flags & TypeFlags.Number ? left : right.flags & TypeFlags.Number ? getNumberLiteralType(+str) : - left.flags & TypeFlags.Enum ? left : right.flags & TypeFlags.Enum ? getNumberLiteralType(+str) : - left.flags & TypeFlags.NumberLiteral ? left : right.flags & TypeFlags.NumberLiteral && (right as NumberLiteralType).value === +str ? right : - left.flags & TypeFlags.BigInt ? left : right.flags & TypeFlags.BigInt ? parseBigIntLiteralType(str) : - left.flags & TypeFlags.BigIntLiteral ? left : right.flags & TypeFlags.BigIntLiteral && pseudoBigIntToString((right as BigIntLiteralType).value) === str ? right : - left.flags & TypeFlags.Boolean ? left : right.flags & TypeFlags.Boolean ? str === "true" ? trueType : str === "false" ? falseType : booleanType : - left.flags & TypeFlags.BooleanLiteral ? left : right.flags & TypeFlags.BooleanLiteral && (right as IntrinsicType).intrinsicName === str ? right : - left.flags & TypeFlags.Undefined ? left : right.flags & TypeFlags.Undefined && (right as IntrinsicType).intrinsicName === str ? right : - left.flags & TypeFlags.Null ? left : right.flags & TypeFlags.Null && (right as IntrinsicType).intrinsicName === str ? right : - left, neverType as Type); + const matchingType = reduceLeft( + constraintTypes, + (left, right) => + !(right.flags & allTypeFlags) + ? left + : left.flags & TypeFlags.String + ? left + : right.flags & TypeFlags.String + ? source + : left.flags & + TypeFlags.TemplateLiteral + ? left + : right.flags & + TypeFlags.TemplateLiteral && + isTypeMatchedByTemplateLiteralType( + source, + right as TemplateLiteralType + ) + ? source + : left.flags & + TypeFlags.StringMapping + ? left + : right.flags & + TypeFlags.StringMapping && + str === + applyStringMapping( + right.symbol, + str + ) + ? source + : left.flags & + TypeFlags.StringLiteral + ? left + : right.flags & + TypeFlags.StringLiteral && + (right as StringLiteralType) + .value === str + ? right + : left.flags & TypeFlags.Number + ? left + : right.flags & TypeFlags.Number + ? getNumberLiteralType(+str) + : left.flags & TypeFlags.Enum + ? left + : right.flags & TypeFlags.Enum + ? getNumberLiteralType(+str) + : left.flags & + TypeFlags.NumberLiteral + ? left + : right.flags & + TypeFlags.NumberLiteral && + (right as NumberLiteralType) + .value === +str + ? right + : left.flags & TypeFlags.BigInt + ? left + : right.flags & TypeFlags.BigInt + ? parseBigIntLiteralType(str) + : left.flags & + TypeFlags.BigIntLiteral + ? left + : right.flags & + TypeFlags.BigIntLiteral && + pseudoBigIntToString( + (right as BigIntLiteralType) + .value + ) === str + ? right + : left.flags & TypeFlags.Boolean + ? left + : right.flags & TypeFlags.Boolean + ? str === "true" + ? trueType + : str === "false" + ? falseType + : booleanType + : left.flags & + TypeFlags.BooleanLiteral + ? left + : right.flags & + TypeFlags.BooleanLiteral && + (right as IntrinsicType) + .intrinsicName === str + ? right + : left.flags & TypeFlags.Undefined + ? left + : right.flags & + TypeFlags.Undefined && + (right as IntrinsicType) + .intrinsicName === str + ? right + : left.flags & TypeFlags.Null + ? left + : right.flags & TypeFlags.Null && + (right as IntrinsicType) + .intrinsicName === str + ? right + : left, + neverType as Type + ); if (!(matchingType.flags & TypeFlags.Never)) { inferFromTypes(matchingType, target); @@ -27182,32 +48294,59 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function inferFromGenericMappedTypes(source: MappedType, target: MappedType) { + function inferFromGenericMappedTypes( + source: MappedType, + target: MappedType + ) { // The source and target types are generic types { [P in S]: X } and { [P in T]: Y }, so we infer // from S to T and from X to Y. - inferFromTypes(getConstraintTypeFromMappedType(source), getConstraintTypeFromMappedType(target)); - inferFromTypes(getTemplateTypeFromMappedType(source), getTemplateTypeFromMappedType(target)); + inferFromTypes( + getConstraintTypeFromMappedType(source), + getConstraintTypeFromMappedType(target) + ); + inferFromTypes( + getTemplateTypeFromMappedType(source), + getTemplateTypeFromMappedType(target) + ); const sourceNameType = getNameTypeFromMappedType(source); const targetNameType = getNameTypeFromMappedType(target); - if (sourceNameType && targetNameType) inferFromTypes(sourceNameType, targetNameType); + if (sourceNameType && targetNameType) + inferFromTypes(sourceNameType, targetNameType); } function inferFromObjectTypes(source: Type, target: Type) { if ( - getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && ( - (source as TypeReference).target === (target as TypeReference).target || isArrayType(source) && isArrayType(target) - ) + getObjectFlags(source) & ObjectFlags.Reference && + getObjectFlags(target) & ObjectFlags.Reference && + ((source as TypeReference).target === + (target as TypeReference).target || + (isArrayType(source) && isArrayType(target))) ) { // If source and target are references to the same generic type, infer from type arguments - inferFromTypeArguments(getTypeArguments(source as TypeReference), getTypeArguments(target as TypeReference), getVariances((source as TypeReference).target)); + inferFromTypeArguments( + getTypeArguments(source as TypeReference), + getTypeArguments(target as TypeReference), + getVariances((source as TypeReference).target) + ); return; } if (isGenericMappedType(source) && isGenericMappedType(target)) { inferFromGenericMappedTypes(source, target); } - if (getObjectFlags(target) & ObjectFlags.Mapped && !(target as MappedType).declaration.nameType) { - const constraintType = getConstraintTypeFromMappedType(target as MappedType); - if (inferToMappedType(source, target as MappedType, constraintType)) { + if ( + getObjectFlags(target) & ObjectFlags.Mapped && + !(target as MappedType).declaration.nameType + ) { + const constraintType = getConstraintTypeFromMappedType( + target as MappedType + ); + if ( + inferToMappedType( + source, + target as MappedType, + constraintType + ) + ) { return; } } @@ -27221,82 +48360,256 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const elementFlags = target.target.elementFlags; // When source and target are tuple types with the same structure (fixed, variadic, and rest are matched // to the same kind in each position), simply infer between the element types. - if (isTupleType(source) && isTupleTypeStructureMatching(source, target)) { + if ( + isTupleType(source) && + isTupleTypeStructureMatching(source, target) + ) { for (let i = 0; i < targetArity; i++) { - inferFromTypes(getTypeArguments(source)[i], elementTypes[i]); + inferFromTypes( + getTypeArguments(source)[i], + elementTypes[i] + ); } return; } - const startLength = isTupleType(source) ? Math.min(source.target.fixedLength, target.target.fixedLength) : 0; - const endLength = Math.min(isTupleType(source) ? getEndElementCount(source.target, ElementFlags.Fixed) : 0, target.target.combinedFlags & ElementFlags.Variable ? getEndElementCount(target.target, ElementFlags.Fixed) : 0); + const startLength = isTupleType(source) + ? Math.min( + source.target.fixedLength, + target.target.fixedLength + ) + : 0; + const endLength = Math.min( + isTupleType(source) + ? getEndElementCount( + source.target, + ElementFlags.Fixed + ) + : 0, + target.target.combinedFlags & ElementFlags.Variable + ? getEndElementCount( + target.target, + ElementFlags.Fixed + ) + : 0 + ); // Infer between starting fixed elements. for (let i = 0; i < startLength; i++) { - inferFromTypes(getTypeArguments(source)[i], elementTypes[i]); + inferFromTypes( + getTypeArguments(source)[i], + elementTypes[i] + ); } - if (!isTupleType(source) || sourceArity - startLength - endLength === 1 && source.target.elementFlags[startLength] & ElementFlags.Rest) { + if ( + !isTupleType(source) || + (sourceArity - startLength - endLength === 1 && + source.target.elementFlags[startLength] & + ElementFlags.Rest) + ) { // Single rest element remains in source, infer from that to every element in target - const restType = getTypeArguments(source)[startLength]; - for (let i = startLength; i < targetArity - endLength; i++) { - inferFromTypes(elementFlags[i] & ElementFlags.Variadic ? createArrayType(restType) : restType, elementTypes[i]); + const restType = + getTypeArguments(source)[startLength]; + for ( + let i = startLength; + i < targetArity - endLength; + i++ + ) { + inferFromTypes( + elementFlags[i] & ElementFlags.Variadic + ? createArrayType(restType) + : restType, + elementTypes[i] + ); } - } - else { - const middleLength = targetArity - startLength - endLength; + } else { + const middleLength = + targetArity - startLength - endLength; if (middleLength === 2) { - if (elementFlags[startLength] & elementFlags[startLength + 1] & ElementFlags.Variadic) { + if ( + elementFlags[startLength] & + elementFlags[startLength + 1] & + ElementFlags.Variadic + ) { // Middle of target is [...T, ...U] and source is tuple type - const targetInfo = getInferenceInfoForType(elementTypes[startLength]); - if (targetInfo && targetInfo.impliedArity !== undefined) { + const targetInfo = getInferenceInfoForType( + elementTypes[startLength] + ); + if ( + targetInfo && + targetInfo.impliedArity !== undefined + ) { // Infer slices from source based on implied arity of T. - inferFromTypes(sliceTupleType(source, startLength, endLength + sourceArity - targetInfo.impliedArity), elementTypes[startLength]); - inferFromTypes(sliceTupleType(source, startLength + targetInfo.impliedArity, endLength), elementTypes[startLength + 1]); + inferFromTypes( + sliceTupleType( + source, + startLength, + endLength + + sourceArity - + targetInfo.impliedArity + ), + elementTypes[startLength] + ); + inferFromTypes( + sliceTupleType( + source, + startLength + + targetInfo.impliedArity, + endLength + ), + elementTypes[startLength + 1] + ); } - } - else if (elementFlags[startLength] & ElementFlags.Variadic && elementFlags[startLength + 1] & ElementFlags.Rest) { + } else if ( + elementFlags[startLength] & + ElementFlags.Variadic && + elementFlags[startLength + 1] & + ElementFlags.Rest + ) { // Middle of target is [...T, ...rest] and source is tuple type // if T is constrained by a fixed-size tuple we might be able to use its arity to infer T - const param = getInferenceInfoForType(elementTypes[startLength])?.typeParameter; - const constraint = param && getBaseConstraintOfType(param); - if (constraint && isTupleType(constraint) && !(constraint.target.combinedFlags & ElementFlags.Variable)) { - const impliedArity = constraint.target.fixedLength; - inferFromTypes(sliceTupleType(source, startLength, sourceArity - (startLength + impliedArity)), elementTypes[startLength]); - inferFromTypes(getElementTypeOfSliceOfTupleType(source, startLength + impliedArity, endLength)!, elementTypes[startLength + 1]); + const param = getInferenceInfoForType( + elementTypes[startLength] + )?.typeParameter; + const constraint = + param && getBaseConstraintOfType(param); + if ( + constraint && + isTupleType(constraint) && + !( + constraint.target.combinedFlags & + ElementFlags.Variable + ) + ) { + const impliedArity = + constraint.target.fixedLength; + inferFromTypes( + sliceTupleType( + source, + startLength, + sourceArity - + (startLength + impliedArity) + ), + elementTypes[startLength] + ); + inferFromTypes( + getElementTypeOfSliceOfTupleType( + source, + startLength + impliedArity, + endLength + )!, + elementTypes[startLength + 1] + ); } - } - else if (elementFlags[startLength] & ElementFlags.Rest && elementFlags[startLength + 1] & ElementFlags.Variadic) { + } else if ( + elementFlags[startLength] & + ElementFlags.Rest && + elementFlags[startLength + 1] & + ElementFlags.Variadic + ) { // Middle of target is [...rest, ...T] and source is tuple type // if T is constrained by a fixed-size tuple we might be able to use its arity to infer T - const param = getInferenceInfoForType(elementTypes[startLength + 1])?.typeParameter; - const constraint = param && getBaseConstraintOfType(param); - if (constraint && isTupleType(constraint) && !(constraint.target.combinedFlags & ElementFlags.Variable)) { - const impliedArity = constraint.target.fixedLength; - const endIndex = sourceArity - getEndElementCount(target.target, ElementFlags.Fixed); - const startIndex = endIndex - impliedArity; - const trailingSlice = createTupleType(getTypeArguments(source).slice(startIndex, endIndex), source.target.elementFlags.slice(startIndex, endIndex), /*readonly*/ false, source.target.labeledElementDeclarations && source.target.labeledElementDeclarations.slice(startIndex, endIndex)); - - inferFromTypes(getElementTypeOfSliceOfTupleType(source, startLength, endLength + impliedArity)!, elementTypes[startLength]); - inferFromTypes(trailingSlice, elementTypes[startLength + 1]); + const param = getInferenceInfoForType( + elementTypes[startLength + 1] + )?.typeParameter; + const constraint = + param && getBaseConstraintOfType(param); + if ( + constraint && + isTupleType(constraint) && + !( + constraint.target.combinedFlags & + ElementFlags.Variable + ) + ) { + const impliedArity = + constraint.target.fixedLength; + const endIndex = + sourceArity - + getEndElementCount( + target.target, + ElementFlags.Fixed + ); + const startIndex = + endIndex - impliedArity; + const trailingSlice = createTupleType( + getTypeArguments(source).slice( + startIndex, + endIndex + ), + source.target.elementFlags.slice( + startIndex, + endIndex + ), + /*readonly*/ false, + source.target + .labeledElementDeclarations && + source.target.labeledElementDeclarations.slice( + startIndex, + endIndex + ) + ); + + inferFromTypes( + getElementTypeOfSliceOfTupleType( + source, + startLength, + endLength + impliedArity + )!, + elementTypes[startLength] + ); + inferFromTypes( + trailingSlice, + elementTypes[startLength + 1] + ); } } - } - else if (middleLength === 1 && elementFlags[startLength] & ElementFlags.Variadic) { + } else if ( + middleLength === 1 && + elementFlags[startLength] & + ElementFlags.Variadic + ) { // Middle of target is exactly one variadic element. Infer the slice between the fixed parts in the source. // If target ends in optional element(s), make a lower priority a speculative inference. - const endsInOptional = target.target.elementFlags[targetArity - 1] & ElementFlags.Optional; - const sourceSlice = sliceTupleType(source, startLength, endLength); - inferWithPriority(sourceSlice, elementTypes[startLength], endsInOptional ? InferencePriority.SpeculativeTuple : 0); - } - else if (middleLength === 1 && elementFlags[startLength] & ElementFlags.Rest) { + const endsInOptional = + target.target.elementFlags[ + targetArity - 1 + ] & ElementFlags.Optional; + const sourceSlice = sliceTupleType( + source, + startLength, + endLength + ); + inferWithPriority( + sourceSlice, + elementTypes[startLength], + endsInOptional + ? InferencePriority.SpeculativeTuple + : 0 + ); + } else if ( + middleLength === 1 && + elementFlags[startLength] & ElementFlags.Rest + ) { // Middle of target is exactly one rest element. If middle of source is not empty, infer union of middle element types. - const restType = getElementTypeOfSliceOfTupleType(source, startLength, endLength); + const restType = + getElementTypeOfSliceOfTupleType( + source, + startLength, + endLength + ); if (restType) { - inferFromTypes(restType, elementTypes[startLength]); + inferFromTypes( + restType, + elementTypes[startLength] + ); } } } // Infer between ending fixed elements for (let i = 0; i < endLength; i++) { - inferFromTypes(getTypeArguments(source)[sourceArity - i - 1], elementTypes[targetArity - i - 1]); + inferFromTypes( + getTypeArguments(source)[sourceArity - i - 1], + elementTypes[targetArity - i - 1] + ); } return; } @@ -27315,17 +48628,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function inferFromProperties(source: Type, target: Type) { const properties = getPropertiesOfObjectType(target); for (const targetProp of properties) { - const sourceProp = getPropertyOfType(source, targetProp.escapedName); - if (sourceProp && !some(sourceProp.declarations, hasSkipDirectInferenceFlag)) { + const sourceProp = getPropertyOfType( + source, + targetProp.escapedName + ); + if ( + sourceProp && + !some(sourceProp.declarations, hasSkipDirectInferenceFlag) + ) { inferFromTypes( - removeMissingType(getTypeOfSymbol(sourceProp), !!(sourceProp.flags & SymbolFlags.Optional)), - removeMissingType(getTypeOfSymbol(targetProp), !!(targetProp.flags & SymbolFlags.Optional)), + removeMissingType( + getTypeOfSymbol(sourceProp), + !!(sourceProp.flags & SymbolFlags.Optional) + ), + removeMissingType( + getTypeOfSymbol(targetProp), + !!(targetProp.flags & SymbolFlags.Optional) + ) ); } } } - function inferFromSignatures(source: Type, target: Type, kind: SignatureKind) { + function inferFromSignatures( + source: Type, + target: Type, + kind: SignatureKind + ) { const sourceSignatures = getSignaturesOfType(source, kind); const sourceLen = sourceSignatures.length; if (sourceLen > 0) { @@ -27335,7 +48664,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const targetLen = targetSignatures.length; for (let i = 0; i < targetLen; i++) { const sourceIndex = Math.max(sourceLen - targetLen + i, 0); - inferFromSignature(getBaseSignature(sourceSignatures[sourceIndex]), getErasedSignature(targetSignatures[i])); + inferFromSignature( + getBaseSignature(sourceSignatures[sourceIndex]), + getErasedSignature(targetSignatures[i]) + ); } } } @@ -27343,10 +48675,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function inferFromSignature(source: Signature, target: Signature) { if (!(source.flags & SignatureFlags.IsNonInferrable)) { const saveBivariant = bivariant; - const kind = target.declaration ? target.declaration.kind : SyntaxKind.Unknown; + const kind = target.declaration + ? target.declaration.kind + : SyntaxKind.Unknown; // Once we descend into a bivariant signature we remain bivariant for all nested inferences - bivariant = bivariant || kind === SyntaxKind.MethodDeclaration || kind === SyntaxKind.MethodSignature || kind === SyntaxKind.Constructor; - applyToParameterTypes(source, target, inferFromContravariantTypesIfStrictFunctionTypes); + bivariant = + bivariant || + kind === SyntaxKind.MethodDeclaration || + kind === SyntaxKind.MethodSignature || + kind === SyntaxKind.Constructor; + applyToParameterTypes( + source, + target, + inferFromContravariantTypesIfStrictFunctionTypes + ); bivariant = saveBivariant; } applyToReturnTypes(source, target, inferFromTypes); @@ -27354,49 +48696,109 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function inferFromIndexTypes(source: Type, target: Type) { // Inferences across mapped type index signatures are pretty much the same a inferences to homomorphic variables - const priority = (getObjectFlags(source) & getObjectFlags(target) & ObjectFlags.Mapped) ? InferencePriority.HomomorphicMappedType : 0; + const priority = + getObjectFlags(source) & + getObjectFlags(target) & + ObjectFlags.Mapped + ? InferencePriority.HomomorphicMappedType + : 0; const indexInfos = getIndexInfosOfType(target); if (isObjectTypeWithInferableIndex(source)) { for (const targetInfo of indexInfos) { const propTypes: Type[] = []; for (const prop of getPropertiesOfType(source)) { - if (isApplicableIndexType(getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique), targetInfo.keyType)) { + if ( + isApplicableIndexType( + getLiteralTypeFromProperty( + prop, + TypeFlags.StringOrNumberLiteralOrUnique + ), + targetInfo.keyType + ) + ) { const propType = getTypeOfSymbol(prop); - propTypes.push(prop.flags & SymbolFlags.Optional ? removeMissingOrUndefinedType(propType) : propType); + propTypes.push( + prop.flags & SymbolFlags.Optional + ? removeMissingOrUndefinedType(propType) + : propType + ); } } for (const info of getIndexInfosOfType(source)) { - if (isApplicableIndexType(info.keyType, targetInfo.keyType)) { + if ( + isApplicableIndexType( + info.keyType, + targetInfo.keyType + ) + ) { propTypes.push(info.type); } } if (propTypes.length) { - inferWithPriority(getUnionType(propTypes), targetInfo.type, priority); + inferWithPriority( + getUnionType(propTypes), + targetInfo.type, + priority + ); } } } for (const targetInfo of indexInfos) { - const sourceInfo = getApplicableIndexInfo(source, targetInfo.keyType); + const sourceInfo = getApplicableIndexInfo( + source, + targetInfo.keyType + ); if (sourceInfo) { - inferWithPriority(sourceInfo.type, targetInfo.type, priority); + inferWithPriority( + sourceInfo.type, + targetInfo.type, + priority + ); } } } } function isTypeOrBaseIdenticalTo(s: Type, t: Type) { - return t === missingType ? s === t : - (isTypeIdenticalTo(s, t) || !!(t.flags & TypeFlags.String && s.flags & TypeFlags.StringLiteral || t.flags & TypeFlags.Number && s.flags & TypeFlags.NumberLiteral)); + return t === missingType + ? s === t + : isTypeIdenticalTo(s, t) || + !!( + (t.flags & TypeFlags.String && + s.flags & TypeFlags.StringLiteral) || + (t.flags & TypeFlags.Number && + s.flags & TypeFlags.NumberLiteral) + ); } function isTypeCloselyMatchedBy(s: Type, t: Type) { - return !!(s.flags & TypeFlags.Object && t.flags & TypeFlags.Object && s.symbol && s.symbol === t.symbol || - s.aliasSymbol && s.aliasTypeArguments && s.aliasSymbol === t.aliasSymbol); + return !!( + (s.flags & TypeFlags.Object && + t.flags & TypeFlags.Object && + s.symbol && + s.symbol === t.symbol) || + (s.aliasSymbol && + s.aliasTypeArguments && + s.aliasSymbol === t.aliasSymbol) + ); } function hasPrimitiveConstraint(type: TypeParameter): boolean { const constraint = getConstraintOfTypeParameter(type); - return !!constraint && maybeTypeOfKind(constraint.flags & TypeFlags.Conditional ? getDefaultConstraintOfConditionalType(constraint as ConditionalType) : constraint, TypeFlags.Primitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping); + return ( + !!constraint && + maybeTypeOfKind( + constraint.flags & TypeFlags.Conditional + ? getDefaultConstraintOfConditionalType( + constraint as ConditionalType + ) + : constraint, + TypeFlags.Primitive | + TypeFlags.Index | + TypeFlags.TemplateLiteral | + TypeFlags.StringMapping + ) + ); } function isObjectLiteralType(type: Type) { @@ -27404,42 +48806,73 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isObjectOrArrayLiteralType(type: Type) { - return !!(getObjectFlags(type) & (ObjectFlags.ObjectLiteral | ObjectFlags.ArrayLiteral)); + return !!( + getObjectFlags(type) & + (ObjectFlags.ObjectLiteral | ObjectFlags.ArrayLiteral) + ); } function unionObjectAndArrayLiteralCandidates(candidates: Type[]): Type[] { if (candidates.length > 1) { - const objectLiterals = filter(candidates, isObjectOrArrayLiteralType); + const objectLiterals = filter( + candidates, + isObjectOrArrayLiteralType + ); if (objectLiterals.length) { - const literalsType = getUnionType(objectLiterals, UnionReduction.Subtype); - return concatenate(filter(candidates, t => !isObjectOrArrayLiteralType(t)), [literalsType]); + const literalsType = getUnionType( + objectLiterals, + UnionReduction.Subtype + ); + return concatenate( + filter(candidates, (t) => !isObjectOrArrayLiteralType(t)), + [literalsType] + ); } } return candidates; } function getContravariantInference(inference: InferenceInfo) { - return inference.priority! & InferencePriority.PriorityImpliesCombination ? getIntersectionType(inference.contraCandidates!) : getCommonSubtype(inference.contraCandidates!); + return inference.priority! & + InferencePriority.PriorityImpliesCombination + ? getIntersectionType(inference.contraCandidates!) + : getCommonSubtype(inference.contraCandidates!); } - function getCovariantInference(inference: InferenceInfo, signature: Signature) { + function getCovariantInference( + inference: InferenceInfo, + signature: Signature + ) { // Extract all object and array literal types and replace them with a single widened and normalized type. - const candidates = unionObjectAndArrayLiteralCandidates(inference.candidates!); + const candidates = unionObjectAndArrayLiteralCandidates( + inference.candidates! + ); // We widen inferred literal types if // all inferences were made to top-level occurrences of the type parameter, and // the type parameter has no constraint or its constraint includes no primitive or literal types, and // the type parameter was fixed during inference or does not occur at top-level in the return type. - const primitiveConstraint = hasPrimitiveConstraint(inference.typeParameter) || isConstTypeVariable(inference.typeParameter); - const widenLiteralTypes = !primitiveConstraint && inference.topLevel && - (inference.isFixed || !isTypeParameterAtTopLevelInReturnType(signature, inference.typeParameter)); - const baseCandidates = primitiveConstraint ? sameMap(candidates, getRegularTypeOfLiteralType) : - widenLiteralTypes ? sameMap(candidates, getWidenedLiteralType) : - candidates; + const primitiveConstraint = + hasPrimitiveConstraint(inference.typeParameter) || + isConstTypeVariable(inference.typeParameter); + const widenLiteralTypes = + !primitiveConstraint && + inference.topLevel && + (inference.isFixed || + !isTypeParameterAtTopLevelInReturnType( + signature, + inference.typeParameter + )); + const baseCandidates = primitiveConstraint + ? sameMap(candidates, getRegularTypeOfLiteralType) + : widenLiteralTypes + ? sameMap(candidates, getWidenedLiteralType) + : candidates; // If all inferences were made from a position that implies a combined result, infer a union type. // Otherwise, infer a common supertype. - const unwidenedType = inference.priority! & InferencePriority.PriorityImpliesCombination ? - getUnionType(baseCandidates, UnionReduction.Subtype) : - getCommonSupertype(baseCandidates); + const unwidenedType = + inference.priority! & InferencePriority.PriorityImpliesCombination + ? getUnionType(baseCandidates, UnionReduction.Subtype) + : getCommonSupertype(baseCandidates); return getWidenedType(unwidenedType); } @@ -27449,8 +48882,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let inferredType: Type | undefined; let fallbackType: Type | undefined; if (context.signature) { - const inferredCovariantType = inference.candidates ? getCovariantInference(inference, context.signature) : undefined; - const inferredContravariantType = inference.contraCandidates ? getContravariantInference(inference) : undefined; + const inferredCovariantType = inference.candidates + ? getCovariantInference(inference, context.signature) + : undefined; + const inferredContravariantType = inference.contraCandidates + ? getContravariantInference(inference) + : undefined; if (inferredCovariantType || inferredContravariantType) { // If we have both co- and contra-variant inferences, we prefer the co-variant inference if it is not 'never', // all co-variant inferences are assignable to it (i.e. it isn't one of a conflicting set of candidates), it is @@ -27458,45 +48895,100 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // and has inferences that would conflict. Otherwise, we prefer the contra-variant inference. // Similarly ignore co-variant `any` inference when both are available as almost everything is assignable to it // and it would spoil the overall inference. - const preferCovariantType = inferredCovariantType && (!inferredContravariantType || - !(inferredCovariantType.flags & (TypeFlags.Never | TypeFlags.Any)) && - some(inference.contraCandidates, t => isTypeAssignableTo(inferredCovariantType, t)) && - every(context.inferences, other => - other !== inference && getConstraintOfTypeParameter(other.typeParameter) !== inference.typeParameter || - every(other.candidates, t => isTypeAssignableTo(t, inferredCovariantType)))); - inferredType = preferCovariantType ? inferredCovariantType : inferredContravariantType; - fallbackType = preferCovariantType ? inferredContravariantType : inferredCovariantType; - } - else if (context.flags & InferenceFlags.NoDefault) { + const preferCovariantType = + inferredCovariantType && + (!inferredContravariantType || + (!( + inferredCovariantType.flags & + (TypeFlags.Never | TypeFlags.Any) + ) && + some(inference.contraCandidates, (t) => + isTypeAssignableTo(inferredCovariantType, t) + ) && + every( + context.inferences, + (other) => + (other !== inference && + getConstraintOfTypeParameter( + other.typeParameter + ) !== inference.typeParameter) || + every(other.candidates, (t) => + isTypeAssignableTo( + t, + inferredCovariantType + ) + ) + ))); + inferredType = preferCovariantType + ? inferredCovariantType + : inferredContravariantType; + fallbackType = preferCovariantType + ? inferredContravariantType + : inferredCovariantType; + } else if (context.flags & InferenceFlags.NoDefault) { // We use silentNeverType as the wildcard that signals no inferences. inferredType = silentNeverType; - } - else { + } else { // Infer either the default or the empty object type when no inferences were // made. It is important to remember that in this case, inference still // succeeds, meaning there is no error for not having inference candidates. An // inference error only occurs when there are *conflicting* candidates, i.e. // candidates with no common supertype. - const defaultType = getDefaultFromTypeParameter(inference.typeParameter); + const defaultType = getDefaultFromTypeParameter( + inference.typeParameter + ); if (defaultType) { // Instantiate the default type. Any forward reference to a type // parameter should be instantiated to the empty object type. - inferredType = instantiateType(defaultType, mergeTypeMappers(createBackreferenceMapper(context, index), context.nonFixingMapper)); + inferredType = instantiateType( + defaultType, + mergeTypeMappers( + createBackreferenceMapper(context, index), + context.nonFixingMapper + ) + ); } } - } - else { + } else { inferredType = getTypeFromInference(inference); } - inference.inferredType = inferredType || getDefaultTypeArgumentType(!!(context.flags & InferenceFlags.AnyDefault)); + inference.inferredType = + inferredType || + getDefaultTypeArgumentType( + !!(context.flags & InferenceFlags.AnyDefault) + ); - const constraint = getConstraintOfTypeParameter(inference.typeParameter); + const constraint = getConstraintOfTypeParameter( + inference.typeParameter + ); if (constraint) { - const instantiatedConstraint = instantiateType(constraint, context.nonFixingMapper); - if (!inferredType || !context.compareTypes(inferredType, getTypeWithThisArgument(instantiatedConstraint, inferredType))) { + const instantiatedConstraint = instantiateType( + constraint, + context.nonFixingMapper + ); + if ( + !inferredType || + !context.compareTypes( + inferredType, + getTypeWithThisArgument( + instantiatedConstraint, + inferredType + ) + ) + ) { // If the fallback type satisfies the constraint, we pick it. Otherwise, we pick the constraint. - inference.inferredType = fallbackType && context.compareTypes(fallbackType, getTypeWithThisArgument(instantiatedConstraint, fallbackType)) ? fallbackType : instantiatedConstraint; + inference.inferredType = + fallbackType && + context.compareTypes( + fallbackType, + getTypeWithThisArgument( + instantiatedConstraint, + fallbackType + ) + ) + ? fallbackType + : instantiatedConstraint; } } clearActiveMapperCaches(); @@ -27519,7 +49011,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // EXPRESSION TYPE CHECKING - function getCannotFindNameDiagnosticForName(node: Identifier): DiagnosticMessage { + function getCannotFindNameDiagnosticForName( + node: Identifier + ): DiagnosticMessage { switch (node.escapedText) { case "document": case "console": @@ -27569,12 +49063,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isCallExpression(node.parent)) { return Diagnostics.Cannot_find_name_0_Did_you_mean_to_write_this_in_an_async_function; } - // falls through + // falls through default: - if (node.parent.kind === SyntaxKind.ShorthandPropertyAssignment) { + if ( + node.parent.kind === SyntaxKind.ShorthandPropertyAssignment + ) { return Diagnostics.No_value_exists_in_scope_for_the_shorthand_property_0_Either_declare_one_or_provide_an_initializer; - } - else { + } else { return Diagnostics.Cannot_find_name_0; } } @@ -27583,54 +49078,111 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getResolvedSymbol(node: Identifier): Symbol { const links = getNodeLinks(node); if (!links.resolvedSymbol) { - links.resolvedSymbol = !nodeIsMissing(node) && + links.resolvedSymbol = + (!nodeIsMissing(node) && resolveName( node, node, SymbolFlags.Value | SymbolFlags.ExportValue, getCannotFindNameDiagnosticForName(node), !isWriteOnlyAccess(node), - /*excludeGlobals*/ false, - ) || unknownSymbol; + /*excludeGlobals*/ false + )) || + unknownSymbol; } return links.resolvedSymbol; } function isInAmbientOrTypeNode(node: Node): boolean { - return !!(node.flags & NodeFlags.Ambient || findAncestor(node, n => isInterfaceDeclaration(n) || isTypeAliasDeclaration(n) || isTypeLiteralNode(n))); + return !!( + node.flags & NodeFlags.Ambient || + findAncestor( + node, + (n) => + isInterfaceDeclaration(n) || + isTypeAliasDeclaration(n) || + isTypeLiteralNode(n) + ) + ); } // Return the flow cache key for a "dotted name" (i.e. a sequence of identifiers // separated by dots). The key consists of the id of the symbol referenced by the // leftmost identifier followed by zero or more property names separated by dots. // The result is undefined if the reference isn't a dotted name. - function getFlowCacheKey(node: Node, declaredType: Type, initialType: Type, flowContainer: Node | undefined): string | undefined { + function getFlowCacheKey( + node: Node, + declaredType: Type, + initialType: Type, + flowContainer: Node | undefined + ): string | undefined { switch (node.kind) { case SyntaxKind.Identifier: if (!isThisInTypeQuery(node)) { const symbol = getResolvedSymbol(node as Identifier); - return symbol !== unknownSymbol ? `${flowContainer ? getNodeId(flowContainer) : "-1"}|${getTypeId(declaredType)}|${getTypeId(initialType)}|${getSymbolId(symbol)}` : undefined; + return symbol !== unknownSymbol + ? `${ + flowContainer ? getNodeId(flowContainer) : "-1" + }|${getTypeId(declaredType)}|${getTypeId( + initialType + )}|${getSymbolId(symbol)}` + : undefined; } - // falls through + // falls through case SyntaxKind.ThisKeyword: - return `0|${flowContainer ? getNodeId(flowContainer) : "-1"}|${getTypeId(declaredType)}|${getTypeId(initialType)}`; + return `0|${ + flowContainer ? getNodeId(flowContainer) : "-1" + }|${getTypeId(declaredType)}|${getTypeId(initialType)}`; case SyntaxKind.NonNullExpression: case SyntaxKind.ParenthesizedExpression: - return getFlowCacheKey((node as NonNullExpression | ParenthesizedExpression).expression, declaredType, initialType, flowContainer); + return getFlowCacheKey( + (node as NonNullExpression | ParenthesizedExpression) + .expression, + declaredType, + initialType, + flowContainer + ); case SyntaxKind.QualifiedName: - const left = getFlowCacheKey((node as QualifiedName).left, declaredType, initialType, flowContainer); - return left && `${left}.${(node as QualifiedName).right.escapedText}`; + const left = getFlowCacheKey( + (node as QualifiedName).left, + declaredType, + initialType, + flowContainer + ); + return ( + left && + `${left}.${(node as QualifiedName).right.escapedText}` + ); case SyntaxKind.PropertyAccessExpression: case SyntaxKind.ElementAccessExpression: - const propName = getAccessedPropertyName(node as AccessExpression); + const propName = getAccessedPropertyName( + node as AccessExpression + ); if (propName !== undefined) { - const key = getFlowCacheKey((node as AccessExpression).expression, declaredType, initialType, flowContainer); + const key = getFlowCacheKey( + (node as AccessExpression).expression, + declaredType, + initialType, + flowContainer + ); return key && `${key}.${propName}`; } - if (isElementAccessExpression(node) && isIdentifier(node.argumentExpression)) { + if ( + isElementAccessExpression(node) && + isIdentifier(node.argumentExpression) + ) { const symbol = getResolvedSymbol(node.argumentExpression); - if (isConstantVariable(symbol) || isParameterOrMutableLocalVariable(symbol) && !isSymbolAssigned(symbol)) { - const key = getFlowCacheKey((node as AccessExpression).expression, declaredType, initialType, flowContainer); + if ( + isConstantVariable(symbol) || + (isParameterOrMutableLocalVariable(symbol) && + !isSymbolAssigned(symbol)) + ) { + const key = getFlowCacheKey( + (node as AccessExpression).expression, + declaredType, + initialType, + flowContainer + ); return key && `${key}.@${getSymbolId(symbol)}`; } } @@ -27651,23 +49203,41 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { switch (target.kind) { case SyntaxKind.ParenthesizedExpression: case SyntaxKind.NonNullExpression: - return isMatchingReference(source, (target as NonNullExpression | ParenthesizedExpression).expression); + return isMatchingReference( + source, + (target as NonNullExpression | ParenthesizedExpression) + .expression + ); case SyntaxKind.BinaryExpression: - return (isAssignmentExpression(target) && isMatchingReference(source, target.left)) || - (isBinaryExpression(target) && target.operatorToken.kind === SyntaxKind.CommaToken && isMatchingReference(source, target.right)); + return ( + (isAssignmentExpression(target) && + isMatchingReference(source, target.left)) || + (isBinaryExpression(target) && + target.operatorToken.kind === SyntaxKind.CommaToken && + isMatchingReference(source, target.right)) + ); } switch (source.kind) { case SyntaxKind.MetaProperty: - return target.kind === SyntaxKind.MetaProperty - && (source as MetaProperty).keywordToken === (target as MetaProperty).keywordToken - && (source as MetaProperty).name.escapedText === (target as MetaProperty).name.escapedText; + return ( + target.kind === SyntaxKind.MetaProperty && + (source as MetaProperty).keywordToken === + (target as MetaProperty).keywordToken && + (source as MetaProperty).name.escapedText === + (target as MetaProperty).name.escapedText + ); case SyntaxKind.Identifier: case SyntaxKind.PrivateIdentifier: - return isThisInTypeQuery(source) ? - target.kind === SyntaxKind.ThisKeyword : - target.kind === SyntaxKind.Identifier && getResolvedSymbol(source as Identifier) === getResolvedSymbol(target as Identifier) || - (isVariableDeclaration(target) || isBindingElement(target)) && - getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(source as Identifier)) === getSymbolOfDeclaration(target); + return isThisInTypeQuery(source) + ? target.kind === SyntaxKind.ThisKeyword + : (target.kind === SyntaxKind.Identifier && + getResolvedSymbol(source as Identifier) === + getResolvedSymbol(target as Identifier)) || + ((isVariableDeclaration(target) || + isBindingElement(target)) && + getExportSymbolOfValueSymbolIfExported( + getResolvedSymbol(source as Identifier) + ) === getSymbolOfDeclaration(target)); case SyntaxKind.ThisKeyword: return target.kind === SyntaxKind.ThisKeyword; case SyntaxKind.SuperKeyword: @@ -27675,34 +49245,78 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.NonNullExpression: case SyntaxKind.ParenthesizedExpression: case SyntaxKind.SatisfiesExpression: - return isMatchingReference((source as NonNullExpression | ParenthesizedExpression | SatisfiesExpression).expression, target); + return isMatchingReference( + ( + source as + | NonNullExpression + | ParenthesizedExpression + | SatisfiesExpression + ).expression, + target + ); case SyntaxKind.PropertyAccessExpression: case SyntaxKind.ElementAccessExpression: - const sourcePropertyName = getAccessedPropertyName(source as AccessExpression); + const sourcePropertyName = getAccessedPropertyName( + source as AccessExpression + ); if (sourcePropertyName !== undefined) { - const targetPropertyName = isAccessExpression(target) ? getAccessedPropertyName(target) : undefined; + const targetPropertyName = isAccessExpression(target) + ? getAccessedPropertyName(target) + : undefined; if (targetPropertyName !== undefined) { - return targetPropertyName === sourcePropertyName && isMatchingReference((source as AccessExpression).expression, (target as AccessExpression).expression); + return ( + targetPropertyName === sourcePropertyName && + isMatchingReference( + (source as AccessExpression).expression, + (target as AccessExpression).expression + ) + ); } } - if (isElementAccessExpression(source) && isElementAccessExpression(target) && isIdentifier(source.argumentExpression) && isIdentifier(target.argumentExpression)) { + if ( + isElementAccessExpression(source) && + isElementAccessExpression(target) && + isIdentifier(source.argumentExpression) && + isIdentifier(target.argumentExpression) + ) { const symbol = getResolvedSymbol(source.argumentExpression); - if (symbol === getResolvedSymbol(target.argumentExpression) && (isConstantVariable(symbol) || isParameterOrMutableLocalVariable(symbol) && !isSymbolAssigned(symbol))) { - return isMatchingReference(source.expression, target.expression); + if ( + symbol === + getResolvedSymbol(target.argumentExpression) && + (isConstantVariable(symbol) || + (isParameterOrMutableLocalVariable(symbol) && + !isSymbolAssigned(symbol))) + ) { + return isMatchingReference( + source.expression, + target.expression + ); } } break; case SyntaxKind.QualifiedName: - return isAccessExpression(target) && - (source as QualifiedName).right.escapedText === getAccessedPropertyName(target) && - isMatchingReference((source as QualifiedName).left, target.expression); + return ( + isAccessExpression(target) && + (source as QualifiedName).right.escapedText === + getAccessedPropertyName(target) && + isMatchingReference( + (source as QualifiedName).left, + target.expression + ) + ); case SyntaxKind.BinaryExpression: - return (isBinaryExpression(source) && source.operatorToken.kind === SyntaxKind.CommaToken && isMatchingReference(source.right, target)); + return ( + isBinaryExpression(source) && + source.operatorToken.kind === SyntaxKind.CommaToken && + isMatchingReference(source.right, target) + ); } return false; } - function getAccessedPropertyName(access: AccessExpression | BindingElement | ParameterDeclaration): __String | undefined { + function getAccessedPropertyName( + access: AccessExpression | BindingElement | ParameterDeclaration + ): __String | undefined { if (isPropertyAccessExpression(access)) { return access.name.escapedText; } @@ -27720,18 +49334,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function tryGetNameFromType(type: Type) { - return type.flags & TypeFlags.UniqueESSymbol ? (type as UniqueESSymbolType).escapedName : - type.flags & TypeFlags.StringOrNumberLiteral ? escapeLeadingUnderscores("" + (type as StringLiteralType | NumberLiteralType).value) : undefined; + return type.flags & TypeFlags.UniqueESSymbol + ? (type as UniqueESSymbolType).escapedName + : type.flags & TypeFlags.StringOrNumberLiteral + ? escapeLeadingUnderscores( + "" + (type as StringLiteralType | NumberLiteralType).value + ) + : undefined; } function tryGetElementAccessExpressionName(node: ElementAccessExpression) { - return isStringOrNumericLiteralLike(node.argumentExpression) ? escapeLeadingUnderscores(node.argumentExpression.text) : - isEntityNameExpression(node.argumentExpression) ? tryGetNameFromEntityNameExpression(node.argumentExpression) : undefined; + return isStringOrNumericLiteralLike(node.argumentExpression) + ? escapeLeadingUnderscores(node.argumentExpression.text) + : isEntityNameExpression(node.argumentExpression) + ? tryGetNameFromEntityNameExpression(node.argumentExpression) + : undefined; } - function tryGetNameFromEntityNameExpression(node: EntityNameOrEntityNameExpression) { - const symbol = resolveEntityName(node, SymbolFlags.Value, /*ignoreErrors*/ true); - if (!symbol || !(isConstantVariable(symbol) || (symbol.flags & SymbolFlags.EnumMember))) return undefined; + function tryGetNameFromEntityNameExpression( + node: EntityNameOrEntityNameExpression + ) { + const symbol = resolveEntityName( + node, + SymbolFlags.Value, + /*ignoreErrors*/ true + ); + if ( + !symbol || + !( + isConstantVariable(symbol) || + symbol.flags & SymbolFlags.EnumMember + ) + ) + return undefined; const declaration = symbol.valueDeclaration; if (declaration === undefined) return undefined; @@ -27743,10 +49378,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return name; } } - if (hasOnlyExpressionInitializer(declaration) && isBlockScopedNameDeclaredBeforeUse(declaration, node)) { + if ( + hasOnlyExpressionInitializer(declaration) && + isBlockScopedNameDeclaredBeforeUse(declaration, node) + ) { const initializer = getEffectiveInitializer(declaration); if (initializer) { - const initializerType = isBindingPattern(declaration.parent) ? getTypeForBindingElement(declaration as BindingElement) : getTypeOfExpression(initializer); + const initializerType = isBindingPattern(declaration.parent) + ? getTypeForBindingElement(declaration as BindingElement) + : getTypeOfExpression(initializer); return initializerType && tryGetNameFromType(initializerType); } if (isEnumMember(declaration)) { @@ -27778,11 +49418,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isDiscriminantProperty(type: Type | undefined, name: __String) { if (type && type.flags & TypeFlags.Union) { - const prop = getUnionOrIntersectionProperty(type as UnionType, name); + const prop = getUnionOrIntersectionProperty( + type as UnionType, + name + ); if (prop && getCheckFlags(prop) & CheckFlags.SyntheticProperty) { // NOTE: cast to TransientSymbol should be safe because only TransientSymbols can have CheckFlags.SyntheticProperty - if ((prop as TransientSymbol).links.isDiscriminantProperty === undefined) { - (prop as TransientSymbol).links.isDiscriminantProperty = ((prop as TransientSymbol).links.checkFlags & CheckFlags.Discriminant) === CheckFlags.Discriminant && + if ( + (prop as TransientSymbol).links.isDiscriminantProperty === + undefined + ) { + (prop as TransientSymbol).links.isDiscriminantProperty = + ((prop as TransientSymbol).links.checkFlags & + CheckFlags.Discriminant) === + CheckFlags.Discriminant && !isGenericType(getTypeOfSymbol(prop)); } return !!(prop as TransientSymbol).links.isDiscriminantProperty; @@ -27791,7 +49440,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function findDiscriminantProperties(sourceProperties: Symbol[], target: Type): Symbol[] | undefined { + function findDiscriminantProperties( + sourceProperties: Symbol[], + target: Type + ): Symbol[] | undefined { let result: Symbol[] | undefined; for (const sourceProperty of sourceProperties) { if (isDiscriminantProperty(target, sourceProperty.escapedName)) { @@ -27813,20 +49465,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const map = new Map(); let count = 0; for (const type of types) { - if (type.flags & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.InstantiableNonPrimitive)) { + if ( + type.flags & + (TypeFlags.Object | + TypeFlags.Intersection | + TypeFlags.InstantiableNonPrimitive) + ) { const discriminant = getTypeOfPropertyOfType(type, name); if (discriminant) { if (!isLiteralType(discriminant)) { return undefined; } let duplicate = false; - forEachType(discriminant, t => { + forEachType(discriminant, (t) => { const id = getTypeId(getRegularTypeOfLiteralType(t)); const existing = map.get(id); if (!existing) { map.set(id, type); - } - else if (existing !== unknownType) { + } else if (existing !== unknownType) { map.set(id, unknownType); duplicate = true; } @@ -27844,62 +49500,115 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const types = unionType.types; // We only construct maps for unions with many non-primitive constituents. if ( - types.length < 10 || getObjectFlags(unionType) & ObjectFlags.PrimitiveUnion || - countWhere(types, t => !!(t.flags & (TypeFlags.Object | TypeFlags.InstantiableNonPrimitive))) < 10 + types.length < 10 || + getObjectFlags(unionType) & ObjectFlags.PrimitiveUnion || + countWhere( + types, + (t) => + !!( + t.flags & + (TypeFlags.Object | TypeFlags.InstantiableNonPrimitive) + ) + ) < 10 ) { return undefined; } if (unionType.keyPropertyName === undefined) { // The candidate key property name is the name of the first property with a unit type in one of the // constituent types. - const keyPropertyName = forEach(types, t => - t.flags & (TypeFlags.Object | TypeFlags.InstantiableNonPrimitive) ? - forEach(getPropertiesOfType(t), p => isUnitType(getTypeOfSymbol(p)) ? p.escapedName : undefined) : - undefined); - const mapByKeyProperty = keyPropertyName && mapTypesByKeyProperty(types, keyPropertyName); - unionType.keyPropertyName = mapByKeyProperty ? keyPropertyName : "" as __String; + const keyPropertyName = forEach(types, (t) => + t.flags & + (TypeFlags.Object | TypeFlags.InstantiableNonPrimitive) + ? forEach(getPropertiesOfType(t), (p) => + isUnitType(getTypeOfSymbol(p)) + ? p.escapedName + : undefined + ) + : undefined + ); + const mapByKeyProperty = + keyPropertyName && + mapTypesByKeyProperty(types, keyPropertyName); + unionType.keyPropertyName = mapByKeyProperty + ? keyPropertyName + : ("" as __String); unionType.constituentMap = mapByKeyProperty; } - return (unionType.keyPropertyName as string).length ? unionType.keyPropertyName : undefined; + return (unionType.keyPropertyName as string).length + ? unionType.keyPropertyName + : undefined; } // Given a union type for which getKeyPropertyName returned a non-undefined result, return the constituent // that corresponds to the given key type for that property name. function getConstituentTypeForKeyType(unionType: UnionType, keyType: Type) { - const result = unionType.constituentMap?.get(getTypeId(getRegularTypeOfLiteralType(keyType))); + const result = unionType.constituentMap?.get( + getTypeId(getRegularTypeOfLiteralType(keyType)) + ); return result !== unknownType ? result : undefined; } - function getMatchingUnionConstituentForType(unionType: UnionType, type: Type) { + function getMatchingUnionConstituentForType( + unionType: UnionType, + type: Type + ) { const keyPropertyName = getKeyPropertyName(unionType); - const propType = keyPropertyName && getTypeOfPropertyOfType(type, keyPropertyName); + const propType = + keyPropertyName && getTypeOfPropertyOfType(type, keyPropertyName); return propType && getConstituentTypeForKeyType(unionType, propType); } - function getMatchingUnionConstituentForObjectLiteral(unionType: UnionType, node: ObjectLiteralExpression) { + function getMatchingUnionConstituentForObjectLiteral( + unionType: UnionType, + node: ObjectLiteralExpression + ) { const keyPropertyName = getKeyPropertyName(unionType); - const propNode = keyPropertyName && find(node.properties, p => - p.symbol && p.kind === SyntaxKind.PropertyAssignment && - p.symbol.escapedName === keyPropertyName && isPossiblyDiscriminantValue(p.initializer)); - const propType = propNode && getContextFreeTypeOfExpression((propNode as PropertyAssignment).initializer); + const propNode = + keyPropertyName && + find( + node.properties, + (p) => + p.symbol && + p.kind === SyntaxKind.PropertyAssignment && + p.symbol.escapedName === keyPropertyName && + isPossiblyDiscriminantValue(p.initializer) + ); + const propType = + propNode && + getContextFreeTypeOfExpression( + (propNode as PropertyAssignment).initializer + ); return propType && getConstituentTypeForKeyType(unionType, propType); } function isOrContainsMatchingReference(source: Node, target: Node) { - return isMatchingReference(source, target) || containsMatchingReference(source, target); + return ( + isMatchingReference(source, target) || + containsMatchingReference(source, target) + ); } - function hasMatchingArgument(expression: CallExpression | NewExpression, reference: Node) { + function hasMatchingArgument( + expression: CallExpression | NewExpression, + reference: Node + ) { if (expression.arguments) { for (const argument of expression.arguments) { - if (isOrContainsMatchingReference(reference, argument) || optionalChainContainsReference(argument, reference)) { + if ( + isOrContainsMatchingReference(reference, argument) || + optionalChainContainsReference(argument, reference) + ) { return true; } } } if ( - expression.expression.kind === SyntaxKind.PropertyAccessExpression && - isOrContainsMatchingReference(reference, (expression.expression as PropertyAccessExpression).expression) + expression.expression.kind === + SyntaxKind.PropertyAccessExpression && + isOrContainsMatchingReference( + reference, + (expression.expression as PropertyAccessExpression).expression + ) ) { return true; } @@ -27929,7 +49638,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Remove those constituent types of declaredType to which no constituent type of assignedType is assignable. // For example, when a variable of type number | string | boolean is assigned a value of type number | boolean, // we remove type string. - function getAssignmentReducedType(declaredType: UnionType, assignedType: Type) { + function getAssignmentReducedType( + declaredType: UnionType, + assignedType: Type + ) { if (declaredType === assignedType) { return declaredType; } @@ -27937,18 +49649,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return assignedType; } const key = `A${getTypeId(declaredType)},${getTypeId(assignedType)}`; - return getCachedType(key) ?? setCachedType(key, getAssignmentReducedTypeWorker(declaredType, assignedType)); + return ( + getCachedType(key) ?? + setCachedType( + key, + getAssignmentReducedTypeWorker(declaredType, assignedType) + ) + ); } - function getAssignmentReducedTypeWorker(declaredType: UnionType, assignedType: Type) { - const filteredType = filterType(declaredType, t => typeMaybeAssignableTo(assignedType, t)); + function getAssignmentReducedTypeWorker( + declaredType: UnionType, + assignedType: Type + ) { + const filteredType = filterType(declaredType, (t) => + typeMaybeAssignableTo(assignedType, t) + ); // Ensure that we narrow to fresh types if the assignment is a fresh boolean literal type. - const reducedType = assignedType.flags & TypeFlags.BooleanLiteral && isFreshLiteralType(assignedType) ? mapType(filteredType, getFreshTypeOfLiteralType) : filteredType; + const reducedType = + assignedType.flags & TypeFlags.BooleanLiteral && + isFreshLiteralType(assignedType) + ? mapType(filteredType, getFreshTypeOfLiteralType) + : filteredType; // Our crude heuristic produces an invalid result in some cases: see GH#26130. // For now, when that happens, we give up and don't narrow at all. (This also // means we'll never narrow for erroneous assignments where the assigned type // is not assignable to the declared type.) - return isTypeAssignableTo(assignedType, reducedType) ? reducedType : declaredType; + return isTypeAssignableTo(assignedType, reducedType) + ? reducedType + : declaredType; } function isFunctionObjectType(type: ObjectType): boolean { @@ -27958,8 +49687,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We do a quick check for a "bind" property before performing the more expensive subtype // check. This gives us a quicker out in the common case where an object type is not a function. const resolved = resolveStructuredTypeMembers(type); - return !!(resolved.callSignatures.length || resolved.constructSignatures.length || - resolved.members.get("bind" as __String) && isTypeSubtypeOf(type, globalFunctionType)); + return !!( + resolved.callSignatures.length || + resolved.constructSignatures.length || + (resolved.members.get("bind" as __String) && + isTypeSubtypeOf(type, globalFunctionType)) + ); } function getTypeFacts(type: Type, mask: TypeFacts): TypeFacts { @@ -27970,50 +49703,83 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getTypeFacts(type, mask) !== 0; } - function getTypeFactsWorker(type: Type, callerOnlyNeeds: TypeFacts): TypeFacts { + function getTypeFactsWorker( + type: Type, + callerOnlyNeeds: TypeFacts + ): TypeFacts { if (type.flags & (TypeFlags.Intersection | TypeFlags.Instantiable)) { type = getBaseConstraintOfType(type) || unknownType; } const flags = type.flags; if (flags & (TypeFlags.String | TypeFlags.StringMapping)) { - return strictNullChecks ? TypeFacts.StringStrictFacts : TypeFacts.StringFacts; + return strictNullChecks + ? TypeFacts.StringStrictFacts + : TypeFacts.StringFacts; } if (flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral)) { - const isEmpty = flags & TypeFlags.StringLiteral && (type as StringLiteralType).value === ""; - return strictNullChecks ? - isEmpty ? TypeFacts.EmptyStringStrictFacts : TypeFacts.NonEmptyStringStrictFacts : - isEmpty ? TypeFacts.EmptyStringFacts : TypeFacts.NonEmptyStringFacts; + const isEmpty = + flags & TypeFlags.StringLiteral && + (type as StringLiteralType).value === ""; + return strictNullChecks + ? isEmpty + ? TypeFacts.EmptyStringStrictFacts + : TypeFacts.NonEmptyStringStrictFacts + : isEmpty + ? TypeFacts.EmptyStringFacts + : TypeFacts.NonEmptyStringFacts; } if (flags & (TypeFlags.Number | TypeFlags.Enum)) { - return strictNullChecks ? TypeFacts.NumberStrictFacts : TypeFacts.NumberFacts; + return strictNullChecks + ? TypeFacts.NumberStrictFacts + : TypeFacts.NumberFacts; } if (flags & TypeFlags.NumberLiteral) { const isZero = (type as NumberLiteralType).value === 0; - return strictNullChecks ? - isZero ? TypeFacts.ZeroNumberStrictFacts : TypeFacts.NonZeroNumberStrictFacts : - isZero ? TypeFacts.ZeroNumberFacts : TypeFacts.NonZeroNumberFacts; + return strictNullChecks + ? isZero + ? TypeFacts.ZeroNumberStrictFacts + : TypeFacts.NonZeroNumberStrictFacts + : isZero + ? TypeFacts.ZeroNumberFacts + : TypeFacts.NonZeroNumberFacts; } if (flags & TypeFlags.BigInt) { - return strictNullChecks ? TypeFacts.BigIntStrictFacts : TypeFacts.BigIntFacts; + return strictNullChecks + ? TypeFacts.BigIntStrictFacts + : TypeFacts.BigIntFacts; } if (flags & TypeFlags.BigIntLiteral) { const isZero = isZeroBigInt(type as BigIntLiteralType); - return strictNullChecks ? - isZero ? TypeFacts.ZeroBigIntStrictFacts : TypeFacts.NonZeroBigIntStrictFacts : - isZero ? TypeFacts.ZeroBigIntFacts : TypeFacts.NonZeroBigIntFacts; + return strictNullChecks + ? isZero + ? TypeFacts.ZeroBigIntStrictFacts + : TypeFacts.NonZeroBigIntStrictFacts + : isZero + ? TypeFacts.ZeroBigIntFacts + : TypeFacts.NonZeroBigIntFacts; } if (flags & TypeFlags.Boolean) { - return strictNullChecks ? TypeFacts.BooleanStrictFacts : TypeFacts.BooleanFacts; + return strictNullChecks + ? TypeFacts.BooleanStrictFacts + : TypeFacts.BooleanFacts; } if (flags & TypeFlags.BooleanLike) { - return strictNullChecks ? - (type === falseType || type === regularFalseType) ? TypeFacts.FalseStrictFacts : TypeFacts.TrueStrictFacts : - (type === falseType || type === regularFalseType) ? TypeFacts.FalseFacts : TypeFacts.TrueFacts; + return strictNullChecks + ? type === falseType || type === regularFalseType + ? TypeFacts.FalseStrictFacts + : TypeFacts.TrueStrictFacts + : type === falseType || type === regularFalseType + ? TypeFacts.FalseFacts + : TypeFacts.TrueFacts; } if (flags & TypeFlags.Object) { const possibleFacts = strictNullChecks - ? TypeFacts.EmptyObjectStrictFacts | TypeFacts.FunctionStrictFacts | TypeFacts.ObjectStrictFacts - : TypeFacts.EmptyObjectFacts | TypeFacts.FunctionFacts | TypeFacts.ObjectFacts; + ? TypeFacts.EmptyObjectStrictFacts | + TypeFacts.FunctionStrictFacts | + TypeFacts.ObjectStrictFacts + : TypeFacts.EmptyObjectFacts | + TypeFacts.FunctionFacts | + TypeFacts.ObjectFacts; if ((callerOnlyNeeds & possibleFacts) === 0) { // If the caller doesn't care about any of the facts that we could possibly produce, @@ -28021,11 +49787,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return 0; } - return getObjectFlags(type) & ObjectFlags.Anonymous && isEmptyObjectType(type as ObjectType) ? - strictNullChecks ? TypeFacts.EmptyObjectStrictFacts : TypeFacts.EmptyObjectFacts : - isFunctionObjectType(type as ObjectType) ? - strictNullChecks ? TypeFacts.FunctionStrictFacts : TypeFacts.FunctionFacts : - strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts; + return getObjectFlags(type) & ObjectFlags.Anonymous && + isEmptyObjectType(type as ObjectType) + ? strictNullChecks + ? TypeFacts.EmptyObjectStrictFacts + : TypeFacts.EmptyObjectFacts + : isFunctionObjectType(type as ObjectType) + ? strictNullChecks + ? TypeFacts.FunctionStrictFacts + : TypeFacts.FunctionFacts + : strictNullChecks + ? TypeFacts.ObjectStrictFacts + : TypeFacts.ObjectFacts; } if (flags & TypeFlags.Void) { return TypeFacts.VoidFacts; @@ -28037,24 +49810,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return TypeFacts.NullFacts; } if (flags & TypeFlags.ESSymbolLike) { - return strictNullChecks ? TypeFacts.SymbolStrictFacts : TypeFacts.SymbolFacts; + return strictNullChecks + ? TypeFacts.SymbolStrictFacts + : TypeFacts.SymbolFacts; } if (flags & TypeFlags.NonPrimitive) { - return strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts; + return strictNullChecks + ? TypeFacts.ObjectStrictFacts + : TypeFacts.ObjectFacts; } if (flags & TypeFlags.Never) { return TypeFacts.None; } if (flags & TypeFlags.Union) { - return reduceLeft((type as UnionType).types, (facts, t) => facts | getTypeFactsWorker(t, callerOnlyNeeds), TypeFacts.None); + return reduceLeft( + (type as UnionType).types, + (facts, t) => facts | getTypeFactsWorker(t, callerOnlyNeeds), + TypeFacts.None + ); } if (flags & TypeFlags.Intersection) { - return getIntersectionTypeFacts(type as IntersectionType, callerOnlyNeeds); + return getIntersectionTypeFacts( + type as IntersectionType, + callerOnlyNeeds + ); } return TypeFacts.UnknownFacts; } - function getIntersectionTypeFacts(type: IntersectionType, callerOnlyNeeds: TypeFacts): TypeFacts { + function getIntersectionTypeFacts( + type: IntersectionType, + callerOnlyNeeds: TypeFacts + ): TypeFacts { // When an intersection contains a primitive type we ignore object type constituents as they are // presumably type tags. For example, in string & { __kind__: "name" } we ignore the object type. const ignoreObjects = maybeTypeOfKind(type, TypeFlags.Primitive); @@ -28069,34 +49856,72 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { andedFacts &= f; } } - return oredFacts & TypeFacts.OrFactsMask | andedFacts & TypeFacts.AndFactsMask; + return ( + (oredFacts & TypeFacts.OrFactsMask) | + (andedFacts & TypeFacts.AndFactsMask) + ); } function getTypeWithFacts(type: Type, include: TypeFacts) { - return filterType(type, t => hasTypeFacts(t, include)); + return filterType(type, (t) => hasTypeFacts(t, include)); } // This function is similar to getTypeWithFacts, except that in strictNullChecks mode it replaces type // unknown with the union {} | null | undefined (and reduces that accordingly), and it intersects remaining // instantiable types with {}, {} | null, or {} | undefined in order to remove null and/or undefined. function getAdjustedTypeWithFacts(type: Type, facts: TypeFacts) { - const reduced = recombineUnknownType(getTypeWithFacts(strictNullChecks && type.flags & TypeFlags.Unknown ? unknownUnionType : type, facts)); + const reduced = recombineUnknownType( + getTypeWithFacts( + strictNullChecks && type.flags & TypeFlags.Unknown + ? unknownUnionType + : type, + facts + ) + ); if (strictNullChecks) { switch (facts) { case TypeFacts.NEUndefined: - return removeNullableByIntersection(reduced, TypeFacts.EQUndefined, TypeFacts.EQNull, TypeFacts.IsNull, nullType); + return removeNullableByIntersection( + reduced, + TypeFacts.EQUndefined, + TypeFacts.EQNull, + TypeFacts.IsNull, + nullType + ); case TypeFacts.NENull: - return removeNullableByIntersection(reduced, TypeFacts.EQNull, TypeFacts.EQUndefined, TypeFacts.IsUndefined, undefinedType); + return removeNullableByIntersection( + reduced, + TypeFacts.EQNull, + TypeFacts.EQUndefined, + TypeFacts.IsUndefined, + undefinedType + ); case TypeFacts.NEUndefinedOrNull: case TypeFacts.Truthy: - return mapType(reduced, t => hasTypeFacts(t, TypeFacts.EQUndefinedOrNull) ? getGlobalNonNullableTypeInstantiation(t) : t); + return mapType(reduced, (t) => + hasTypeFacts(t, TypeFacts.EQUndefinedOrNull) + ? getGlobalNonNullableTypeInstantiation(t) + : t + ); } } return reduced; } - function removeNullableByIntersection(type: Type, targetFacts: TypeFacts, otherFacts: TypeFacts, otherIncludesFacts: TypeFacts, otherType: Type) { - const facts = getTypeFacts(type, TypeFacts.EQUndefined | TypeFacts.EQNull | TypeFacts.IsUndefined | TypeFacts.IsNull); + function removeNullableByIntersection( + type: Type, + targetFacts: TypeFacts, + otherFacts: TypeFacts, + otherIncludesFacts: TypeFacts, + otherType: Type + ) { + const facts = getTypeFacts( + type, + TypeFacts.EQUndefined | + TypeFacts.EQNull | + TypeFacts.IsUndefined | + TypeFacts.IsNull + ); // Simply return the type if it never compares equal to the target nullable. if (!(facts & targetFacts)) { return type; @@ -28106,7 +49931,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // For each constituent type that can compare equal to the target nullable, intersect with the above union // if the type doesn't already include the opppsite nullable and the constituent can compare equal to the // opposite nullable; otherwise, just intersect with {}. - return mapType(type, t => hasTypeFacts(t, targetFacts) ? getIntersectionType([t, !(facts & otherIncludesFacts) && hasTypeFacts(t, otherFacts) ? emptyAndOtherUnion : emptyObjectType]) : t); + return mapType(type, (t) => + hasTypeFacts(t, targetFacts) + ? getIntersectionType([ + t, + !(facts & otherIncludesFacts) && + hasTypeFacts(t, otherFacts) + ? emptyAndOtherUnion + : emptyObjectType, + ]) + : t + ); } function recombineUnknownType(type: Type) { @@ -28114,62 +49949,115 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getTypeWithDefault(type: Type, defaultExpression: Expression) { - return defaultExpression ? - getUnionType([getNonUndefinedType(type), getTypeOfExpression(defaultExpression)]) : - type; + return defaultExpression + ? getUnionType([ + getNonUndefinedType(type), + getTypeOfExpression(defaultExpression), + ]) + : type; } function getTypeOfDestructuredProperty(type: Type, name: PropertyName) { const nameType = getLiteralTypeFromPropertyName(name); if (!isTypeUsableAsPropertyName(nameType)) return errorType; const text = getPropertyNameFromType(nameType); - return getTypeOfPropertyOfType(type, text) || includeUndefinedInIndexSignature(getApplicableIndexInfoForName(type, text)?.type) || errorType; + return ( + getTypeOfPropertyOfType(type, text) || + includeUndefinedInIndexSignature( + getApplicableIndexInfoForName(type, text)?.type + ) || + errorType + ); } function getTypeOfDestructuredArrayElement(type: Type, index: number) { - return everyType(type, isTupleLikeType) && getTupleElementType(type, index) || - includeUndefinedInIndexSignature(checkIteratedTypeOrElementType(IterationUse.Destructuring, type, undefinedType, /*errorNode*/ undefined)) || - errorType; + return ( + (everyType(type, isTupleLikeType) && + getTupleElementType(type, index)) || + includeUndefinedInIndexSignature( + checkIteratedTypeOrElementType( + IterationUse.Destructuring, + type, + undefinedType, + /*errorNode*/ undefined + ) + ) || + errorType + ); } - function includeUndefinedInIndexSignature(type: Type | undefined): Type | undefined { + function includeUndefinedInIndexSignature( + type: Type | undefined + ): Type | undefined { if (!type) return type; - return compilerOptions.noUncheckedIndexedAccess ? - getUnionType([type, missingType]) : - type; + return compilerOptions.noUncheckedIndexedAccess + ? getUnionType([type, missingType]) + : type; } function getTypeOfDestructuredSpreadExpression(type: Type) { - return createArrayType(checkIteratedTypeOrElementType(IterationUse.Destructuring, type, undefinedType, /*errorNode*/ undefined) || errorType); + return createArrayType( + checkIteratedTypeOrElementType( + IterationUse.Destructuring, + type, + undefinedType, + /*errorNode*/ undefined + ) || errorType + ); } function getAssignedTypeOfBinaryExpression(node: BinaryExpression): Type { - const isDestructuringDefaultAssignment = node.parent.kind === SyntaxKind.ArrayLiteralExpression && isDestructuringAssignmentTarget(node.parent) || - node.parent.kind === SyntaxKind.PropertyAssignment && isDestructuringAssignmentTarget(node.parent.parent); - return isDestructuringDefaultAssignment ? - getTypeWithDefault(getAssignedType(node), node.right) : - getTypeOfExpression(node.right); + const isDestructuringDefaultAssignment = + (node.parent.kind === SyntaxKind.ArrayLiteralExpression && + isDestructuringAssignmentTarget(node.parent)) || + (node.parent.kind === SyntaxKind.PropertyAssignment && + isDestructuringAssignmentTarget(node.parent.parent)); + return isDestructuringDefaultAssignment + ? getTypeWithDefault(getAssignedType(node), node.right) + : getTypeOfExpression(node.right); } function isDestructuringAssignmentTarget(parent: Node) { - return parent.parent.kind === SyntaxKind.BinaryExpression && (parent.parent as BinaryExpression).left === parent || - parent.parent.kind === SyntaxKind.ForOfStatement && (parent.parent as ForOfStatement).initializer === parent; + return ( + (parent.parent.kind === SyntaxKind.BinaryExpression && + (parent.parent as BinaryExpression).left === parent) || + (parent.parent.kind === SyntaxKind.ForOfStatement && + (parent.parent as ForOfStatement).initializer === parent) + ); } - function getAssignedTypeOfArrayLiteralElement(node: ArrayLiteralExpression, element: Expression): Type { - return getTypeOfDestructuredArrayElement(getAssignedType(node), node.elements.indexOf(element)); + function getAssignedTypeOfArrayLiteralElement( + node: ArrayLiteralExpression, + element: Expression + ): Type { + return getTypeOfDestructuredArrayElement( + getAssignedType(node), + node.elements.indexOf(element) + ); } function getAssignedTypeOfSpreadExpression(node: SpreadElement): Type { - return getTypeOfDestructuredSpreadExpression(getAssignedType(node.parent as ArrayLiteralExpression)); + return getTypeOfDestructuredSpreadExpression( + getAssignedType(node.parent as ArrayLiteralExpression) + ); } - function getAssignedTypeOfPropertyAssignment(node: PropertyAssignment | ShorthandPropertyAssignment): Type { - return getTypeOfDestructuredProperty(getAssignedType(node.parent), node.name); + function getAssignedTypeOfPropertyAssignment( + node: PropertyAssignment | ShorthandPropertyAssignment + ): Type { + return getTypeOfDestructuredProperty( + getAssignedType(node.parent), + node.name + ); } - function getAssignedTypeOfShorthandPropertyAssignment(node: ShorthandPropertyAssignment): Type { - return getTypeWithDefault(getAssignedTypeOfPropertyAssignment(node), node.objectAssignmentInitializer!); + function getAssignedTypeOfShorthandPropertyAssignment( + node: ShorthandPropertyAssignment + ): Type { + return getTypeWithDefault( + getAssignedTypeOfPropertyAssignment(node), + node.objectAssignmentInitializer! + ); } function getAssignedType(node: Expression): Type { @@ -28178,31 +50066,54 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ForInStatement: return stringType; case SyntaxKind.ForOfStatement: - return checkRightHandSideOfForOf(parent as ForOfStatement) || errorType; + return ( + checkRightHandSideOfForOf(parent as ForOfStatement) || + errorType + ); case SyntaxKind.BinaryExpression: - return getAssignedTypeOfBinaryExpression(parent as BinaryExpression); + return getAssignedTypeOfBinaryExpression( + parent as BinaryExpression + ); case SyntaxKind.DeleteExpression: return undefinedType; case SyntaxKind.ArrayLiteralExpression: - return getAssignedTypeOfArrayLiteralElement(parent as ArrayLiteralExpression, node); + return getAssignedTypeOfArrayLiteralElement( + parent as ArrayLiteralExpression, + node + ); case SyntaxKind.SpreadElement: - return getAssignedTypeOfSpreadExpression(parent as SpreadElement); + return getAssignedTypeOfSpreadExpression( + parent as SpreadElement + ); case SyntaxKind.PropertyAssignment: - return getAssignedTypeOfPropertyAssignment(parent as PropertyAssignment); + return getAssignedTypeOfPropertyAssignment( + parent as PropertyAssignment + ); case SyntaxKind.ShorthandPropertyAssignment: - return getAssignedTypeOfShorthandPropertyAssignment(parent as ShorthandPropertyAssignment); + return getAssignedTypeOfShorthandPropertyAssignment( + parent as ShorthandPropertyAssignment + ); } return errorType; } function getInitialTypeOfBindingElement(node: BindingElement): Type { const pattern = node.parent; - const parentType = getInitialType(pattern.parent as VariableDeclaration | BindingElement); - const type = pattern.kind === SyntaxKind.ObjectBindingPattern ? - getTypeOfDestructuredProperty(parentType, node.propertyName || node.name as Identifier) : - !node.dotDotDotToken ? - getTypeOfDestructuredArrayElement(parentType, pattern.elements.indexOf(node)) : - getTypeOfDestructuredSpreadExpression(parentType); + const parentType = getInitialType( + pattern.parent as VariableDeclaration | BindingElement + ); + const type = + pattern.kind === SyntaxKind.ObjectBindingPattern + ? getTypeOfDestructuredProperty( + parentType, + node.propertyName || (node.name as Identifier) + ) + : !node.dotDotDotToken + ? getTypeOfDestructuredArrayElement( + parentType, + pattern.elements.indexOf(node) + ) + : getTypeOfDestructuredSpreadExpression(parentType); return getTypeWithDefault(type, node.initializer!); } @@ -28228,31 +50139,45 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getInitialType(node: VariableDeclaration | BindingElement) { - return node.kind === SyntaxKind.VariableDeclaration ? - getInitialTypeOfVariableDeclaration(node) : - getInitialTypeOfBindingElement(node); + return node.kind === SyntaxKind.VariableDeclaration + ? getInitialTypeOfVariableDeclaration(node) + : getInitialTypeOfBindingElement(node); } - function isEmptyArrayAssignment(node: VariableDeclaration | BindingElement | Expression) { - return node.kind === SyntaxKind.VariableDeclaration && (node as VariableDeclaration).initializer && - isEmptyArrayLiteral((node as VariableDeclaration).initializer!) || - node.kind !== SyntaxKind.BindingElement && node.parent.kind === SyntaxKind.BinaryExpression && - isEmptyArrayLiteral((node.parent as BinaryExpression).right); + function isEmptyArrayAssignment( + node: VariableDeclaration | BindingElement | Expression + ) { + return ( + (node.kind === SyntaxKind.VariableDeclaration && + (node as VariableDeclaration).initializer && + isEmptyArrayLiteral( + (node as VariableDeclaration).initializer! + )) || + (node.kind !== SyntaxKind.BindingElement && + node.parent.kind === SyntaxKind.BinaryExpression && + isEmptyArrayLiteral((node.parent as BinaryExpression).right)) + ); } function getReferenceCandidate(node: Expression): Expression { switch (node.kind) { case SyntaxKind.ParenthesizedExpression: - return getReferenceCandidate((node as ParenthesizedExpression).expression); + return getReferenceCandidate( + (node as ParenthesizedExpression).expression + ); case SyntaxKind.BinaryExpression: switch ((node as BinaryExpression).operatorToken.kind) { case SyntaxKind.EqualsToken: case SyntaxKind.BarBarEqualsToken: case SyntaxKind.AmpersandAmpersandEqualsToken: case SyntaxKind.QuestionQuestionEqualsToken: - return getReferenceCandidate((node as BinaryExpression).left); + return getReferenceCandidate( + (node as BinaryExpression).left + ); case SyntaxKind.CommaToken: - return getReferenceCandidate((node as BinaryExpression).right); + return getReferenceCandidate( + (node as BinaryExpression).right + ); } } return node; @@ -28261,14 +50186,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getReferenceRoot(node: Node): Node { const { parent } = node; return parent.kind === SyntaxKind.ParenthesizedExpression || - parent.kind === SyntaxKind.BinaryExpression && (parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken && (parent as BinaryExpression).left === node || - parent.kind === SyntaxKind.BinaryExpression && (parent as BinaryExpression).operatorToken.kind === SyntaxKind.CommaToken && (parent as BinaryExpression).right === node ? - getReferenceRoot(parent) : node; + (parent.kind === SyntaxKind.BinaryExpression && + (parent as BinaryExpression).operatorToken.kind === + SyntaxKind.EqualsToken && + (parent as BinaryExpression).left === node) || + (parent.kind === SyntaxKind.BinaryExpression && + (parent as BinaryExpression).operatorToken.kind === + SyntaxKind.CommaToken && + (parent as BinaryExpression).right === node) + ? getReferenceRoot(parent) + : node; } function getTypeOfSwitchClause(clause: CaseClause | DefaultClause) { if (clause.kind === SyntaxKind.CaseClause) { - return getRegularTypeOfLiteralType(getTypeOfExpression(clause.expression)); + return getRegularTypeOfLiteralType( + getTypeOfExpression(clause.expression) + ); } return neverType; } @@ -28286,24 +50220,45 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Get the type names from all cases in a switch on `typeof`. The default clause and/or duplicate type names are // represented as undefined. Return undefined if one or more case clause expressions are not string literals. - function getSwitchClauseTypeOfWitnesses(switchStatement: SwitchStatement): (string | undefined)[] | undefined { - if (some(switchStatement.caseBlock.clauses, clause => clause.kind === SyntaxKind.CaseClause && !isStringLiteralLike(clause.expression))) { + function getSwitchClauseTypeOfWitnesses( + switchStatement: SwitchStatement + ): (string | undefined)[] | undefined { + if ( + some( + switchStatement.caseBlock.clauses, + (clause) => + clause.kind === SyntaxKind.CaseClause && + !isStringLiteralLike(clause.expression) + ) + ) { return undefined; } const witnesses: (string | undefined)[] = []; for (const clause of switchStatement.caseBlock.clauses) { - const text = clause.kind === SyntaxKind.CaseClause ? (clause.expression as StringLiteralLike).text : undefined; - witnesses.push(text && !contains(witnesses, text) ? text : undefined); + const text = + clause.kind === SyntaxKind.CaseClause + ? (clause.expression as StringLiteralLike).text + : undefined; + witnesses.push( + text && !contains(witnesses, text) ? text : undefined + ); } return witnesses; } function eachTypeContainedIn(source: Type, types: Type[]) { - return source.flags & TypeFlags.Union ? !forEach((source as UnionType).types, t => !contains(types, t)) : contains(types, source); + return source.flags & TypeFlags.Union + ? !forEach((source as UnionType).types, (t) => !contains(types, t)) + : contains(types, source); } function isTypeSubsetOf(source: Type, target: Type) { - return !!(source === target || source.flags & TypeFlags.Never || target.flags & TypeFlags.Union && isTypeSubsetOfUnion(source, target as UnionType)); + return !!( + source === target || + source.flags & TypeFlags.Never || + (target.flags & TypeFlags.Union && + isTypeSubsetOfUnion(source, target as UnionType)) + ); } function isTypeSubsetOfUnion(source: Type, target: UnionType) { @@ -28315,26 +50270,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } return true; } - if (source.flags & TypeFlags.EnumLike && getBaseTypeOfEnumLikeType(source as LiteralType) === target) { + if ( + source.flags & TypeFlags.EnumLike && + getBaseTypeOfEnumLikeType(source as LiteralType) === target + ) { return true; } return containsType(target.types, source); } - function forEachType(type: Type, f: (t: Type) => T | undefined): T | undefined { - return type.flags & TypeFlags.Union ? forEach((type as UnionType).types, f) : f(type); + function forEachType( + type: Type, + f: (t: Type) => T | undefined + ): T | undefined { + return type.flags & TypeFlags.Union + ? forEach((type as UnionType).types, f) + : f(type); } function someType(type: Type, f: (t: Type) => boolean): boolean { - return type.flags & TypeFlags.Union ? some((type as UnionType).types, f) : f(type); + return type.flags & TypeFlags.Union + ? some((type as UnionType).types, f) + : f(type); } function everyType(type: Type, f: (t: Type) => boolean): boolean { - return type.flags & TypeFlags.Union ? every((type as UnionType).types, f) : f(type); + return type.flags & TypeFlags.Union + ? every((type as UnionType).types, f) + : f(type); } function everyContainedType(type: Type, f: (t: Type) => boolean): boolean { - return type.flags & TypeFlags.UnionOrIntersection ? every((type as UnionOrIntersectionType).types, f) : f(type); + return type.flags & TypeFlags.UnionOrIntersection + ? every((type as UnionOrIntersectionType).types, f) + : f(type); } function filterType(type: Type, f: (t: Type) => boolean): Type { @@ -28353,35 +50322,66 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Otherwise, if we have exactly one type left in the origin set, return that as the filtered type. // Otherwise, construct a new filtered origin type. const originTypes = (origin as UnionType).types; - const originFiltered = filter(originTypes, t => !!(t.flags & TypeFlags.Union) || f(t)); - if (originTypes.length - originFiltered.length === types.length - filtered.length) { + const originFiltered = filter( + originTypes, + (t) => !!(t.flags & TypeFlags.Union) || f(t) + ); + if ( + originTypes.length - originFiltered.length === + types.length - filtered.length + ) { if (originFiltered.length === 1) { return originFiltered[0]; } - newOrigin = createOriginUnionOrIntersectionType(TypeFlags.Union, originFiltered); + newOrigin = createOriginUnionOrIntersectionType( + TypeFlags.Union, + originFiltered + ); } } // filtering could remove intersections so `ContainsIntersections` might be forwarded "incorrectly" // it is purely an optimization hint so there is no harm in accidentally forwarding it - return getUnionTypeFromSortedList(filtered, (type as UnionType).objectFlags & (ObjectFlags.PrimitiveUnion | ObjectFlags.ContainsIntersections), /*aliasSymbol*/ undefined, /*aliasTypeArguments*/ undefined, newOrigin); + return getUnionTypeFromSortedList( + filtered, + (type as UnionType).objectFlags & + (ObjectFlags.PrimitiveUnion | + ObjectFlags.ContainsIntersections), + /*aliasSymbol*/ undefined, + /*aliasTypeArguments*/ undefined, + newOrigin + ); } return type.flags & TypeFlags.Never || f(type) ? type : neverType; } function removeType(type: Type, targetType: Type) { - return filterType(type, t => t !== targetType); + return filterType(type, (t) => t !== targetType); } function countTypes(type: Type) { - return type.flags & TypeFlags.Union ? (type as UnionType).types.length : 1; + return type.flags & TypeFlags.Union + ? (type as UnionType).types.length + : 1; } // Apply a mapping function to a type and return the resulting type. If the source type // is a union type, the mapping function is applied to each constituent type and a union // of the resulting types is returned. - function mapType(type: Type, mapper: (t: Type) => Type, noReductions?: boolean): Type; - function mapType(type: Type, mapper: (t: Type) => Type | undefined, noReductions?: boolean): Type | undefined; - function mapType(type: Type, mapper: (t: Type) => Type | undefined, noReductions?: boolean): Type | undefined { + function mapType( + type: Type, + mapper: (t: Type) => Type, + noReductions?: boolean + ): Type; + function mapType( + type: Type, + mapper: (t: Type) => Type | undefined, + noReductions?: boolean + ): Type | undefined; + function mapType( + type: Type, + mapper: (t: Type) => Type | undefined, + noReductions?: boolean + ): Type | undefined { if (type.flags & TypeFlags.Never) { return type; } @@ -28389,32 +50389,55 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return mapper(type); } const origin = (type as UnionType).origin; - const types = origin && origin.flags & TypeFlags.Union ? (origin as UnionType).types : (type as UnionType).types; + const types = + origin && origin.flags & TypeFlags.Union + ? (origin as UnionType).types + : (type as UnionType).types; let mappedTypes: Type[] | undefined; let changed = false; for (const t of types) { - const mapped = t.flags & TypeFlags.Union ? mapType(t, mapper, noReductions) : mapper(t); + const mapped = + t.flags & TypeFlags.Union + ? mapType(t, mapper, noReductions) + : mapper(t); changed ||= t !== mapped; if (mapped) { if (!mappedTypes) { mappedTypes = [mapped]; - } - else { + } else { mappedTypes.push(mapped); } } } - return changed ? mappedTypes && getUnionType(mappedTypes, noReductions ? UnionReduction.None : UnionReduction.Literal) : type; + return changed + ? mappedTypes && + getUnionType( + mappedTypes, + noReductions + ? UnionReduction.None + : UnionReduction.Literal + ) + : type; } - function mapTypeWithAlias(type: Type, mapper: (t: Type) => Type, aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined) { - return type.flags & TypeFlags.Union && aliasSymbol ? - getUnionType(map((type as UnionType).types, mapper), UnionReduction.Literal, aliasSymbol, aliasTypeArguments) : - mapType(type, mapper); + function mapTypeWithAlias( + type: Type, + mapper: (t: Type) => Type, + aliasSymbol: Symbol | undefined, + aliasTypeArguments: readonly Type[] | undefined + ) { + return type.flags & TypeFlags.Union && aliasSymbol + ? getUnionType( + map((type as UnionType).types, mapper), + UnionReduction.Literal, + aliasSymbol, + aliasTypeArguments + ) + : mapType(type, mapper); } function extractTypesOfKind(type: Type, kind: TypeFlags) { - return filterType(type, t => (t.flags & kind) !== 0); + return filterType(type, (t) => (t.flags & kind) !== 0); } // Return a new type in which occurrences of the string, number and bigint primitives and placeholder template @@ -28422,16 +50445,59 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // from typeWithLiterals. This is essentially a limited form of intersection between the two types. We avoid a // true intersection because it is more costly and, when applied to union types, generates a large number of // types we don't actually care about. - function replacePrimitivesWithLiterals(typeWithPrimitives: Type, typeWithLiterals: Type) { + function replacePrimitivesWithLiterals( + typeWithPrimitives: Type, + typeWithLiterals: Type + ) { if ( - maybeTypeOfKind(typeWithPrimitives, TypeFlags.String | TypeFlags.TemplateLiteral | TypeFlags.Number | TypeFlags.BigInt) && - maybeTypeOfKind(typeWithLiterals, TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping | TypeFlags.NumberLiteral | TypeFlags.BigIntLiteral) + maybeTypeOfKind( + typeWithPrimitives, + TypeFlags.String | + TypeFlags.TemplateLiteral | + TypeFlags.Number | + TypeFlags.BigInt + ) && + maybeTypeOfKind( + typeWithLiterals, + TypeFlags.StringLiteral | + TypeFlags.TemplateLiteral | + TypeFlags.StringMapping | + TypeFlags.NumberLiteral | + TypeFlags.BigIntLiteral + ) ) { - return mapType(typeWithPrimitives, t => - t.flags & TypeFlags.String ? extractTypesOfKind(typeWithLiterals, TypeFlags.String | TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) : - isPatternLiteralType(t) && !maybeTypeOfKind(typeWithLiterals, TypeFlags.String | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) ? extractTypesOfKind(typeWithLiterals, TypeFlags.StringLiteral) : - t.flags & TypeFlags.Number ? extractTypesOfKind(typeWithLiterals, TypeFlags.Number | TypeFlags.NumberLiteral) : - t.flags & TypeFlags.BigInt ? extractTypesOfKind(typeWithLiterals, TypeFlags.BigInt | TypeFlags.BigIntLiteral) : t); + return mapType(typeWithPrimitives, (t) => + t.flags & TypeFlags.String + ? extractTypesOfKind( + typeWithLiterals, + TypeFlags.String | + TypeFlags.StringLiteral | + TypeFlags.TemplateLiteral | + TypeFlags.StringMapping + ) + : isPatternLiteralType(t) && + !maybeTypeOfKind( + typeWithLiterals, + TypeFlags.String | + TypeFlags.TemplateLiteral | + TypeFlags.StringMapping + ) + ? extractTypesOfKind( + typeWithLiterals, + TypeFlags.StringLiteral + ) + : t.flags & TypeFlags.Number + ? extractTypesOfKind( + typeWithLiterals, + TypeFlags.Number | TypeFlags.NumberLiteral + ) + : t.flags & TypeFlags.BigInt + ? extractTypesOfKind( + typeWithLiterals, + TypeFlags.BigInt | TypeFlags.BigIntLiteral + ) + : t + ); } return typeWithPrimitives; } @@ -28441,11 +50507,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getTypeFromFlowType(flowType: FlowType) { - return flowType.flags === 0 ? flowType.type : flowType as Type; + return flowType.flags === 0 ? flowType.type : (flowType as Type); } function createFlowType(type: Type, incomplete: boolean): FlowType { - return incomplete ? { flags: 0, type: type.flags & TypeFlags.Never ? silentNeverType : type } : type; + return incomplete + ? { + flags: 0, + type: type.flags & TypeFlags.Never ? silentNeverType : type, + } + : type; } // An evolving array type tracks the element types that have so far been seen in an @@ -28453,44 +50524,71 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // array types are ultimately converted into manifest array types (using getFinalArrayType) // and never escape the getFlowTypeOfReference function. function createEvolvingArrayType(elementType: Type): EvolvingArrayType { - const result = createObjectType(ObjectFlags.EvolvingArray) as EvolvingArrayType; + const result = createObjectType( + ObjectFlags.EvolvingArray + ) as EvolvingArrayType; result.elementType = elementType; return result; } function getEvolvingArrayType(elementType: Type): EvolvingArrayType { - return evolvingArrayTypes[elementType.id] || (evolvingArrayTypes[elementType.id] = createEvolvingArrayType(elementType)); + return ( + evolvingArrayTypes[elementType.id] || + (evolvingArrayTypes[elementType.id] = + createEvolvingArrayType(elementType)) + ); } // When adding evolving array element types we do not perform subtype reduction. Instead, // we defer subtype reduction until the evolving array type is finalized into a manifest // array type. - function addEvolvingArrayElementType(evolvingArrayType: EvolvingArrayType, node: Expression): EvolvingArrayType { - const elementType = getRegularTypeOfObjectLiteral(getBaseTypeOfLiteralType(getContextFreeTypeOfExpression(node))); - return isTypeSubsetOf(elementType, evolvingArrayType.elementType) ? evolvingArrayType : getEvolvingArrayType(getUnionType([evolvingArrayType.elementType, elementType])); + function addEvolvingArrayElementType( + evolvingArrayType: EvolvingArrayType, + node: Expression + ): EvolvingArrayType { + const elementType = getRegularTypeOfObjectLiteral( + getBaseTypeOfLiteralType(getContextFreeTypeOfExpression(node)) + ); + return isTypeSubsetOf(elementType, evolvingArrayType.elementType) + ? evolvingArrayType + : getEvolvingArrayType( + getUnionType([evolvingArrayType.elementType, elementType]) + ); } function createFinalArrayType(elementType: Type) { - return elementType.flags & TypeFlags.Never ? - autoArrayType : - createArrayType( - elementType.flags & TypeFlags.Union ? - getUnionType((elementType as UnionType).types, UnionReduction.Subtype) : - elementType, - ); + return elementType.flags & TypeFlags.Never + ? autoArrayType + : createArrayType( + elementType.flags & TypeFlags.Union + ? getUnionType( + (elementType as UnionType).types, + UnionReduction.Subtype + ) + : elementType + ); } // We perform subtype reduction upon obtaining the final array type from an evolving array type. function getFinalArrayType(evolvingArrayType: EvolvingArrayType): Type { - return evolvingArrayType.finalArrayType || (evolvingArrayType.finalArrayType = createFinalArrayType(evolvingArrayType.elementType)); + return ( + evolvingArrayType.finalArrayType || + (evolvingArrayType.finalArrayType = createFinalArrayType( + evolvingArrayType.elementType + )) + ); } function finalizeEvolvingArrayType(type: Type): Type { - return getObjectFlags(type) & ObjectFlags.EvolvingArray ? getFinalArrayType(type as EvolvingArrayType) : type; + return getObjectFlags(type) & ObjectFlags.EvolvingArray + ? getFinalArrayType(type as EvolvingArrayType) + : type; } function getElementTypeOfEvolvingArrayType(type: Type) { - return getObjectFlags(type) & ObjectFlags.EvolvingArray ? (type as EvolvingArrayType).elementType : neverType; + return getObjectFlags(type) & ObjectFlags.EvolvingArray + ? (type as EvolvingArrayType).elementType + : neverType; } function isEvolvingArrayTypeList(types: Type[]) { @@ -28511,31 +50609,55 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isEvolvingArrayOperationTarget(node: Node) { const root = getReferenceRoot(node); const parent = root.parent; - const isLengthPushOrUnshift = isPropertyAccessExpression(parent) && ( - parent.name.escapedText === "length" || - parent.parent.kind === SyntaxKind.CallExpression - && isIdentifier(parent.name) - && isPushOrUnshiftIdentifier(parent.name) - ); - const isElementAssignment = parent.kind === SyntaxKind.ElementAccessExpression && + const isLengthPushOrUnshift = + isPropertyAccessExpression(parent) && + (parent.name.escapedText === "length" || + (parent.parent.kind === SyntaxKind.CallExpression && + isIdentifier(parent.name) && + isPushOrUnshiftIdentifier(parent.name))); + const isElementAssignment = + parent.kind === SyntaxKind.ElementAccessExpression && (parent as ElementAccessExpression).expression === root && parent.parent.kind === SyntaxKind.BinaryExpression && - (parent.parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken && + (parent.parent as BinaryExpression).operatorToken.kind === + SyntaxKind.EqualsToken && (parent.parent as BinaryExpression).left === parent && !isAssignmentTarget(parent.parent) && - isTypeAssignableToKind(getTypeOfExpression((parent as ElementAccessExpression).argumentExpression), TypeFlags.NumberLike); + isTypeAssignableToKind( + getTypeOfExpression( + (parent as ElementAccessExpression).argumentExpression + ), + TypeFlags.NumberLike + ); return isLengthPushOrUnshift || isElementAssignment; } function isDeclarationWithExplicitTypeAnnotation(node: Declaration) { - return (isVariableDeclaration(node) || isPropertyDeclaration(node) || isPropertySignature(node) || isParameter(node)) && - !!(getEffectiveTypeAnnotationNode(node) || - isInJSFile(node) && hasInitializer(node) && node.initializer && isFunctionExpressionOrArrowFunction(node.initializer) && getEffectiveReturnTypeNode(node.initializer)); + return ( + (isVariableDeclaration(node) || + isPropertyDeclaration(node) || + isPropertySignature(node) || + isParameter(node)) && + !!( + getEffectiveTypeAnnotationNode(node) || + (isInJSFile(node) && + hasInitializer(node) && + node.initializer && + isFunctionExpressionOrArrowFunction(node.initializer) && + getEffectiveReturnTypeNode(node.initializer)) + ) + ); } function getExplicitTypeOfSymbol(symbol: Symbol, diagnostic?: Diagnostic) { symbol = resolveSymbol(symbol); - if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.ValueModule)) { + if ( + symbol.flags & + (SymbolFlags.Function | + SymbolFlags.Method | + SymbolFlags.Class | + SymbolFlags.ValueModule) + ) { return getTypeOfSymbol(symbol); } if (symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property)) { @@ -28550,16 +50672,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isDeclarationWithExplicitTypeAnnotation(declaration)) { return getTypeOfSymbol(symbol); } - if (isVariableDeclaration(declaration) && declaration.parent.parent.kind === SyntaxKind.ForOfStatement) { + if ( + isVariableDeclaration(declaration) && + declaration.parent.parent.kind === SyntaxKind.ForOfStatement + ) { const statement = declaration.parent.parent; - const expressionType = getTypeOfDottedName(statement.expression, /*diagnostic*/ undefined); + const expressionType = getTypeOfDottedName( + statement.expression, + /*diagnostic*/ undefined + ); if (expressionType) { - const use = statement.awaitModifier ? IterationUse.ForAwaitOf : IterationUse.ForOf; - return checkIteratedTypeOrElementType(use, expressionType, undefinedType, /*errorNode*/ undefined); + const use = statement.awaitModifier + ? IterationUse.ForAwaitOf + : IterationUse.ForOf; + return checkIteratedTypeOrElementType( + use, + expressionType, + undefinedType, + /*errorNode*/ undefined + ); } } if (diagnostic) { - addRelatedInfo(diagnostic, createDiagnosticForNode(declaration, Diagnostics._0_needs_an_explicit_type_annotation, symbolToString(symbol))); + addRelatedInfo( + diagnostic, + createDiagnosticForNode( + declaration, + Diagnostics._0_needs_an_explicit_type_annotation, + symbolToString(symbol) + ) + ); } } } @@ -28569,18 +50711,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // that reference function, method, class or value module symbols; or variable, property or // parameter symbols with declarations that have explicit type annotations. Such references are // resolvable with no possibility of triggering circularities in control flow analysis. - function getTypeOfDottedName(node: Expression, diagnostic: Diagnostic | undefined): Type | undefined { + function getTypeOfDottedName( + node: Expression, + diagnostic: Diagnostic | undefined + ): Type | undefined { if (!(node.flags & NodeFlags.InWithStatement)) { switch (node.kind) { case SyntaxKind.Identifier: - const symbol = getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(node as Identifier)); + const symbol = getExportSymbolOfValueSymbolIfExported( + getResolvedSymbol(node as Identifier) + ); return getExplicitTypeOfSymbol(symbol, diagnostic); case SyntaxKind.ThisKeyword: return getExplicitThisType(node); case SyntaxKind.SuperKeyword: return checkSuperExpression(node); case SyntaxKind.PropertyAccessExpression: { - const type = getTypeOfDottedName((node as PropertyAccessExpression).expression, diagnostic); + const type = getTypeOfDottedName( + (node as PropertyAccessExpression).expression, + diagnostic + ); if (type) { const name = (node as PropertyAccessExpression).name; let prop: Symbol | undefined; @@ -28588,17 +50738,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!type.symbol) { return undefined; } - prop = getPropertyOfType(type, getSymbolNameForPrivateIdentifier(type.symbol, name.escapedText)); - } - else { + prop = getPropertyOfType( + type, + getSymbolNameForPrivateIdentifier( + type.symbol, + name.escapedText + ) + ); + } else { prop = getPropertyOfType(type, name.escapedText); } - return prop && getExplicitTypeOfSymbol(prop, diagnostic); + return ( + prop && getExplicitTypeOfSymbol(prop, diagnostic) + ); } return undefined; } case SyntaxKind.ParenthesizedExpression: - return getTypeOfDottedName((node as ParenthesizedExpression).expression, diagnostic); + return getTypeOfDottedName( + (node as ParenthesizedExpression).expression, + diagnostic + ); } } } @@ -28615,48 +50775,84 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isBinaryExpression(node)) { const rightType = checkNonNullExpression(node.right); funcType = getSymbolHasInstanceMethodOfObjectType(rightType); - } - else if (node.parent.kind === SyntaxKind.ExpressionStatement) { - funcType = getTypeOfDottedName(node.expression, /*diagnostic*/ undefined); - } - else if (node.expression.kind !== SyntaxKind.SuperKeyword) { + } else if (node.parent.kind === SyntaxKind.ExpressionStatement) { + funcType = getTypeOfDottedName( + node.expression, + /*diagnostic*/ undefined + ); + } else if (node.expression.kind !== SyntaxKind.SuperKeyword) { if (isOptionalChain(node)) { funcType = checkNonNullType( - getOptionalExpressionType(checkExpression(node.expression), node.expression), - node.expression, + getOptionalExpressionType( + checkExpression(node.expression), + node.expression + ), + node.expression ); - } - else { + } else { funcType = checkNonNullExpression(node.expression); } } - const signatures = getSignaturesOfType(funcType && getApparentType(funcType) || unknownType, SignatureKind.Call); - const candidate = signatures.length === 1 && !signatures[0].typeParameters ? signatures[0] : - some(signatures, hasTypePredicateOrNeverReturnType) ? getResolvedSignature(node) : - undefined; - signature = links.effectsSignature = candidate && hasTypePredicateOrNeverReturnType(candidate) ? candidate : unknownSignature; + const signatures = getSignaturesOfType( + (funcType && getApparentType(funcType)) || unknownType, + SignatureKind.Call + ); + const candidate = + signatures.length === 1 && !signatures[0].typeParameters + ? signatures[0] + : some(signatures, hasTypePredicateOrNeverReturnType) + ? getResolvedSignature(node) + : undefined; + signature = links.effectsSignature = + candidate && hasTypePredicateOrNeverReturnType(candidate) + ? candidate + : unknownSignature; } return signature === unknownSignature ? undefined : signature; } function hasTypePredicateOrNeverReturnType(signature: Signature) { - return !!(getTypePredicateOfSignature(signature) || - signature.declaration && (getReturnTypeFromAnnotation(signature.declaration) || unknownType).flags & TypeFlags.Never); + return !!( + getTypePredicateOfSignature(signature) || + (signature.declaration && + ( + getReturnTypeFromAnnotation(signature.declaration) || + unknownType + ).flags & TypeFlags.Never) + ); } - function getTypePredicateArgument(predicate: TypePredicate, callExpression: CallExpression) { - if (predicate.kind === TypePredicateKind.Identifier || predicate.kind === TypePredicateKind.AssertsIdentifier) { + function getTypePredicateArgument( + predicate: TypePredicate, + callExpression: CallExpression + ) { + if ( + predicate.kind === TypePredicateKind.Identifier || + predicate.kind === TypePredicateKind.AssertsIdentifier + ) { return callExpression.arguments[predicate.parameterIndex]; } const invokedExpression = skipParentheses(callExpression.expression); - return isAccessExpression(invokedExpression) ? skipParentheses(invokedExpression.expression) : undefined; + return isAccessExpression(invokedExpression) + ? skipParentheses(invokedExpression.expression) + : undefined; } function reportFlowControlError(node: Node) { - const block = findAncestor(node, isFunctionOrModuleBlock) as Block | ModuleBlock | SourceFile; + const block = findAncestor(node, isFunctionOrModuleBlock) as + | Block + | ModuleBlock + | SourceFile; const sourceFile = getSourceFileOfNode(node); const span = getSpanOfTokenAtPosition(sourceFile, block.statements.pos); - diagnostics.add(createFileDiagnostic(sourceFile, span.start, span.length, Diagnostics.The_containing_function_or_module_body_is_too_large_for_control_flow_analysis)); + diagnostics.add( + createFileDiagnostic( + sourceFile, + span.start, + span.length, + Diagnostics.The_containing_function_or_module_body_is_too_large_for_control_flow_analysis + ) + ); } function isReachableFlowNode(flow: FlowNode) { @@ -28668,13 +50864,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isFalseExpression(expr: Expression): boolean { const node = skipParentheses(expr, /*excludeJSDocTypeAssertions*/ true); - return node.kind === SyntaxKind.FalseKeyword || node.kind === SyntaxKind.BinaryExpression && ( - (node as BinaryExpression).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken && (isFalseExpression((node as BinaryExpression).left) || isFalseExpression((node as BinaryExpression).right)) || - (node as BinaryExpression).operatorToken.kind === SyntaxKind.BarBarToken && isFalseExpression((node as BinaryExpression).left) && isFalseExpression((node as BinaryExpression).right) - ); + return ( + node.kind === SyntaxKind.FalseKeyword || + (node.kind === SyntaxKind.BinaryExpression && + (((node as BinaryExpression).operatorToken.kind === + SyntaxKind.AmpersandAmpersandToken && + (isFalseExpression((node as BinaryExpression).left) || + isFalseExpression((node as BinaryExpression).right))) || + ((node as BinaryExpression).operatorToken.kind === + SyntaxKind.BarBarToken && + isFalseExpression((node as BinaryExpression).left) && + isFalseExpression((node as BinaryExpression).right)))) + ); } - function isReachableFlowNodeWorker(flow: FlowNode, noCacheCheck: boolean): boolean { + function isReachableFlowNodeWorker( + flow: FlowNode, + noCacheCheck: boolean + ): boolean { while (true) { if (flow === lastFlowNode) { return lastFlowNodeReachable; @@ -28684,61 +50891,87 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!noCacheCheck) { const id = getFlowNodeId(flow); const reachable = flowNodeReachable[id]; - return reachable !== undefined ? reachable : (flowNodeReachable[id] = isReachableFlowNodeWorker(flow, /*noCacheCheck*/ true)); + return reachable !== undefined + ? reachable + : (flowNodeReachable[id] = isReachableFlowNodeWorker( + flow, + /*noCacheCheck*/ true + )); } noCacheCheck = false; } - if (flags & (FlowFlags.Assignment | FlowFlags.Condition | FlowFlags.ArrayMutation)) { - flow = (flow as FlowAssignment | FlowCondition | FlowArrayMutation).antecedent; - } - else if (flags & FlowFlags.Call) { + if ( + flags & + (FlowFlags.Assignment | + FlowFlags.Condition | + FlowFlags.ArrayMutation) + ) { + flow = ( + flow as FlowAssignment | FlowCondition | FlowArrayMutation + ).antecedent; + } else if (flags & FlowFlags.Call) { const signature = getEffectsSignature((flow as FlowCall).node); if (signature) { const predicate = getTypePredicateOfSignature(signature); - if (predicate && predicate.kind === TypePredicateKind.AssertsIdentifier && !predicate.type) { - const predicateArgument = (flow as FlowCall).node.arguments[predicate.parameterIndex]; - if (predicateArgument && isFalseExpression(predicateArgument)) { + if ( + predicate && + predicate.kind === + TypePredicateKind.AssertsIdentifier && + !predicate.type + ) { + const predicateArgument = (flow as FlowCall).node + .arguments[predicate.parameterIndex]; + if ( + predicateArgument && + isFalseExpression(predicateArgument) + ) { return false; } } - if (getReturnTypeOfSignature(signature).flags & TypeFlags.Never) { + if ( + getReturnTypeOfSignature(signature).flags & + TypeFlags.Never + ) { return false; } } flow = (flow as FlowCall).antecedent; - } - else if (flags & FlowFlags.BranchLabel) { + } else if (flags & FlowFlags.BranchLabel) { // A branching point is reachable if any branch is reachable. - return some((flow as FlowLabel).antecedent, f => isReachableFlowNodeWorker(f, /*noCacheCheck*/ false)); - } - else if (flags & FlowFlags.LoopLabel) { + return some((flow as FlowLabel).antecedent, (f) => + isReachableFlowNodeWorker(f, /*noCacheCheck*/ false) + ); + } else if (flags & FlowFlags.LoopLabel) { const antecedents = (flow as FlowLabel).antecedent; if (antecedents === undefined || antecedents.length === 0) { return false; } // A loop is reachable if the control flow path that leads to the top is reachable. flow = antecedents[0]; - } - else if (flags & FlowFlags.SwitchClause) { + } else if (flags & FlowFlags.SwitchClause) { // The control flow path representing an unmatched value in a switch statement with // no default clause is unreachable if the switch statement is exhaustive. const data = (flow as FlowSwitchClause).node; - if (data.clauseStart === data.clauseEnd && isExhaustiveSwitchStatement(data.switchStatement)) { + if ( + data.clauseStart === data.clauseEnd && + isExhaustiveSwitchStatement(data.switchStatement) + ) { return false; } flow = (flow as FlowSwitchClause).antecedent; - } - else if (flags & FlowFlags.ReduceLabel) { + } else if (flags & FlowFlags.ReduceLabel) { // Cache is unreliable once we start adjusting labels lastFlowNode = undefined; const target = (flow as FlowReduceLabel).node.target; const saveAntecedents = target.antecedent; target.antecedent = (flow as FlowReduceLabel).node.antecedents; - const result = isReachableFlowNodeWorker((flow as FlowReduceLabel).antecedent, /*noCacheCheck*/ false); + const result = isReachableFlowNodeWorker( + (flow as FlowReduceLabel).antecedent, + /*noCacheCheck*/ false + ); target.antecedent = saveAntecedents; return result; - } - else { + } else { return !(flags & FlowFlags.Unreachable); } } @@ -28746,43 +50979,66 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Return true if the given flow node is preceded by a 'super(...)' call in every possible code path // leading to the node. - function isPostSuperFlowNode(flow: FlowNode, noCacheCheck: boolean): boolean { + function isPostSuperFlowNode( + flow: FlowNode, + noCacheCheck: boolean + ): boolean { while (true) { const flags = flow.flags; if (flags & FlowFlags.Shared) { if (!noCacheCheck) { const id = getFlowNodeId(flow); const postSuper = flowNodePostSuper[id]; - return postSuper !== undefined ? postSuper : (flowNodePostSuper[id] = isPostSuperFlowNode(flow, /*noCacheCheck*/ true)); + return postSuper !== undefined + ? postSuper + : (flowNodePostSuper[id] = isPostSuperFlowNode( + flow, + /*noCacheCheck*/ true + )); } noCacheCheck = false; } - if (flags & (FlowFlags.Assignment | FlowFlags.Condition | FlowFlags.ArrayMutation | FlowFlags.SwitchClause)) { - flow = (flow as FlowAssignment | FlowCondition | FlowArrayMutation | FlowSwitchClause).antecedent; - } - else if (flags & FlowFlags.Call) { - if ((flow as FlowCall).node.expression.kind === SyntaxKind.SuperKeyword) { + if ( + flags & + (FlowFlags.Assignment | + FlowFlags.Condition | + FlowFlags.ArrayMutation | + FlowFlags.SwitchClause) + ) { + flow = ( + flow as + | FlowAssignment + | FlowCondition + | FlowArrayMutation + | FlowSwitchClause + ).antecedent; + } else if (flags & FlowFlags.Call) { + if ( + (flow as FlowCall).node.expression.kind === + SyntaxKind.SuperKeyword + ) { return true; } flow = (flow as FlowCall).antecedent; - } - else if (flags & FlowFlags.BranchLabel) { + } else if (flags & FlowFlags.BranchLabel) { // A branching point is post-super if every branch is post-super. - return every((flow as FlowLabel).antecedent, f => isPostSuperFlowNode(f, /*noCacheCheck*/ false)); - } - else if (flags & FlowFlags.LoopLabel) { + return every((flow as FlowLabel).antecedent, (f) => + isPostSuperFlowNode(f, /*noCacheCheck*/ false) + ); + } else if (flags & FlowFlags.LoopLabel) { // A loop is post-super if the control flow path that leads to the top is post-super. flow = (flow as FlowLabel).antecedent![0]; - } - else if (flags & FlowFlags.ReduceLabel) { + } else if (flags & FlowFlags.ReduceLabel) { const target = (flow as FlowReduceLabel).node.target; const saveAntecedents = target.antecedent; target.antecedent = (flow as FlowReduceLabel).node.antecedents; - const result = isPostSuperFlowNode((flow as FlowReduceLabel).antecedent, /*noCacheCheck*/ false); + const result = isPostSuperFlowNode( + (flow as FlowReduceLabel).antecedent, + /*noCacheCheck*/ false + ); target.antecedent = saveAntecedents; return result; - } - else { + } else { // Unreachable nodes are considered post-super to silence errors return !!(flags & FlowFlags.Unreachable); } @@ -28796,26 +51052,45 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.Identifier: if (!isThisInTypeQuery(node)) { const symbol = getResolvedSymbol(node as Identifier); - return isConstantVariable(symbol) - || isParameterOrMutableLocalVariable(symbol) && !isSymbolAssigned(symbol) - || !!symbol.valueDeclaration && isFunctionExpression(symbol.valueDeclaration); + return ( + isConstantVariable(symbol) || + (isParameterOrMutableLocalVariable(symbol) && + !isSymbolAssigned(symbol)) || + (!!symbol.valueDeclaration && + isFunctionExpression(symbol.valueDeclaration)) + ); } break; case SyntaxKind.PropertyAccessExpression: case SyntaxKind.ElementAccessExpression: // The resolvedSymbol property is initialized by checkPropertyAccess or checkElementAccess before we get here. - return isConstantReference((node as AccessExpression).expression) && isReadonlySymbol(getNodeLinks(node).resolvedSymbol || unknownSymbol); + return ( + isConstantReference( + (node as AccessExpression).expression + ) && + isReadonlySymbol( + getNodeLinks(node).resolvedSymbol || unknownSymbol + ) + ); case SyntaxKind.ObjectBindingPattern: case SyntaxKind.ArrayBindingPattern: const rootDeclaration = getRootDeclaration(node.parent); - return isParameter(rootDeclaration) || isCatchClauseVariableDeclaration(rootDeclaration) + return isParameter(rootDeclaration) || + isCatchClauseVariableDeclaration(rootDeclaration) ? !isSomeSymbolAssigned(rootDeclaration) - : isVariableDeclaration(rootDeclaration) && isVarConstLike(rootDeclaration); + : isVariableDeclaration(rootDeclaration) && + isVarConstLike(rootDeclaration); } return false; } - function getFlowTypeOfReference(reference: Node, declaredType: Type, initialType = declaredType, flowContainer?: Node, flowNode = tryCast(reference, canHaveFlowNode)?.flowNode) { + function getFlowTypeOfReference( + reference: Node, + declaredType: Type, + initialType = declaredType, + flowContainer?: Node, + flowNode = tryCast(reference, canHaveFlowNode)?.flowNode + ) { let key: string | undefined; let isKeySet = false; let flowDepth = 0; @@ -28833,8 +51108,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // we give type 'any[]' to 'x' instead of using the type determined by control flow analysis such that operations // on empty arrays are possible without implicit any errors and new element types can be inferred without // type mismatch errors. - const resultType = getObjectFlags(evolvedType) & ObjectFlags.EvolvingArray && isEvolvingArrayOperationTarget(reference) ? autoArrayType : finalizeEvolvingArrayType(evolvedType); - if (resultType === unreachableNeverType || reference.parent && reference.parent.kind === SyntaxKind.NonNullExpression && !(resultType.flags & TypeFlags.Never) && getTypeWithFacts(resultType, TypeFacts.NEUndefinedOrNull).flags & TypeFlags.Never) { + const resultType = + getObjectFlags(evolvedType) & ObjectFlags.EvolvingArray && + isEvolvingArrayOperationTarget(reference) + ? autoArrayType + : finalizeEvolvingArrayType(evolvedType); + if ( + resultType === unreachableNeverType || + (reference.parent && + reference.parent.kind === SyntaxKind.NonNullExpression && + !(resultType.flags & TypeFlags.Never) && + getTypeWithFacts(resultType, TypeFacts.NEUndefinedOrNull) + .flags & TypeFlags.Never) + ) { return declaredType; } return resultType; @@ -28844,14 +51130,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return key; } isKeySet = true; - return key = getFlowCacheKey(reference, declaredType, initialType, flowContainer); + return (key = getFlowCacheKey( + reference, + declaredType, + initialType, + flowContainer + )); } function getTypeAtFlowNode(flow: FlowNode): FlowType { if (flowDepth === 2000) { // We have made 2000 recursive invocations. To avoid overflowing the call stack we report an error // and disable further control flow analysis in the containing function or module body. - tracing?.instant(tracing.Phase.CheckTypes, "getTypeAtFlowNode_DepthLimit", { flowId: flow.id }); + tracing?.instant( + tracing.Phase.CheckTypes, + "getTypeAtFlowNode_DepthLimit", + { flowId: flow.id } + ); flowAnalysisDisabled = true; reportFlowControlError(reference); return errorType; @@ -28879,59 +51174,63 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { flow = (flow as FlowAssignment).antecedent; continue; } - } - else if (flags & FlowFlags.Call) { + } else if (flags & FlowFlags.Call) { type = getTypeAtFlowCall(flow as FlowCall); if (!type) { flow = (flow as FlowCall).antecedent; continue; } - } - else if (flags & FlowFlags.Condition) { + } else if (flags & FlowFlags.Condition) { type = getTypeAtFlowCondition(flow as FlowCondition); - } - else if (flags & FlowFlags.SwitchClause) { + } else if (flags & FlowFlags.SwitchClause) { type = getTypeAtSwitchClause(flow as FlowSwitchClause); - } - else if (flags & FlowFlags.Label) { + } else if (flags & FlowFlags.Label) { if ((flow as FlowLabel).antecedent!.length === 1) { flow = (flow as FlowLabel).antecedent![0]; continue; } - type = flags & FlowFlags.BranchLabel ? - getTypeAtFlowBranchLabel(flow as FlowLabel) : - getTypeAtFlowLoopLabel(flow as FlowLabel); - } - else if (flags & FlowFlags.ArrayMutation) { - type = getTypeAtFlowArrayMutation(flow as FlowArrayMutation); + type = + flags & FlowFlags.BranchLabel + ? getTypeAtFlowBranchLabel(flow as FlowLabel) + : getTypeAtFlowLoopLabel(flow as FlowLabel); + } else if (flags & FlowFlags.ArrayMutation) { + type = getTypeAtFlowArrayMutation( + flow as FlowArrayMutation + ); if (!type) { flow = (flow as FlowArrayMutation).antecedent; continue; } - } - else if (flags & FlowFlags.ReduceLabel) { + } else if (flags & FlowFlags.ReduceLabel) { const target = (flow as FlowReduceLabel).node.target; const saveAntecedents = target.antecedent; - target.antecedent = (flow as FlowReduceLabel).node.antecedents; - type = getTypeAtFlowNode((flow as FlowReduceLabel).antecedent); + target.antecedent = ( + flow as FlowReduceLabel + ).node.antecedents; + type = getTypeAtFlowNode( + (flow as FlowReduceLabel).antecedent + ); target.antecedent = saveAntecedents; - } - else if (flags & FlowFlags.Start) { + } else if (flags & FlowFlags.Start) { // Check if we should continue with the control flow of the containing function. const container = (flow as FlowStart).node; if ( - container && container !== flowContainer && - reference.kind !== SyntaxKind.PropertyAccessExpression && + container && + container !== flowContainer && + reference.kind !== + SyntaxKind.PropertyAccessExpression && reference.kind !== SyntaxKind.ElementAccessExpression && - !(reference.kind === SyntaxKind.ThisKeyword && container.kind !== SyntaxKind.ArrowFunction) + !( + reference.kind === SyntaxKind.ThisKeyword && + container.kind !== SyntaxKind.ArrowFunction + ) ) { flow = container.flowNode!; continue; } // At the top of the flow we have the initial type. type = initialType; - } - else { + } else { // Unreachable code errors are reported in the binding phase. Here we // simply return the non-auto declared type to reduce follow-on errors. type = convertAutoToAny(declaredType); @@ -28950,10 +51249,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getInitialOrAssignedType(flow: FlowAssignment) { const node = flow.node; return getNarrowableTypeForReference( - node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement ? - getInitialType(node as VariableDeclaration | BindingElement) : - getAssignedType(node), - reference, + node.kind === SyntaxKind.VariableDeclaration || + node.kind === SyntaxKind.BindingElement + ? getInitialType( + node as VariableDeclaration | BindingElement + ) + : getAssignedType(node), + reference ); } @@ -28967,18 +51269,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (getAssignmentTargetKind(node) === AssignmentKind.Compound) { const flowType = getTypeAtFlowNode(flow.antecedent); - return createFlowType(getBaseTypeOfLiteralType(getTypeFromFlowType(flowType)), isIncomplete(flowType)); + return createFlowType( + getBaseTypeOfLiteralType(getTypeFromFlowType(flowType)), + isIncomplete(flowType) + ); } - if (declaredType === autoType || declaredType === autoArrayType) { + if ( + declaredType === autoType || + declaredType === autoArrayType + ) { if (isEmptyArrayAssignment(node)) { return getEvolvingArrayType(neverType); } - const assignedType = getWidenedLiteralType(getInitialOrAssignedType(flow)); - return isTypeAssignableTo(assignedType, declaredType) ? assignedType : anyArrayType; + const assignedType = getWidenedLiteralType( + getInitialOrAssignedType(flow) + ); + return isTypeAssignableTo(assignedType, declaredType) + ? assignedType + : anyArrayType; } - const t = isInCompoundLikeAssignment(node) ? getBaseTypeOfLiteralType(declaredType) : declaredType; + const t = isInCompoundLikeAssignment(node) + ? getBaseTypeOfLiteralType(declaredType) + : declaredType; if (t.flags & TypeFlags.Union) { - return getAssignmentReducedType(t as UnionType, getInitialOrAssignedType(flow)); + return getAssignmentReducedType( + t as UnionType, + getInitialOrAssignedType(flow) + ); } return t; } @@ -28992,9 +51309,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // A matching dotted name might also be an expando property on a function *expression*, // in which case we continue control flow analysis back to the function's declaration - if (isVariableDeclaration(node) && (isInJSFile(node) || isVarConstLike(node))) { + if ( + isVariableDeclaration(node) && + (isInJSFile(node) || isVarConstLike(node)) + ) { const init = getDeclaredExpandoInitializer(node); - if (init && (init.kind === SyntaxKind.FunctionExpression || init.kind === SyntaxKind.ArrowFunction)) { + if ( + init && + (init.kind === SyntaxKind.FunctionExpression || + init.kind === SyntaxKind.ArrowFunction) + ) { return getTypeAtFlowNode(flow.antecedent); } } @@ -29004,25 +51328,60 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if ( isVariableDeclaration(node) && node.parent.parent.kind === SyntaxKind.ForInStatement && - (isMatchingReference(reference, node.parent.parent.expression) || optionalChainContainsReference(node.parent.parent.expression, reference)) + (isMatchingReference( + reference, + node.parent.parent.expression + ) || + optionalChainContainsReference( + node.parent.parent.expression, + reference + )) ) { - return getNonNullableTypeIfNeeded(finalizeEvolvingArrayType(getTypeFromFlowType(getTypeAtFlowNode(flow.antecedent)))); + return getNonNullableTypeIfNeeded( + finalizeEvolvingArrayType( + getTypeFromFlowType(getTypeAtFlowNode(flow.antecedent)) + ) + ); } // Assignment doesn't affect reference return undefined; } function narrowTypeByAssertion(type: Type, expr: Expression): Type { - const node = skipParentheses(expr, /*excludeJSDocTypeAssertions*/ true); + const node = skipParentheses( + expr, + /*excludeJSDocTypeAssertions*/ true + ); if (node.kind === SyntaxKind.FalseKeyword) { return unreachableNeverType; } if (node.kind === SyntaxKind.BinaryExpression) { - if ((node as BinaryExpression).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) { - return narrowTypeByAssertion(narrowTypeByAssertion(type, (node as BinaryExpression).left), (node as BinaryExpression).right); + if ( + (node as BinaryExpression).operatorToken.kind === + SyntaxKind.AmpersandAmpersandToken + ) { + return narrowTypeByAssertion( + narrowTypeByAssertion( + type, + (node as BinaryExpression).left + ), + (node as BinaryExpression).right + ); } - if ((node as BinaryExpression).operatorToken.kind === SyntaxKind.BarBarToken) { - return getUnionType([narrowTypeByAssertion(type, (node as BinaryExpression).left), narrowTypeByAssertion(type, (node as BinaryExpression).right)]); + if ( + (node as BinaryExpression).operatorToken.kind === + SyntaxKind.BarBarToken + ) { + return getUnionType([ + narrowTypeByAssertion( + type, + (node as BinaryExpression).left + ), + narrowTypeByAssertion( + type, + (node as BinaryExpression).right + ), + ]); } } return narrowType(type, node, /*assumeTrue*/ true); @@ -29032,45 +51391,92 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const signature = getEffectsSignature(flow.node); if (signature) { const predicate = getTypePredicateOfSignature(signature); - if (predicate && (predicate.kind === TypePredicateKind.AssertsThis || predicate.kind === TypePredicateKind.AssertsIdentifier)) { + if ( + predicate && + (predicate.kind === TypePredicateKind.AssertsThis || + predicate.kind === TypePredicateKind.AssertsIdentifier) + ) { const flowType = getTypeAtFlowNode(flow.antecedent); - const type = finalizeEvolvingArrayType(getTypeFromFlowType(flowType)); - const narrowedType = predicate.type ? narrowTypeByTypePredicate(type, predicate, flow.node, /*assumeTrue*/ true) : - predicate.kind === TypePredicateKind.AssertsIdentifier && predicate.parameterIndex >= 0 && predicate.parameterIndex < flow.node.arguments.length ? narrowTypeByAssertion(type, flow.node.arguments[predicate.parameterIndex]) : - type; - return narrowedType === type ? flowType : createFlowType(narrowedType, isIncomplete(flowType)); + const type = finalizeEvolvingArrayType( + getTypeFromFlowType(flowType) + ); + const narrowedType = predicate.type + ? narrowTypeByTypePredicate( + type, + predicate, + flow.node, + /*assumeTrue*/ true + ) + : predicate.kind === + TypePredicateKind.AssertsIdentifier && + predicate.parameterIndex >= 0 && + predicate.parameterIndex < flow.node.arguments.length + ? narrowTypeByAssertion( + type, + flow.node.arguments[predicate.parameterIndex] + ) + : type; + return narrowedType === type + ? flowType + : createFlowType(narrowedType, isIncomplete(flowType)); } - if (getReturnTypeOfSignature(signature).flags & TypeFlags.Never) { + if ( + getReturnTypeOfSignature(signature).flags & TypeFlags.Never + ) { return unreachableNeverType; } } return undefined; } - function getTypeAtFlowArrayMutation(flow: FlowArrayMutation): FlowType | undefined { + function getTypeAtFlowArrayMutation( + flow: FlowArrayMutation + ): FlowType | undefined { if (declaredType === autoType || declaredType === autoArrayType) { const node = flow.node; - const expr = node.kind === SyntaxKind.CallExpression ? - (node.expression as PropertyAccessExpression).expression : - (node.left as ElementAccessExpression).expression; - if (isMatchingReference(reference, getReferenceCandidate(expr))) { + const expr = + node.kind === SyntaxKind.CallExpression + ? (node.expression as PropertyAccessExpression) + .expression + : (node.left as ElementAccessExpression).expression; + if ( + isMatchingReference(reference, getReferenceCandidate(expr)) + ) { const flowType = getTypeAtFlowNode(flow.antecedent); const type = getTypeFromFlowType(flowType); if (getObjectFlags(type) & ObjectFlags.EvolvingArray) { let evolvedType = type as EvolvingArrayType; if (node.kind === SyntaxKind.CallExpression) { for (const arg of node.arguments) { - evolvedType = addEvolvingArrayElementType(evolvedType, arg); + evolvedType = addEvolvingArrayElementType( + evolvedType, + arg + ); } - } - else { + } else { // 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) - const indexType = getContextFreeTypeOfExpression((node.left as ElementAccessExpression).argumentExpression); - if (isTypeAssignableToKind(indexType, TypeFlags.NumberLike)) { - evolvedType = addEvolvingArrayElementType(evolvedType, node.right); + const indexType = getContextFreeTypeOfExpression( + (node.left as ElementAccessExpression) + .argumentExpression + ); + if ( + isTypeAssignableToKind( + indexType, + TypeFlags.NumberLike + ) + ) { + evolvedType = addEvolvingArrayElementType( + evolvedType, + node.right + ); } } - return evolvedType === type ? flowType : createFlowType(evolvedType, isIncomplete(flowType)); + return evolvedType === type + ? flowType + : createFlowType( + evolvedType, + isIncomplete(flowType) + ); } return flowType; } @@ -29093,7 +51499,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // *only* place a silent never type is ever generated. const assumeTrue = (flow.flags & FlowFlags.TrueCondition) !== 0; const nonEvolvingType = finalizeEvolvingArrayType(type); - const narrowedType = narrowType(nonEvolvingType, flow.node, assumeTrue); + const narrowedType = narrowType( + nonEvolvingType, + flow.node, + assumeTrue + ); if (narrowedType === nonEvolvingType) { return flowType; } @@ -29106,25 +51516,55 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let type = getTypeFromFlowType(flowType); if (isMatchingReference(reference, expr)) { type = narrowTypeBySwitchOnDiscriminant(type, flow.node); - } - else if (expr.kind === SyntaxKind.TypeOfExpression && isMatchingReference(reference, (expr as TypeOfExpression).expression)) { + } else if ( + expr.kind === SyntaxKind.TypeOfExpression && + isMatchingReference( + reference, + (expr as TypeOfExpression).expression + ) + ) { type = narrowTypeBySwitchOnTypeOf(type, flow.node); - } - else if (expr.kind === SyntaxKind.TrueKeyword) { + } else if (expr.kind === SyntaxKind.TrueKeyword) { type = narrowTypeBySwitchOnTrue(type, flow.node); - } - else { + } else { if (strictNullChecks) { if (optionalChainContainsReference(expr, reference)) { - type = narrowTypeBySwitchOptionalChainContainment(type, flow.node, t => !(t.flags & (TypeFlags.Undefined | TypeFlags.Never))); - } - else if (expr.kind === SyntaxKind.TypeOfExpression && optionalChainContainsReference((expr as TypeOfExpression).expression, reference)) { - type = narrowTypeBySwitchOptionalChainContainment(type, flow.node, t => !(t.flags & TypeFlags.Never || t.flags & TypeFlags.StringLiteral && (t as StringLiteralType).value === "undefined")); + type = narrowTypeBySwitchOptionalChainContainment( + type, + flow.node, + (t) => + !( + t.flags & + (TypeFlags.Undefined | TypeFlags.Never) + ) + ); + } else if ( + expr.kind === SyntaxKind.TypeOfExpression && + optionalChainContainsReference( + (expr as TypeOfExpression).expression, + reference + ) + ) { + type = narrowTypeBySwitchOptionalChainContainment( + type, + flow.node, + (t) => + !( + t.flags & TypeFlags.Never || + (t.flags & TypeFlags.StringLiteral && + (t as StringLiteralType).value === + "undefined") + ) + ); } } const access = getDiscriminantPropertyAccess(expr, type); if (access) { - type = narrowTypeBySwitchOnDiscriminantProperty(type, access, flow.node); + type = narrowTypeBySwitchOnDiscriminantProperty( + type, + access, + flow.node + ); } } return createFlowType(type, isIncomplete(flowType)); @@ -29136,7 +51576,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let seenIncomplete = false; let bypassFlow: FlowSwitchClause | undefined; for (const antecedent of flow.antecedent!) { - if (!bypassFlow && antecedent.flags & FlowFlags.SwitchClause && (antecedent as FlowSwitchClause).node.clauseStart === (antecedent as FlowSwitchClause).node.clauseEnd) { + if ( + !bypassFlow && + antecedent.flags & FlowFlags.SwitchClause && + (antecedent as FlowSwitchClause).node.clauseStart === + (antecedent as FlowSwitchClause).node.clauseEnd + ) { // The antecedent is the bypass branch of a potentially exhaustive switch statement. bypassFlow = antecedent as FlowSwitchClause; continue; @@ -29167,7 +51612,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If the bypass flow contributes a type we haven't seen yet and the switch statement // isn't exhaustive, process the bypass flow type. Since exhaustiveness checks increase // the risk of circularities, we only want to perform them when they make a difference. - if (!(type.flags & TypeFlags.Never) && !contains(antecedentTypes, type) && !isExhaustiveSwitchStatement(bypassFlow.node.switchStatement)) { + if ( + !(type.flags & TypeFlags.Never) && + !contains(antecedentTypes, type) && + !isExhaustiveSwitchStatement( + bypassFlow.node.switchStatement + ) + ) { if (type === declaredType && declaredType === initialType) { return type; } @@ -29180,14 +51631,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } } - return createFlowType(getUnionOrEvolvingArrayType(antecedentTypes, subtypeReduction ? UnionReduction.Subtype : UnionReduction.Literal), seenIncomplete); + return createFlowType( + getUnionOrEvolvingArrayType( + antecedentTypes, + subtypeReduction + ? UnionReduction.Subtype + : UnionReduction.Literal + ), + seenIncomplete + ); } function getTypeAtFlowLoopLabel(flow: FlowLabel): FlowType { // If we have previously computed the control flow type for the reference at // this flow loop junction, return the cached type. const id = getFlowNodeId(flow); - const cache = flowLoopCaches[id] || (flowLoopCaches[id] = new Map()); + const cache = + flowLoopCaches[id] || + (flowLoopCaches[id] = new Map()); const key = getOrSetCacheKey(); if (!key) { // No cache key is generated when binding patterns are in unnarrowable situations @@ -29206,8 +51667,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // the first antecedent of a loop junction is always the non-looping control flow // path that leads to the top. for (let i = flowLoopStart; i < flowLoopCount; i++) { - if (flowLoopNodes[i] === flow && flowLoopKeys[i] === key && flowLoopTypes[i].length) { - return createFlowType(getUnionOrEvolvingArrayType(flowLoopTypes[i], UnionReduction.Literal), /*incomplete*/ true); + if ( + flowLoopNodes[i] === flow && + flowLoopKeys[i] === key && + flowLoopTypes[i].length + ) { + return createFlowType( + getUnionOrEvolvingArrayType( + flowLoopTypes[i], + UnionReduction.Literal + ), + /*incomplete*/ true + ); } } // Add the flow loop junction and reference to the in-process stack and analyze @@ -29220,9 +51691,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!firstAntecedentType) { // The first antecedent of a loop junction is always the non-looping control // flow path that leads to the top. - flowType = firstAntecedentType = getTypeAtFlowNode(antecedent); - } - else { + flowType = firstAntecedentType = + getTypeAtFlowNode(antecedent); + } else { // All but the first antecedent are the looping control flow paths that lead // back to the loop junction. We track these on the flow loop stack. flowLoopNodes[flowLoopCount] = flow; @@ -29259,7 +51730,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // The result is incomplete if the first antecedent (the non-looping control flow path) // is incomplete. - const result = getUnionOrEvolvingArrayType(antecedentTypes, subtypeReduction ? UnionReduction.Subtype : UnionReduction.Literal); + const result = getUnionOrEvolvingArrayType( + antecedentTypes, + subtypeReduction + ? UnionReduction.Subtype + : UnionReduction.Literal + ); if (isIncomplete(firstAntecedentType!)) { return createFlowType(result, /*incomplete*/ true); } @@ -29270,52 +51746,94 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // At flow control branch or loop junctions, if the type along every antecedent code path // is an evolving array type, we construct a combined evolving array type. Otherwise we // finalize all evolving array types. - function getUnionOrEvolvingArrayType(types: Type[], subtypeReduction: UnionReduction) { + function getUnionOrEvolvingArrayType( + types: Type[], + subtypeReduction: UnionReduction + ) { if (isEvolvingArrayTypeList(types)) { - return getEvolvingArrayType(getUnionType(map(types, getElementTypeOfEvolvingArrayType))); + return getEvolvingArrayType( + getUnionType(map(types, getElementTypeOfEvolvingArrayType)) + ); } - const result = recombineUnknownType(getUnionType(sameMap(types, finalizeEvolvingArrayType), subtypeReduction)); - if (result !== declaredType && result.flags & declaredType.flags & TypeFlags.Union && arrayIsEqualTo((result as UnionType).types, (declaredType as UnionType).types)) { + const result = recombineUnknownType( + getUnionType( + sameMap(types, finalizeEvolvingArrayType), + subtypeReduction + ) + ); + if ( + result !== declaredType && + result.flags & declaredType.flags & TypeFlags.Union && + arrayIsEqualTo( + (result as UnionType).types, + (declaredType as UnionType).types + ) + ) { return declaredType; } return result; } function getCandidateDiscriminantPropertyAccess(expr: Expression) { - if (isBindingPattern(reference) || isFunctionExpressionOrArrowFunction(reference) || isObjectLiteralMethod(reference)) { + if ( + isBindingPattern(reference) || + isFunctionExpressionOrArrowFunction(reference) || + isObjectLiteralMethod(reference) + ) { // When the reference is a binding pattern or function or arrow expression, we are narrowing a pesudo-reference in // getNarrowedTypeOfSymbol. An identifier for a destructuring variable declared in the same binding pattern or // parameter declared in the same parameter list is a candidate. if (isIdentifier(expr)) { const symbol = getResolvedSymbol(expr); - const declaration = getExportSymbolOfValueSymbolIfExported(symbol).valueDeclaration; - if (declaration && (isBindingElement(declaration) || isParameter(declaration)) && reference === declaration.parent && !declaration.initializer && !declaration.dotDotDotToken) { + const declaration = + getExportSymbolOfValueSymbolIfExported( + symbol + ).valueDeclaration; + if ( + declaration && + (isBindingElement(declaration) || + isParameter(declaration)) && + reference === declaration.parent && + !declaration.initializer && + !declaration.dotDotDotToken + ) { return declaration; } } - } - else if (isAccessExpression(expr)) { + } else if (isAccessExpression(expr)) { // An access expression is a candidate if the reference matches the left hand expression. if (isMatchingReference(reference, expr.expression)) { return expr; } - } - else if (isIdentifier(expr)) { + } else if (isIdentifier(expr)) { const symbol = getResolvedSymbol(expr); if (isConstantVariable(symbol)) { const declaration = symbol.valueDeclaration!; // Given 'const x = obj.kind', allow 'x' as an alias for 'obj.kind' if ( - isVariableDeclaration(declaration) && !declaration.type && declaration.initializer && isAccessExpression(declaration.initializer) && - isMatchingReference(reference, declaration.initializer.expression) + isVariableDeclaration(declaration) && + !declaration.type && + declaration.initializer && + isAccessExpression(declaration.initializer) && + isMatchingReference( + reference, + declaration.initializer.expression + ) ) { return declaration.initializer; } // Given 'const { kind: x } = obj', allow 'x' as an alias for 'obj.kind' - if (isBindingElement(declaration) && !declaration.initializer) { + if ( + isBindingElement(declaration) && + !declaration.initializer + ) { const parent = declaration.parent.parent; if ( - isVariableDeclaration(parent) && !parent.type && parent.initializer && (isIdentifier(parent.initializer) || isAccessExpression(parent.initializer)) && + isVariableDeclaration(parent) && + !parent.type && + parent.initializer && + (isIdentifier(parent.initializer) || + isAccessExpression(parent.initializer)) && isMatchingReference(reference, parent.initializer) ) { return declaration; @@ -29326,16 +51844,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - function getDiscriminantPropertyAccess(expr: Expression, computedType: Type) { + function getDiscriminantPropertyAccess( + expr: Expression, + computedType: Type + ) { // As long as the computed type is a subset of the declared type, we use the full declared type to detect // a discriminant property. In cases where the computed type isn't a subset, e.g because of a preceding type // predicate narrowing, we use the actual computed type. - if (declaredType.flags & TypeFlags.Union || computedType.flags & TypeFlags.Union) { + if ( + declaredType.flags & TypeFlags.Union || + computedType.flags & TypeFlags.Union + ) { const access = getCandidateDiscriminantPropertyAccess(expr); if (access) { const name = getAccessedPropertyName(access); if (name) { - const type = declaredType.flags & TypeFlags.Union && isTypeSubsetOf(computedType, declaredType) ? declaredType : computedType; + const type = + declaredType.flags & TypeFlags.Union && + isTypeSubsetOf(computedType, declaredType) + ? declaredType + : computedType; if (isDiscriminantProperty(type, name)) { return access; } @@ -29345,103 +51873,235 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - function narrowTypeByDiscriminant(type: Type, access: AccessExpression | BindingElement | ParameterDeclaration, narrowType: (t: Type) => Type): Type { + function narrowTypeByDiscriminant( + type: Type, + access: AccessExpression | BindingElement | ParameterDeclaration, + narrowType: (t: Type) => Type + ): Type { const propName = getAccessedPropertyName(access); if (propName === undefined) { return type; } const optionalChain = isOptionalChain(access); - const removeNullable = strictNullChecks && (optionalChain || isNonNullAccess(access)) && maybeTypeOfKind(type, TypeFlags.Nullable); - let propType = getTypeOfPropertyOfType(removeNullable ? getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type, propName); + const removeNullable = + strictNullChecks && + (optionalChain || isNonNullAccess(access)) && + maybeTypeOfKind(type, TypeFlags.Nullable); + let propType = getTypeOfPropertyOfType( + removeNullable + ? getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) + : type, + propName + ); if (!propType) { return type; } - propType = removeNullable && optionalChain ? getOptionalType(propType) : propType; + propType = + removeNullable && optionalChain + ? getOptionalType(propType) + : propType; const narrowedPropType = narrowType(propType); - return filterType(type, t => { - const discriminantType = getTypeOfPropertyOrIndexSignatureOfType(t, propName) || unknownType; - return !(discriminantType.flags & TypeFlags.Never) && !(narrowedPropType.flags & TypeFlags.Never) && areTypesComparable(narrowedPropType, discriminantType); + return filterType(type, (t) => { + const discriminantType = + getTypeOfPropertyOrIndexSignatureOfType(t, propName) || + unknownType; + return ( + !(discriminantType.flags & TypeFlags.Never) && + !(narrowedPropType.flags & TypeFlags.Never) && + areTypesComparable(narrowedPropType, discriminantType) + ); }); } - function narrowTypeByDiscriminantProperty(type: Type, access: AccessExpression | BindingElement | ParameterDeclaration, operator: SyntaxKind, value: Expression, assumeTrue: boolean) { - if ((operator === SyntaxKind.EqualsEqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken) && type.flags & TypeFlags.Union) { + function narrowTypeByDiscriminantProperty( + type: Type, + access: AccessExpression | BindingElement | ParameterDeclaration, + operator: SyntaxKind, + value: Expression, + assumeTrue: boolean + ) { + if ( + (operator === SyntaxKind.EqualsEqualsEqualsToken || + operator === SyntaxKind.ExclamationEqualsEqualsToken) && + type.flags & TypeFlags.Union + ) { const keyPropertyName = getKeyPropertyName(type as UnionType); - if (keyPropertyName && keyPropertyName === getAccessedPropertyName(access)) { - const candidate = getConstituentTypeForKeyType(type as UnionType, getTypeOfExpression(value)); + if ( + keyPropertyName && + keyPropertyName === getAccessedPropertyName(access) + ) { + const candidate = getConstituentTypeForKeyType( + type as UnionType, + getTypeOfExpression(value) + ); if (candidate) { - return operator === (assumeTrue ? SyntaxKind.EqualsEqualsEqualsToken : SyntaxKind.ExclamationEqualsEqualsToken) ? candidate : - isUnitType(getTypeOfPropertyOfType(candidate, keyPropertyName) || unknownType) ? removeType(type, candidate) : - type; - } - } - } - return narrowTypeByDiscriminant(type, access, t => narrowTypeByEquality(t, operator, value, assumeTrue)); + return operator === + (assumeTrue + ? SyntaxKind.EqualsEqualsEqualsToken + : SyntaxKind.ExclamationEqualsEqualsToken) + ? candidate + : isUnitType( + getTypeOfPropertyOfType( + candidate, + keyPropertyName + ) || unknownType + ) + ? removeType(type, candidate) + : type; + } + } + } + return narrowTypeByDiscriminant(type, access, (t) => + narrowTypeByEquality(t, operator, value, assumeTrue) + ); } - function narrowTypeBySwitchOnDiscriminantProperty(type: Type, access: AccessExpression | BindingElement | ParameterDeclaration, data: FlowSwitchClauseData) { - if (data.clauseStart < data.clauseEnd && type.flags & TypeFlags.Union && getKeyPropertyName(type as UnionType) === getAccessedPropertyName(access)) { - const clauseTypes = getSwitchClauseTypes(data.switchStatement).slice(data.clauseStart, data.clauseEnd); - const candidate = getUnionType(map(clauseTypes, t => getConstituentTypeForKeyType(type as UnionType, t) || unknownType)); + function narrowTypeBySwitchOnDiscriminantProperty( + type: Type, + access: AccessExpression | BindingElement | ParameterDeclaration, + data: FlowSwitchClauseData + ) { + if ( + data.clauseStart < data.clauseEnd && + type.flags & TypeFlags.Union && + getKeyPropertyName(type as UnionType) === + getAccessedPropertyName(access) + ) { + const clauseTypes = getSwitchClauseTypes( + data.switchStatement + ).slice(data.clauseStart, data.clauseEnd); + const candidate = getUnionType( + map( + clauseTypes, + (t) => + getConstituentTypeForKeyType( + type as UnionType, + t + ) || unknownType + ) + ); if (candidate !== unknownType) { return candidate; } } - return narrowTypeByDiscriminant(type, access, t => narrowTypeBySwitchOnDiscriminant(t, data)); + return narrowTypeByDiscriminant(type, access, (t) => + narrowTypeBySwitchOnDiscriminant(t, data) + ); } - function narrowTypeByTruthiness(type: Type, expr: Expression, assumeTrue: boolean): Type { + function narrowTypeByTruthiness( + type: Type, + expr: Expression, + assumeTrue: boolean + ): Type { if (isMatchingReference(reference, expr)) { - return getAdjustedTypeWithFacts(type, assumeTrue ? TypeFacts.Truthy : TypeFacts.Falsy); + return getAdjustedTypeWithFacts( + type, + assumeTrue ? TypeFacts.Truthy : TypeFacts.Falsy + ); } - if (strictNullChecks && assumeTrue && optionalChainContainsReference(expr, reference)) { - type = getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); + if ( + strictNullChecks && + assumeTrue && + optionalChainContainsReference(expr, reference) + ) { + type = getAdjustedTypeWithFacts( + type, + TypeFacts.NEUndefinedOrNull + ); } const access = getDiscriminantPropertyAccess(expr, type); if (access) { - return narrowTypeByDiscriminant(type, access, t => getTypeWithFacts(t, assumeTrue ? TypeFacts.Truthy : TypeFacts.Falsy)); + return narrowTypeByDiscriminant(type, access, (t) => + getTypeWithFacts( + t, + assumeTrue ? TypeFacts.Truthy : TypeFacts.Falsy + ) + ); } return type; } - function isTypePresencePossible(type: Type, propName: __String, assumeTrue: boolean) { + function isTypePresencePossible( + type: Type, + propName: __String, + assumeTrue: boolean + ) { const prop = getPropertyOfType(type, propName); - return prop ? - !!(prop.flags & SymbolFlags.Optional || getCheckFlags(prop) & CheckFlags.Partial) || assumeTrue : - !!getApplicableIndexInfoForName(type, propName) || !assumeTrue; - } - - function narrowTypeByInKeyword(type: Type, nameType: StringLiteralType | NumberLiteralType | UniqueESSymbolType, assumeTrue: boolean) { + return prop + ? !!( + prop.flags & SymbolFlags.Optional || + getCheckFlags(prop) & CheckFlags.Partial + ) || assumeTrue + : !!getApplicableIndexInfoForName(type, propName) || + !assumeTrue; + } + + function narrowTypeByInKeyword( + type: Type, + nameType: + | StringLiteralType + | NumberLiteralType + | UniqueESSymbolType, + assumeTrue: boolean + ) { const name = getPropertyNameFromType(nameType); - const isKnownProperty = someType(type, t => isTypePresencePossible(t, name, /*assumeTrue*/ true)); + const isKnownProperty = someType(type, (t) => + isTypePresencePossible(t, name, /*assumeTrue*/ true) + ); if (isKnownProperty) { // If the check is for a known property (i.e. a property declared in some constituent of // the target type), we filter the target type by presence of absence of the property. - return filterType(type, t => isTypePresencePossible(t, name, assumeTrue)); + return filterType(type, (t) => + isTypePresencePossible(t, name, assumeTrue) + ); } if (assumeTrue) { // If the check is for an unknown property, we intersect the target type with `Record`, // where X is the name of the property. const recordSymbol = getGlobalRecordSymbol(); if (recordSymbol) { - return getIntersectionType([type, getTypeAliasInstantiation(recordSymbol, [nameType, unknownType])]); + return getIntersectionType([ + type, + getTypeAliasInstantiation(recordSymbol, [ + nameType, + unknownType, + ]), + ]); } } return type; } - function narrowTypeByBooleanComparison(type: Type, expr: Expression, bool: BooleanLiteral, operator: BinaryOperator, assumeTrue: boolean): Type { - assumeTrue = (assumeTrue !== (bool.kind === SyntaxKind.TrueKeyword)) !== (operator !== SyntaxKind.ExclamationEqualsEqualsToken && operator !== SyntaxKind.ExclamationEqualsToken); + function narrowTypeByBooleanComparison( + type: Type, + expr: Expression, + bool: BooleanLiteral, + operator: BinaryOperator, + assumeTrue: boolean + ): Type { + assumeTrue = + (assumeTrue !== (bool.kind === SyntaxKind.TrueKeyword)) !== + (operator !== SyntaxKind.ExclamationEqualsEqualsToken && + operator !== SyntaxKind.ExclamationEqualsToken); return narrowType(type, expr, assumeTrue); } - function narrowTypeByBinaryExpression(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type { + function narrowTypeByBinaryExpression( + type: Type, + expr: BinaryExpression, + assumeTrue: boolean + ): Type { switch (expr.operatorToken.kind) { case SyntaxKind.EqualsToken: case SyntaxKind.BarBarEqualsToken: case SyntaxKind.AmpersandAmpersandEqualsToken: case SyntaxKind.QuestionQuestionEqualsToken: - return narrowTypeByTruthiness(narrowType(type, expr.right, assumeTrue), expr.left, assumeTrue); + return narrowTypeByTruthiness( + narrowType(type, expr.right, assumeTrue), + expr.left, + assumeTrue + ); case SyntaxKind.EqualsEqualsToken: case SyntaxKind.ExclamationEqualsToken: case SyntaxKind.EqualsEqualsEqualsToken: @@ -29449,64 +52109,168 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const operator = expr.operatorToken.kind; const left = getReferenceCandidate(expr.left); const right = getReferenceCandidate(expr.right); - if (left.kind === SyntaxKind.TypeOfExpression && isStringLiteralLike(right)) { - return narrowTypeByTypeof(type, left as TypeOfExpression, operator, right, assumeTrue); + if ( + left.kind === SyntaxKind.TypeOfExpression && + isStringLiteralLike(right) + ) { + return narrowTypeByTypeof( + type, + left as TypeOfExpression, + operator, + right, + assumeTrue + ); } - if (right.kind === SyntaxKind.TypeOfExpression && isStringLiteralLike(left)) { - return narrowTypeByTypeof(type, right as TypeOfExpression, operator, left, assumeTrue); + if ( + right.kind === SyntaxKind.TypeOfExpression && + isStringLiteralLike(left) + ) { + return narrowTypeByTypeof( + type, + right as TypeOfExpression, + operator, + left, + assumeTrue + ); } if (isMatchingReference(reference, left)) { - return narrowTypeByEquality(type, operator, right, assumeTrue); + return narrowTypeByEquality( + type, + operator, + right, + assumeTrue + ); } if (isMatchingReference(reference, right)) { - return narrowTypeByEquality(type, operator, left, assumeTrue); + return narrowTypeByEquality( + type, + operator, + left, + assumeTrue + ); } if (strictNullChecks) { if (optionalChainContainsReference(left, reference)) { - type = narrowTypeByOptionalChainContainment(type, operator, right, assumeTrue); - } - else if (optionalChainContainsReference(right, reference)) { - type = narrowTypeByOptionalChainContainment(type, operator, left, assumeTrue); + type = narrowTypeByOptionalChainContainment( + type, + operator, + right, + assumeTrue + ); + } else if ( + optionalChainContainsReference(right, reference) + ) { + type = narrowTypeByOptionalChainContainment( + type, + operator, + left, + assumeTrue + ); } } - const leftAccess = getDiscriminantPropertyAccess(left, type); + const leftAccess = getDiscriminantPropertyAccess( + left, + type + ); if (leftAccess) { - return narrowTypeByDiscriminantProperty(type, leftAccess, operator, right, assumeTrue); + return narrowTypeByDiscriminantProperty( + type, + leftAccess, + operator, + right, + assumeTrue + ); } - const rightAccess = getDiscriminantPropertyAccess(right, type); + const rightAccess = getDiscriminantPropertyAccess( + right, + type + ); if (rightAccess) { - return narrowTypeByDiscriminantProperty(type, rightAccess, operator, left, assumeTrue); + return narrowTypeByDiscriminantProperty( + type, + rightAccess, + operator, + left, + assumeTrue + ); } if (isMatchingConstructorReference(left)) { - return narrowTypeByConstructor(type, operator, right, assumeTrue); + return narrowTypeByConstructor( + type, + operator, + right, + assumeTrue + ); } if (isMatchingConstructorReference(right)) { - return narrowTypeByConstructor(type, operator, left, assumeTrue); + return narrowTypeByConstructor( + type, + operator, + left, + assumeTrue + ); } if (isBooleanLiteral(right) && !isAccessExpression(left)) { - return narrowTypeByBooleanComparison(type, left, right, operator, assumeTrue); + return narrowTypeByBooleanComparison( + type, + left, + right, + operator, + assumeTrue + ); } if (isBooleanLiteral(left) && !isAccessExpression(right)) { - return narrowTypeByBooleanComparison(type, right, left, operator, assumeTrue); + return narrowTypeByBooleanComparison( + type, + right, + left, + operator, + assumeTrue + ); } break; case SyntaxKind.InstanceOfKeyword: - return narrowTypeByInstanceof(type, expr as InstanceofExpression, assumeTrue); + return narrowTypeByInstanceof( + type, + expr as InstanceofExpression, + assumeTrue + ); case SyntaxKind.InKeyword: if (isPrivateIdentifier(expr.left)) { - return narrowTypeByPrivateIdentifierInInExpression(type, expr, assumeTrue); + return narrowTypeByPrivateIdentifierInInExpression( + type, + expr, + assumeTrue + ); } const target = getReferenceCandidate(expr.right); - if (containsMissingType(type) && isAccessExpression(reference) && isMatchingReference(reference.expression, target)) { + if ( + containsMissingType(type) && + isAccessExpression(reference) && + isMatchingReference(reference.expression, target) + ) { const leftType = getTypeOfExpression(expr.left); - if (isTypeUsableAsPropertyName(leftType) && getAccessedPropertyName(reference) === getPropertyNameFromType(leftType)) { - return getTypeWithFacts(type, assumeTrue ? TypeFacts.NEUndefined : TypeFacts.EQUndefined); + if ( + isTypeUsableAsPropertyName(leftType) && + getAccessedPropertyName(reference) === + getPropertyNameFromType(leftType) + ) { + return getTypeWithFacts( + type, + assumeTrue + ? TypeFacts.NEUndefined + : TypeFacts.EQUndefined + ); } } if (isMatchingReference(reference, target)) { const leftType = getTypeOfExpression(expr.left); if (isTypeUsableAsPropertyName(leftType)) { - return narrowTypeByInKeyword(type, leftType, assumeTrue); + return narrowTypeByInKeyword( + type, + leftType, + assumeTrue + ); } } break; @@ -29516,18 +52280,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // expressions down to individual conditional control flows. However, we may encounter them when analyzing // aliased conditional expressions. case SyntaxKind.AmpersandAmpersandToken: - return assumeTrue ? - narrowType(narrowType(type, expr.left, /*assumeTrue*/ true), expr.right, /*assumeTrue*/ true) : - getUnionType([narrowType(type, expr.left, /*assumeTrue*/ false), narrowType(type, expr.right, /*assumeTrue*/ false)]); + return assumeTrue + ? narrowType( + narrowType(type, expr.left, /*assumeTrue*/ true), + expr.right, + /*assumeTrue*/ true + ) + : getUnionType([ + narrowType(type, expr.left, /*assumeTrue*/ false), + narrowType( + type, + expr.right, + /*assumeTrue*/ false + ), + ]); case SyntaxKind.BarBarToken: - return assumeTrue ? - getUnionType([narrowType(type, expr.left, /*assumeTrue*/ true), narrowType(type, expr.right, /*assumeTrue*/ true)]) : - narrowType(narrowType(type, expr.left, /*assumeTrue*/ false), expr.right, /*assumeTrue*/ false); + return assumeTrue + ? getUnionType([ + narrowType(type, expr.left, /*assumeTrue*/ true), + narrowType(type, expr.right, /*assumeTrue*/ true), + ]) + : narrowType( + narrowType(type, expr.left, /*assumeTrue*/ false), + expr.right, + /*assumeTrue*/ false + ); } return type; } - function narrowTypeByPrivateIdentifierInInExpression(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type { + function narrowTypeByPrivateIdentifierInInExpression( + type: Type, + expr: BinaryExpression, + assumeTrue: boolean + ): Type { const target = getReferenceCandidate(expr.right); if (!isMatchingReference(reference, target)) { return type; @@ -29539,13 +52325,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return type; } const classSymbol = symbol.parent!; - const targetType = hasStaticModifier(Debug.checkDefined(symbol.valueDeclaration, "should always have a declaration")) - ? getTypeOfSymbol(classSymbol) as InterfaceType + const targetType = hasStaticModifier( + Debug.checkDefined( + symbol.valueDeclaration, + "should always have a declaration" + ) + ) + ? (getTypeOfSymbol(classSymbol) as InterfaceType) : getDeclaredTypeOfSymbol(classSymbol); - return getNarrowedType(type, targetType, assumeTrue, /*checkDerived*/ true); + return getNarrowedType( + type, + targetType, + assumeTrue, + /*checkDerived*/ true + ); } - function narrowTypeByOptionalChainContainment(type: Type, operator: SyntaxKind, value: Expression, assumeTrue: boolean): Type { + function narrowTypeByOptionalChainContainment( + type: Type, + operator: SyntaxKind, + value: Expression, + assumeTrue: boolean + ): Type { // We are in a branch of obj?.foo === value (or any one of the other equality operators). We narrow obj as follows: // When operator is === and type of value excludes undefined, null and undefined is removed from type of obj in true branch. // When operator is !== and type of value excludes undefined, null and undefined is removed from type of obj in false branch. @@ -29555,84 +52356,182 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // When operator is !== and type of value is undefined, null and undefined is removed from type of obj in true branch. // When operator is == and type of value is null or undefined, null and undefined is removed from type of obj in false branch. // When operator is != and type of value is null or undefined, null and undefined is removed from type of obj in true branch. - const equalsOperator = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.EqualsEqualsEqualsToken; - const nullableFlags = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken ? TypeFlags.Nullable : TypeFlags.Undefined; + const equalsOperator = + operator === SyntaxKind.EqualsEqualsToken || + operator === SyntaxKind.EqualsEqualsEqualsToken; + const nullableFlags = + operator === SyntaxKind.EqualsEqualsToken || + operator === SyntaxKind.ExclamationEqualsToken + ? TypeFlags.Nullable + : TypeFlags.Undefined; const valueType = getTypeOfExpression(value); // Note that we include any and unknown in the exclusion test because their domain includes null and undefined. - const removeNullable = equalsOperator !== assumeTrue && everyType(valueType, t => !!(t.flags & nullableFlags)) || - equalsOperator === assumeTrue && everyType(valueType, t => !(t.flags & (TypeFlags.AnyOrUnknown | nullableFlags))); - return removeNullable ? getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type; + const removeNullable = + (equalsOperator !== assumeTrue && + everyType(valueType, (t) => !!(t.flags & nullableFlags))) || + (equalsOperator === assumeTrue && + everyType( + valueType, + (t) => + !( + t.flags & + (TypeFlags.AnyOrUnknown | nullableFlags) + ) + )); + return removeNullable + ? getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) + : type; } - function narrowTypeByEquality(type: Type, operator: SyntaxKind, value: Expression, assumeTrue: boolean): Type { + function narrowTypeByEquality( + type: Type, + operator: SyntaxKind, + value: Expression, + assumeTrue: boolean + ): Type { if (type.flags & TypeFlags.Any) { return type; } - if (operator === SyntaxKind.ExclamationEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken) { + if ( + operator === SyntaxKind.ExclamationEqualsToken || + operator === SyntaxKind.ExclamationEqualsEqualsToken + ) { assumeTrue = !assumeTrue; } const valueType = getTypeOfExpression(value); - const doubleEquals = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken; + const doubleEquals = + operator === SyntaxKind.EqualsEqualsToken || + operator === SyntaxKind.ExclamationEqualsToken; if (valueType.flags & TypeFlags.Nullable) { if (!strictNullChecks) { return type; } - const facts = doubleEquals ? - assumeTrue ? TypeFacts.EQUndefinedOrNull : TypeFacts.NEUndefinedOrNull : - valueType.flags & TypeFlags.Null ? - assumeTrue ? TypeFacts.EQNull : TypeFacts.NENull : - assumeTrue ? TypeFacts.EQUndefined : TypeFacts.NEUndefined; + const facts = doubleEquals + ? assumeTrue + ? TypeFacts.EQUndefinedOrNull + : TypeFacts.NEUndefinedOrNull + : valueType.flags & TypeFlags.Null + ? assumeTrue + ? TypeFacts.EQNull + : TypeFacts.NENull + : assumeTrue + ? TypeFacts.EQUndefined + : TypeFacts.NEUndefined; return getAdjustedTypeWithFacts(type, facts); } if (assumeTrue) { - if (!doubleEquals && (type.flags & TypeFlags.Unknown || someType(type, isEmptyAnonymousObjectType))) { - if (valueType.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive) || isEmptyAnonymousObjectType(valueType)) { + if ( + !doubleEquals && + (type.flags & TypeFlags.Unknown || + someType(type, isEmptyAnonymousObjectType)) + ) { + if ( + valueType.flags & + (TypeFlags.Primitive | TypeFlags.NonPrimitive) || + isEmptyAnonymousObjectType(valueType) + ) { return valueType; } if (valueType.flags & TypeFlags.Object) { return nonPrimitiveType; } } - const filteredType = filterType(type, t => areTypesComparable(t, valueType) || doubleEquals && isCoercibleUnderDoubleEquals(t, valueType)); + const filteredType = filterType( + type, + (t) => + areTypesComparable(t, valueType) || + (doubleEquals && + isCoercibleUnderDoubleEquals(t, valueType)) + ); return replacePrimitivesWithLiterals(filteredType, valueType); } if (isUnitType(valueType)) { - return filterType(type, t => !(isUnitLikeType(t) && areTypesComparable(t, valueType))); + return filterType( + type, + (t) => + !(isUnitLikeType(t) && areTypesComparable(t, valueType)) + ); } return type; } - function narrowTypeByTypeof(type: Type, typeOfExpr: TypeOfExpression, operator: SyntaxKind, literal: LiteralExpression, assumeTrue: boolean): Type { + function narrowTypeByTypeof( + type: Type, + typeOfExpr: TypeOfExpression, + operator: SyntaxKind, + literal: LiteralExpression, + assumeTrue: boolean + ): Type { // We have '==', '!=', '===', or !==' operator with 'typeof xxx' and string literal operands - if (operator === SyntaxKind.ExclamationEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken) { + if ( + operator === SyntaxKind.ExclamationEqualsToken || + operator === SyntaxKind.ExclamationEqualsEqualsToken + ) { assumeTrue = !assumeTrue; } const target = getReferenceCandidate(typeOfExpr.expression); if (!isMatchingReference(reference, target)) { - if (strictNullChecks && optionalChainContainsReference(target, reference) && assumeTrue === (literal.text !== "undefined")) { - type = getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); + if ( + strictNullChecks && + optionalChainContainsReference(target, reference) && + assumeTrue === (literal.text !== "undefined") + ) { + type = getAdjustedTypeWithFacts( + type, + TypeFacts.NEUndefinedOrNull + ); } - const propertyAccess = getDiscriminantPropertyAccess(target, type); + const propertyAccess = getDiscriminantPropertyAccess( + target, + type + ); if (propertyAccess) { - return narrowTypeByDiscriminant(type, propertyAccess, t => narrowTypeByLiteralExpression(t, literal, assumeTrue)); + return narrowTypeByDiscriminant(type, propertyAccess, (t) => + narrowTypeByLiteralExpression(t, literal, assumeTrue) + ); } return type; } return narrowTypeByLiteralExpression(type, literal, assumeTrue); } - function narrowTypeByLiteralExpression(type: Type, literal: LiteralExpression, assumeTrue: boolean) { - return assumeTrue ? - narrowTypeByTypeName(type, literal.text) : - getAdjustedTypeWithFacts(type, typeofNEFacts.get(literal.text) || TypeFacts.TypeofNEHostObject); - } - - function narrowTypeBySwitchOptionalChainContainment(type: Type, { switchStatement, clauseStart, clauseEnd }: FlowSwitchClauseData, clauseCheck: (type: Type) => boolean) { - const everyClauseChecks = clauseStart !== clauseEnd && every(getSwitchClauseTypes(switchStatement).slice(clauseStart, clauseEnd), clauseCheck); - return everyClauseChecks ? getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type; + function narrowTypeByLiteralExpression( + type: Type, + literal: LiteralExpression, + assumeTrue: boolean + ) { + return assumeTrue + ? narrowTypeByTypeName(type, literal.text) + : getAdjustedTypeWithFacts( + type, + typeofNEFacts.get(literal.text) || + TypeFacts.TypeofNEHostObject + ); + } + + function narrowTypeBySwitchOptionalChainContainment( + type: Type, + { switchStatement, clauseStart, clauseEnd }: FlowSwitchClauseData, + clauseCheck: (type: Type) => boolean + ) { + const everyClauseChecks = + clauseStart !== clauseEnd && + every( + getSwitchClauseTypes(switchStatement).slice( + clauseStart, + clauseEnd + ), + clauseCheck + ); + return everyClauseChecks + ? getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) + : type; } - function narrowTypeBySwitchOnDiscriminant(type: Type, { switchStatement, clauseStart, clauseEnd }: FlowSwitchClauseData) { + function narrowTypeBySwitchOnDiscriminant( + type: Type, + { switchStatement, clauseStart, clauseEnd }: FlowSwitchClauseData + ) { // We only narrow if all case expressions specify // values with unit types, except for the case where // `type` is unknown. In this instance we map object @@ -29642,104 +52541,221 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return type; } const clauseTypes = switchTypes.slice(clauseStart, clauseEnd); - const hasDefaultClause = clauseStart === clauseEnd || contains(clauseTypes, neverType); - if ((type.flags & TypeFlags.Unknown) && !hasDefaultClause) { + const hasDefaultClause = + clauseStart === clauseEnd || contains(clauseTypes, neverType); + if (type.flags & TypeFlags.Unknown && !hasDefaultClause) { let groundClauseTypes: Type[] | undefined; for (let i = 0; i < clauseTypes.length; i += 1) { const t = clauseTypes[i]; - if (t.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive)) { + if ( + t.flags & + (TypeFlags.Primitive | TypeFlags.NonPrimitive) + ) { if (groundClauseTypes !== undefined) { groundClauseTypes.push(t); } - } - else if (t.flags & TypeFlags.Object) { + } else if (t.flags & TypeFlags.Object) { if (groundClauseTypes === undefined) { groundClauseTypes = clauseTypes.slice(0, i); } groundClauseTypes.push(nonPrimitiveType); - } - else { + } else { return type; } } - return getUnionType(groundClauseTypes === undefined ? clauseTypes : groundClauseTypes); + return getUnionType( + groundClauseTypes === undefined + ? clauseTypes + : groundClauseTypes + ); } const discriminantType = getUnionType(clauseTypes); - const caseType = discriminantType.flags & TypeFlags.Never ? neverType : - replacePrimitivesWithLiterals(filterType(type, t => areTypesComparable(discriminantType, t)), discriminantType); + const caseType = + discriminantType.flags & TypeFlags.Never + ? neverType + : replacePrimitivesWithLiterals( + filterType(type, (t) => + areTypesComparable(discriminantType, t) + ), + discriminantType + ); if (!hasDefaultClause) { return caseType; } - const defaultType = filterType(type, t => !(isUnitLikeType(t) && contains(switchTypes, t.flags & TypeFlags.Undefined ? undefinedType : getRegularTypeOfLiteralType(extractUnitType(t))))); - return caseType.flags & TypeFlags.Never ? defaultType : getUnionType([caseType, defaultType]); + const defaultType = filterType( + type, + (t) => + !( + isUnitLikeType(t) && + contains( + switchTypes, + t.flags & TypeFlags.Undefined + ? undefinedType + : getRegularTypeOfLiteralType( + extractUnitType(t) + ) + ) + ) + ); + return caseType.flags & TypeFlags.Never + ? defaultType + : getUnionType([caseType, defaultType]); } function narrowTypeByTypeName(type: Type, typeName: string) { switch (typeName) { case "string": - return narrowTypeByTypeFacts(type, stringType, TypeFacts.TypeofEQString); + return narrowTypeByTypeFacts( + type, + stringType, + TypeFacts.TypeofEQString + ); case "number": - return narrowTypeByTypeFacts(type, numberType, TypeFacts.TypeofEQNumber); + return narrowTypeByTypeFacts( + type, + numberType, + TypeFacts.TypeofEQNumber + ); case "bigint": - return narrowTypeByTypeFacts(type, bigintType, TypeFacts.TypeofEQBigInt); + return narrowTypeByTypeFacts( + type, + bigintType, + TypeFacts.TypeofEQBigInt + ); case "boolean": - return narrowTypeByTypeFacts(type, booleanType, TypeFacts.TypeofEQBoolean); + return narrowTypeByTypeFacts( + type, + booleanType, + TypeFacts.TypeofEQBoolean + ); case "symbol": - return narrowTypeByTypeFacts(type, esSymbolType, TypeFacts.TypeofEQSymbol); + return narrowTypeByTypeFacts( + type, + esSymbolType, + TypeFacts.TypeofEQSymbol + ); case "object": - return type.flags & TypeFlags.Any ? type : getUnionType([narrowTypeByTypeFacts(type, nonPrimitiveType, TypeFacts.TypeofEQObject), narrowTypeByTypeFacts(type, nullType, TypeFacts.EQNull)]); + return type.flags & TypeFlags.Any + ? type + : getUnionType([ + narrowTypeByTypeFacts( + type, + nonPrimitiveType, + TypeFacts.TypeofEQObject + ), + narrowTypeByTypeFacts( + type, + nullType, + TypeFacts.EQNull + ), + ]); case "function": - return type.flags & TypeFlags.Any ? type : narrowTypeByTypeFacts(type, globalFunctionType, TypeFacts.TypeofEQFunction); + return type.flags & TypeFlags.Any + ? type + : narrowTypeByTypeFacts( + type, + globalFunctionType, + TypeFacts.TypeofEQFunction + ); case "undefined": - return narrowTypeByTypeFacts(type, undefinedType, TypeFacts.EQUndefined); + return narrowTypeByTypeFacts( + type, + undefinedType, + TypeFacts.EQUndefined + ); } - return narrowTypeByTypeFacts(type, nonPrimitiveType, TypeFacts.TypeofEQHostObject); + return narrowTypeByTypeFacts( + type, + nonPrimitiveType, + TypeFacts.TypeofEQHostObject + ); } - function narrowTypeByTypeFacts(type: Type, impliedType: Type, facts: TypeFacts) { - return mapType(type, t => + function narrowTypeByTypeFacts( + type: Type, + impliedType: Type, + facts: TypeFacts + ) { + return mapType(type, (t) => // We first check if a constituent is a subtype of the implied type. If so, we either keep or eliminate // the constituent based on its type facts. We use the strict subtype relation because it treats `object` // as a subtype of `{}`, and we need the type facts check because function types are subtypes of `object`, // but are classified as "function" according to `typeof`. - isTypeRelatedTo(t, impliedType, strictSubtypeRelation) ? hasTypeFacts(t, facts) ? t : neverType : - // We next check if the consituent is a supertype of the implied type. If so, we substitute the implied + isTypeRelatedTo(t, impliedType, strictSubtypeRelation) + ? hasTypeFacts(t, facts) + ? t + : neverType + : // We next check if the consituent is a supertype of the implied type. If so, we substitute the implied // type. This handles top types like `unknown` and `{}`, and supertypes like `{ toString(): string }`. - isTypeSubtypeOf(impliedType, t) ? impliedType : - // Neither the constituent nor the implied type is a subtype of the other, however their domains may still + isTypeSubtypeOf(impliedType, t) + ? impliedType + : // Neither the constituent nor the implied type is a subtype of the other, however their domains may still // overlap. For example, an unconstrained type parameter and type `string`. If the type facts indicate // possible overlap, we form an intersection. Otherwise, we eliminate the constituent. - hasTypeFacts(t, facts) ? getIntersectionType([t, impliedType]) : - neverType); + hasTypeFacts(t, facts) + ? getIntersectionType([t, impliedType]) + : neverType + ); } - function narrowTypeBySwitchOnTypeOf(type: Type, { switchStatement, clauseStart, clauseEnd }: FlowSwitchClauseData): Type { + function narrowTypeBySwitchOnTypeOf( + type: Type, + { switchStatement, clauseStart, clauseEnd }: FlowSwitchClauseData + ): Type { const witnesses = getSwitchClauseTypeOfWitnesses(switchStatement); if (!witnesses) { return type; } // Equal start and end denotes implicit fallthrough; undefined marks explicit default clause. - const defaultIndex = findIndex(switchStatement.caseBlock.clauses, clause => clause.kind === SyntaxKind.DefaultClause); - const hasDefaultClause = clauseStart === clauseEnd || (defaultIndex >= clauseStart && defaultIndex < clauseEnd); + const defaultIndex = findIndex( + switchStatement.caseBlock.clauses, + (clause) => clause.kind === SyntaxKind.DefaultClause + ); + const hasDefaultClause = + clauseStart === clauseEnd || + (defaultIndex >= clauseStart && defaultIndex < clauseEnd); if (hasDefaultClause) { // In the default clause we filter constituents down to those that are not-equal to all handled cases. - const notEqualFacts = getNotEqualFactsFromTypeofSwitch(clauseStart, clauseEnd, witnesses); - return filterType(type, t => getTypeFacts(t, notEqualFacts) === notEqualFacts); + const notEqualFacts = getNotEqualFactsFromTypeofSwitch( + clauseStart, + clauseEnd, + witnesses + ); + return filterType( + type, + (t) => getTypeFacts(t, notEqualFacts) === notEqualFacts + ); } // In the non-default cause we create a union of the type narrowed by each of the listed cases. const clauseWitnesses = witnesses.slice(clauseStart, clauseEnd); - return getUnionType(map(clauseWitnesses, text => text ? narrowTypeByTypeName(type, text) : neverType)); + return getUnionType( + map(clauseWitnesses, (text) => + text ? narrowTypeByTypeName(type, text) : neverType + ) + ); } - function narrowTypeBySwitchOnTrue(type: Type, { switchStatement, clauseStart, clauseEnd }: FlowSwitchClauseData): Type { - const defaultIndex = findIndex(switchStatement.caseBlock.clauses, clause => clause.kind === SyntaxKind.DefaultClause); - const hasDefaultClause = clauseStart === clauseEnd || (defaultIndex >= clauseStart && defaultIndex < clauseEnd); + function narrowTypeBySwitchOnTrue( + type: Type, + { switchStatement, clauseStart, clauseEnd }: FlowSwitchClauseData + ): Type { + const defaultIndex = findIndex( + switchStatement.caseBlock.clauses, + (clause) => clause.kind === SyntaxKind.DefaultClause + ); + const hasDefaultClause = + clauseStart === clauseEnd || + (defaultIndex >= clauseStart && defaultIndex < clauseEnd); // First, narrow away all of the cases that preceded this set of cases. for (let i = 0; i < clauseStart; i++) { const clause = switchStatement.caseBlock.clauses[i]; if (clause.kind === SyntaxKind.CaseClause) { - type = narrowType(type, clause.expression, /*assumeTrue*/ false); + type = narrowType( + type, + clause.expression, + /*assumeTrue*/ false + ); } } @@ -29747,48 +52763,97 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // There's no point in narrowing by the the other cases in the set, since we can // get here through other paths. if (hasDefaultClause) { - for (let i = clauseEnd; i < switchStatement.caseBlock.clauses.length; i++) { + for ( + let i = clauseEnd; + i < switchStatement.caseBlock.clauses.length; + i++ + ) { const clause = switchStatement.caseBlock.clauses[i]; if (clause.kind === SyntaxKind.CaseClause) { - type = narrowType(type, clause.expression, /*assumeTrue*/ false); + type = narrowType( + type, + clause.expression, + /*assumeTrue*/ false + ); } } return type; } // Now, narrow based on the cases in this set. - const clauses = switchStatement.caseBlock.clauses.slice(clauseStart, clauseEnd); - return getUnionType(map(clauses, clause => clause.kind === SyntaxKind.CaseClause ? narrowType(type, clause.expression, /*assumeTrue*/ true) : neverType)); + const clauses = switchStatement.caseBlock.clauses.slice( + clauseStart, + clauseEnd + ); + return getUnionType( + map(clauses, (clause) => + clause.kind === SyntaxKind.CaseClause + ? narrowType( + type, + clause.expression, + /*assumeTrue*/ true + ) + : neverType + ) + ); } function isMatchingConstructorReference(expr: Expression) { - return (isPropertyAccessExpression(expr) && idText(expr.name) === "constructor" || - isElementAccessExpression(expr) && isStringLiteralLike(expr.argumentExpression) && expr.argumentExpression.text === "constructor") && - isMatchingReference(reference, expr.expression); + return ( + ((isPropertyAccessExpression(expr) && + idText(expr.name) === "constructor") || + (isElementAccessExpression(expr) && + isStringLiteralLike(expr.argumentExpression) && + expr.argumentExpression.text === "constructor")) && + isMatchingReference(reference, expr.expression) + ); } - function narrowTypeByConstructor(type: Type, operator: SyntaxKind, identifier: Expression, assumeTrue: boolean): Type { + function narrowTypeByConstructor( + type: Type, + operator: SyntaxKind, + identifier: Expression, + assumeTrue: boolean + ): Type { // Do not narrow when checking inequality. - if (assumeTrue ? (operator !== SyntaxKind.EqualsEqualsToken && operator !== SyntaxKind.EqualsEqualsEqualsToken) : (operator !== SyntaxKind.ExclamationEqualsToken && operator !== SyntaxKind.ExclamationEqualsEqualsToken)) { + if ( + assumeTrue + ? operator !== SyntaxKind.EqualsEqualsToken && + operator !== SyntaxKind.EqualsEqualsEqualsToken + : operator !== SyntaxKind.ExclamationEqualsToken && + operator !== SyntaxKind.ExclamationEqualsEqualsToken + ) { return type; } // Get the type of the constructor identifier expression, if it is not a function then do not narrow. const identifierType = getTypeOfExpression(identifier); - if (!isFunctionType(identifierType) && !isConstructorType(identifierType)) { + if ( + !isFunctionType(identifierType) && + !isConstructorType(identifierType) + ) { return type; } // Get the prototype property of the type identifier so we can find out its type. - const prototypeProperty = getPropertyOfType(identifierType, "prototype" as __String); + const prototypeProperty = getPropertyOfType( + identifierType, + "prototype" as __String + ); if (!prototypeProperty) { return type; } // Get the type of the prototype, if it is undefined, or the global `Object` or `Function` types then do not narrow. const prototypeType = getTypeOfSymbol(prototypeProperty); - const candidate = !isTypeAny(prototypeType) ? prototypeType : undefined; - if (!candidate || candidate === globalObjectType || candidate === globalFunctionType) { + const candidate = !isTypeAny(prototypeType) + ? prototypeType + : undefined; + if ( + !candidate || + candidate === globalObjectType || + candidate === globalFunctionType + ) { return type; } @@ -29798,7 +52863,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Filter out types that are not considered to be "constructed by" the `candidate` type. - return filterType(type, t => isConstructedBy(t, candidate)); + return filterType(type, (t) => isConstructedBy(t, candidate)); function isConstructedBy(source: Type, target: Type) { // If either the source or target type are a class type then we need to check that they are the same exact type. @@ -29806,8 +52871,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // that defines the same set of properties as class `A`, in that case they are structurally the same // type, but when you do something like `instanceOfA.constructor === B` it will return false. if ( - source.flags & TypeFlags.Object && getObjectFlags(source) & ObjectFlags.Class || - target.flags & TypeFlags.Object && getObjectFlags(target) & ObjectFlags.Class + (source.flags & TypeFlags.Object && + getObjectFlags(source) & ObjectFlags.Class) || + (target.flags & TypeFlags.Object && + getObjectFlags(target) & ObjectFlags.Class) ) { return source.symbol === target.symbol; } @@ -29817,11 +52884,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function narrowTypeByInstanceof(type: Type, expr: InstanceofExpression, assumeTrue: boolean): Type { + function narrowTypeByInstanceof( + type: Type, + expr: InstanceofExpression, + assumeTrue: boolean + ): Type { const left = getReferenceCandidate(expr.left); if (!isMatchingReference(reference, left)) { - if (assumeTrue && strictNullChecks && optionalChainContainsReference(left, reference)) { - return getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); + if ( + assumeTrue && + strictNullChecks && + optionalChainContainsReference(left, reference) + ) { + return getAdjustedTypeWithFacts( + type, + TypeFacts.NEUndefinedOrNull + ); } return type; } @@ -29835,9 +52913,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // has a type predicate, use the type predicate to perform narrowing. This allows normal `object` types to // participate in `instanceof`, as per Step 2 of https://tc39.es/ecma262/#sec-instanceofoperator. const signature = getEffectsSignature(expr); - const predicate = signature && getTypePredicateOfSignature(signature); - if (predicate && predicate.kind === TypePredicateKind.Identifier && predicate.parameterIndex === 0) { - return getNarrowedType(type, predicate.type, assumeTrue, /*checkDerived*/ true); + const predicate = + signature && getTypePredicateOfSignature(signature); + if ( + predicate && + predicate.kind === TypePredicateKind.Identifier && + predicate.parameterIndex === 0 + ) { + return getNarrowedType( + type, + predicate.type, + assumeTrue, + /*checkDerived*/ true + ); } if (!isTypeDerivedFrom(rightType, globalFunctionType)) { return type; @@ -29846,44 +52934,101 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Don't narrow from `any` if the target type is exactly `Object` or `Function`, and narrow // in the false branch only if the target is a non-empty object type. if ( - isTypeAny(type) && (instanceType === globalObjectType || instanceType === globalFunctionType) || - !assumeTrue && !(instanceType.flags & TypeFlags.Object && !isEmptyAnonymousObjectType(instanceType)) + (isTypeAny(type) && + (instanceType === globalObjectType || + instanceType === globalFunctionType)) || + (!assumeTrue && + !( + instanceType.flags & TypeFlags.Object && + !isEmptyAnonymousObjectType(instanceType) + )) ) { return type; } - return getNarrowedType(type, instanceType, assumeTrue, /*checkDerived*/ true); + return getNarrowedType( + type, + instanceType, + assumeTrue, + /*checkDerived*/ true + ); } function getInstanceType(constructorType: Type) { - const prototypePropertyType = getTypeOfPropertyOfType(constructorType, "prototype" as __String); + const prototypePropertyType = getTypeOfPropertyOfType( + constructorType, + "prototype" as __String + ); if (prototypePropertyType && !isTypeAny(prototypePropertyType)) { return prototypePropertyType; } - const constructSignatures = getSignaturesOfType(constructorType, SignatureKind.Construct); + const constructSignatures = getSignaturesOfType( + constructorType, + SignatureKind.Construct + ); if (constructSignatures.length) { - return getUnionType(map(constructSignatures, signature => getReturnTypeOfSignature(getErasedSignature(signature)))); + return getUnionType( + map(constructSignatures, (signature) => + getReturnTypeOfSignature(getErasedSignature(signature)) + ) + ); } // We use the empty object type to indicate we don't know the type of objects created by // this constructor function. return emptyObjectType; } - function getNarrowedType(type: Type, candidate: Type, assumeTrue: boolean, checkDerived: boolean): Type { - const key = type.flags & TypeFlags.Union ? `N${getTypeId(type)},${getTypeId(candidate)},${(assumeTrue ? 1 : 0) | (checkDerived ? 2 : 0)}` : undefined; - return getCachedType(key) ?? setCachedType(key, getNarrowedTypeWorker(type, candidate, assumeTrue, checkDerived)); + function getNarrowedType( + type: Type, + candidate: Type, + assumeTrue: boolean, + checkDerived: boolean + ): Type { + const key = + type.flags & TypeFlags.Union + ? `N${getTypeId(type)},${getTypeId(candidate)},${ + (assumeTrue ? 1 : 0) | (checkDerived ? 2 : 0) + }` + : undefined; + return ( + getCachedType(key) ?? + setCachedType( + key, + getNarrowedTypeWorker( + type, + candidate, + assumeTrue, + checkDerived + ) + ) + ); } - function getNarrowedTypeWorker(type: Type, candidate: Type, assumeTrue: boolean, checkDerived: boolean) { + function getNarrowedTypeWorker( + type: Type, + candidate: Type, + assumeTrue: boolean, + checkDerived: boolean + ) { if (!assumeTrue) { if (type === candidate) { return neverType; } if (checkDerived) { - return filterType(type, t => !isTypeDerivedFrom(t, candidate)); + return filterType( + type, + (t) => !isTypeDerivedFrom(t, candidate) + ); } type = type.flags & TypeFlags.Unknown ? unknownUnionType : type; - const trueType = getNarrowedType(type, candidate, /*assumeTrue*/ true, /*checkDerived*/ false); - return recombineUnknownType(filterType(type, t => !isTypeSubsetOf(t, trueType))); + const trueType = getNarrowedType( + type, + candidate, + /*assumeTrue*/ true, + /*checkDerived*/ false + ); + return recombineUnknownType( + filterType(type, (t) => !isTypeSubsetOf(t, trueType)) + ); } if (type.flags & TypeFlags.AnyOrUnknown) { return candidate; @@ -29894,80 +53039,193 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We first attempt to filter the current type, narrowing constituents as appropriate and removing // constituents that are unrelated to the candidate. - const isRelated = checkDerived ? isTypeDerivedFrom : isTypeSubtypeOf; - const keyPropertyName = type.flags & TypeFlags.Union ? getKeyPropertyName(type as UnionType) : undefined; - const narrowedType = mapType(candidate, c => { + const isRelated = checkDerived + ? isTypeDerivedFrom + : isTypeSubtypeOf; + const keyPropertyName = + type.flags & TypeFlags.Union + ? getKeyPropertyName(type as UnionType) + : undefined; + const narrowedType = mapType(candidate, (c) => { // If a discriminant property is available, use that to reduce the type. - const discriminant = keyPropertyName && getTypeOfPropertyOfType(c, keyPropertyName); - const matching = discriminant && getConstituentTypeForKeyType(type as UnionType, discriminant); + const discriminant = + keyPropertyName && + getTypeOfPropertyOfType(c, keyPropertyName); + const matching = + discriminant && + getConstituentTypeForKeyType( + type as UnionType, + discriminant + ); // For each constituent t in the current type, if t and and c are directly related, pick the most // specific of the two. When t and c are related in both directions, we prefer c for type predicates // because that is the asserted type, but t for `instanceof` because generics aren't reflected in // prototype object types. const directlyRelated = mapType( matching || type, - checkDerived ? - t => isTypeDerivedFrom(t, c) ? t : isTypeDerivedFrom(c, t) ? c : neverType : - t => isTypeStrictSubtypeOf(t, c) ? t : isTypeStrictSubtypeOf(c, t) ? c : isTypeSubtypeOf(t, c) ? t : isTypeSubtypeOf(c, t) ? c : neverType, + checkDerived + ? (t) => + isTypeDerivedFrom(t, c) + ? t + : isTypeDerivedFrom(c, t) + ? c + : neverType + : (t) => + isTypeStrictSubtypeOf(t, c) + ? t + : isTypeStrictSubtypeOf(c, t) + ? c + : isTypeSubtypeOf(t, c) + ? t + : isTypeSubtypeOf(c, t) + ? c + : neverType ); // If no constituents are directly related, create intersections for any generic constituents that // are related by constraint. - return directlyRelated.flags & TypeFlags.Never ? - mapType(type, t => maybeTypeOfKind(t, TypeFlags.Instantiable) && isRelated(c, getBaseConstraintOfType(t) || unknownType) ? getIntersectionType([t, c]) : neverType) : - directlyRelated; + return directlyRelated.flags & TypeFlags.Never + ? mapType(type, (t) => + maybeTypeOfKind(t, TypeFlags.Instantiable) && + isRelated( + c, + getBaseConstraintOfType(t) || unknownType + ) + ? getIntersectionType([t, c]) + : neverType + ) + : directlyRelated; }); // If filtering produced a non-empty type, return that. Otherwise, pick the most specific of the two // based on assignability, or as a last resort produce an intersection. - return !(narrowedType.flags & TypeFlags.Never) ? narrowedType : - isTypeSubtypeOf(candidate, type) ? candidate : - isTypeAssignableTo(type, candidate) ? type : - isTypeAssignableTo(candidate, type) ? candidate : - getIntersectionType([type, candidate]); - } - - function narrowTypeByCallExpression(type: Type, callExpression: CallExpression, assumeTrue: boolean): Type { + return !(narrowedType.flags & TypeFlags.Never) + ? narrowedType + : isTypeSubtypeOf(candidate, type) + ? candidate + : isTypeAssignableTo(type, candidate) + ? type + : isTypeAssignableTo(candidate, type) + ? candidate + : getIntersectionType([type, candidate]); + } + + function narrowTypeByCallExpression( + type: Type, + callExpression: CallExpression, + assumeTrue: boolean + ): Type { if (hasMatchingArgument(callExpression, reference)) { - const signature = assumeTrue || !isCallChain(callExpression) ? getEffectsSignature(callExpression) : undefined; - const predicate = signature && getTypePredicateOfSignature(signature); - if (predicate && (predicate.kind === TypePredicateKind.This || predicate.kind === TypePredicateKind.Identifier)) { - return narrowTypeByTypePredicate(type, predicate, callExpression, assumeTrue); + const signature = + assumeTrue || !isCallChain(callExpression) + ? getEffectsSignature(callExpression) + : undefined; + const predicate = + signature && getTypePredicateOfSignature(signature); + if ( + predicate && + (predicate.kind === TypePredicateKind.This || + predicate.kind === TypePredicateKind.Identifier) + ) { + return narrowTypeByTypePredicate( + type, + predicate, + callExpression, + assumeTrue + ); } } - if (containsMissingType(type) && isAccessExpression(reference) && isPropertyAccessExpression(callExpression.expression)) { + if ( + containsMissingType(type) && + isAccessExpression(reference) && + isPropertyAccessExpression(callExpression.expression) + ) { const callAccess = callExpression.expression; if ( - isMatchingReference(reference.expression, getReferenceCandidate(callAccess.expression)) && - isIdentifier(callAccess.name) && callAccess.name.escapedText === "hasOwnProperty" && callExpression.arguments.length === 1 + isMatchingReference( + reference.expression, + getReferenceCandidate(callAccess.expression) + ) && + isIdentifier(callAccess.name) && + callAccess.name.escapedText === "hasOwnProperty" && + callExpression.arguments.length === 1 ) { const argument = callExpression.arguments[0]; - if (isStringLiteralLike(argument) && getAccessedPropertyName(reference) === escapeLeadingUnderscores(argument.text)) { - return getTypeWithFacts(type, assumeTrue ? TypeFacts.NEUndefined : TypeFacts.EQUndefined); + if ( + isStringLiteralLike(argument) && + getAccessedPropertyName(reference) === + escapeLeadingUnderscores(argument.text) + ) { + return getTypeWithFacts( + type, + assumeTrue + ? TypeFacts.NEUndefined + : TypeFacts.EQUndefined + ); } } } return type; } - function narrowTypeByTypePredicate(type: Type, predicate: TypePredicate, callExpression: CallExpression, assumeTrue: boolean): Type { + function narrowTypeByTypePredicate( + type: Type, + predicate: TypePredicate, + callExpression: CallExpression, + assumeTrue: boolean + ): Type { // Don't narrow from 'any' if the predicate type is exactly 'Object' or 'Function' - if (predicate.type && !(isTypeAny(type) && (predicate.type === globalObjectType || predicate.type === globalFunctionType))) { - const predicateArgument = getTypePredicateArgument(predicate, callExpression); + if ( + predicate.type && + !( + isTypeAny(type) && + (predicate.type === globalObjectType || + predicate.type === globalFunctionType) + ) + ) { + const predicateArgument = getTypePredicateArgument( + predicate, + callExpression + ); if (predicateArgument) { if (isMatchingReference(reference, predicateArgument)) { - return getNarrowedType(type, predicate.type, assumeTrue, /*checkDerived*/ false); + return getNarrowedType( + type, + predicate.type, + assumeTrue, + /*checkDerived*/ false + ); } if ( - strictNullChecks && optionalChainContainsReference(predicateArgument, reference) && - ( - assumeTrue && !(hasTypeFacts(predicate.type, TypeFacts.EQUndefined)) || - !assumeTrue && everyType(predicate.type, isNullableType) - ) + strictNullChecks && + optionalChainContainsReference( + predicateArgument, + reference + ) && + ((assumeTrue && + !hasTypeFacts( + predicate.type, + TypeFacts.EQUndefined + )) || + (!assumeTrue && + everyType(predicate.type, isNullableType))) ) { - type = getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); + type = getAdjustedTypeWithFacts( + type, + TypeFacts.NEUndefinedOrNull + ); } - const access = getDiscriminantPropertyAccess(predicateArgument, type); + const access = getDiscriminantPropertyAccess( + predicateArgument, + type + ); if (access) { - return narrowTypeByDiscriminant(type, access, t => getNarrowedType(t, predicate.type!, assumeTrue, /*checkDerived*/ false)); + return narrowTypeByDiscriminant(type, access, (t) => + getNarrowedType( + t, + predicate.type!, + assumeTrue, + /*checkDerived*/ false + ) + ); } } } @@ -29976,11 +53234,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Narrow the given type based on the given expression having the assumed boolean value. The returned type // will be a subtype or the same type as the argument. - function narrowType(type: Type, expr: Expression, assumeTrue: boolean): Type { + function narrowType( + type: Type, + expr: Expression, + assumeTrue: boolean + ): Type { // for `a?.b`, we emulate a synthetic `a !== null && a !== undefined` condition for `a` if ( isExpressionOfOptionalChainRoot(expr) || - isBinaryExpression(expr.parent) && (expr.parent.operatorToken.kind === SyntaxKind.QuestionQuestionToken || expr.parent.operatorToken.kind === SyntaxKind.QuestionQuestionEqualsToken) && expr.parent.left === expr + (isBinaryExpression(expr.parent) && + (expr.parent.operatorToken.kind === + SyntaxKind.QuestionQuestionToken || + expr.parent.operatorToken.kind === + SyntaxKind.QuestionQuestionEqualsToken) && + expr.parent.left === expr) ) { return narrowTypeByOptionality(type, expr, assumeTrue); } @@ -29988,48 +53255,101 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.Identifier: // When narrowing a reference to a const variable, non-assigned parameter, or readonly property, we inline // up to five levels of aliased conditional expressions that are themselves declared as const variables. - if (!isMatchingReference(reference, expr) && inlineLevel < 5) { + if ( + !isMatchingReference(reference, expr) && + inlineLevel < 5 + ) { const symbol = getResolvedSymbol(expr as Identifier); if (isConstantVariable(symbol)) { const declaration = symbol.valueDeclaration; - if (declaration && isVariableDeclaration(declaration) && !declaration.type && declaration.initializer && isConstantReference(reference)) { + if ( + declaration && + isVariableDeclaration(declaration) && + !declaration.type && + declaration.initializer && + isConstantReference(reference) + ) { inlineLevel++; - const result = narrowType(type, declaration.initializer, assumeTrue); + const result = narrowType( + type, + declaration.initializer, + assumeTrue + ); inlineLevel--; return result; } } } - // falls through + // falls through case SyntaxKind.ThisKeyword: case SyntaxKind.SuperKeyword: case SyntaxKind.PropertyAccessExpression: case SyntaxKind.ElementAccessExpression: return narrowTypeByTruthiness(type, expr, assumeTrue); case SyntaxKind.CallExpression: - return narrowTypeByCallExpression(type, expr as CallExpression, assumeTrue); + return narrowTypeByCallExpression( + type, + expr as CallExpression, + assumeTrue + ); case SyntaxKind.ParenthesizedExpression: case SyntaxKind.NonNullExpression: case SyntaxKind.SatisfiesExpression: - return narrowType(type, (expr as ParenthesizedExpression | NonNullExpression | SatisfiesExpression).expression, assumeTrue); + return narrowType( + type, + ( + expr as + | ParenthesizedExpression + | NonNullExpression + | SatisfiesExpression + ).expression, + assumeTrue + ); case SyntaxKind.BinaryExpression: - return narrowTypeByBinaryExpression(type, expr as BinaryExpression, assumeTrue); + return narrowTypeByBinaryExpression( + type, + expr as BinaryExpression, + assumeTrue + ); case SyntaxKind.PrefixUnaryExpression: - if ((expr as PrefixUnaryExpression).operator === SyntaxKind.ExclamationToken) { - return narrowType(type, (expr as PrefixUnaryExpression).operand, !assumeTrue); + if ( + (expr as PrefixUnaryExpression).operator === + SyntaxKind.ExclamationToken + ) { + return narrowType( + type, + (expr as PrefixUnaryExpression).operand, + !assumeTrue + ); } break; } return type; } - function narrowTypeByOptionality(type: Type, expr: Expression, assumePresent: boolean): Type { + function narrowTypeByOptionality( + type: Type, + expr: Expression, + assumePresent: boolean + ): Type { if (isMatchingReference(reference, expr)) { - return getAdjustedTypeWithFacts(type, assumePresent ? TypeFacts.NEUndefinedOrNull : TypeFacts.EQUndefinedOrNull); + return getAdjustedTypeWithFacts( + type, + assumePresent + ? TypeFacts.NEUndefinedOrNull + : TypeFacts.EQUndefinedOrNull + ); } const access = getDiscriminantPropertyAccess(expr, type); if (access) { - return narrowTypeByDiscriminant(type, access, t => getTypeWithFacts(t, assumePresent ? TypeFacts.NEUndefinedOrNull : TypeFacts.EQUndefinedOrNull)); + return narrowTypeByDiscriminant(type, access, (t) => + getTypeWithFacts( + t, + assumePresent + ? TypeFacts.NEUndefinedOrNull + : TypeFacts.EQUndefinedOrNull + ) + ); } return type; } @@ -30042,22 +53362,41 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // an dotted name expression, and if the location is not an assignment target, obtain the type // of the expression (which will reflect control flow analysis). If the expression indeed // resolved to the given symbol, return the narrowed type. - if (location.kind === SyntaxKind.Identifier || location.kind === SyntaxKind.PrivateIdentifier) { + if ( + location.kind === SyntaxKind.Identifier || + location.kind === SyntaxKind.PrivateIdentifier + ) { if (isRightSideOfQualifiedNameOrPropertyAccess(location)) { location = location.parent; } - if (isExpressionNode(location) && (!isAssignmentTarget(location) || isWriteAccess(location))) { + if ( + isExpressionNode(location) && + (!isAssignmentTarget(location) || isWriteAccess(location)) + ) { const type = removeOptionalTypeMarker( - isWriteAccess(location) && location.kind === SyntaxKind.PropertyAccessExpression ? - checkPropertyAccessExpression(location as PropertyAccessExpression, /*checkMode*/ undefined, /*writeOnly*/ true) : - getTypeOfExpression(location as Expression), + isWriteAccess(location) && + location.kind === SyntaxKind.PropertyAccessExpression + ? checkPropertyAccessExpression( + location as PropertyAccessExpression, + /*checkMode*/ undefined, + /*writeOnly*/ true + ) + : getTypeOfExpression(location as Expression) ); - if (getExportSymbolOfValueSymbolIfExported(getNodeLinks(location).resolvedSymbol) === symbol) { + if ( + getExportSymbolOfValueSymbolIfExported( + getNodeLinks(location).resolvedSymbol + ) === symbol + ) { return type; } } } - if (isDeclarationName(location) && isSetAccessor(location.parent) && getAnnotatedAccessorTypeNode(location.parent)) { + if ( + isDeclarationName(location) && + isSetAccessor(location.parent) && + getAnnotatedAccessorTypeNode(location.parent) + ) { return getWriteTypeOfAccessors(location.parent.symbol); } // The location isn't a reference to the given symbol, meaning we're being asked @@ -30065,15 +53404,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // to it at the given location. Since we have no control flow information for the // hypothetical reference (control flow information is created and attached by the // binder), we simply return the declared type of the symbol. - return isRightSideOfAccessExpression(location) && isWriteAccess(location.parent) ? getWriteTypeOfSymbol(symbol) : getNonMissingTypeOfSymbol(symbol); + return isRightSideOfAccessExpression(location) && + isWriteAccess(location.parent) + ? getWriteTypeOfSymbol(symbol) + : getNonMissingTypeOfSymbol(symbol); } function getControlFlowContainer(node: Node): Node { - return findAncestor(node.parent, node => - isFunctionLike(node) && !getImmediatelyInvokedFunctionExpression(node) || - node.kind === SyntaxKind.ModuleBlock || - node.kind === SyntaxKind.SourceFile || - node.kind === SyntaxKind.PropertyDeclaration)!; + return findAncestor( + node.parent, + (node) => + (isFunctionLike(node) && + !getImmediatelyInvokedFunctionExpression(node)) || + node.kind === SyntaxKind.ModuleBlock || + node.kind === SyntaxKind.SourceFile || + node.kind === SyntaxKind.PropertyDeclaration + )!; } // Check if a parameter, catch variable, or mutable local variable is assigned anywhere definitely @@ -30081,7 +53427,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (symbol.lastAssignmentPos !== undefined) { return symbol.lastAssignmentPos < 0; } - return isSymbolAssigned(symbol) && symbol.lastAssignmentPos !== undefined && symbol.lastAssignmentPos < 0; + return ( + isSymbolAssigned(symbol) && + symbol.lastAssignmentPos !== undefined && + symbol.lastAssignmentPos < 0 + ); } // Check if a parameter, catch variable, or mutable local variable is assigned anywhere @@ -30092,7 +53442,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Return true if there are no assignments to the given symbol or if the given location // is past the last assignment to the symbol. function isPastLastAssignment(symbol: Symbol, location: Node | undefined) { - const parent = findAncestor(symbol.valueDeclaration, isFunctionOrSourceFile); + const parent = findAncestor( + symbol.valueDeclaration, + isFunctionOrSourceFile + ); if (!parent) { return false; } @@ -30103,25 +53456,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { markNodeAssignments(parent); } } - return !symbol.lastAssignmentPos || location && Math.abs(symbol.lastAssignmentPos) < location.pos; + return ( + !symbol.lastAssignmentPos || + (location && Math.abs(symbol.lastAssignmentPos) < location.pos) + ); } // Check if a parameter or catch variable (or their bindings elements) is assigned anywhere function isSomeSymbolAssigned(rootDeclaration: Node) { - Debug.assert(isVariableDeclaration(rootDeclaration) || isParameter(rootDeclaration)); + Debug.assert( + isVariableDeclaration(rootDeclaration) || + isParameter(rootDeclaration) + ); return isSomeSymbolAssignedWorker(rootDeclaration.name); } function isSomeSymbolAssignedWorker(node: BindingName): boolean { if (node.kind === SyntaxKind.Identifier) { - return isSymbolAssigned(getSymbolOfDeclaration(node.parent as Declaration)); + return isSymbolAssigned( + getSymbolOfDeclaration(node.parent as Declaration) + ); } - return some(node.elements, e => e.kind !== SyntaxKind.OmittedExpression && isSomeSymbolAssignedWorker(e.name)); + return some( + node.elements, + (e) => + e.kind !== SyntaxKind.OmittedExpression && + isSomeSymbolAssignedWorker(e.name) + ); } function hasParentWithAssignmentsMarked(node: Node) { - return !!findAncestor(node.parent, node => isFunctionOrSourceFile(node) && !!(getNodeLinks(node).flags & NodeCheckFlags.AssignmentsMarked)); + return !!findAncestor( + node.parent, + (node) => + isFunctionOrSourceFile(node) && + !!(getNodeLinks(node).flags & NodeCheckFlags.AssignmentsMarked) + ); } function isFunctionOrSourceFile(node: Node) { @@ -30140,26 +53511,65 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const assigmentTarget = getAssignmentTargetKind(node); if (assigmentTarget !== AssignmentKind.None) { const symbol = getResolvedSymbol(node as Identifier); - const hasDefiniteAssignment = assigmentTarget === AssignmentKind.Definite || (symbol.lastAssignmentPos !== undefined && symbol.lastAssignmentPos < 0); + const hasDefiniteAssignment = + assigmentTarget === AssignmentKind.Definite || + (symbol.lastAssignmentPos !== undefined && + symbol.lastAssignmentPos < 0); if (isParameterOrMutableLocalVariable(symbol)) { - if (symbol.lastAssignmentPos === undefined || Math.abs(symbol.lastAssignmentPos) !== Number.MAX_VALUE) { - const referencingFunction = findAncestor(node, isFunctionOrSourceFile); - const declaringFunction = findAncestor(symbol.valueDeclaration, isFunctionOrSourceFile); - symbol.lastAssignmentPos = referencingFunction === declaringFunction ? extendAssignmentPosition(node, symbol.valueDeclaration!) : Number.MAX_VALUE; + if ( + symbol.lastAssignmentPos === undefined || + Math.abs(symbol.lastAssignmentPos) !== + Number.MAX_VALUE + ) { + const referencingFunction = findAncestor( + node, + isFunctionOrSourceFile + ); + const declaringFunction = findAncestor( + symbol.valueDeclaration, + isFunctionOrSourceFile + ); + symbol.lastAssignmentPos = + referencingFunction === declaringFunction + ? extendAssignmentPosition( + node, + symbol.valueDeclaration! + ) + : Number.MAX_VALUE; } - if (hasDefiniteAssignment && symbol.lastAssignmentPos > 0) { + if ( + hasDefiniteAssignment && + symbol.lastAssignmentPos > 0 + ) { symbol.lastAssignmentPos *= -1; } } } return; case SyntaxKind.ExportSpecifier: - const exportDeclaration = (node as ExportSpecifier).parent.parent; - const name = (node as ExportSpecifier).propertyName || (node as ExportSpecifier).name; - if (!(node as ExportSpecifier).isTypeOnly && !exportDeclaration.isTypeOnly && !exportDeclaration.moduleSpecifier && name.kind !== SyntaxKind.StringLiteral) { - const symbol = resolveEntityName(name, SymbolFlags.Value, /*ignoreErrors*/ true, /*dontResolveAlias*/ true); + const exportDeclaration = (node as ExportSpecifier).parent + .parent; + const name = + (node as ExportSpecifier).propertyName || + (node as ExportSpecifier).name; + if ( + !(node as ExportSpecifier).isTypeOnly && + !exportDeclaration.isTypeOnly && + !exportDeclaration.moduleSpecifier && + name.kind !== SyntaxKind.StringLiteral + ) { + const symbol = resolveEntityName( + name, + SymbolFlags.Value, + /*ignoreErrors*/ true, + /*dontResolveAlias*/ true + ); if (symbol && isParameterOrMutableLocalVariable(symbol)) { - const sign = symbol.lastAssignmentPos !== undefined && symbol.lastAssignmentPos < 0 ? -1 : 1; + const sign = + symbol.lastAssignmentPos !== undefined && + symbol.lastAssignmentPos < 0 + ? -1 + : 1; symbol.lastAssignmentPos = sign * Number.MAX_VALUE; } } @@ -30202,36 +53612,62 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isConstantVariable(symbol: Symbol) { - return symbol.flags & SymbolFlags.Variable && (getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Constant) !== 0; + return ( + symbol.flags & SymbolFlags.Variable && + (getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Constant) !== + 0 + ); } function isParameterOrMutableLocalVariable(symbol: Symbol) { // Return true if symbol is a parameter, a catch clause variable, or a mutable local variable - const declaration = symbol.valueDeclaration && getRootDeclaration(symbol.valueDeclaration); - return !!declaration && ( - isParameter(declaration) || - isVariableDeclaration(declaration) && (isCatchClause(declaration.parent) || isMutableLocalVariableDeclaration(declaration)) + const declaration = + symbol.valueDeclaration && + getRootDeclaration(symbol.valueDeclaration); + return ( + !!declaration && + (isParameter(declaration) || + (isVariableDeclaration(declaration) && + (isCatchClause(declaration.parent) || + isMutableLocalVariableDeclaration(declaration)))) ); } - function isMutableLocalVariableDeclaration(declaration: VariableDeclaration) { + function isMutableLocalVariableDeclaration( + declaration: VariableDeclaration + ) { // Return true if symbol is a non-exported and non-global `let` variable - return !!(declaration.parent.flags & NodeFlags.Let) && !( - getCombinedModifierFlags(declaration) & ModifierFlags.Export || - declaration.parent.parent.kind === SyntaxKind.VariableStatement && isGlobalSourceFile(declaration.parent.parent.parent) + return ( + !!(declaration.parent.flags & NodeFlags.Let) && + !( + getCombinedModifierFlags(declaration) & ModifierFlags.Export || + (declaration.parent.parent.kind === + SyntaxKind.VariableStatement && + isGlobalSourceFile(declaration.parent.parent.parent)) + ) ); } - function parameterInitializerContainsUndefined(declaration: ParameterDeclaration): boolean { + function parameterInitializerContainsUndefined( + declaration: ParameterDeclaration + ): boolean { const links = getNodeLinks(declaration); if (links.parameterInitializerContainsUndefined === undefined) { - if (!pushTypeResolution(declaration, TypeSystemPropertyName.ParameterInitializerContainsUndefined)) { + if ( + !pushTypeResolution( + declaration, + TypeSystemPropertyName.ParameterInitializerContainsUndefined + ) + ) { reportCircularityError(declaration.symbol); return true; } - const containsUndefined = !!(hasTypeFacts(checkDeclarationInitializer(declaration, CheckMode.Normal), TypeFacts.IsUndefined)); + const containsUndefined = !!hasTypeFacts( + checkDeclarationInitializer(declaration, CheckMode.Normal), + TypeFacts.IsUndefined + ); if (!popTypeResolution()) { reportCircularityError(declaration.symbol); @@ -30245,14 +53681,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } /** remove undefined from the annotated type of a parameter when there is an initializer (that doesn't include undefined) */ - function removeOptionalityFromDeclaredType(declaredType: Type, declaration: VariableLikeDeclaration): Type { - const removeUndefined = strictNullChecks && + function removeOptionalityFromDeclaredType( + declaredType: Type, + declaration: VariableLikeDeclaration + ): Type { + const removeUndefined = + strictNullChecks && declaration.kind === SyntaxKind.Parameter && declaration.initializer && hasTypeFacts(declaredType, TypeFacts.IsUndefined) && !parameterInitializerContainsUndefined(declaration); - return removeUndefined ? getTypeWithFacts(declaredType, TypeFacts.NEUndefined) : declaredType; + return removeUndefined + ? getTypeWithFacts(declaredType, TypeFacts.NEUndefined) + : declaredType; } function isConstraintPosition(type: Type, node: Node) { @@ -30260,40 +53702,83 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // In an element access obj[x], we consider obj to be in a constraint position, except when obj is of // a generic type without a nullable constraint and x is a generic type. This is because when both obj // and x are of generic types T and K, we want the resulting type to be T[K]. - return parent.kind === SyntaxKind.PropertyAccessExpression || + return ( + parent.kind === SyntaxKind.PropertyAccessExpression || parent.kind === SyntaxKind.QualifiedName || - parent.kind === SyntaxKind.CallExpression && (parent as CallExpression).expression === node || - parent.kind === SyntaxKind.NewExpression && (parent as NewExpression).expression === node || - parent.kind === SyntaxKind.ElementAccessExpression && (parent as ElementAccessExpression).expression === node && - !(someType(type, isGenericTypeWithoutNullableConstraint) && isGenericIndexType(getTypeOfExpression((parent as ElementAccessExpression).argumentExpression))); + (parent.kind === SyntaxKind.CallExpression && + (parent as CallExpression).expression === node) || + (parent.kind === SyntaxKind.NewExpression && + (parent as NewExpression).expression === node) || + (parent.kind === SyntaxKind.ElementAccessExpression && + (parent as ElementAccessExpression).expression === node && + !( + someType(type, isGenericTypeWithoutNullableConstraint) && + isGenericIndexType( + getTypeOfExpression( + (parent as ElementAccessExpression) + .argumentExpression + ) + ) + )) + ); } function isGenericTypeWithUnionConstraint(type: Type): boolean { - return type.flags & TypeFlags.Intersection ? - some((type as IntersectionType).types, isGenericTypeWithUnionConstraint) : - !!(type.flags & TypeFlags.Instantiable && getBaseConstraintOrType(type).flags & (TypeFlags.Nullable | TypeFlags.Union)); + return type.flags & TypeFlags.Intersection + ? some( + (type as IntersectionType).types, + isGenericTypeWithUnionConstraint + ) + : !!( + type.flags & TypeFlags.Instantiable && + getBaseConstraintOrType(type).flags & + (TypeFlags.Nullable | TypeFlags.Union) + ); } function isGenericTypeWithoutNullableConstraint(type: Type): boolean { - return type.flags & TypeFlags.Intersection ? - some((type as IntersectionType).types, isGenericTypeWithoutNullableConstraint) : - !!(type.flags & TypeFlags.Instantiable && !maybeTypeOfKind(getBaseConstraintOrType(type), TypeFlags.Nullable)); + return type.flags & TypeFlags.Intersection + ? some( + (type as IntersectionType).types, + isGenericTypeWithoutNullableConstraint + ) + : !!( + type.flags & TypeFlags.Instantiable && + !maybeTypeOfKind( + getBaseConstraintOrType(type), + TypeFlags.Nullable + ) + ); } - function hasContextualTypeWithNoGenericTypes(node: Node, checkMode: CheckMode | undefined) { + function hasContextualTypeWithNoGenericTypes( + node: Node, + checkMode: CheckMode | undefined + ) { // Computing the contextual type for a child of a JSX element involves resolving the type of the // element's tag name, so we exclude that here to avoid circularities. // If check mode has `CheckMode.RestBindingElement`, we skip binding pattern contextual types, // as we want the type of a rest element to be generic when possible. - const contextualType = (isIdentifier(node) || isPropertyAccessExpression(node) || isElementAccessExpression(node)) && - !((isJsxOpeningElement(node.parent) || isJsxSelfClosingElement(node.parent)) && node.parent.tagName === node) && - (checkMode && checkMode & CheckMode.RestBindingElement ? - getContextualType(node, ContextFlags.SkipBindingPatterns) + const contextualType = + (isIdentifier(node) || + isPropertyAccessExpression(node) || + isElementAccessExpression(node)) && + !( + (isJsxOpeningElement(node.parent) || + isJsxSelfClosingElement(node.parent)) && + node.parent.tagName === node + ) && + (checkMode && checkMode & CheckMode.RestBindingElement + ? getContextualType(node, ContextFlags.SkipBindingPatterns) : getContextualType(node, /*contextFlags*/ undefined)); return contextualType && !isGenericType(contextualType); } - function getNarrowableTypeForReference(type: Type, reference: Node, checkMode?: CheckMode) { + function getNarrowableTypeForReference( + type: Type, + reference: Node, + checkMode?: CheckMode + ) { if (isNoInferType(type)) { type = (type as SubstitutionType).baseType; } @@ -30304,14 +53789,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // control flow analysis an opportunity to narrow it further. For example, for a reference of a type // parameter type 'T extends string | undefined' with a contextual type 'string', we substitute // 'string | undefined' to give control flow analysis the opportunity to narrow to type 'string'. - const substituteConstraints = !(checkMode && checkMode & CheckMode.Inferential) && + const substituteConstraints = + !(checkMode && checkMode & CheckMode.Inferential) && someType(type, isGenericTypeWithUnionConstraint) && - (isConstraintPosition(type, reference) || hasContextualTypeWithNoGenericTypes(reference, checkMode)); - return substituteConstraints ? mapType(type, getBaseConstraintOrType) : type; + (isConstraintPosition(type, reference) || + hasContextualTypeWithNoGenericTypes(reference, checkMode)); + return substituteConstraints + ? mapType(type, getBaseConstraintOrType) + : type; } function isExportOrExportExpression(location: Node) { - return !!findAncestor(location, n => { + return !!findAncestor(location, (n) => { const parent = n.parent; if (parent === undefined) { return "quit"; @@ -30338,20 +53827,60 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param propSymbol The optional symbol of the property we're looking up - this is used for property accesses when `const enum`s do not count as references (no `isolatedModules`, no `preserveConstEnums` + export). It will be calculated if not provided. * @param parentType The optional type of the parent of the LHS of the property access - this will be recalculated if not provided (but is costly). */ - function markLinkedReferences(location: PropertyAccessExpression | QualifiedName, hint: ReferenceHint.Property, propSymbol: Symbol | undefined, parentType: Type): void; - function markLinkedReferences(location: Identifier, hint: ReferenceHint.Identifier): void; - function markLinkedReferences(location: ExportAssignment, hint: ReferenceHint.ExportAssignment): void; - function markLinkedReferences(location: JsxOpeningLikeElement | JsxOpeningFragment, hint: ReferenceHint.Jsx): void; - function markLinkedReferences(location: FunctionLikeDeclaration | MethodSignature, hint: ReferenceHint.AsyncFunction): void; - function markLinkedReferences(location: ImportEqualsDeclaration, hint: ReferenceHint.ExportImportEquals): void; - function markLinkedReferences(location: ExportSpecifier, hint: ReferenceHint.ExportSpecifier): void; - function markLinkedReferences(location: HasDecorators, hint: ReferenceHint.Decorator): void; - function markLinkedReferences(location: Node, hint: ReferenceHint.Unspecified, propSymbol?: Symbol, parentType?: Type): void; - function markLinkedReferences(location: Node, hint: ReferenceHint, propSymbol?: Symbol, parentType?: Type) { + function markLinkedReferences( + location: PropertyAccessExpression | QualifiedName, + hint: ReferenceHint.Property, + propSymbol: Symbol | undefined, + parentType: Type + ): void; + function markLinkedReferences( + location: Identifier, + hint: ReferenceHint.Identifier + ): void; + function markLinkedReferences( + location: ExportAssignment, + hint: ReferenceHint.ExportAssignment + ): void; + function markLinkedReferences( + location: JsxOpeningLikeElement | JsxOpeningFragment, + hint: ReferenceHint.Jsx + ): void; + function markLinkedReferences( + location: FunctionLikeDeclaration | MethodSignature, + hint: ReferenceHint.AsyncFunction + ): void; + function markLinkedReferences( + location: ImportEqualsDeclaration, + hint: ReferenceHint.ExportImportEquals + ): void; + function markLinkedReferences( + location: ExportSpecifier, + hint: ReferenceHint.ExportSpecifier + ): void; + function markLinkedReferences( + location: HasDecorators, + hint: ReferenceHint.Decorator + ): void; + function markLinkedReferences( + location: Node, + hint: ReferenceHint.Unspecified, + propSymbol?: Symbol, + parentType?: Type + ): void; + function markLinkedReferences( + location: Node, + hint: ReferenceHint, + propSymbol?: Symbol, + parentType?: Type + ) { if (!canCollectSymbolAliasAccessabilityData) { return; } - if (location.flags & NodeFlags.Ambient && !isPropertySignature(location) && !isPropertyDeclaration(location)) { + if ( + location.flags & NodeFlags.Ambient && + !isPropertySignature(location) && + !isPropertyDeclaration(location) + ) { // References within types and declaration files are never going to contribute to retaining a JS import, // except for properties (which can be decorated). return; @@ -30360,26 +53889,49 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case ReferenceHint.Identifier: return markIdentifierAliasReferenced(location as Identifier); case ReferenceHint.Property: - return markPropertyAliasReferenced(location as PropertyAccessExpression | QualifiedName, propSymbol, parentType); + return markPropertyAliasReferenced( + location as PropertyAccessExpression | QualifiedName, + propSymbol, + parentType + ); case ReferenceHint.ExportAssignment: - return markExportAssignmentAliasReferenced(location as ExportAssignment); + return markExportAssignmentAliasReferenced( + location as ExportAssignment + ); case ReferenceHint.Jsx: - return markJsxAliasReferenced(location as JsxOpeningLikeElement | JsxOpeningFragment); + return markJsxAliasReferenced( + location as JsxOpeningLikeElement | JsxOpeningFragment + ); case ReferenceHint.AsyncFunction: - return markAsyncFunctionAliasReferenced(location as FunctionLikeDeclaration | MethodSignature); + return markAsyncFunctionAliasReferenced( + location as FunctionLikeDeclaration | MethodSignature + ); case ReferenceHint.ExportImportEquals: - return markImportEqualsAliasReferenced(location as ImportEqualsDeclaration); + return markImportEqualsAliasReferenced( + location as ImportEqualsDeclaration + ); case ReferenceHint.ExportSpecifier: - return markExportSpecifierAliasReferenced(location as ExportSpecifier); + return markExportSpecifierAliasReferenced( + location as ExportSpecifier + ); case ReferenceHint.Decorator: return markDecoratorAliasReferenced(location as HasDecorators); case ReferenceHint.Unspecified: { // Identifiers in expression contexts are emitted, so we need to follow their referenced aliases and mark them as used // Some non-expression identifiers are also treated as expression identifiers for this purpose, eg, `a` in `b = {a}` or `q` in `import r = q` // This is the exception, rather than the rule - most non-expression identifiers are declaration names. - if (isIdentifier(location) && (isExpressionNode(location) || isShorthandPropertyAssignment(location.parent) || (isImportEqualsDeclaration(location.parent) && location.parent.moduleReference === location)) && shouldMarkIdentifierAliasReferenced(location)) { + if ( + isIdentifier(location) && + (isExpressionNode(location) || + isShorthandPropertyAssignment(location.parent) || + (isImportEqualsDeclaration(location.parent) && + location.parent.moduleReference === location)) && + shouldMarkIdentifierAliasReferenced(location) + ) { if (isPropertyAccessOrQualifiedName(location.parent)) { - const left = isPropertyAccessExpression(location.parent) ? location.parent.expression : location.parent.left; + const left = isPropertyAccessExpression(location.parent) + ? location.parent.expression + : location.parent.left; if (left !== location) return; // Only mark the LHS (the RHS is a property lookup) } markIdentifierAliasReferenced(location); @@ -30396,11 +53948,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isExportAssignment(location)) { return markExportAssignmentAliasReferenced(location); } - if (isJsxOpeningLikeElement(location) || isJsxOpeningFragment(location)) { + if ( + isJsxOpeningLikeElement(location) || + isJsxOpeningFragment(location) + ) { return markJsxAliasReferenced(location); } if (isImportEqualsDeclaration(location)) { - if (isInternalModuleImportEqualsDeclaration(location) || checkExternalImportOrExportDeclaration(location)) { + if ( + isInternalModuleImportEqualsDeclaration(location) || + checkExternalImportOrExportDeclaration(location) + ) { return markImportEqualsAliasReferenced(location); } return; @@ -30408,14 +53966,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isExportSpecifier(location)) { return markExportSpecifierAliasReferenced(location); } - if (isFunctionLikeDeclaration(location) || isMethodSignature(location)) { + if ( + isFunctionLikeDeclaration(location) || + isMethodSignature(location) + ) { markAsyncFunctionAliasReferenced(location); // Might be decorated, fall through to decorator final case } if (!compilerOptions.emitDecoratorMetadata) { return; } - if (!canHaveDecorators(location) || !hasDecorators(location) || !location.modifiers || !nodeCanBeDecorated(legacyDecorators, location, location.parent, location.parent.parent)) { + if ( + !canHaveDecorators(location) || + !hasDecorators(location) || + !location.modifiers || + !nodeCanBeDecorated( + legacyDecorators, + location, + location.parent, + location.parent.parent + ) + ) { return; } @@ -30428,13 +53999,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function markIdentifierAliasReferenced(location: Identifier) { const symbol = getResolvedSymbol(location); - if (symbol && symbol !== argumentsSymbol && symbol !== unknownSymbol && !isThisInTypeQuery(location)) { + if ( + symbol && + symbol !== argumentsSymbol && + symbol !== unknownSymbol && + !isThisInTypeQuery(location) + ) { markAliasReferenced(symbol, location); } } - function markPropertyAliasReferenced(location: PropertyAccessExpression | QualifiedName, propSymbol?: Symbol, parentType?: Type) { - const left = isPropertyAccessExpression(location) ? location.expression : location.left; + function markPropertyAliasReferenced( + location: PropertyAccessExpression | QualifiedName, + propSymbol?: Symbol, + parentType?: Type + ) { + const left = isPropertyAccessExpression(location) + ? location.expression + : location.left; if (isThisIdentifier(left) || !isIdentifier(left)) { return; } @@ -30452,7 +54034,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // // The property lookup is deferred as much as possible, in as many situations as possible, to avoid alias marking // pulling on types/symbols it doesn't strictly need to. - if (getIsolatedModules(compilerOptions) || (shouldPreserveConstEnums(compilerOptions) && isExportOrExportExpression(location))) { + if ( + getIsolatedModules(compilerOptions) || + (shouldPreserveConstEnums(compilerOptions) && + isExportOrExportExpression(location)) + ) { markAliasReferenced(parentSymbol, location); return; } @@ -30464,14 +54050,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } let prop = propSymbol; if (!prop && !parentType) { - const right = isPropertyAccessExpression(location) ? location.name : location.right; - const lexicallyScopedSymbol = isPrivateIdentifier(right) && lookupSymbolForPrivateIdentifierDeclaration(right.escapedText, right); + const right = isPropertyAccessExpression(location) + ? location.name + : location.right; + const lexicallyScopedSymbol = + isPrivateIdentifier(right) && + lookupSymbolForPrivateIdentifierDeclaration( + right.escapedText, + right + ); const assignmentKind = getAssignmentTargetKind(location); - const apparentType = getApparentType(assignmentKind !== AssignmentKind.None || isMethodAccessForCall(location) ? getWidenedType(leftType) : leftType); - prop = isPrivateIdentifier(right) ? lexicallyScopedSymbol && getPrivateIdentifierPropertyOfType(apparentType, lexicallyScopedSymbol) || undefined : getPropertyOfType(apparentType, right.escapedText); + const apparentType = getApparentType( + assignmentKind !== AssignmentKind.None || + isMethodAccessForCall(location) + ? getWidenedType(leftType) + : leftType + ); + prop = isPrivateIdentifier(right) + ? (lexicallyScopedSymbol && + getPrivateIdentifierPropertyOfType( + apparentType, + lexicallyScopedSymbol + )) || + undefined + : getPropertyOfType(apparentType, right.escapedText); } if ( - !(prop && (isConstEnumOrConstEnumOnlyModule(prop) || prop.flags & SymbolFlags.EnumMember && location.parent.kind === SyntaxKind.EnumMember)) + !( + prop && + (isConstEnumOrConstEnumOnlyModule(prop) || + (prop.flags & SymbolFlags.EnumMember && + location.parent.kind === SyntaxKind.EnumMember)) + ) ) { markAliasReferenced(parentSymbol, location); } @@ -30481,31 +54091,52 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function markExportAssignmentAliasReferenced(location: ExportAssignment) { if (isIdentifier(location.expression)) { const id = location.expression; - const sym = getExportSymbolOfValueSymbolIfExported(resolveEntityName(id, SymbolFlags.All, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, location)); + const sym = getExportSymbolOfValueSymbolIfExported( + resolveEntityName( + id, + SymbolFlags.All, + /*ignoreErrors*/ true, + /*dontResolveAlias*/ true, + location + ) + ); if (sym) { markAliasReferenced(sym, id); } } } - function markJsxAliasReferenced(node: JsxOpeningLikeElement | JsxOpeningFragment) { + function markJsxAliasReferenced( + node: JsxOpeningLikeElement | JsxOpeningFragment + ) { if (!getJsxNamespaceContainerForImplicitImport(node)) { // The reactNamespace/jsxFactory's root symbol should be marked as 'used' so we don't incorrectly elide its import. // And if there is no reactNamespace/jsxFactory's symbol in scope when targeting React emit, we should issue an error. - const jsxFactoryRefErr = diagnostics && compilerOptions.jsx === JsxEmit.React ? Diagnostics.This_JSX_tag_requires_0_to_be_in_scope_but_it_could_not_be_found : undefined; + const jsxFactoryRefErr = + diagnostics && compilerOptions.jsx === JsxEmit.React + ? Diagnostics.This_JSX_tag_requires_0_to_be_in_scope_but_it_could_not_be_found + : undefined; const jsxFactoryNamespace = getJsxNamespace(node); - const jsxFactoryLocation = isJsxOpeningLikeElement(node) ? node.tagName : node; - const shouldFactoryRefErr = compilerOptions.jsx !== JsxEmit.Preserve && compilerOptions.jsx !== JsxEmit.ReactNative; + const jsxFactoryLocation = isJsxOpeningLikeElement(node) + ? node.tagName + : node; + const shouldFactoryRefErr = + compilerOptions.jsx !== JsxEmit.Preserve && + compilerOptions.jsx !== JsxEmit.ReactNative; // #38720/60122, allow null as jsxFragmentFactory let jsxFactorySym: Symbol | undefined; - if (!(isJsxOpeningFragment(node) && jsxFactoryNamespace === "null")) { + if ( + !(isJsxOpeningFragment(node) && jsxFactoryNamespace === "null") + ) { jsxFactorySym = resolveName( jsxFactoryLocation, jsxFactoryNamespace, - shouldFactoryRefErr ? SymbolFlags.Value : SymbolFlags.Value & ~SymbolFlags.Enum, + shouldFactoryRefErr + ? SymbolFlags.Value + : SymbolFlags.Value & ~SymbolFlags.Enum, jsxFactoryRefErr, - /*isUse*/ true, + /*isUse*/ true ); } @@ -30515,7 +54146,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { jsxFactorySym.isReferenced = SymbolFlags.All; // If react/jsxFactory symbol is alias, mark it as refereced - if (canCollectSymbolAliasAccessabilityData && jsxFactorySym.flags & SymbolFlags.Alias && !getTypeOnlyAliasDeclaration(jsxFactorySym)) { + if ( + canCollectSymbolAliasAccessabilityData && + jsxFactorySym.flags & SymbolFlags.Alias && + !getTypeOnlyAliasDeclaration(jsxFactorySym) + ) { markAliasSymbolAsReferenced(jsxFactorySym); } } @@ -30525,13 +54160,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const file = getSourceFileOfNode(node); const entity = getJsxFactoryEntity(file); if (entity) { - const localJsxNamespace = getFirstIdentifier(entity).escapedText; + const localJsxNamespace = + getFirstIdentifier(entity).escapedText; resolveName( jsxFactoryLocation, localJsxNamespace, - shouldFactoryRefErr ? SymbolFlags.Value : SymbolFlags.Value & ~SymbolFlags.Enum, + shouldFactoryRefErr + ? SymbolFlags.Value + : SymbolFlags.Value & ~SymbolFlags.Enum, jsxFactoryRefErr, - /*isUse*/ true, + /*isUse*/ true ); } } @@ -30539,7 +54177,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return; } - function markAsyncFunctionAliasReferenced(location: FunctionLikeDeclaration | MethodSignature) { + function markAsyncFunctionAliasReferenced( + location: FunctionLikeDeclaration | MethodSignature + ) { if (languageVersion < ScriptTarget.ES2015) { if (getFunctionFlags(location) & FunctionFlags.Async) { const returnTypeNode = getEffectiveReturnTypeNode(location); @@ -30548,24 +54188,50 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function markImportEqualsAliasReferenced(location: ImportEqualsDeclaration) { + function markImportEqualsAliasReferenced( + location: ImportEqualsDeclaration + ) { if (hasSyntacticModifier(location, ModifierFlags.Export)) { markExportAsReferenced(location); } } function markExportSpecifierAliasReferenced(location: ExportSpecifier) { - if (!location.parent.parent.moduleSpecifier && !location.isTypeOnly && !location.parent.parent.isTypeOnly) { + if ( + !location.parent.parent.moduleSpecifier && + !location.isTypeOnly && + !location.parent.parent.isTypeOnly + ) { const exportedName = location.propertyName || location.name; if (exportedName.kind === SyntaxKind.StringLiteral) { return; // Skip for invalid syntax like this: export { "x" } } - const symbol = resolveName(exportedName, exportedName.escapedText, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, /*nameNotFoundMessage*/ undefined, /*isUse*/ true); - if (symbol && (symbol === undefinedSymbol || symbol === globalThisSymbol || symbol.declarations && isGlobalSourceFile(getDeclarationContainer(symbol.declarations[0])))) { + const symbol = resolveName( + exportedName, + exportedName.escapedText, + SymbolFlags.Value | + SymbolFlags.Type | + SymbolFlags.Namespace | + SymbolFlags.Alias, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ true + ); + if ( + symbol && + (symbol === undefinedSymbol || + symbol === globalThisSymbol || + (symbol.declarations && + isGlobalSourceFile( + getDeclarationContainer(symbol.declarations[0]) + ))) + ) { // Do nothing, non-local symbol - } - else { - const target = symbol && (symbol.flags & SymbolFlags.Alias ? resolveAlias(symbol) : symbol); + } else { + const target = + symbol && + (symbol.flags & SymbolFlags.Alias + ? resolveAlias(symbol) + : symbol); if (!target || getSymbolFlags(target) & SymbolFlags.Value) { markExportAsReferenced(location); // marks export as used markIdentifierAliasReferenced(exportedName); // marks target of export as used @@ -30582,7 +54248,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return; } - checkExternalEmitHelpers(firstDecorator, ExternalEmitHelpers.Metadata); + checkExternalEmitHelpers( + firstDecorator, + ExternalEmitHelpers.Metadata + ); // we only need to perform these checks if we are emitting serialized type metadata for the target of a decorator. switch (node.kind) { @@ -30590,36 +54259,61 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const constructor = getFirstConstructorWithBody(node); if (constructor) { for (const parameter of constructor.parameters) { - markDecoratorMedataDataTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(parameter)); + markDecoratorMedataDataTypeNodeAsReferenced( + getParameterTypeNodeForDecoratorCheck(parameter) + ); } } break; case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: - const otherKind = node.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor : SyntaxKind.GetAccessor; - const otherAccessor = getDeclarationOfKind(getSymbolOfDeclaration(node), otherKind); - markDecoratorMedataDataTypeNodeAsReferenced(getAnnotatedAccessorTypeNode(node) || otherAccessor && getAnnotatedAccessorTypeNode(otherAccessor)); + const otherKind = + node.kind === SyntaxKind.GetAccessor + ? SyntaxKind.SetAccessor + : SyntaxKind.GetAccessor; + const otherAccessor = + getDeclarationOfKind( + getSymbolOfDeclaration(node), + otherKind + ); + markDecoratorMedataDataTypeNodeAsReferenced( + getAnnotatedAccessorTypeNode(node) || + (otherAccessor && + getAnnotatedAccessorTypeNode(otherAccessor)) + ); break; case SyntaxKind.MethodDeclaration: for (const parameter of node.parameters) { - markDecoratorMedataDataTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(parameter)); + markDecoratorMedataDataTypeNodeAsReferenced( + getParameterTypeNodeForDecoratorCheck(parameter) + ); } - markDecoratorMedataDataTypeNodeAsReferenced(getEffectiveReturnTypeNode(node)); + markDecoratorMedataDataTypeNodeAsReferenced( + getEffectiveReturnTypeNode(node) + ); break; case SyntaxKind.PropertyDeclaration: - markDecoratorMedataDataTypeNodeAsReferenced(getEffectiveTypeAnnotationNode(node)); + markDecoratorMedataDataTypeNodeAsReferenced( + getEffectiveTypeAnnotationNode(node) + ); break; case SyntaxKind.Parameter: - markDecoratorMedataDataTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(node)); + markDecoratorMedataDataTypeNodeAsReferenced( + getParameterTypeNodeForDecoratorCheck(node) + ); const containingSignature = node.parent; for (const parameter of containingSignature.parameters) { - markDecoratorMedataDataTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(parameter)); + markDecoratorMedataDataTypeNodeAsReferenced( + getParameterTypeNodeForDecoratorCheck(parameter) + ); } - markDecoratorMedataDataTypeNodeAsReferenced(getEffectiveReturnTypeNode(containingSignature)); + markDecoratorMedataDataTypeNodeAsReferenced( + getEffectiveReturnTypeNode(containingSignature) + ); break; } } @@ -30629,16 +54323,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!canCollectSymbolAliasAccessabilityData) { return; } - if (isNonLocalAlias(symbol, /*excludes*/ SymbolFlags.Value) && !isInTypeQuery(location)) { + if ( + isNonLocalAlias(symbol, /*excludes*/ SymbolFlags.Value) && + !isInTypeQuery(location) + ) { const target = resolveAlias(symbol); - if (getSymbolFlags(symbol, /*excludeTypeOnlyMeanings*/ true) & (SymbolFlags.Value | SymbolFlags.ExportValue)) { + if ( + getSymbolFlags(symbol, /*excludeTypeOnlyMeanings*/ true) & + (SymbolFlags.Value | SymbolFlags.ExportValue) + ) { // An alias resolving to a const enum cannot be elided if (1) 'isolatedModules' is enabled // (because the const enum value will not be inlined), or if (2) the alias is an export // of a const enum declaration that will be preserved. if ( getIsolatedModules(compilerOptions) || - shouldPreserveConstEnums(compilerOptions) && isExportOrExportExpression(location) || - !isConstEnumOrConstEnumOnlyModule(getExportSymbolOfValueSymbolIfExported(target)) + (shouldPreserveConstEnums(compilerOptions) && + isExportOrExportExpression(location)) || + !isConstEnumOrConstEnumOnlyModule( + getExportSymbolOfValueSymbolIfExported(target) + ) ) { markAliasSymbolAsReferenced(symbol); } @@ -30662,19 +54365,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isInternalModuleImportEqualsDeclaration(node)) { if (getSymbolFlags(resolveSymbol(symbol)) & SymbolFlags.Value) { // import foo = - const left = getFirstIdentifier(node.moduleReference as EntityNameExpression); + const left = getFirstIdentifier( + node.moduleReference as EntityNameExpression + ); markIdentifierAliasReferenced(left); } } } } - function markExportAsReferenced(node: ImportEqualsDeclaration | ExportSpecifier) { + function markExportAsReferenced( + node: ImportEqualsDeclaration | ExportSpecifier + ) { const symbol = getSymbolOfDeclaration(node); const target = resolveAlias(symbol); if (target) { - const markAlias = target === unknownSymbol || - ((getSymbolFlags(symbol, /*excludeTypeOnlyMeanings*/ true) & SymbolFlags.Value) && !isConstEnumOrConstEnumOnlyModule(target)); + const markAlias = + target === unknownSymbol || + (getSymbolFlags(symbol, /*excludeTypeOnlyMeanings*/ true) & + SymbolFlags.Value && + !isConstEnumOrConstEnumOnlyModule(target)); if (markAlias) { markAliasSymbolAsReferenced(symbol); @@ -30682,32 +54392,59 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function markEntityNameOrEntityExpressionAsReference(typeName: EntityNameOrEntityNameExpression | undefined, forDecoratorMetadata: boolean) { + function markEntityNameOrEntityExpressionAsReference( + typeName: EntityNameOrEntityNameExpression | undefined, + forDecoratorMetadata: boolean + ) { if (!typeName) return; const rootName = getFirstIdentifier(typeName); - const meaning = (typeName.kind === SyntaxKind.Identifier ? SymbolFlags.Type : SymbolFlags.Namespace) | SymbolFlags.Alias; - const rootSymbol = resolveName(rootName, rootName.escapedText, meaning, /*nameNotFoundMessage*/ undefined, /*isUse*/ true); + const meaning = + (typeName.kind === SyntaxKind.Identifier + ? SymbolFlags.Type + : SymbolFlags.Namespace) | SymbolFlags.Alias; + const rootSymbol = resolveName( + rootName, + rootName.escapedText, + meaning, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ true + ); if (rootSymbol && rootSymbol.flags & SymbolFlags.Alias) { if ( - canCollectSymbolAliasAccessabilityData - && symbolIsValue(rootSymbol) - && !isConstEnumOrConstEnumOnlyModule(resolveAlias(rootSymbol)) - && !getTypeOnlyAliasDeclaration(rootSymbol) + canCollectSymbolAliasAccessabilityData && + symbolIsValue(rootSymbol) && + !isConstEnumOrConstEnumOnlyModule(resolveAlias(rootSymbol)) && + !getTypeOnlyAliasDeclaration(rootSymbol) ) { markAliasSymbolAsReferenced(rootSymbol); - } - else if ( - forDecoratorMetadata - && getIsolatedModules(compilerOptions) - && getEmitModuleKind(compilerOptions) >= ModuleKind.ES2015 - && !symbolIsValue(rootSymbol) - && !some(rootSymbol.declarations, isTypeOnlyImportOrExportDeclaration) - ) { - 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); - const aliasDeclaration = find(rootSymbol.declarations || emptyArray, isAliasSymbolDeclaration); + } else if ( + forDecoratorMetadata && + getIsolatedModules(compilerOptions) && + getEmitModuleKind(compilerOptions) >= ModuleKind.ES2015 && + !symbolIsValue(rootSymbol) && + !some( + rootSymbol.declarations, + isTypeOnlyImportOrExportDeclaration + ) + ) { + 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 + ); + const aliasDeclaration = find( + rootSymbol.declarations || emptyArray, + isAliasSymbolDeclaration + ); if (aliasDeclaration) { - addRelatedInfo(diag, createDiagnosticForNode(aliasDeclaration, Diagnostics._0_was_imported_here, idText(rootName))); + addRelatedInfo( + diag, + createDiagnosticForNode( + aliasDeclaration, + Diagnostics._0_was_imported_here, + idText(rootName) + ) + ); } } } @@ -30718,7 +54455,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * marked as referenced to prevent import elision. */ function markTypeNodeAsReferenced(node: TypeNode | undefined) { - markEntityNameOrEntityExpressionAsReference(node && getEntityNameFromTypeNode(node), /*forDecoratorMetadata*/ false); + markEntityNameOrEntityExpressionAsReference( + node && getEntityNameFromTypeNode(node), + /*forDecoratorMetadata*/ false + ); } /** @@ -30728,10 +54468,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * union and intersection type * @param node */ - function markDecoratorMedataDataTypeNodeAsReferenced(node: TypeNode | undefined): void { + function markDecoratorMedataDataTypeNodeAsReferenced( + node: TypeNode | undefined + ): void { const entityName = getEntityNameForDecoratorMetadata(node); if (entityName && isEntityName(entityName)) { - markEntityNameOrEntityExpressionAsReference(entityName, /*forDecoratorMetadata*/ true); + markEntityNameOrEntityExpressionAsReference( + entityName, + /*forDecoratorMetadata*/ true + ); } } @@ -30762,26 +54507,58 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // the binding pattern AST instance for '{ kind, payload }' as a pseudo-reference and narrow this reference // as if it occurred in the specified location. We then recompute the narrowed binding element type by // destructuring from the narrowed parent type. - if (isBindingElement(declaration) && !declaration.initializer && !declaration.dotDotDotToken && declaration.parent.elements.length >= 2) { + if ( + isBindingElement(declaration) && + !declaration.initializer && + !declaration.dotDotDotToken && + declaration.parent.elements.length >= 2 + ) { const parent = declaration.parent.parent; const rootDeclaration = getRootDeclaration(parent); - if (rootDeclaration.kind === SyntaxKind.VariableDeclaration && getCombinedNodeFlagsCached(rootDeclaration) & NodeFlags.Constant || rootDeclaration.kind === SyntaxKind.Parameter) { + if ( + (rootDeclaration.kind === SyntaxKind.VariableDeclaration && + getCombinedNodeFlagsCached(rootDeclaration) & + NodeFlags.Constant) || + rootDeclaration.kind === SyntaxKind.Parameter + ) { const links = getNodeLinks(parent); if (!(links.flags & NodeCheckFlags.InCheckIdentifier)) { links.flags |= NodeCheckFlags.InCheckIdentifier; - const parentType = getTypeForBindingElementParent(parent, CheckMode.Normal); - const parentTypeConstraint = parentType && mapType(parentType, getBaseConstraintOrType); + const parentType = getTypeForBindingElementParent( + parent, + CheckMode.Normal + ); + const parentTypeConstraint = + parentType && + mapType(parentType, getBaseConstraintOrType); links.flags &= ~NodeCheckFlags.InCheckIdentifier; - if (parentTypeConstraint && parentTypeConstraint.flags & TypeFlags.Union && !(rootDeclaration.kind === SyntaxKind.Parameter && isSomeSymbolAssigned(rootDeclaration))) { + if ( + parentTypeConstraint && + parentTypeConstraint.flags & TypeFlags.Union && + !( + rootDeclaration.kind === SyntaxKind.Parameter && + isSomeSymbolAssigned(rootDeclaration) + ) + ) { const pattern = declaration.parent; - const narrowedType = getFlowTypeOfReference(pattern, parentTypeConstraint, parentTypeConstraint, /*flowContainer*/ undefined, location.flowNode); + const narrowedType = getFlowTypeOfReference( + pattern, + parentTypeConstraint, + parentTypeConstraint, + /*flowContainer*/ undefined, + location.flowNode + ); if (narrowedType.flags & TypeFlags.Never) { return neverType; } // Destructurings are validated against the parent type elsewhere. Here we disable tuple bounds // checks because the narrowed type may have lower arity than the full parent type. For example, // for the declaration [x, y]: [1, 2] | [3], we may have narrowed the parent type to just [3]. - return getBindingElementTypeFromParentType(declaration, narrowedType, /*noTupleBoundsCheck*/ true); + return getBindingElementTypeFromParentType( + declaration, + narrowedType, + /*noTupleBoundsCheck*/ true + ); } } } @@ -30806,16 +54583,50 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // the arrow function AST node for '(kind, payload) => ...' as a pseudo-reference and narrow this reference as // if it occurred in the specified location. We then recompute the narrowed parameter type by indexing into the // narrowed tuple type. - if (isParameter(declaration) && !declaration.type && !declaration.initializer && !declaration.dotDotDotToken) { + if ( + isParameter(declaration) && + !declaration.type && + !declaration.initializer && + !declaration.dotDotDotToken + ) { const func = declaration.parent; - if (func.parameters.length >= 2 && isContextSensitiveFunctionOrObjectLiteralMethod(func)) { + if ( + func.parameters.length >= 2 && + isContextSensitiveFunctionOrObjectLiteralMethod(func) + ) { const contextualSignature = getContextualSignature(func); - if (contextualSignature && contextualSignature.parameters.length === 1 && signatureHasRestParameter(contextualSignature)) { - const restType = getReducedApparentType(instantiateType(getTypeOfSymbol(contextualSignature.parameters[0]), getInferenceContext(func)?.nonFixingMapper)); - if (restType.flags & TypeFlags.Union && everyType(restType, isTupleType) && !some(func.parameters, isSomeSymbolAssigned)) { - const narrowedType = getFlowTypeOfReference(func, restType, restType, /*flowContainer*/ undefined, location.flowNode); - const index = func.parameters.indexOf(declaration) - (getThisParameter(func) ? 1 : 0); - return getIndexedAccessType(narrowedType, getNumberLiteralType(index)); + if ( + contextualSignature && + contextualSignature.parameters.length === 1 && + signatureHasRestParameter(contextualSignature) + ) { + const restType = getReducedApparentType( + instantiateType( + getTypeOfSymbol( + contextualSignature.parameters[0] + ), + getInferenceContext(func)?.nonFixingMapper + ) + ); + if ( + restType.flags & TypeFlags.Union && + everyType(restType, isTupleType) && + !some(func.parameters, isSomeSymbolAssigned) + ) { + const narrowedType = getFlowTypeOfReference( + func, + restType, + restType, + /*flowContainer*/ undefined, + location.flowNode + ); + const index = + func.parameters.indexOf(declaration) - + (getThisParameter(func) ? 1 : 0); + return getIndexedAccessType( + narrowedType, + getNumberLiteralType(index) + ); } } } @@ -30828,7 +54639,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * This part of `checkIdentifier` is kept seperate from the rest, so `NodeCheckFlags` (and related diagnostics) can be lazily calculated * without calculating the flow type of the identifier. */ - function checkIdentifierCalculateNodeCheckFlags(node: Identifier, symbol: Symbol) { + function checkIdentifierCalculateNodeCheckFlags( + node: Identifier, + symbol: Symbol + ) { if (isThisInTypeQuery(node)) return; // As noted in ECMAScript 6 language spec, arrow functions never have an arguments objects. @@ -30838,8 +54652,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // To avoid that we will give an error to users if they use arguments objects in arrow function so that they // can explicitly bound arguments objects if (symbol === argumentsSymbol) { - if (isInPropertyInitializerOrClassStaticBlock(node, /*ignoreArrowFunctions*/ true)) { - error(node, Diagnostics.arguments_cannot_be_referenced_in_property_initializers_or_class_static_initialization_blocks); + if ( + isInPropertyInitializerOrClassStaticBlock( + node, + /*ignoreArrowFunctions*/ true + ) + ) { + error( + node, + Diagnostics.arguments_cannot_be_referenced_in_property_initializers_or_class_static_initialization_blocks + ); return; } @@ -30847,28 +54669,49 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (container) { if (languageVersion < ScriptTarget.ES2015) { if (container.kind === SyntaxKind.ArrowFunction) { - error(node, Diagnostics.The_arguments_object_cannot_be_referenced_in_an_arrow_function_in_ES5_Consider_using_a_standard_function_expression); - } - else if (hasSyntacticModifier(container, ModifierFlags.Async)) { - error(node, Diagnostics.The_arguments_object_cannot_be_referenced_in_an_async_function_or_method_in_ES5_Consider_using_a_standard_function_or_method); + error( + node, + Diagnostics.The_arguments_object_cannot_be_referenced_in_an_arrow_function_in_ES5_Consider_using_a_standard_function_expression + ); + } else if ( + hasSyntacticModifier(container, ModifierFlags.Async) + ) { + error( + node, + Diagnostics.The_arguments_object_cannot_be_referenced_in_an_async_function_or_method_in_ES5_Consider_using_a_standard_function_or_method + ); } } - getNodeLinks(container).flags |= NodeCheckFlags.CaptureArguments; + getNodeLinks(container).flags |= + NodeCheckFlags.CaptureArguments; while (container && isArrowFunction(container)) { container = getContainingFunction(container); if (container) { - getNodeLinks(container).flags |= NodeCheckFlags.CaptureArguments; + getNodeLinks(container).flags |= + NodeCheckFlags.CaptureArguments; } } } return; } - const localOrExportSymbol = getExportSymbolOfValueSymbolIfExported(symbol); - const targetSymbol = resolveAliasWithDeprecationCheck(localOrExportSymbol, node); - if (isDeprecatedSymbol(targetSymbol) && isUncalledFunctionReference(node, targetSymbol) && targetSymbol.declarations) { - addDeprecatedSuggestion(node, targetSymbol.declarations, node.escapedText as string); + const localOrExportSymbol = + getExportSymbolOfValueSymbolIfExported(symbol); + const targetSymbol = resolveAliasWithDeprecationCheck( + localOrExportSymbol, + node + ); + if ( + isDeprecatedSymbol(targetSymbol) && + isUncalledFunctionReference(node, targetSymbol) && + targetSymbol.declarations + ) { + addDeprecatedSuggestion( + node, + targetSymbol.declarations, + node.escapedText as string + ); } const declaration = localOrExportSymbol.valueDeclaration; @@ -30877,15 +54720,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // class name is double-bound, we must ensure we mark references to the class name so that we can // emit an alias to the class later. if (isClassLike(declaration) && declaration.name !== node) { - let container = getThisContainer(node, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); - while (container.kind !== SyntaxKind.SourceFile && container.parent !== declaration) { - container = getThisContainer(container, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); + let container = getThisContainer( + node, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false + ); + while ( + container.kind !== SyntaxKind.SourceFile && + container.parent !== declaration + ) { + container = getThisContainer( + container, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false + ); } if (container.kind !== SyntaxKind.SourceFile) { - getNodeLinks(declaration).flags |= NodeCheckFlags.ContainsConstructorReference; - getNodeLinks(container).flags |= NodeCheckFlags.ContainsConstructorReference; - getNodeLinks(node).flags |= NodeCheckFlags.ConstructorReference; + getNodeLinks(declaration).flags |= + NodeCheckFlags.ContainsConstructorReference; + getNodeLinks(container).flags |= + NodeCheckFlags.ContainsConstructorReference; + getNodeLinks(node).flags |= + NodeCheckFlags.ConstructorReference; } } } @@ -30893,7 +54750,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkNestedBlockScopedBinding(node, symbol); } - function checkIdentifier(node: Identifier, checkMode: CheckMode | undefined): Type { + function checkIdentifier( + node: Identifier, + checkMode: CheckMode | undefined + ): Type { if (isThisInTypeQuery(node)) { return checkThisExpression(node); } @@ -30916,14 +54776,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { markLinkedReferences(node, ReferenceHint.Identifier); } - const localOrExportSymbol = getExportSymbolOfValueSymbolIfExported(symbol); + const localOrExportSymbol = + getExportSymbolOfValueSymbolIfExported(symbol); let declaration = localOrExportSymbol.valueDeclaration; const immediateDeclaration = declaration; // If the identifier is declared in a binding pattern for which we're currently computing the implied type and the // reference occurs with the same binding pattern, return the non-inferrable any type. This for example occurs in // 'const [a, b = a + 1] = [2]' when we're computing the contextual type for the array literal '[2]'. - if (declaration && declaration.kind === SyntaxKind.BindingElement && contains(contextualBindingPatterns, declaration.parent) && findAncestor(node, parent => parent === declaration!.parent)) { + if ( + declaration && + declaration.kind === SyntaxKind.BindingElement && + contains(contextualBindingPatterns, declaration.parent) && + findAncestor(node, (parent) => parent === declaration!.parent) + ) { return nonInferrableAnyType; } @@ -30933,24 +54799,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (assignmentKind) { if ( !(localOrExportSymbol.flags & SymbolFlags.Variable) && - !(isInJSFile(node) && localOrExportSymbol.flags & SymbolFlags.ValueModule) + !( + isInJSFile(node) && + localOrExportSymbol.flags & SymbolFlags.ValueModule + ) ) { - const assignmentError = localOrExportSymbol.flags & SymbolFlags.Enum ? Diagnostics.Cannot_assign_to_0_because_it_is_an_enum - : localOrExportSymbol.flags & SymbolFlags.Class ? Diagnostics.Cannot_assign_to_0_because_it_is_a_class - : localOrExportSymbol.flags & SymbolFlags.Module ? Diagnostics.Cannot_assign_to_0_because_it_is_a_namespace - : localOrExportSymbol.flags & SymbolFlags.Function ? Diagnostics.Cannot_assign_to_0_because_it_is_a_function - : localOrExportSymbol.flags & SymbolFlags.Alias ? Diagnostics.Cannot_assign_to_0_because_it_is_an_import - : Diagnostics.Cannot_assign_to_0_because_it_is_not_a_variable; + const assignmentError = + localOrExportSymbol.flags & SymbolFlags.Enum + ? Diagnostics.Cannot_assign_to_0_because_it_is_an_enum + : localOrExportSymbol.flags & SymbolFlags.Class + ? Diagnostics.Cannot_assign_to_0_because_it_is_a_class + : localOrExportSymbol.flags & SymbolFlags.Module + ? Diagnostics.Cannot_assign_to_0_because_it_is_a_namespace + : localOrExportSymbol.flags & SymbolFlags.Function + ? Diagnostics.Cannot_assign_to_0_because_it_is_a_function + : localOrExportSymbol.flags & SymbolFlags.Alias + ? Diagnostics.Cannot_assign_to_0_because_it_is_an_import + : Diagnostics.Cannot_assign_to_0_because_it_is_not_a_variable; error(node, assignmentError, symbolToString(symbol)); return errorType; } if (isReadonlySymbol(localOrExportSymbol)) { if (localOrExportSymbol.flags & SymbolFlags.Variable) { - error(node, Diagnostics.Cannot_assign_to_0_because_it_is_a_constant, symbolToString(symbol)); - } - else { - error(node, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, symbolToString(symbol)); + error( + node, + Diagnostics.Cannot_assign_to_0_because_it_is_a_constant, + symbolToString(symbol) + ); + } else { + error( + node, + Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, + symbolToString(symbol) + ); } return errorType; } @@ -30962,13 +54844,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // entities we simply return the declared type. if (localOrExportSymbol.flags & SymbolFlags.Variable) { if (assignmentKind === AssignmentKind.Definite) { - return isInCompoundLikeAssignment(node) ? getBaseTypeOfLiteralType(type) : type; + return isInCompoundLikeAssignment(node) + ? getBaseTypeOfLiteralType(type) + : type; } - } - else if (isAlias) { + } else if (isAlias) { declaration = getDeclarationOfAliasSymbol(symbol); - } - else { + } else { return type; } @@ -30981,71 +54863,136 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // The declaration container is the innermost function that encloses the declaration of the variable // or parameter. The flow container is the innermost function starting with which we analyze the control // flow graph to determine the control flow based type. - const isParameter = getRootDeclaration(declaration).kind === SyntaxKind.Parameter; + const isParameter = + getRootDeclaration(declaration).kind === SyntaxKind.Parameter; const declarationContainer = getControlFlowContainer(declaration); let flowContainer = getControlFlowContainer(node); const isOuterVariable = flowContainer !== declarationContainer; - const isSpreadDestructuringAssignmentTarget = node.parent && node.parent.parent && isSpreadAssignment(node.parent) && isDestructuringAssignmentTarget(node.parent.parent); + const isSpreadDestructuringAssignmentTarget = + node.parent && + node.parent.parent && + isSpreadAssignment(node.parent) && + isDestructuringAssignmentTarget(node.parent.parent); const isModuleExports = symbol.flags & SymbolFlags.ModuleExports; const typeIsAutomatic = type === autoType || type === autoArrayType; - const isAutomaticTypeInNonNull = typeIsAutomatic && node.parent.kind === SyntaxKind.NonNullExpression; + const isAutomaticTypeInNonNull = + typeIsAutomatic && + node.parent.kind === SyntaxKind.NonNullExpression; // When the control flow originates in a function expression, arrow function, method, or accessor, and // we are referencing a closed-over const variable or parameter or mutable local variable past its last // assignment, we extend the origin of the control flow analysis to include the immediately enclosing // control flow container. while ( - flowContainer !== declarationContainer && ( - flowContainer.kind === SyntaxKind.FunctionExpression || + flowContainer !== declarationContainer && + (flowContainer.kind === SyntaxKind.FunctionExpression || flowContainer.kind === SyntaxKind.ArrowFunction || - isObjectLiteralOrClassExpressionMethodOrAccessor(flowContainer) - ) && ( - isConstantVariable(localOrExportSymbol) && type !== autoArrayType || - isParameterOrMutableLocalVariable(localOrExportSymbol) && isPastLastAssignment(localOrExportSymbol, node) - ) + isObjectLiteralOrClassExpressionMethodOrAccessor( + flowContainer + )) && + ((isConstantVariable(localOrExportSymbol) && + type !== autoArrayType) || + (isParameterOrMutableLocalVariable(localOrExportSymbol) && + isPastLastAssignment(localOrExportSymbol, node))) ) { flowContainer = getControlFlowContainer(flowContainer); } // We only look for uninitialized variables in strict null checking mode, and only when we can analyze // the entire control flow graph from the variable's declaration (i.e. when the flow container and // declaration container are the same). - const isNeverInitialized = immediateDeclaration && isVariableDeclaration(immediateDeclaration) && !immediateDeclaration.initializer && !immediateDeclaration.exclamationToken && isMutableLocalVariableDeclaration(immediateDeclaration) && !isSymbolAssignedDefinitely(symbol); - const assumeInitialized = isParameter || isAlias || + const isNeverInitialized = + immediateDeclaration && + isVariableDeclaration(immediateDeclaration) && + !immediateDeclaration.initializer && + !immediateDeclaration.exclamationToken && + isMutableLocalVariableDeclaration(immediateDeclaration) && + !isSymbolAssignedDefinitely(symbol); + const assumeInitialized = + isParameter || + isAlias || (isOuterVariable && !isNeverInitialized) || - isSpreadDestructuringAssignmentTarget || isModuleExports || isSameScopedBindingElement(node, declaration) || - type !== autoType && type !== autoArrayType && (!strictNullChecks || (type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Void)) !== 0 || - isInTypeQuery(node) || isInAmbientOrTypeNode(node) || node.parent.kind === SyntaxKind.ExportSpecifier) || + isSpreadDestructuringAssignmentTarget || + isModuleExports || + isSameScopedBindingElement(node, declaration) || + (type !== autoType && + type !== autoArrayType && + (!strictNullChecks || + (type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Void)) !== + 0 || + isInTypeQuery(node) || + isInAmbientOrTypeNode(node) || + node.parent.kind === SyntaxKind.ExportSpecifier)) || node.parent.kind === SyntaxKind.NonNullExpression || - declaration.kind === SyntaxKind.VariableDeclaration && (declaration as VariableDeclaration).exclamationToken || + (declaration.kind === SyntaxKind.VariableDeclaration && + (declaration as VariableDeclaration).exclamationToken) || declaration.flags & NodeFlags.Ambient; - const initialType = isAutomaticTypeInNonNull ? undefinedType : - assumeInitialized ? (isParameter ? removeOptionalityFromDeclaredType(type, declaration as VariableLikeDeclaration) : type) : - typeIsAutomatic ? undefinedType : getOptionalType(type); - const flowType = isAutomaticTypeInNonNull ? getNonNullableType(getFlowTypeOfReference(node, type, initialType, flowContainer)) : - getFlowTypeOfReference(node, type, initialType, flowContainer); + const initialType = isAutomaticTypeInNonNull + ? undefinedType + : assumeInitialized + ? isParameter + ? removeOptionalityFromDeclaredType( + type, + declaration as VariableLikeDeclaration + ) + : type + : typeIsAutomatic + ? undefinedType + : getOptionalType(type); + const flowType = isAutomaticTypeInNonNull + ? getNonNullableType( + getFlowTypeOfReference(node, type, initialType, flowContainer) + ) + : getFlowTypeOfReference(node, type, initialType, flowContainer); // A variable is considered uninitialized when it is possible to analyze the entire control flow graph // from declaration to use, and when the variable's declared type doesn't include undefined but the // control flow based type does include undefined. - if (!isEvolvingArrayOperationTarget(node) && (type === autoType || type === autoArrayType)) { + if ( + !isEvolvingArrayOperationTarget(node) && + (type === autoType || type === autoArrayType) + ) { if (flowType === autoType || flowType === autoArrayType) { if (noImplicitAny) { - error(getNameOfDeclaration(declaration), Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined, symbolToString(symbol), typeToString(flowType)); - error(node, Diagnostics.Variable_0_implicitly_has_an_1_type, symbolToString(symbol), typeToString(flowType)); + error( + getNameOfDeclaration(declaration), + Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined, + symbolToString(symbol), + typeToString(flowType) + ); + error( + node, + Diagnostics.Variable_0_implicitly_has_an_1_type, + symbolToString(symbol), + typeToString(flowType) + ); } return convertAutoToAny(flowType); } - } - else if (!assumeInitialized && !containsUndefinedType(type) && containsUndefinedType(flowType)) { - error(node, Diagnostics.Variable_0_is_used_before_being_assigned, symbolToString(symbol)); + } else if ( + !assumeInitialized && + !containsUndefinedType(type) && + containsUndefinedType(flowType) + ) { + error( + node, + Diagnostics.Variable_0_is_used_before_being_assigned, + symbolToString(symbol) + ); // Return the declared type to reduce follow-on errors return type; } return assignmentKind ? getBaseTypeOfLiteralType(flowType) : flowType; } - function isSameScopedBindingElement(node: Identifier, declaration: Declaration) { + function isSameScopedBindingElement( + node: Identifier, + declaration: Declaration + ) { if (isBindingElement(declaration)) { const bindingElement = findAncestor(node, isBindingElement); - return bindingElement && getRootDeclaration(bindingElement) === getRootDeclaration(declaration); + return ( + bindingElement && + getRootDeclaration(bindingElement) === + getRootDeclaration(declaration) + ); } } @@ -31053,7 +55000,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const parent = node.parent; if (parent) { // A property access expression LHS? checkPropertyAccessExpression will handle that. - if (isPropertyAccessExpression(parent) && parent.expression === node) { + if ( + isPropertyAccessExpression(parent) && + parent.expression === node + ) { return false; } // Next two check for an identifier inside a type only export. @@ -31061,32 +55011,63 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } const greatGrandparent = parent.parent?.parent; - if (greatGrandparent && isExportDeclaration(greatGrandparent) && greatGrandparent.isTypeOnly) { + if ( + greatGrandparent && + isExportDeclaration(greatGrandparent) && + greatGrandparent.isTypeOnly + ) { return false; } } return true; } - function isInsideFunctionOrInstancePropertyInitializer(node: Node, threshold: Node): boolean { - return !!findAncestor(node, n => - n === threshold ? "quit" : isFunctionLike(n) || ( - n.parent && isPropertyDeclaration(n.parent) && !hasStaticModifier(n.parent) && n.parent.initializer === n - )); + function isInsideFunctionOrInstancePropertyInitializer( + node: Node, + threshold: Node + ): boolean { + return !!findAncestor(node, (n) => + n === threshold + ? "quit" + : isFunctionLike(n) || + (n.parent && + isPropertyDeclaration(n.parent) && + !hasStaticModifier(n.parent) && + n.parent.initializer === n) + ); } - function getPartOfForStatementContainingNode(node: Node, container: ForStatement) { - return findAncestor(node, n => n === container ? "quit" : n === container.initializer || n === container.condition || n === container.incrementor || n === container.statement); + function getPartOfForStatementContainingNode( + node: Node, + container: ForStatement + ) { + return findAncestor(node, (n) => + n === container + ? "quit" + : n === container.initializer || + n === container.condition || + n === container.incrementor || + n === container.statement + ); } function getEnclosingIterationStatement(node: Node): Node | undefined { - return findAncestor(node, n => (!n || nodeStartsNewLexicalEnvironment(n)) ? "quit" : isIterationStatement(n, /*lookInLabeledStatements*/ false)); + return findAncestor(node, (n) => + !n || nodeStartsNewLexicalEnvironment(n) + ? "quit" + : isIterationStatement(n, /*lookInLabeledStatements*/ false) + ); } - function checkNestedBlockScopedBinding(node: Identifier, symbol: Symbol): void { + function checkNestedBlockScopedBinding( + node: Identifier, + symbol: Symbol + ): void { if ( languageVersion >= ScriptTarget.ES2015 || - (symbol.flags & (SymbolFlags.BlockScopedVariable | SymbolFlags.Class)) === 0 || + (symbol.flags & + (SymbolFlags.BlockScopedVariable | SymbolFlags.Class)) === + 0 || !symbol.valueDeclaration || isSourceFile(symbol.valueDeclaration) || symbol.valueDeclaration.parent.kind === SyntaxKind.CatchClause @@ -31099,23 +55080,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // 2. walk from the declaration up to the boundary of lexical environment and check // if there is an iteration statement in between declaration and boundary (is binding/class declared inside iteration statement) - const container = getEnclosingBlockScopeContainer(symbol.valueDeclaration); - const isCaptured = isInsideFunctionOrInstancePropertyInitializer(node, container); + const container = getEnclosingBlockScopeContainer( + symbol.valueDeclaration + ); + const isCaptured = isInsideFunctionOrInstancePropertyInitializer( + node, + container + ); - const enclosingIterationStatement = getEnclosingIterationStatement(container); + const enclosingIterationStatement = + getEnclosingIterationStatement(container); if (enclosingIterationStatement) { if (isCaptured) { // mark iteration statement as containing block-scoped binding captured in some function let capturesBlockScopeBindingInLoopBody = true; if (isForStatement(container)) { - const varDeclList = getAncestor(symbol.valueDeclaration, SyntaxKind.VariableDeclarationList); + const varDeclList = getAncestor( + symbol.valueDeclaration, + SyntaxKind.VariableDeclarationList + ); if (varDeclList && varDeclList.parent === container) { - const part = getPartOfForStatementContainingNode(node.parent, container); + const part = getPartOfForStatementContainingNode( + node.parent, + container + ); if (part) { const links = getNodeLinks(part); - links.flags |= NodeCheckFlags.ContainsCapturedBlockScopeBinding; + links.flags |= + NodeCheckFlags.ContainsCapturedBlockScopeBinding; - const capturedBindings = links.capturedBlockScopeBindings || (links.capturedBlockScopeBindings = []); + const capturedBindings = + links.capturedBlockScopeBindings || + (links.capturedBlockScopeBindings = []); pushIfUnique(capturedBindings, symbol); if (part === container.initializer) { @@ -31125,34 +55121,57 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } if (capturesBlockScopeBindingInLoopBody) { - getNodeLinks(enclosingIterationStatement).flags |= NodeCheckFlags.LoopWithCapturedBlockScopedBinding; + getNodeLinks(enclosingIterationStatement).flags |= + NodeCheckFlags.LoopWithCapturedBlockScopedBinding; } } // mark variables that are declared in loop initializer and reassigned inside the body of ForStatement. // if body of ForStatement will be converted to function then we'll need a extra machinery to propagate reassigned values back. if (isForStatement(container)) { - const varDeclList = getAncestor(symbol.valueDeclaration, SyntaxKind.VariableDeclarationList); - if (varDeclList && varDeclList.parent === container && isAssignedInBodyOfForStatement(node, container)) { - getNodeLinks(symbol.valueDeclaration).flags |= NodeCheckFlags.NeedsLoopOutParameter; + const varDeclList = getAncestor( + symbol.valueDeclaration, + SyntaxKind.VariableDeclarationList + ); + if ( + varDeclList && + varDeclList.parent === container && + isAssignedInBodyOfForStatement(node, container) + ) { + getNodeLinks(symbol.valueDeclaration).flags |= + NodeCheckFlags.NeedsLoopOutParameter; } } // set 'declared inside loop' bit on the block-scoped binding - getNodeLinks(symbol.valueDeclaration).flags |= NodeCheckFlags.BlockScopedBindingInLoop; + getNodeLinks(symbol.valueDeclaration).flags |= + NodeCheckFlags.BlockScopedBindingInLoop; } if (isCaptured) { - getNodeLinks(symbol.valueDeclaration).flags |= NodeCheckFlags.CapturedBlockScopedBinding; + getNodeLinks(symbol.valueDeclaration).flags |= + NodeCheckFlags.CapturedBlockScopedBinding; } } - function isBindingCapturedByNode(node: Node, decl: VariableDeclaration | BindingElement) { + function isBindingCapturedByNode( + node: Node, + decl: VariableDeclaration | BindingElement + ) { const links = getNodeLinks(node); - return !!links && contains(links.capturedBlockScopeBindings, getSymbolOfDeclaration(decl)); + return ( + !!links && + contains( + links.capturedBlockScopeBindings, + getSymbolOfDeclaration(decl) + ) + ); } - function isAssignedInBodyOfForStatement(node: Identifier, container: ForStatement): boolean { + function isAssignedInBodyOfForStatement( + node: Identifier, + container: ForStatement + ): boolean { // skip parenthesized nodes let current: Node = node; while (current.parent.kind === SyntaxKind.ParenthesizedExpression) { @@ -31163,10 +55182,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let isAssigned = false; if (isAssignmentTarget(current)) { isAssigned = true; - } - else if ((current.parent.kind === SyntaxKind.PrefixUnaryExpression || current.parent.kind === SyntaxKind.PostfixUnaryExpression)) { - const expr = current.parent as PrefixUnaryExpression | PostfixUnaryExpression; - isAssigned = expr.operator === SyntaxKind.PlusPlusToken || expr.operator === SyntaxKind.MinusMinusToken; + } else if ( + current.parent.kind === SyntaxKind.PrefixUnaryExpression || + current.parent.kind === SyntaxKind.PostfixUnaryExpression + ) { + const expr = current.parent as + | PrefixUnaryExpression + | PostfixUnaryExpression; + isAssigned = + expr.operator === SyntaxKind.PlusPlusToken || + expr.operator === SyntaxKind.MinusMinusToken; } if (!isAssigned) { @@ -31175,24 +55200,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // at this point we know that node is the target of assignment // now check that modification happens inside the statement part of the ForStatement - return !!findAncestor(current, n => n === container ? "quit" : n === container.statement); + return !!findAncestor(current, (n) => + n === container ? "quit" : n === container.statement + ); } function captureLexicalThis(node: Node, container: Node): void { getNodeLinks(node).flags |= NodeCheckFlags.LexicalThis; - if (container.kind === SyntaxKind.PropertyDeclaration || container.kind === SyntaxKind.Constructor) { + if ( + container.kind === SyntaxKind.PropertyDeclaration || + container.kind === SyntaxKind.Constructor + ) { const classNode = container.parent; getNodeLinks(classNode).flags |= NodeCheckFlags.CaptureThis; - } - else { + } else { getNodeLinks(container).flags |= NodeCheckFlags.CaptureThis; } } function findFirstSuperCall(node: Node): SuperCall | undefined { - return isSuperCall(node) ? node : - isFunctionLike(node) ? undefined : - forEachChild(node, findFirstSuperCall); + return isSuperCall(node) + ? node + : isFunctionLike(node) + ? undefined + : forEachChild(node, findFirstSuperCall); } /** @@ -31200,33 +55231,60 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Otherwise, return false * @param classDecl a class declaration to check if it extends null */ - function classDeclarationExtendsNull(classDecl: ClassLikeDeclaration): boolean { + function classDeclarationExtendsNull( + classDecl: ClassLikeDeclaration + ): boolean { const classSymbol = getSymbolOfDeclaration(classDecl); - const classInstanceType = getDeclaredTypeOfSymbol(classSymbol) as InterfaceType; - const baseConstructorType = getBaseConstructorTypeOfClass(classInstanceType); + const classInstanceType = getDeclaredTypeOfSymbol( + classSymbol + ) as InterfaceType; + const baseConstructorType = + getBaseConstructorTypeOfClass(classInstanceType); return baseConstructorType === nullWideningType; } - function checkThisBeforeSuper(node: Node, container: Node, diagnosticMessage: DiagnosticMessage) { + function checkThisBeforeSuper( + node: Node, + container: Node, + diagnosticMessage: DiagnosticMessage + ) { const containingClassDecl = container.parent as ClassDeclaration; - const baseTypeNode = getClassExtendsHeritageElement(containingClassDecl); + const baseTypeNode = + getClassExtendsHeritageElement(containingClassDecl); // If a containing class does not have extends clause or the class extends null // skip checking whether super statement is called before "this" accessing. if (baseTypeNode && !classDeclarationExtendsNull(containingClassDecl)) { - if (canHaveFlowNode(node) && node.flowNode && !isPostSuperFlowNode(node.flowNode, /*noCacheCheck*/ false)) { + if ( + canHaveFlowNode(node) && + node.flowNode && + !isPostSuperFlowNode(node.flowNode, /*noCacheCheck*/ false) + ) { error(node, diagnosticMessage); } } } - function checkThisInStaticClassFieldInitializerInDecoratedClass(thisExpression: Node, container: Node) { + function checkThisInStaticClassFieldInitializerInDecoratedClass( + thisExpression: Node, + container: Node + ) { if ( - isPropertyDeclaration(container) && hasStaticModifier(container) && legacyDecorators && - container.initializer && textRangeContainsPositionInclusive(container.initializer, thisExpression.pos) && hasDecorators(container.parent) + isPropertyDeclaration(container) && + hasStaticModifier(container) && + legacyDecorators && + container.initializer && + textRangeContainsPositionInclusive( + container.initializer, + thisExpression.pos + ) && + hasDecorators(container.parent) ) { - error(thisExpression, Diagnostics.Cannot_use_this_in_a_static_property_initializer_of_a_decorated_class); + error( + thisExpression, + Diagnostics.Cannot_use_this_in_a_static_property_initializer_of_a_decorated_class + ); } } @@ -31234,23 +55292,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const isNodeInTypeQuery = isInTypeQuery(node); // Stop at the first arrow function so that we can // tell whether 'this' needs to be captured. - let container = getThisContainer(node, /*includeArrowFunctions*/ true, /*includeClassComputedPropertyName*/ true); + let container = getThisContainer( + node, + /*includeArrowFunctions*/ true, + /*includeClassComputedPropertyName*/ true + ); let capturedByArrowFunction = false; let thisInComputedPropertyName = false; if (container.kind === SyntaxKind.Constructor) { - checkThisBeforeSuper(node, container, Diagnostics.super_must_be_called_before_accessing_this_in_the_constructor_of_a_derived_class); + checkThisBeforeSuper( + node, + container, + Diagnostics.super_must_be_called_before_accessing_this_in_the_constructor_of_a_derived_class + ); } while (true) { // Now skip arrow functions to get the "real" owner of 'this'. if (container.kind === SyntaxKind.ArrowFunction) { - container = getThisContainer(container, /*includeArrowFunctions*/ false, !thisInComputedPropertyName); + container = getThisContainer( + container, + /*includeArrowFunctions*/ false, + !thisInComputedPropertyName + ); capturedByArrowFunction = true; } if (container.kind === SyntaxKind.ComputedPropertyName) { - container = getThisContainer(container, !capturedByArrowFunction, /*includeClassComputedPropertyName*/ false); + container = getThisContainer( + container, + !capturedByArrowFunction, + /*includeClassComputedPropertyName*/ false + ); thisInComputedPropertyName = true; continue; } @@ -31260,39 +55334,66 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkThisInStaticClassFieldInitializerInDecoratedClass(node, container); if (thisInComputedPropertyName) { - error(node, Diagnostics.this_cannot_be_referenced_in_a_computed_property_name); - } - else { + error( + node, + Diagnostics.this_cannot_be_referenced_in_a_computed_property_name + ); + } else { switch (container.kind) { case SyntaxKind.ModuleDeclaration: - error(node, Diagnostics.this_cannot_be_referenced_in_a_module_or_namespace_body); + error( + node, + Diagnostics.this_cannot_be_referenced_in_a_module_or_namespace_body + ); // do not return here so in case if lexical this is captured - it will be reflected in flags on NodeLinks break; case SyntaxKind.EnumDeclaration: - error(node, Diagnostics.this_cannot_be_referenced_in_current_location); + error( + node, + Diagnostics.this_cannot_be_referenced_in_current_location + ); // do not return here so in case if lexical this is captured - it will be reflected in flags on NodeLinks break; } } // When targeting es6, mark that we'll need to capture `this` in its lexically bound scope. - if (!isNodeInTypeQuery && capturedByArrowFunction && languageVersion < ScriptTarget.ES2015) { + if ( + !isNodeInTypeQuery && + capturedByArrowFunction && + languageVersion < ScriptTarget.ES2015 + ) { captureLexicalThis(node, container); } - const type = tryGetThisTypeAt(node, /*includeGlobalThis*/ true, container); + const type = tryGetThisTypeAt( + node, + /*includeGlobalThis*/ true, + container + ); if (noImplicitThis) { const globalThisType = getTypeOfSymbol(globalThisSymbol); if (type === globalThisType && capturedByArrowFunction) { - error(node, Diagnostics.The_containing_arrow_function_captures_the_global_value_of_this); - } - else if (!type) { + error( + node, + Diagnostics.The_containing_arrow_function_captures_the_global_value_of_this + ); + } else if (!type) { // With noImplicitThis, functions may not reference 'this' if it has type 'any' - const diag = error(node, Diagnostics.this_implicitly_has_type_any_because_it_does_not_have_a_type_annotation); + const diag = error( + node, + Diagnostics.this_implicitly_has_type_any_because_it_does_not_have_a_type_annotation + ); if (!isSourceFile(container)) { const outsideThis = tryGetThisTypeAt(container); if (outsideThis && outsideThis !== globalThisType) { - addRelatedInfo(diag, createDiagnosticForNode(container, Diagnostics.An_outer_value_of_this_is_shadowed_by_this_container)); + addRelatedInfo( + diag, + createDiagnosticForNode( + container, + Diagnostics.An_outer_value_of_this_is_shadowed_by_this_container + ) + ); } } } @@ -31300,25 +55401,47 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return type || anyType; } - function tryGetThisTypeAt(node: Node, includeGlobalThis = true, container = getThisContainer(node, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false)): Type | undefined { + function tryGetThisTypeAt( + node: Node, + includeGlobalThis = true, + container = getThisContainer( + node, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false + ) + ): Type | undefined { const isInJS = isInJSFile(node); if ( isFunctionLike(container) && - (!isInParameterInitializerBeforeContainingFunction(node) || getThisParameter(container)) + (!isInParameterInitializerBeforeContainingFunction(node) || + getThisParameter(container)) ) { - let thisType = getThisTypeOfDeclaration(container) || isInJS && getTypeForThisExpressionFromJSDoc(container); + let thisType = + getThisTypeOfDeclaration(container) || + (isInJS && getTypeForThisExpressionFromJSDoc(container)); // Note: a parameter initializer should refer to class-this unless function-this is explicitly annotated. // If this is a function in a JS file, it might be a class method. if (!thisType) { const className = getClassNameFromPrototypeMethod(container); if (isInJS && className) { const classSymbol = checkExpression(className).symbol; - if (classSymbol && classSymbol.members && (classSymbol.flags & SymbolFlags.Function)) { - thisType = (getDeclaredTypeOfSymbol(classSymbol) as InterfaceType).thisType; - } - } - else if (isJSConstructor(container)) { - thisType = (getDeclaredTypeOfSymbol(getMergedSymbol(container.symbol)) as InterfaceType).thisType; + if ( + classSymbol && + classSymbol.members && + classSymbol.flags & SymbolFlags.Function + ) { + thisType = ( + getDeclaredTypeOfSymbol( + classSymbol + ) as InterfaceType + ).thisType; + } + } else if (isJSConstructor(container)) { + thisType = ( + getDeclaredTypeOfSymbol( + getMergedSymbol(container.symbol) + ) as InterfaceType + ).thisType; } thisType ||= getContextualThisParameterType(container); } @@ -31330,7 +55453,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isClassLike(container.parent)) { const symbol = getSymbolOfDeclaration(container.parent); - const type = isStatic(container) ? getTypeOfSymbol(symbol) : (getDeclaredTypeOfSymbol(symbol) as InterfaceType).thisType!; + const type = isStatic(container) + ? getTypeOfSymbol(symbol) + : (getDeclaredTypeOfSymbol(symbol) as InterfaceType).thisType!; return getFlowTypeOfReference(node, type); } @@ -31339,19 +55464,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (container.commonJsModuleIndicator) { const fileSymbol = getSymbolOfDeclaration(container); return fileSymbol && getTypeOfSymbol(fileSymbol); - } - else if (container.externalModuleIndicator) { + } else if (container.externalModuleIndicator) { // TODO: Maybe issue a better error than 'object is possibly undefined' return undefinedType; - } - else if (includeGlobalThis) { + } else if (includeGlobalThis) { return getTypeOfSymbol(globalThisSymbol); } } } function getExplicitThisType(node: Expression) { - const container = getThisContainer(node, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); + const container = getThisContainer( + node, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false + ); if (isFunctionLike(container)) { const signature = getSignatureFromDeclaration(container); if (signature.thisParameter) { @@ -31360,7 +55487,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (isClassLike(container.parent)) { const symbol = getSymbolOfDeclaration(container.parent); - return isStatic(container) ? getTypeOfSymbol(symbol) : (getDeclaredTypeOfSymbol(symbol) as InterfaceType).thisType!; + return isStatic(container) + ? getTypeOfSymbol(symbol) + : (getDeclaredTypeOfSymbol(symbol) as InterfaceType).thisType!; } } @@ -31369,32 +55498,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if ( container.kind === SyntaxKind.FunctionExpression && isBinaryExpression(container.parent) && - getAssignmentDeclarationKind(container.parent) === AssignmentDeclarationKind.PrototypeProperty + getAssignmentDeclarationKind(container.parent) === + AssignmentDeclarationKind.PrototypeProperty ) { // Get the 'x' of 'x.prototype.y = container' - return ((container.parent // x.prototype.y = container - .left as PropertyAccessExpression) // x.prototype.y - .expression as PropertyAccessExpression) // x.prototype - .expression; // x + return ( + (container.parent.left as PropertyAccessExpression) // x.prototype.y = container + .expression as PropertyAccessExpression + ).expression; // x.prototype.y // x.prototype // x } // x.prototype = { method() { } } else if ( container.kind === SyntaxKind.MethodDeclaration && container.parent.kind === SyntaxKind.ObjectLiteralExpression && isBinaryExpression(container.parent.parent) && - getAssignmentDeclarationKind(container.parent.parent) === AssignmentDeclarationKind.Prototype + getAssignmentDeclarationKind(container.parent.parent) === + AssignmentDeclarationKind.Prototype ) { - return (container.parent.parent.left as PropertyAccessExpression).expression; + return (container.parent.parent.left as PropertyAccessExpression) + .expression; } // x.prototype = { method: function() { } } else if ( container.kind === SyntaxKind.FunctionExpression && container.parent.kind === SyntaxKind.PropertyAssignment && - container.parent.parent.kind === SyntaxKind.ObjectLiteralExpression && + container.parent.parent.kind === + SyntaxKind.ObjectLiteralExpression && isBinaryExpression(container.parent.parent.parent) && - getAssignmentDeclarationKind(container.parent.parent.parent) === AssignmentDeclarationKind.Prototype + getAssignmentDeclarationKind(container.parent.parent.parent) === + AssignmentDeclarationKind.Prototype ) { - return (container.parent.parent.parent.left as PropertyAccessExpression).expression; + return ( + container.parent.parent.parent.left as PropertyAccessExpression + ).expression; } // Object.defineProperty(x, "method", { value: function() { } }); // Object.defineProperty(x, "method", { set: (x: () => void) => void }); @@ -31403,13 +55539,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { container.kind === SyntaxKind.FunctionExpression && isPropertyAssignment(container.parent) && isIdentifier(container.parent.name) && - (container.parent.name.escapedText === "value" || container.parent.name.escapedText === "get" || container.parent.name.escapedText === "set") && + (container.parent.name.escapedText === "value" || + container.parent.name.escapedText === "get" || + container.parent.name.escapedText === "set") && isObjectLiteralExpression(container.parent.parent) && isCallExpression(container.parent.parent.parent) && - container.parent.parent.parent.arguments[2] === container.parent.parent && - getAssignmentDeclarationKind(container.parent.parent.parent) === AssignmentDeclarationKind.ObjectDefinePrototypeProperty + container.parent.parent.parent.arguments[2] === + container.parent.parent && + getAssignmentDeclarationKind(container.parent.parent.parent) === + AssignmentDeclarationKind.ObjectDefinePrototypeProperty ) { - return (container.parent.parent.parent.arguments[0] as PropertyAccessExpression).expression; + return ( + container.parent.parent.parent + .arguments[0] as PropertyAccessExpression + ).expression; } // Object.defineProperty(x, "method", { value() { } }); // Object.defineProperty(x, "method", { set(x: () => void) {} }); @@ -31417,13 +55560,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else if ( isMethodDeclaration(container) && isIdentifier(container.name) && - (container.name.escapedText === "value" || container.name.escapedText === "get" || container.name.escapedText === "set") && + (container.name.escapedText === "value" || + container.name.escapedText === "get" || + container.name.escapedText === "set") && isObjectLiteralExpression(container.parent) && isCallExpression(container.parent.parent) && container.parent.parent.arguments[2] === container.parent && - getAssignmentDeclarationKind(container.parent.parent) === AssignmentDeclarationKind.ObjectDefinePrototypeProperty + getAssignmentDeclarationKind(container.parent.parent) === + AssignmentDeclarationKind.ObjectDefinePrototypeProperty ) { - return (container.parent.parent.arguments[0] as PropertyAccessExpression).expression; + return ( + container.parent.parent.arguments[0] as PropertyAccessExpression + ).expression; } } @@ -31438,14 +55586,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function isInConstructorArgumentInitializer(node: Node, constructorDecl: Node): boolean { - return !!findAncestor(node, n => isFunctionLikeDeclaration(n) ? "quit" : n.kind === SyntaxKind.Parameter && n.parent === constructorDecl); + function isInConstructorArgumentInitializer( + node: Node, + constructorDecl: Node + ): boolean { + return !!findAncestor(node, (n) => + isFunctionLikeDeclaration(n) + ? "quit" + : n.kind === SyntaxKind.Parameter && + n.parent === constructorDecl + ); } function checkSuperExpression(node: Node): Type { - const isCallExpression = node.parent.kind === SyntaxKind.CallExpression && (node.parent as CallExpression).expression === node; + const isCallExpression = + node.parent.kind === SyntaxKind.CallExpression && + (node.parent as CallExpression).expression === node; - const immediateContainer = getSuperContainer(node, /*stopOnFunctions*/ true); + const immediateContainer = getSuperContainer( + node, + /*stopOnFunctions*/ true + ); let container = immediateContainer; let needToCaptureLexicalThis = false; let inAsyncFunction = false; @@ -31453,11 +55614,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // adjust the container reference in case if super is used inside arrow functions with arbitrarily deep nesting if (!isCallExpression) { while (container && container.kind === SyntaxKind.ArrowFunction) { - if (hasSyntacticModifier(container, ModifierFlags.Async)) inAsyncFunction = true; - container = getSuperContainer(container, /*stopOnFunctions*/ true); - needToCaptureLexicalThis = languageVersion < ScriptTarget.ES2015; + if (hasSyntacticModifier(container, ModifierFlags.Async)) + inAsyncFunction = true; + container = getSuperContainer( + container, + /*stopOnFunctions*/ true + ); + needToCaptureLexicalThis = + languageVersion < ScriptTarget.ES2015; } - if (container && hasSyntacticModifier(container, ModifierFlags.Async)) inAsyncFunction = true; + if ( + container && + hasSyntacticModifier(container, ModifierFlags.Async) + ) + inAsyncFunction = true; } let nodeCheckFlag: NodeCheckFlags = 0; @@ -31468,44 +55638,76 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // class B { // [super.foo()]() {} // } - const current = findAncestor(node, n => n === container ? "quit" : n.kind === SyntaxKind.ComputedPropertyName); + const current = findAncestor(node, (n) => + n === container + ? "quit" + : n.kind === SyntaxKind.ComputedPropertyName + ); if (current && current.kind === SyntaxKind.ComputedPropertyName) { - error(node, Diagnostics.super_cannot_be_referenced_in_a_computed_property_name); - } - else if (isCallExpression) { - error(node, Diagnostics.Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors); - } - else if (!container || !container.parent || !(isClassLike(container.parent) || container.parent.kind === SyntaxKind.ObjectLiteralExpression)) { - error(node, Diagnostics.super_can_only_be_referenced_in_members_of_derived_classes_or_object_literal_expressions); - } - else { - error(node, Diagnostics.super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class); + error( + node, + Diagnostics.super_cannot_be_referenced_in_a_computed_property_name + ); + } else if (isCallExpression) { + error( + node, + Diagnostics.Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors + ); + } else if ( + !container || + !container.parent || + !( + isClassLike(container.parent) || + container.parent.kind === SyntaxKind.ObjectLiteralExpression + ) + ) { + error( + node, + Diagnostics.super_can_only_be_referenced_in_members_of_derived_classes_or_object_literal_expressions + ); + } else { + error( + node, + Diagnostics.super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class + ); } return errorType; } - if (!isCallExpression && immediateContainer!.kind === SyntaxKind.Constructor) { - checkThisBeforeSuper(node, container, Diagnostics.super_must_be_called_before_accessing_a_property_of_super_in_the_constructor_of_a_derived_class); + if ( + !isCallExpression && + immediateContainer!.kind === SyntaxKind.Constructor + ) { + checkThisBeforeSuper( + node, + container, + Diagnostics.super_must_be_called_before_accessing_a_property_of_super_in_the_constructor_of_a_derived_class + ); } if (isStatic(container) || isCallExpression) { nodeCheckFlag = NodeCheckFlags.SuperStatic; if ( !isCallExpression && - languageVersion >= ScriptTarget.ES2015 && languageVersion <= ScriptTarget.ES2021 && - (isPropertyDeclaration(container) || isClassStaticBlockDeclaration(container)) + languageVersion >= ScriptTarget.ES2015 && + languageVersion <= ScriptTarget.ES2021 && + (isPropertyDeclaration(container) || + isClassStaticBlockDeclaration(container)) ) { // for `super.x` or `super[x]` in a static initializer, mark all enclosing // block scope containers so that we can report potential collisions with // `Reflect`. - forEachEnclosingBlockScopeContainer(node.parent, current => { - if (!isSourceFile(current) || isExternalOrCommonJsModule(current)) { - getNodeLinks(current).flags |= NodeCheckFlags.ContainsSuperPropertyInStaticInitializer; + forEachEnclosingBlockScopeContainer(node.parent, (current) => { + if ( + !isSourceFile(current) || + isExternalOrCommonJsModule(current) + ) { + getNodeLinks(current).flags |= + NodeCheckFlags.ContainsSuperPropertyInStaticInitializer; } }); } - } - else { + } else { nodeCheckFlag = NodeCheckFlags.SuperInstance; } @@ -31570,12 +55772,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // as a call expression cannot be used as the target of a destructuring assignment while a property access can. // // For element access expressions (`super[x]`), we emit a generic helper that forwards the element access in both situations. - if (container.kind === SyntaxKind.MethodDeclaration && inAsyncFunction) { - if (isSuperProperty(node.parent) && isAssignmentTarget(node.parent)) { - getNodeLinks(container).flags |= NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync; - } - else { - getNodeLinks(container).flags |= NodeCheckFlags.MethodWithSuperPropertyAccessInAsync; + if ( + container.kind === SyntaxKind.MethodDeclaration && + inAsyncFunction + ) { + if ( + isSuperProperty(node.parent) && + isAssignmentTarget(node.parent) + ) { + getNodeLinks(container).flags |= + NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync; + } else { + getNodeLinks(container).flags |= + NodeCheckFlags.MethodWithSuperPropertyAccessInAsync; } } @@ -31588,10 +55797,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (container.parent.kind === SyntaxKind.ObjectLiteralExpression) { if (languageVersion < ScriptTarget.ES2015) { - error(node, Diagnostics.super_is_only_allowed_in_members_of_object_literal_expressions_when_option_target_is_ES2015_or_higher); + error( + node, + Diagnostics.super_is_only_allowed_in_members_of_object_literal_expressions_when_option_target_is_ES2015_or_higher + ); return errorType; - } - else { + } else { // for object literal assume that type of 'super' is 'any' return anyType; } @@ -31600,7 +55811,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // at this point the only legal case for parent is ClassLikeDeclaration const classLikeDeclaration = container.parent as ClassLikeDeclaration; if (!getClassExtendsHeritageElement(classLikeDeclaration)) { - error(node, Diagnostics.super_can_only_be_referenced_in_a_derived_class); + error( + node, + Diagnostics.super_can_only_be_referenced_in_a_derived_class + ); return errorType; } @@ -31608,15 +55822,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return isCallExpression ? errorType : nullWideningType; } - const classType = getDeclaredTypeOfSymbol(getSymbolOfDeclaration(classLikeDeclaration)) as InterfaceType; + const classType = getDeclaredTypeOfSymbol( + getSymbolOfDeclaration(classLikeDeclaration) + ) as InterfaceType; const baseClassType = classType && getBaseTypes(classType)[0]; if (!baseClassType) { return errorType; } - if (container.kind === SyntaxKind.Constructor && isInConstructorArgumentInitializer(node, container)) { + if ( + container.kind === SyntaxKind.Constructor && + isInConstructorArgumentInitializer(node, container) + ) { // issue custom error message for super property access in constructor arguments (to be aligned with old compiler) - error(node, Diagnostics.super_cannot_be_referenced_in_constructor_arguments); + error( + node, + Diagnostics.super_cannot_be_referenced_in_constructor_arguments + ); return errorType; } @@ -31629,31 +55851,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // TS 1.0 SPEC (April 2014): 4.8.1 // Super calls are only permitted in constructors of derived classes return container.kind === SyntaxKind.Constructor; - } - else { + } else { // TS 1.0 SPEC (April 2014) // 'super' property access is allowed // - In a constructor, instance member function, instance member accessor, or instance member variable initializer where this references a derived class instance // - In a static member function or static member accessor // topmost container must be something that is directly nested in the class declaration\object literal expression - if (isClassLike(container.parent) || container.parent.kind === SyntaxKind.ObjectLiteralExpression) { + if ( + isClassLike(container.parent) || + container.parent.kind === SyntaxKind.ObjectLiteralExpression + ) { if (isStatic(container)) { - return container.kind === SyntaxKind.MethodDeclaration || + return ( + container.kind === SyntaxKind.MethodDeclaration || container.kind === SyntaxKind.MethodSignature || container.kind === SyntaxKind.GetAccessor || container.kind === SyntaxKind.SetAccessor || container.kind === SyntaxKind.PropertyDeclaration || - container.kind === SyntaxKind.ClassStaticBlockDeclaration; - } - else { - return container.kind === SyntaxKind.MethodDeclaration || + container.kind === + SyntaxKind.ClassStaticBlockDeclaration + ); + } else { + return ( + container.kind === SyntaxKind.MethodDeclaration || container.kind === SyntaxKind.MethodSignature || container.kind === SyntaxKind.GetAccessor || container.kind === SyntaxKind.SetAccessor || container.kind === SyntaxKind.PropertyDeclaration || container.kind === SyntaxKind.PropertySignature || - container.kind === SyntaxKind.Constructor; + container.kind === SyntaxKind.Constructor + ); } } } @@ -31662,25 +55890,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getContainingObjectLiteral(func: SignatureDeclaration): ObjectLiteralExpression | undefined { + function getContainingObjectLiteral( + func: SignatureDeclaration + ): ObjectLiteralExpression | undefined { return (func.kind === SyntaxKind.MethodDeclaration || - func.kind === SyntaxKind.GetAccessor || - func.kind === SyntaxKind.SetAccessor) && func.parent.kind === SyntaxKind.ObjectLiteralExpression ? func.parent : - func.kind === SyntaxKind.FunctionExpression && func.parent.kind === SyntaxKind.PropertyAssignment ? func.parent.parent as ObjectLiteralExpression : - undefined; + func.kind === SyntaxKind.GetAccessor || + func.kind === SyntaxKind.SetAccessor) && + func.parent.kind === SyntaxKind.ObjectLiteralExpression + ? func.parent + : func.kind === SyntaxKind.FunctionExpression && + func.parent.kind === SyntaxKind.PropertyAssignment + ? (func.parent.parent as ObjectLiteralExpression) + : undefined; } function getThisTypeArgument(type: Type): Type | undefined { - return getObjectFlags(type) & ObjectFlags.Reference && (type as TypeReference).target === globalThisType ? getTypeArguments(type as TypeReference)[0] : undefined; + return getObjectFlags(type) & ObjectFlags.Reference && + (type as TypeReference).target === globalThisType + ? getTypeArguments(type as TypeReference)[0] + : undefined; } function getThisTypeFromContextualType(type: Type): Type | undefined { - return mapType(type, t => { - return t.flags & TypeFlags.Intersection ? forEach((t as IntersectionType).types, getThisTypeArgument) : getThisTypeArgument(t); + return mapType(type, (t) => { + return t.flags & TypeFlags.Intersection + ? forEach((t as IntersectionType).types, getThisTypeArgument) + : getThisTypeArgument(t); }); } - function getThisTypeOfObjectLiteralFromContextualType(containingLiteral: ObjectLiteralExpression, contextualType: Type | undefined) { + function getThisTypeOfObjectLiteralFromContextualType( + containingLiteral: ObjectLiteralExpression, + contextualType: Type | undefined + ) { let literal = containingLiteral; let type = contextualType; while (type) { @@ -31692,11 +55934,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { break; } literal = literal.parent.parent as ObjectLiteralExpression; - type = getApparentTypeOfContextualType(literal, /*contextFlags*/ undefined); + type = getApparentTypeOfContextualType( + literal, + /*contextFlags*/ undefined + ); } } - function getContextualThisParameterType(func: SignatureDeclaration): Type | undefined { + function getContextualThisParameterType( + func: SignatureDeclaration + ): Type | undefined { if (func.kind === SyntaxKind.ArrowFunction) { return undefined; } @@ -31716,15 +55963,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We have an object literal method. Check if the containing object literal has a contextual type // that includes a ThisType. If so, T is the contextual type for 'this'. We continue looking in // any directly enclosing object literals. - const contextualType = getApparentTypeOfContextualType(containingLiteral, /*contextFlags*/ undefined); - const thisType = getThisTypeOfObjectLiteralFromContextualType(containingLiteral, contextualType); + const contextualType = getApparentTypeOfContextualType( + containingLiteral, + /*contextFlags*/ undefined + ); + const thisType = getThisTypeOfObjectLiteralFromContextualType( + containingLiteral, + contextualType + ); if (thisType) { - return instantiateType(thisType, getMapperFromContext(getInferenceContext(containingLiteral))); + return instantiateType( + thisType, + getMapperFromContext( + getInferenceContext(containingLiteral) + ) + ); } // There was no contextual ThisType for the containing object literal, so the contextual type // for 'this' is the non-null form of the contextual type for the containing object literal or // the type of the object literal itself. - return getWidenedType(contextualType ? getNonNullableType(contextualType) : checkExpressionCached(containingLiteral)); + return getWidenedType( + contextualType + ? getNonNullableType(contextualType) + : checkExpressionCached(containingLiteral) + ); } // In an assignment of the form 'obj.xxx = function(...)' or 'obj[xxx] = function(...)', the // contextual type for 'this' is 'obj'. @@ -31736,7 +55998,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Don't contextually type `this` as `exports` in `exports.Point = function(x, y) { this.x = x; this.y = y; }` if (inJs && isIdentifier(expression)) { const sourceFile = getSourceFileOfNode(parent); - if (sourceFile.commonJsModuleIndicator && getResolvedSymbol(expression) === sourceFile.symbol) { + if ( + sourceFile.commonJsModuleIndicator && + getResolvedSymbol(expression) === sourceFile.symbol + ) { return undefined; } } @@ -31749,7 +56014,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Return contextual type of parameter or undefined if no contextual type is available - function getContextuallyTypedParameterType(parameter: ParameterDeclaration): Type | undefined { + function getContextuallyTypedParameterType( + parameter: ParameterDeclaration + ): Type | undefined { const func = parameter.parent; if (!isContextSensitiveFunctionOrObjectLiteralMethod(func)) { return undefined; @@ -31759,28 +56026,50 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const args = getEffectiveCallArguments(iife); const indexOfParameter = func.parameters.indexOf(parameter); if (parameter.dotDotDotToken) { - return getSpreadArgumentType(args, indexOfParameter, args.length, anyType, /*context*/ undefined, CheckMode.Normal); + return getSpreadArgumentType( + args, + indexOfParameter, + args.length, + anyType, + /*context*/ undefined, + CheckMode.Normal + ); } const links = getNodeLinks(iife); const cached = links.resolvedSignature; links.resolvedSignature = anySignature; - const type = indexOfParameter < args.length ? - getWidenedLiteralType(checkExpression(args[indexOfParameter])) : - parameter.initializer ? undefined : undefinedWideningType; + const type = + indexOfParameter < args.length + ? getWidenedLiteralType( + checkExpression(args[indexOfParameter]) + ) + : parameter.initializer + ? undefined + : undefinedWideningType; links.resolvedSignature = cached; return type; } const contextualSignature = getContextualSignature(func); if (contextualSignature) { - const index = func.parameters.indexOf(parameter) - (getThisParameter(func) ? 1 : 0); - return parameter.dotDotDotToken && lastOrUndefined(func.parameters) === parameter ? - getRestTypeAtPosition(contextualSignature, index) : - tryGetTypeAtPosition(contextualSignature, index); + const index = + func.parameters.indexOf(parameter) - + (getThisParameter(func) ? 1 : 0); + return parameter.dotDotDotToken && + lastOrUndefined(func.parameters) === parameter + ? getRestTypeAtPosition(contextualSignature, index) + : tryGetTypeAtPosition(contextualSignature, index); } } - function getContextualTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration, contextFlags: ContextFlags | undefined): Type | undefined { - const typeNode = getEffectiveTypeAnnotationNode(declaration) || (isInJSFile(declaration) ? tryGetJSDocSatisfiesTypeNode(declaration) : undefined); + function getContextualTypeForVariableLikeDeclaration( + declaration: VariableLikeDeclaration, + contextFlags: ContextFlags | undefined + ): Type | undefined { + const typeNode = + getEffectiveTypeAnnotationNode(declaration) || + (isInJSFile(declaration) + ? tryGetJSDocSatisfiesTypeNode(declaration) + : undefined); if (typeNode) { return getTypeFromTypeNode(typeNode); } @@ -31788,21 +56077,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.Parameter: return getContextuallyTypedParameterType(declaration); case SyntaxKind.BindingElement: - return getContextualTypeForBindingElement(declaration, contextFlags); + return getContextualTypeForBindingElement( + declaration, + contextFlags + ); case SyntaxKind.PropertyDeclaration: if (isStatic(declaration)) { - return getContextualTypeForStaticPropertyDeclaration(declaration, contextFlags); + return getContextualTypeForStaticPropertyDeclaration( + declaration, + contextFlags + ); } - // By default, do nothing and return undefined - only the above cases have context implied by a parent + // By default, do nothing and return undefined - only the above cases have context implied by a parent } } - function getContextualTypeForBindingElement(declaration: BindingElement, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForBindingElement( + declaration: BindingElement, + contextFlags: ContextFlags | undefined + ): Type | undefined { const parent = declaration.parent.parent; const name = declaration.propertyName || declaration.name; - const parentType = getContextualTypeForVariableLikeDeclaration(parent, contextFlags) || - parent.kind !== SyntaxKind.BindingElement && parent.initializer && checkDeclarationInitializer(parent, declaration.dotDotDotToken ? CheckMode.RestBindingElement : CheckMode.Normal); - if (!parentType || isBindingPattern(name) || isComputedNonLiteralName(name)) return undefined; + const parentType = + getContextualTypeForVariableLikeDeclaration(parent, contextFlags) || + (parent.kind !== SyntaxKind.BindingElement && + parent.initializer && + checkDeclarationInitializer( + parent, + declaration.dotDotDotToken + ? CheckMode.RestBindingElement + : CheckMode.Normal + )); + if ( + !parentType || + isBindingPattern(name) || + isComputedNonLiteralName(name) + ) + return undefined; if (parent.name.kind === SyntaxKind.ArrayBindingPattern) { const index = indexOfNode(declaration.parent.elements, declaration); if (index < 0) return undefined; @@ -31815,10 +56126,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getContextualTypeForStaticPropertyDeclaration(declaration: PropertyDeclaration, contextFlags: ContextFlags | undefined): Type | undefined { - const parentType = isExpression(declaration.parent) && getContextualType(declaration.parent, contextFlags); + function getContextualTypeForStaticPropertyDeclaration( + declaration: PropertyDeclaration, + contextFlags: ContextFlags | undefined + ): Type | undefined { + const parentType = + isExpression(declaration.parent) && + getContextualType(declaration.parent, contextFlags); if (!parentType) return undefined; - return getTypeOfPropertyOfContextualType(parentType, getSymbolOfDeclaration(declaration).escapedName); + return getTypeOfPropertyOfContextualType( + parentType, + getSymbolOfDeclaration(declaration).escapedName + ); } // In a variable, parameter or property declaration with a type annotation, @@ -31829,32 +56148,67 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // the contextual type of an initializer expression is the type implied by the binding pattern. // Otherwise, in a binding pattern inside a variable or parameter declaration, // the contextual type of an initializer expression is the type annotation of the containing declaration, if present. - function getContextualTypeForInitializerExpression(node: Expression, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForInitializerExpression( + node: Expression, + contextFlags: ContextFlags | undefined + ): Type | undefined { const declaration = node.parent as VariableLikeDeclaration; if (hasInitializer(declaration) && node === declaration.initializer) { - const result = getContextualTypeForVariableLikeDeclaration(declaration, contextFlags); + const result = getContextualTypeForVariableLikeDeclaration( + declaration, + contextFlags + ); if (result) { return result; } - if (!(contextFlags! & ContextFlags.SkipBindingPatterns) && isBindingPattern(declaration.name) && declaration.name.elements.length > 0) { - return getTypeFromBindingPattern(declaration.name, /*includePatternInType*/ true, /*reportErrors*/ false); + if ( + !(contextFlags! & ContextFlags.SkipBindingPatterns) && + isBindingPattern(declaration.name) && + declaration.name.elements.length > 0 + ) { + return getTypeFromBindingPattern( + declaration.name, + /*includePatternInType*/ true, + /*reportErrors*/ false + ); } } return undefined; } - function getContextualTypeForReturnExpression(node: Expression, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForReturnExpression( + node: Expression, + contextFlags: ContextFlags | undefined + ): Type | undefined { const func = getContainingFunction(node); if (func) { - let contextualReturnType = getContextualReturnType(func, contextFlags); + let contextualReturnType = getContextualReturnType( + func, + contextFlags + ); if (contextualReturnType) { const functionFlags = getFunctionFlags(func); - if (functionFlags & FunctionFlags.Generator) { // Generator or AsyncGenerator function - const isAsyncGenerator = (functionFlags & FunctionFlags.Async) !== 0; + if (functionFlags & FunctionFlags.Generator) { + // Generator or AsyncGenerator function + const isAsyncGenerator = + (functionFlags & FunctionFlags.Async) !== 0; if (contextualReturnType.flags & TypeFlags.Union) { - contextualReturnType = filterType(contextualReturnType, type => !!getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, type, isAsyncGenerator)); + contextualReturnType = filterType( + contextualReturnType, + (type) => + !!getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Return, + type, + isAsyncGenerator + ) + ); } - const iterationReturnType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, contextualReturnType, (functionFlags & FunctionFlags.Async) !== 0); + const iterationReturnType = + getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Return, + contextualReturnType, + (functionFlags & FunctionFlags.Async) !== 0 + ); if (!iterationReturnType) { return undefined; } @@ -31862,10 +56216,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // falls through to unwrap Promise for AsyncGenerators } - if (functionFlags & FunctionFlags.Async) { // Async function or AsyncGenerator function + if (functionFlags & FunctionFlags.Async) { + // Async function or AsyncGenerator function // Get the awaited type without the `Awaited` alias - const contextualAwaitedType = mapType(contextualReturnType, getAwaitedTypeNoAlias); - return contextualAwaitedType && getUnionType([contextualAwaitedType, createPromiseLikeType(contextualAwaitedType)]); + const contextualAwaitedType = mapType( + contextualReturnType, + getAwaitedTypeNoAlias + ); + return ( + contextualAwaitedType && + getUnionType([ + contextualAwaitedType, + createPromiseLikeType(contextualAwaitedType), + ]) + ); } return contextualReturnType; // Regular function or Generator function @@ -31874,38 +56238,89 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - function getContextualTypeForAwaitOperand(node: AwaitExpression, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForAwaitOperand( + node: AwaitExpression, + contextFlags: ContextFlags | undefined + ): Type | undefined { const contextualType = getContextualType(node, contextFlags); if (contextualType) { const contextualAwaitedType = getAwaitedTypeNoAlias(contextualType); - return contextualAwaitedType && getUnionType([contextualAwaitedType, createPromiseLikeType(contextualAwaitedType)]); + return ( + contextualAwaitedType && + getUnionType([ + contextualAwaitedType, + createPromiseLikeType(contextualAwaitedType), + ]) + ); } return undefined; } - function getContextualTypeForYieldOperand(node: YieldExpression, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForYieldOperand( + node: YieldExpression, + contextFlags: ContextFlags | undefined + ): Type | undefined { const func = getContainingFunction(node); if (func) { const functionFlags = getFunctionFlags(func); - let contextualReturnType = getContextualReturnType(func, contextFlags); + let contextualReturnType = getContextualReturnType( + func, + contextFlags + ); if (contextualReturnType) { - const isAsyncGenerator = (functionFlags & FunctionFlags.Async) !== 0; - if (!node.asteriskToken && contextualReturnType.flags & TypeFlags.Union) { - contextualReturnType = filterType(contextualReturnType, type => !!getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, type, isAsyncGenerator)); + const isAsyncGenerator = + (functionFlags & FunctionFlags.Async) !== 0; + if ( + !node.asteriskToken && + contextualReturnType.flags & TypeFlags.Union + ) { + contextualReturnType = filterType( + contextualReturnType, + (type) => + !!getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Return, + type, + isAsyncGenerator + ) + ); } if (node.asteriskToken) { - const iterationTypes = getIterationTypesOfGeneratorFunctionReturnType(contextualReturnType, isAsyncGenerator); - const yieldType = iterationTypes?.yieldType ?? silentNeverType; - const returnType = getContextualType(node, contextFlags) ?? silentNeverType; + const iterationTypes = + getIterationTypesOfGeneratorFunctionReturnType( + contextualReturnType, + isAsyncGenerator + ); + const yieldType = + iterationTypes?.yieldType ?? silentNeverType; + const returnType = + getContextualType(node, contextFlags) ?? + silentNeverType; const nextType = iterationTypes?.nextType ?? unknownType; - const generatorType = createGeneratorType(yieldType, returnType, nextType, /*isAsyncGenerator*/ false); + const generatorType = createGeneratorType( + yieldType, + returnType, + nextType, + /*isAsyncGenerator*/ false + ); if (isAsyncGenerator) { - const asyncGeneratorType = createGeneratorType(yieldType, returnType, nextType, /*isAsyncGenerator*/ true); - return getUnionType([generatorType, asyncGeneratorType]); + const asyncGeneratorType = createGeneratorType( + yieldType, + returnType, + nextType, + /*isAsyncGenerator*/ true + ); + return getUnionType([ + generatorType, + asyncGeneratorType, + ]); } return generatorType; } - return getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Yield, contextualReturnType, isAsyncGenerator); + return getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Yield, + contextualReturnType, + isAsyncGenerator + ); } } @@ -31915,10 +56330,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isInParameterInitializerBeforeContainingFunction(node: Node) { let inBindingInitializer = false; while (node.parent && !isFunctionLike(node.parent)) { - if (isParameter(node.parent) && (inBindingInitializer || node.parent.initializer === node)) { + if ( + isParameter(node.parent) && + (inBindingInitializer || node.parent.initializer === node) + ) { return true; } - if (isBindingElement(node.parent) && node.parent.initializer === node) { + if ( + isBindingElement(node.parent) && + node.parent.initializer === node + ) { inBindingInitializer = true; } @@ -31928,18 +56349,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function getContextualIterationType(kind: IterationTypeKind, functionDecl: SignatureDeclaration): Type | undefined { - const isAsync = !!(getFunctionFlags(functionDecl) & FunctionFlags.Async); - const contextualReturnType = getContextualReturnType(functionDecl, /*contextFlags*/ undefined); + function getContextualIterationType( + kind: IterationTypeKind, + functionDecl: SignatureDeclaration + ): Type | undefined { + const isAsync = !!( + getFunctionFlags(functionDecl) & FunctionFlags.Async + ); + const contextualReturnType = getContextualReturnType( + functionDecl, + /*contextFlags*/ undefined + ); if (contextualReturnType) { - return getIterationTypeOfGeneratorFunctionReturnType(kind, contextualReturnType, isAsync) - || undefined; + return ( + getIterationTypeOfGeneratorFunctionReturnType( + kind, + contextualReturnType, + isAsync + ) || undefined + ); } return undefined; } - function getContextualReturnType(functionDecl: SignatureDeclaration, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualReturnType( + functionDecl: SignatureDeclaration, + contextFlags: ContextFlags | undefined + ): Type | undefined { // If the containing function has a return type annotation, is a constructor, or is a get accessor whose // corresponding set accessor has a type annotation, return statements in the function are contextually typed const returnType = getReturnTypeFromAnnotation(functionDecl); @@ -31948,18 +56385,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Otherwise, if the containing function is contextually typed by a function type with exactly one call signature // and that call signature is non-generic, return statements are contextually typed by the return type of the signature - const signature = getContextualSignatureForFunctionLikeDeclaration(functionDecl as FunctionExpression); + const signature = getContextualSignatureForFunctionLikeDeclaration( + functionDecl as FunctionExpression + ); if (signature && !isResolvingReturnTypeOfSignature(signature)) { const returnType = getReturnTypeOfSignature(signature); const functionFlags = getFunctionFlags(functionDecl); if (functionFlags & FunctionFlags.Generator) { - return filterType(returnType, t => { - return !!(t.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Void | TypeFlags.InstantiableNonPrimitive)) || checkGeneratorInstantiationAssignabilityToReturnType(t, functionFlags, /*errorNode*/ undefined); + return filterType(returnType, (t) => { + return ( + !!( + t.flags & + (TypeFlags.AnyOrUnknown | + TypeFlags.Void | + TypeFlags.InstantiableNonPrimitive) + ) || + checkGeneratorInstantiationAssignabilityToReturnType( + t, + functionFlags, + /*errorNode*/ undefined + ) + ); }); } if (functionFlags & FunctionFlags.Async) { - return filterType(returnType, t => { - return !!(t.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Void | TypeFlags.InstantiableNonPrimitive)) || !!getAwaitedTypeOfPromise(t); + return filterType(returnType, (t) => { + return ( + !!( + t.flags & + (TypeFlags.AnyOrUnknown | + TypeFlags.Void | + TypeFlags.InstantiableNonPrimitive) + ) || !!getAwaitedTypeOfPromise(t) + ); }); } return returnType; @@ -31972,46 +56430,77 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // In a typed function call, an argument or substitution expression is contextually typed by the type of the corresponding parameter. - function getContextualTypeForArgument(callTarget: CallLikeExpression, arg: Expression): Type | undefined { + function getContextualTypeForArgument( + callTarget: CallLikeExpression, + arg: Expression + ): Type | undefined { const args = getEffectiveCallArguments(callTarget); const argIndex = args.indexOf(arg); // -1 for e.g. the expression of a CallExpression, or the tag of a TaggedTemplateExpression - return argIndex === -1 ? undefined : getContextualTypeForArgumentAtIndex(callTarget, argIndex); + return argIndex === -1 + ? undefined + : getContextualTypeForArgumentAtIndex(callTarget, argIndex); } - function getContextualTypeForArgumentAtIndex(callTarget: CallLikeExpression, argIndex: number): Type { + function getContextualTypeForArgumentAtIndex( + callTarget: CallLikeExpression, + argIndex: number + ): Type { if (isImportCall(callTarget)) { - return argIndex === 0 ? stringType : - argIndex === 1 ? getGlobalImportCallOptionsType(/*reportErrors*/ false) : - anyType; + return argIndex === 0 + ? stringType + : argIndex === 1 + ? getGlobalImportCallOptionsType(/*reportErrors*/ false) + : anyType; } // If we're already in the process of resolving the given signature, don't resolve again as // that could cause infinite recursion. Instead, return anySignature. - const signature = getNodeLinks(callTarget).resolvedSignature === resolvingSignature ? resolvingSignature : getResolvedSignature(callTarget); + const signature = + getNodeLinks(callTarget).resolvedSignature === resolvingSignature + ? resolvingSignature + : getResolvedSignature(callTarget); if (isJsxOpeningLikeElement(callTarget) && argIndex === 0) { - return getEffectiveFirstArgumentForJsxSignature(signature, callTarget); + return getEffectiveFirstArgumentForJsxSignature( + signature, + callTarget + ); } const restIndex = signature.parameters.length - 1; - return signatureHasRestParameter(signature) && argIndex >= restIndex ? - getIndexedAccessType(getTypeOfSymbol(signature.parameters[restIndex]), getNumberLiteralType(argIndex - restIndex), AccessFlags.Contextual) : - getTypeAtPosition(signature, argIndex); + return signatureHasRestParameter(signature) && argIndex >= restIndex + ? getIndexedAccessType( + getTypeOfSymbol(signature.parameters[restIndex]), + getNumberLiteralType(argIndex - restIndex), + AccessFlags.Contextual + ) + : getTypeAtPosition(signature, argIndex); } - function getContextualTypeForDecorator(decorator: Decorator): Type | undefined { + function getContextualTypeForDecorator( + decorator: Decorator + ): Type | undefined { const signature = getDecoratorCallSignature(decorator); return signature ? getOrCreateTypeFromSignature(signature) : undefined; } - function getContextualTypeForSubstitutionExpression(template: TemplateExpression, substitutionExpression: Expression) { + function getContextualTypeForSubstitutionExpression( + template: TemplateExpression, + substitutionExpression: Expression + ) { if (template.parent.kind === SyntaxKind.TaggedTemplateExpression) { - return getContextualTypeForArgument(template.parent as TaggedTemplateExpression, substitutionExpression); + return getContextualTypeForArgument( + template.parent as TaggedTemplateExpression, + substitutionExpression + ); } return undefined; } - function getContextualTypeForBinaryOperand(node: Expression, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForBinaryOperand( + node: Expression, + contextFlags: ContextFlags | undefined + ): Type | undefined { const binaryExpression = node.parent as BinaryExpression; const { left, operatorToken, right } = binaryExpression; switch (operatorToken.kind) { @@ -32019,7 +56508,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.AmpersandAmpersandEqualsToken: case SyntaxKind.BarBarEqualsToken: case SyntaxKind.QuestionQuestionEqualsToken: - return node === right ? getContextualTypeForAssignmentDeclaration(binaryExpression) : undefined; + return node === right + ? getContextualTypeForAssignmentDeclaration( + binaryExpression + ) + : undefined; case SyntaxKind.BarBarToken: case SyntaxKind.QuestionQuestionToken: // When an || expression has a contextual type, the operands are contextually typed by that type, except @@ -32028,11 +56521,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // by the type of the left operand, except for the special case of Javascript declarations of the form // `namespace.prop = namespace.prop || {}`. const type = getContextualType(binaryExpression, contextFlags); - return node === right && (type && type.pattern || !type && !isDefaultedExpandoInitializer(binaryExpression)) ? - getTypeOfExpression(left) : type; + return node === right && + ((type && type.pattern) || + (!type && + !isDefaultedExpandoInitializer(binaryExpression))) + ? getTypeOfExpression(left) + : type; case SyntaxKind.AmpersandAmpersandToken: case SyntaxKind.CommaToken: - return node === right ? getContextualType(binaryExpression, contextFlags) : undefined; + return node === right + ? getContextualType(binaryExpression, contextFlags) + : undefined; default: return undefined; } @@ -32051,7 +56550,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (isPropertyAccessExpression(e)) { const lhsType = getTypeOfExpression(e.expression); - return isPrivateIdentifier(e.name) ? tryGetPrivateIdentifierPropertyOfType(lhsType, e.name) : getPropertyOfType(lhsType, e.name.escapedText); + return isPrivateIdentifier(e.name) + ? tryGetPrivateIdentifierPropertyOfType(lhsType, e.name) + : getPropertyOfType(lhsType, e.name.escapedText); } if (isElementAccessExpression(e)) { const propType = checkExpressionCached(e.argumentExpression); @@ -32059,19 +56560,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } const lhsType = getTypeOfExpression(e.expression); - return getPropertyOfType(lhsType, getPropertyNameFromType(propType)); + return getPropertyOfType( + lhsType, + getPropertyNameFromType(propType) + ); } return undefined; - function tryGetPrivateIdentifierPropertyOfType(type: Type, id: PrivateIdentifier) { - const lexicallyScopedSymbol = lookupSymbolForPrivateIdentifierDeclaration(id.escapedText, id); - return lexicallyScopedSymbol && getPrivateIdentifierPropertyOfType(type, lexicallyScopedSymbol); + function tryGetPrivateIdentifierPropertyOfType( + type: Type, + id: PrivateIdentifier + ) { + const lexicallyScopedSymbol = + lookupSymbolForPrivateIdentifierDeclaration(id.escapedText, id); + return ( + lexicallyScopedSymbol && + getPrivateIdentifierPropertyOfType(type, lexicallyScopedSymbol) + ); } } // In an assignment expression, the right operand is contextually typed by the type of the left operand. // Don't do this for assignment declarations unless there is a type tag on the assignment, to avoid circularity from checking the right operand. - function getContextualTypeForAssignmentDeclaration(binaryExpression: BinaryExpression): Type | undefined { + function getContextualTypeForAssignmentDeclaration( + binaryExpression: BinaryExpression + ): Type | undefined { const kind = getAssignmentDeclarationKind(binaryExpression); switch (kind) { case AssignmentDeclarationKind.None: @@ -32080,49 +56593,84 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const decl = lhsSymbol && lhsSymbol.valueDeclaration; // Unannotated, uninitialized property declarations have a type implied by their usage in the constructor. // We avoid calling back into `getTypeOfExpression` and reentering contextual typing to avoid a bogus circularity error in that case. - if (decl && (isPropertyDeclaration(decl) || isPropertySignature(decl))) { - const overallAnnotation = getEffectiveTypeAnnotationNode(decl); - return (overallAnnotation && instantiateType(getTypeFromTypeNode(overallAnnotation), getSymbolLinks(lhsSymbol).mapper)) || - (isPropertyDeclaration(decl) ? decl.initializer && getTypeOfExpression(binaryExpression.left) : undefined); + if ( + decl && + (isPropertyDeclaration(decl) || isPropertySignature(decl)) + ) { + const overallAnnotation = + getEffectiveTypeAnnotationNode(decl); + return ( + (overallAnnotation && + instantiateType( + getTypeFromTypeNode(overallAnnotation), + getSymbolLinks(lhsSymbol).mapper + )) || + (isPropertyDeclaration(decl) + ? decl.initializer && + getTypeOfExpression(binaryExpression.left) + : undefined) + ); } if (kind === AssignmentDeclarationKind.None) { return getTypeOfExpression(binaryExpression.left); } - return getContextualTypeForThisPropertyAssignment(binaryExpression); + return getContextualTypeForThisPropertyAssignment( + binaryExpression + ); case AssignmentDeclarationKind.Property: if (isPossiblyAliasedThisProperty(binaryExpression, kind)) { - return getContextualTypeForThisPropertyAssignment(binaryExpression); + return getContextualTypeForThisPropertyAssignment( + binaryExpression + ); } // If `binaryExpression.left` was assigned a symbol, then this is a new declaration; otherwise it is an assignment to an existing declaration. // See `bindStaticPropertyAssignment` in `binder.ts`. - else if (!canHaveSymbol(binaryExpression.left) || !binaryExpression.left.symbol) { + else if ( + !canHaveSymbol(binaryExpression.left) || + !binaryExpression.left.symbol + ) { return getTypeOfExpression(binaryExpression.left); - } - else { + } else { const decl = binaryExpression.left.symbol.valueDeclaration; if (!decl) { return undefined; } const lhs = cast(binaryExpression.left, isAccessExpression); - const overallAnnotation = getEffectiveTypeAnnotationNode(decl); + const overallAnnotation = + getEffectiveTypeAnnotationNode(decl); if (overallAnnotation) { return getTypeFromTypeNode(overallAnnotation); - } - else if (isIdentifier(lhs.expression)) { + } else if (isIdentifier(lhs.expression)) { const id = lhs.expression; - const parentSymbol = resolveName(id, id.escapedText, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*isUse*/ true); + const parentSymbol = resolveName( + id, + id.escapedText, + SymbolFlags.Value, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ true + ); if (parentSymbol) { - const annotated = parentSymbol.valueDeclaration && getEffectiveTypeAnnotationNode(parentSymbol.valueDeclaration); + const annotated = + parentSymbol.valueDeclaration && + getEffectiveTypeAnnotationNode( + parentSymbol.valueDeclaration + ); if (annotated) { - const nameStr = getElementOrPropertyAccessName(lhs); + const nameStr = + getElementOrPropertyAccessName(lhs); if (nameStr !== undefined) { - return getTypeOfPropertyOfContextualType(getTypeFromTypeNode(annotated), nameStr); + return getTypeOfPropertyOfContextualType( + getTypeFromTypeNode(annotated), + nameStr + ); } } return undefined; } } - return isInJSFile(decl) || decl === binaryExpression.left ? undefined : getTypeOfExpression(binaryExpression.left); + return isInJSFile(decl) || decl === binaryExpression.left + ? undefined + : getTypeOfExpression(binaryExpression.left); } case AssignmentDeclarationKind.ExportsProperty: case AssignmentDeclarationKind.Prototype: @@ -32130,10 +56678,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case AssignmentDeclarationKind.ModuleExports: let valueDeclaration: Declaration | undefined; if (kind !== AssignmentDeclarationKind.ModuleExports) { - valueDeclaration = canHaveSymbol(binaryExpression.left) ? binaryExpression.left.symbol?.valueDeclaration : undefined; + valueDeclaration = canHaveSymbol(binaryExpression.left) + ? binaryExpression.left.symbol?.valueDeclaration + : undefined; } valueDeclaration ||= binaryExpression.symbol?.valueDeclaration; - const annotated = valueDeclaration && getEffectiveTypeAnnotationNode(valueDeclaration); + const annotated = + valueDeclaration && + getEffectiveTypeAnnotationNode(valueDeclaration); return annotated ? getTypeFromTypeNode(annotated) : undefined; case AssignmentDeclarationKind.ObjectDefinePropertyValue: case AssignmentDeclarationKind.ObjectDefinePropertyExports: @@ -32144,22 +56696,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function isPossiblyAliasedThisProperty(declaration: BinaryExpression, kind = getAssignmentDeclarationKind(declaration)) { + function isPossiblyAliasedThisProperty( + declaration: BinaryExpression, + kind = getAssignmentDeclarationKind(declaration) + ) { if (kind === AssignmentDeclarationKind.ThisProperty) { return true; } - if (!isInJSFile(declaration) || kind !== AssignmentDeclarationKind.Property || !isIdentifier((declaration.left as AccessExpression).expression)) { + if ( + !isInJSFile(declaration) || + kind !== AssignmentDeclarationKind.Property || + !isIdentifier((declaration.left as AccessExpression).expression) + ) { return false; } - const name = ((declaration.left as AccessExpression).expression as Identifier).escapedText; - const symbol = resolveName(declaration.left, name, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*isUse*/ true, /*excludeGlobals*/ true); + const name = ( + (declaration.left as AccessExpression).expression as Identifier + ).escapedText; + const symbol = resolveName( + declaration.left, + name, + SymbolFlags.Value, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ true, + /*excludeGlobals*/ true + ); return isThisInitializedDeclaration(symbol?.valueDeclaration); } - function getContextualTypeForThisPropertyAssignment(binaryExpression: BinaryExpression): Type | undefined { - if (!binaryExpression.symbol) return getTypeOfExpression(binaryExpression.left); + function getContextualTypeForThisPropertyAssignment( + binaryExpression: BinaryExpression + ): Type | undefined { + if (!binaryExpression.symbol) + return getTypeOfExpression(binaryExpression.left); if (binaryExpression.symbol.valueDeclaration) { - const annotated = getEffectiveTypeAnnotationNode(binaryExpression.symbol.valueDeclaration); + const annotated = getEffectiveTypeAnnotationNode( + binaryExpression.symbol.valueDeclaration + ); if (annotated) { const type = getTypeFromTypeNode(annotated); if (type) { @@ -32168,122 +56741,242 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } const thisAccess = cast(binaryExpression.left, isAccessExpression); - if (!isObjectLiteralMethod(getThisContainer(thisAccess.expression, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false))) { + if ( + !isObjectLiteralMethod( + getThisContainer( + thisAccess.expression, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false + ) + ) + ) { return undefined; } const thisType = checkThisExpression(thisAccess.expression); const nameStr = getElementOrPropertyAccessName(thisAccess); - return nameStr !== undefined && getTypeOfPropertyOfContextualType(thisType, nameStr) || undefined; + return ( + (nameStr !== undefined && + getTypeOfPropertyOfContextualType(thisType, nameStr)) || + undefined + ); } function isCircularMappedProperty(symbol: Symbol) { - return !!(getCheckFlags(symbol) & CheckFlags.Mapped && !(symbol as MappedSymbol).links.type && findResolutionCycleStartIndex(symbol, TypeSystemPropertyName.Type) >= 0); + return !!( + getCheckFlags(symbol) & CheckFlags.Mapped && + !(symbol as MappedSymbol).links.type && + findResolutionCycleStartIndex( + symbol, + TypeSystemPropertyName.Type + ) >= 0 + ); } - function isExcludedMappedPropertyName(constraint: Type, propertyNameType: Type): boolean { + function isExcludedMappedPropertyName( + constraint: Type, + propertyNameType: Type + ): boolean { if (constraint.flags & TypeFlags.Conditional) { const type = constraint as ConditionalType; - return !!(getReducedType(getTrueTypeFromConditionalType(type)).flags & TypeFlags.Never) && - getActualTypeVariable(getFalseTypeFromConditionalType(type)) === getActualTypeVariable(type.checkType) && - isTypeAssignableTo(propertyNameType, type.extendsType); + return ( + !!( + getReducedType(getTrueTypeFromConditionalType(type)).flags & + TypeFlags.Never + ) && + getActualTypeVariable(getFalseTypeFromConditionalType(type)) === + getActualTypeVariable(type.checkType) && + isTypeAssignableTo(propertyNameType, type.extendsType) + ); } if (constraint.flags & TypeFlags.Intersection) { - return some((constraint as IntersectionType).types, t => isExcludedMappedPropertyName(t, propertyNameType)); + return some((constraint as IntersectionType).types, (t) => + isExcludedMappedPropertyName(t, propertyNameType) + ); } return false; } - function getTypeOfPropertyOfContextualType(type: Type, name: __String, nameType?: Type) { - return mapType(type, t => { - if (t.flags & TypeFlags.Intersection) { - let types: Type[] | undefined; - let indexInfoCandidates: Type[] | undefined; - let ignoreIndexInfos = false; - for (const constituentType of (t as IntersectionType).types) { - if (!(constituentType.flags & TypeFlags.Object)) { - continue; - } - if (isGenericMappedType(constituentType) && getMappedTypeNameTypeKind(constituentType) !== MappedTypeNameTypeKind.Remapping) { - const substitutedType = getIndexedMappedTypeSubstitutedTypeOfContextualType(constituentType, name, nameType); - types = appendContextualPropertyTypeConstituent(types, substitutedType); - continue; + function getTypeOfPropertyOfContextualType( + type: Type, + name: __String, + nameType?: Type + ) { + return mapType( + type, + (t) => { + if (t.flags & TypeFlags.Intersection) { + let types: Type[] | undefined; + let indexInfoCandidates: Type[] | undefined; + let ignoreIndexInfos = false; + for (const constituentType of (t as IntersectionType) + .types) { + if (!(constituentType.flags & TypeFlags.Object)) { + continue; + } + if ( + isGenericMappedType(constituentType) && + getMappedTypeNameTypeKind(constituentType) !== + MappedTypeNameTypeKind.Remapping + ) { + const substitutedType = + getIndexedMappedTypeSubstitutedTypeOfContextualType( + constituentType, + name, + nameType + ); + types = appendContextualPropertyTypeConstituent( + types, + substitutedType + ); + continue; + } + const propertyType = + getTypeOfConcretePropertyOfContextualType( + constituentType, + name + ); + if (!propertyType) { + if (!ignoreIndexInfos) { + indexInfoCandidates = append( + indexInfoCandidates, + constituentType + ); + } + continue; + } + ignoreIndexInfos = true; + indexInfoCandidates = undefined; + types = appendContextualPropertyTypeConstituent( + types, + propertyType + ); } - const propertyType = getTypeOfConcretePropertyOfContextualType(constituentType, name); - if (!propertyType) { - if (!ignoreIndexInfos) { - indexInfoCandidates = append(indexInfoCandidates, constituentType); + if (indexInfoCandidates) { + for (const candidate of indexInfoCandidates) { + const indexInfoType = + getTypeFromIndexInfosOfContextualType( + candidate, + name, + nameType + ); + types = appendContextualPropertyTypeConstituent( + types, + indexInfoType + ); } - continue; } - ignoreIndexInfos = true; - indexInfoCandidates = undefined; - types = appendContextualPropertyTypeConstituent(types, propertyType); - } - if (indexInfoCandidates) { - for (const candidate of indexInfoCandidates) { - const indexInfoType = getTypeFromIndexInfosOfContextualType(candidate, name, nameType); - types = appendContextualPropertyTypeConstituent(types, indexInfoType); + if (!types) { + return; } + if (types.length === 1) { + return types[0]; + } + return getIntersectionType(types); } - if (!types) { + if (!(t.flags & TypeFlags.Object)) { return; } - if (types.length === 1) { - return types[0]; - } - return getIntersectionType(types); - } - if (!(t.flags & TypeFlags.Object)) { - return; - } - return isGenericMappedType(t) && getMappedTypeNameTypeKind(t) !== MappedTypeNameTypeKind.Remapping - ? getIndexedMappedTypeSubstitutedTypeOfContextualType(t, name, nameType) - : getTypeOfConcretePropertyOfContextualType(t, name) ?? getTypeFromIndexInfosOfContextualType(t, name, nameType); - }, /*noReductions*/ true); + return isGenericMappedType(t) && + getMappedTypeNameTypeKind(t) !== + MappedTypeNameTypeKind.Remapping + ? getIndexedMappedTypeSubstitutedTypeOfContextualType( + t, + name, + nameType + ) + : getTypeOfConcretePropertyOfContextualType(t, name) ?? + getTypeFromIndexInfosOfContextualType( + t, + name, + nameType + ); + }, + /*noReductions*/ true + ); } - function appendContextualPropertyTypeConstituent(types: Type[] | undefined, type: Type | undefined) { + function appendContextualPropertyTypeConstituent( + types: Type[] | undefined, + type: Type | undefined + ) { // any doesn't provide any contextual information but could spoil the overall result by nullifying contextual information provided by other intersection constituents // so it gets replaced with `unknown` as `T & unknown` is just `T` and all types computed based on the contextual information provided by other constituens are still assignable to any - return type ? append(types, type.flags & TypeFlags.Any ? unknownType : type) : types; + return type + ? append(types, type.flags & TypeFlags.Any ? unknownType : type) + : types; } - function getIndexedMappedTypeSubstitutedTypeOfContextualType(type: MappedType, name: __String, nameType: Type | undefined) { - const propertyNameType = nameType || getStringLiteralType(unescapeLeadingUnderscores(name)); + function getIndexedMappedTypeSubstitutedTypeOfContextualType( + type: MappedType, + name: __String, + nameType: Type | undefined + ) { + const propertyNameType = + nameType || getStringLiteralType(unescapeLeadingUnderscores(name)); const constraint = getConstraintTypeFromMappedType(type); // special case for conditional types pretending to be negated types - if (type.nameType && isExcludedMappedPropertyName(type.nameType, propertyNameType) || isExcludedMappedPropertyName(constraint, propertyNameType)) { + if ( + (type.nameType && + isExcludedMappedPropertyName( + type.nameType, + propertyNameType + )) || + isExcludedMappedPropertyName(constraint, propertyNameType) + ) { return; } - const constraintOfConstraint = getBaseConstraintOfType(constraint) || constraint; + const constraintOfConstraint = + getBaseConstraintOfType(constraint) || constraint; if (!isTypeAssignableTo(propertyNameType, constraintOfConstraint)) { return; } return substituteIndexedMappedType(type, propertyNameType); } - function getTypeOfConcretePropertyOfContextualType(type: Type, name: __String) { + function getTypeOfConcretePropertyOfContextualType( + type: Type, + name: __String + ) { const prop = getPropertyOfType(type, name); if (!prop || isCircularMappedProperty(prop)) { return; } - return removeMissingType(getTypeOfSymbol(prop), !!(prop.flags & SymbolFlags.Optional)); + return removeMissingType( + getTypeOfSymbol(prop), + !!(prop.flags & SymbolFlags.Optional) + ); } - function getTypeFromIndexInfosOfContextualType(type: Type, name: __String, nameType: Type | undefined) { + function getTypeFromIndexInfosOfContextualType( + type: Type, + name: __String, + nameType: Type | undefined + ) { if (isTupleType(type) && isNumericLiteralName(name) && +name >= 0) { - const restType = getElementTypeOfSliceOfTupleType(type, type.target.fixedLength, /*endSkipCount*/ 0, /*writing*/ false, /*noReductions*/ true); + const restType = getElementTypeOfSliceOfTupleType( + type, + type.target.fixedLength, + /*endSkipCount*/ 0, + /*writing*/ false, + /*noReductions*/ true + ); if (restType) { return restType; } } - return findApplicableIndexInfo(getIndexInfosOfStructuredType(type), nameType || getStringLiteralType(unescapeLeadingUnderscores(name)))?.type; + return findApplicableIndexInfo( + getIndexInfosOfStructuredType(type), + nameType || getStringLiteralType(unescapeLeadingUnderscores(name)) + )?.type; } // In an object literal contextually typed by a type T, the contextual type of a property assignment is the type of // the matching property in T, if one exists. Otherwise, it is the type of the numeric index signature in T, if one // exists. Otherwise, it is the type of the string index signature in T, if one exists. - function getContextualTypeForObjectLiteralMethod(node: MethodDeclaration, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForObjectLiteralMethod( + node: MethodDeclaration, + contextFlags: ContextFlags | undefined + ): Type | undefined { Debug.assert(isObjectLiteralMethod(node)); if (node.flags & NodeFlags.InWithStatement) { // We cannot answer semantic questions within a with block, do not proceed any further @@ -32292,26 +56985,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getContextualTypeForObjectLiteralElement(node, contextFlags); } - function getContextualTypeForObjectLiteralElement(element: ObjectLiteralElementLike, contextFlags: ContextFlags | undefined) { + function getContextualTypeForObjectLiteralElement( + element: ObjectLiteralElementLike, + contextFlags: ContextFlags | undefined + ) { const objectLiteral = element.parent as ObjectLiteralExpression; - const propertyAssignmentType = isPropertyAssignment(element) && getContextualTypeForVariableLikeDeclaration(element, contextFlags); + const propertyAssignmentType = + isPropertyAssignment(element) && + getContextualTypeForVariableLikeDeclaration(element, contextFlags); if (propertyAssignmentType) { return propertyAssignmentType; } - const type = getApparentTypeOfContextualType(objectLiteral, contextFlags); + const type = getApparentTypeOfContextualType( + objectLiteral, + contextFlags + ); if (type) { if (hasBindableName(element)) { // For a (non-symbol) computed property, there is no reason to look up the name // in the type. It will just be "__computed", which does not appear in any // SymbolTable. const symbol = getSymbolOfDeclaration(element); - return getTypeOfPropertyOfContextualType(type, symbol.escapedName, getSymbolLinks(symbol).nameType); + return getTypeOfPropertyOfContextualType( + type, + symbol.escapedName, + getSymbolLinks(symbol).nameType + ); } if (hasDynamicName(element)) { const name = getNameOfDeclaration(element); if (name && isComputedPropertyName(name)) { const exprType = checkExpression(name.expression); - const propType = isTypeUsableAsPropertyName(exprType) && getTypeOfPropertyOfContextualType(type, getPropertyNameFromType(exprType)); + const propType = + isTypeUsableAsPropertyName(exprType) && + getTypeOfPropertyOfContextualType( + type, + getPropertyNameFromType(exprType) + ); if (propType) { return propType; } @@ -32320,7 +57030,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (element.name) { const nameType = getLiteralTypeFromPropertyName(element.name); // We avoid calling getApplicableIndexInfo here because it performs potentially expensive intersection reduction. - return mapType(type, t => findApplicableIndexInfo(getIndexInfosOfStructuredType(t), nameType)?.type, /*noReductions*/ true); + return mapType( + type, + (t) => + findApplicableIndexInfo( + getIndexInfosOfStructuredType(t), + nameType + )?.type, + /*noReductions*/ true + ); } } return undefined; @@ -32337,80 +57055,196 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return { first, last }; } - function getContextualTypeForElementExpression(type: Type | undefined, index: number, length?: number, firstSpreadIndex?: number, lastSpreadIndex?: number): Type | undefined { - return type && mapType(type, t => { - if (isTupleType(t)) { - // If index is before any spread element and within the fixed part of the contextual tuple type, return - // the type of the contextual tuple element. - if ((firstSpreadIndex === undefined || index < firstSpreadIndex) && index < t.target.fixedLength) { - return removeMissingType(getTypeArguments(t)[index], !!(t.target.elementFlags[index] && ElementFlags.Optional)); - } - // When the length is known and the index is after all spread elements we compute the offset from the element - // to the end and the number of ending fixed elements in the contextual tuple type. - const offset = length !== undefined && (lastSpreadIndex === undefined || index > lastSpreadIndex) ? length - index : 0; - const fixedEndLength = offset > 0 && (t.target.combinedFlags & ElementFlags.Variable) ? getEndElementCount(t.target, ElementFlags.Fixed) : 0; - // If the offset is within the ending fixed part of the contextual tuple type, return the type of the contextual - // tuple element. - if (offset > 0 && offset <= fixedEndLength) { - return getTypeArguments(t)[getTypeReferenceArity(t) - offset]; - } - // Return a union of the possible contextual element types with no subtype reduction. - return getElementTypeOfSliceOfTupleType(t, firstSpreadIndex === undefined ? t.target.fixedLength : Math.min(t.target.fixedLength, firstSpreadIndex), length === undefined || lastSpreadIndex === undefined ? fixedEndLength : Math.min(fixedEndLength, length - lastSpreadIndex), /*writing*/ false, /*noReductions*/ true); - } - // If element index is known and a contextual property with that name exists, return it. Otherwise return the - // iterated or element type of the contextual type. - return (!firstSpreadIndex || index < firstSpreadIndex) && getTypeOfPropertyOfContextualType(t, "" + index as __String) || - getIteratedTypeOrElementType(IterationUse.Element, t, undefinedType, /*errorNode*/ undefined, /*checkAssignability*/ false); - }, /*noReductions*/ true); + function getContextualTypeForElementExpression( + type: Type | undefined, + index: number, + length?: number, + firstSpreadIndex?: number, + lastSpreadIndex?: number + ): Type | undefined { + return ( + type && + mapType( + type, + (t) => { + if (isTupleType(t)) { + // If index is before any spread element and within the fixed part of the contextual tuple type, return + // the type of the contextual tuple element. + if ( + (firstSpreadIndex === undefined || + index < firstSpreadIndex) && + index < t.target.fixedLength + ) { + return removeMissingType( + getTypeArguments(t)[index], + !!( + t.target.elementFlags[index] && + ElementFlags.Optional + ) + ); + } + // When the length is known and the index is after all spread elements we compute the offset from the element + // to the end and the number of ending fixed elements in the contextual tuple type. + const offset = + length !== undefined && + (lastSpreadIndex === undefined || + index > lastSpreadIndex) + ? length - index + : 0; + const fixedEndLength = + offset > 0 && + t.target.combinedFlags & ElementFlags.Variable + ? getEndElementCount( + t.target, + ElementFlags.Fixed + ) + : 0; + // If the offset is within the ending fixed part of the contextual tuple type, return the type of the contextual + // tuple element. + if (offset > 0 && offset <= fixedEndLength) { + return getTypeArguments(t)[ + getTypeReferenceArity(t) - offset + ]; + } + // Return a union of the possible contextual element types with no subtype reduction. + return getElementTypeOfSliceOfTupleType( + t, + firstSpreadIndex === undefined + ? t.target.fixedLength + : Math.min( + t.target.fixedLength, + firstSpreadIndex + ), + length === undefined || + lastSpreadIndex === undefined + ? fixedEndLength + : Math.min( + fixedEndLength, + length - lastSpreadIndex + ), + /*writing*/ false, + /*noReductions*/ true + ); + } + // If element index is known and a contextual property with that name exists, return it. Otherwise return the + // iterated or element type of the contextual type. + return ( + ((!firstSpreadIndex || index < firstSpreadIndex) && + getTypeOfPropertyOfContextualType( + t, + ("" + index) as __String + )) || + getIteratedTypeOrElementType( + IterationUse.Element, + t, + undefinedType, + /*errorNode*/ undefined, + /*checkAssignability*/ false + ) + ); + }, + /*noReductions*/ true + ) + ); } // In a contextually typed conditional expression, the true/false expressions are contextually typed by the same type. - function getContextualTypeForConditionalOperand(node: Expression, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForConditionalOperand( + node: Expression, + contextFlags: ContextFlags | undefined + ): Type | undefined { const conditional = node.parent as ConditionalExpression; - return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional, contextFlags) : undefined; + return node === conditional.whenTrue || node === conditional.whenFalse + ? getContextualType(conditional, contextFlags) + : undefined; } - function getContextualTypeForChildJsxExpression(node: JsxElement, child: JsxChild, contextFlags: ContextFlags | undefined) { - const attributesType = getApparentTypeOfContextualType(node.openingElement.attributes, contextFlags); + function getContextualTypeForChildJsxExpression( + node: JsxElement, + child: JsxChild, + contextFlags: ContextFlags | undefined + ) { + const attributesType = getApparentTypeOfContextualType( + node.openingElement.attributes, + contextFlags + ); // JSX expression is in children of JSX Element, we will look for an "children" attribute (we get the name from JSX.ElementAttributesProperty) - const jsxChildrenPropertyName = getJsxElementChildrenPropertyName(getJsxNamespaceAt(node)); - if (!(attributesType && !isTypeAny(attributesType) && jsxChildrenPropertyName && jsxChildrenPropertyName !== "")) { + const jsxChildrenPropertyName = getJsxElementChildrenPropertyName( + getJsxNamespaceAt(node) + ); + if ( + !( + attributesType && + !isTypeAny(attributesType) && + jsxChildrenPropertyName && + jsxChildrenPropertyName !== "" + ) + ) { return undefined; } const realChildren = getSemanticJsxChildren(node.children); const childIndex = realChildren.indexOf(child); - const childFieldType = getTypeOfPropertyOfContextualType(attributesType, jsxChildrenPropertyName); - return childFieldType && (realChildren.length === 1 ? childFieldType : mapType(childFieldType, t => { - if (isArrayLikeType(t)) { - return getIndexedAccessType(t, getNumberLiteralType(childIndex)); - } - else { - return t; - } - }, /*noReductions*/ true)); + const childFieldType = getTypeOfPropertyOfContextualType( + attributesType, + jsxChildrenPropertyName + ); + return ( + childFieldType && + (realChildren.length === 1 + ? childFieldType + : mapType( + childFieldType, + (t) => { + if (isArrayLikeType(t)) { + return getIndexedAccessType( + t, + getNumberLiteralType(childIndex) + ); + } else { + return t; + } + }, + /*noReductions*/ true + )) + ); } - function getContextualTypeForJsxExpression(node: JsxExpression, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForJsxExpression( + node: JsxExpression, + contextFlags: ContextFlags | undefined + ): Type | undefined { const exprParent = node.parent; return isJsxAttributeLike(exprParent) ? getContextualType(node, contextFlags) : isJsxElement(exprParent) - ? getContextualTypeForChildJsxExpression(exprParent, node, contextFlags) + ? getContextualTypeForChildJsxExpression( + exprParent, + node, + contextFlags + ) : undefined; } - function getContextualTypeForJsxAttribute(attribute: JsxAttribute | JsxSpreadAttribute, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForJsxAttribute( + attribute: JsxAttribute | JsxSpreadAttribute, + contextFlags: ContextFlags | undefined + ): Type | undefined { // When we trying to resolve JsxOpeningLikeElement as a stateless function element, we will already give its attributes a contextual type // which is a type of the parameter of the signature we are trying out. // If there is no contextual type (e.g. we are trying to resolve stateful component), get attributes type from resolving element's tagName if (isJsxAttribute(attribute)) { - const attributesType = getApparentTypeOfContextualType(attribute.parent, contextFlags); + const attributesType = getApparentTypeOfContextualType( + attribute.parent, + contextFlags + ); if (!attributesType || isTypeAny(attributesType)) { return undefined; } - return getTypeOfPropertyOfContextualType(attributesType, getEscapedTextOfJsxAttributeName(attribute.name)); - } - else { + return getTypeOfPropertyOfContextualType( + attributesType, + getEscapedTextOfJsxAttributeName(attribute.name) + ); + } else { return getContextualType(attribute.parent, contextFlags); } } @@ -32433,123 +57267,281 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; case SyntaxKind.PropertyAccessExpression: case SyntaxKind.ParenthesizedExpression: - return isPossiblyDiscriminantValue((node as PropertyAccessExpression | ParenthesizedExpression).expression); + return isPossiblyDiscriminantValue( + (node as PropertyAccessExpression | ParenthesizedExpression) + .expression + ); case SyntaxKind.JsxExpression: - return !(node as JsxExpression).expression || isPossiblyDiscriminantValue((node as JsxExpression).expression!); + return ( + !(node as JsxExpression).expression || + isPossiblyDiscriminantValue( + (node as JsxExpression).expression! + ) + ); } return false; } - function discriminateContextualTypeByObjectMembers(node: ObjectLiteralExpression, contextualType: UnionType) { + function discriminateContextualTypeByObjectMembers( + node: ObjectLiteralExpression, + contextualType: UnionType + ) { const key = `D${getNodeId(node)},${getTypeId(contextualType)}`; - return getCachedType(key) ?? setCachedType( - key, - getMatchingUnionConstituentForObjectLiteral(contextualType, node) ?? discriminateTypeByDiscriminableItems( - contextualType, - concatenate( - map( - filter(node.properties, (p): p is PropertyAssignment | ShorthandPropertyAssignment => { - if (!p.symbol) { - return false; - } - if (p.kind === SyntaxKind.PropertyAssignment) { - return isPossiblyDiscriminantValue(p.initializer) && isDiscriminantProperty(contextualType, p.symbol.escapedName); - } - if (p.kind === SyntaxKind.ShorthandPropertyAssignment) { - return isDiscriminantProperty(contextualType, p.symbol.escapedName); - } - return false; - }), - prop => ([() => getContextFreeTypeOfExpression(prop.kind === SyntaxKind.PropertyAssignment ? prop.initializer : prop.name), prop.symbol.escapedName] as const), - ), - map( - filter(getPropertiesOfType(contextualType), s => !!(s.flags & SymbolFlags.Optional) && !!node?.symbol?.members && !node.symbol.members.has(s.escapedName) && isDiscriminantProperty(contextualType, s.escapedName)), - s => [() => undefinedType, s.escapedName] as const, - ), - ), - isTypeAssignableTo, - ), + return ( + getCachedType(key) ?? + setCachedType( + key, + getMatchingUnionConstituentForObjectLiteral( + contextualType, + node + ) ?? + discriminateTypeByDiscriminableItems( + contextualType, + concatenate( + map( + filter( + node.properties, + ( + p + ): p is + | PropertyAssignment + | ShorthandPropertyAssignment => { + if (!p.symbol) { + return false; + } + if ( + p.kind === + SyntaxKind.PropertyAssignment + ) { + return ( + isPossiblyDiscriminantValue( + p.initializer + ) && + isDiscriminantProperty( + contextualType, + p.symbol.escapedName + ) + ); + } + if ( + p.kind === + SyntaxKind.ShorthandPropertyAssignment + ) { + return isDiscriminantProperty( + contextualType, + p.symbol.escapedName + ); + } + return false; + } + ), + (prop) => + [ + () => + getContextFreeTypeOfExpression( + prop.kind === + SyntaxKind.PropertyAssignment + ? prop.initializer + : prop.name + ), + prop.symbol.escapedName, + ] as const + ), + map( + filter( + getPropertiesOfType(contextualType), + (s) => + !!(s.flags & SymbolFlags.Optional) && + !!node?.symbol?.members && + !node.symbol.members.has( + s.escapedName + ) && + isDiscriminantProperty( + contextualType, + s.escapedName + ) + ), + (s) => + [ + () => undefinedType, + s.escapedName, + ] as const + ) + ), + isTypeAssignableTo + ) + ) ); } - function discriminateContextualTypeByJSXAttributes(node: JsxAttributes, contextualType: UnionType) { + function discriminateContextualTypeByJSXAttributes( + node: JsxAttributes, + contextualType: UnionType + ) { const key = `D${getNodeId(node)},${getTypeId(contextualType)}`; const cached = getCachedType(key); if (cached) return cached; - const jsxChildrenPropertyName = getJsxElementChildrenPropertyName(getJsxNamespaceAt(node)); + const jsxChildrenPropertyName = getJsxElementChildrenPropertyName( + getJsxNamespaceAt(node) + ); return setCachedType( key, discriminateTypeByDiscriminableItems( contextualType, concatenate( map( - filter(node.properties, p => !!p.symbol && p.kind === SyntaxKind.JsxAttribute && isDiscriminantProperty(contextualType, p.symbol.escapedName) && (!p.initializer || isPossiblyDiscriminantValue(p.initializer))), - prop => ([!(prop as JsxAttribute).initializer ? (() => trueType) : (() => getContextFreeTypeOfExpression((prop as JsxAttribute).initializer!)), prop.symbol.escapedName] as const), + filter( + node.properties, + (p) => + !!p.symbol && + p.kind === SyntaxKind.JsxAttribute && + isDiscriminantProperty( + contextualType, + p.symbol.escapedName + ) && + (!p.initializer || + isPossiblyDiscriminantValue(p.initializer)) + ), + (prop) => + [ + !(prop as JsxAttribute).initializer + ? () => trueType + : () => + getContextFreeTypeOfExpression( + (prop as JsxAttribute) + .initializer! + ), + prop.symbol.escapedName, + ] as const ), map( - filter(getPropertiesOfType(contextualType), s => { - if (!(s.flags & SymbolFlags.Optional) || !node?.symbol?.members) { + filter(getPropertiesOfType(contextualType), (s) => { + if ( + !(s.flags & SymbolFlags.Optional) || + !node?.symbol?.members + ) { return false; } const element = node.parent.parent; - if (s.escapedName === jsxChildrenPropertyName && isJsxElement(element) && getSemanticJsxChildren(element.children).length) { + if ( + s.escapedName === jsxChildrenPropertyName && + isJsxElement(element) && + getSemanticJsxChildren(element.children).length + ) { return false; } - return !node.symbol.members.has(s.escapedName) && isDiscriminantProperty(contextualType, s.escapedName); + return ( + !node.symbol.members.has(s.escapedName) && + isDiscriminantProperty( + contextualType, + s.escapedName + ) + ); }), - s => [() => undefinedType, s.escapedName] as const, - ), + (s) => [() => undefinedType, s.escapedName] as const + ) ), - isTypeAssignableTo, - ), + isTypeAssignableTo + ) ); } // Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily // be "pushed" onto a node using the contextualType property. - function getApparentTypeOfContextualType(node: Expression | MethodDeclaration, contextFlags: ContextFlags | undefined): Type | undefined { - const contextualType = isObjectLiteralMethod(node) ? - getContextualTypeForObjectLiteralMethod(node, contextFlags) : - getContextualType(node, contextFlags); - const instantiatedType = instantiateContextualType(contextualType, node, contextFlags); - if (instantiatedType && !(contextFlags && contextFlags & ContextFlags.NoConstraints && instantiatedType.flags & TypeFlags.TypeVariable)) { + function getApparentTypeOfContextualType( + node: Expression | MethodDeclaration, + contextFlags: ContextFlags | undefined + ): Type | undefined { + const contextualType = isObjectLiteralMethod(node) + ? getContextualTypeForObjectLiteralMethod(node, contextFlags) + : getContextualType(node, contextFlags); + const instantiatedType = instantiateContextualType( + contextualType, + node, + contextFlags + ); + if ( + instantiatedType && + !( + contextFlags && + contextFlags & ContextFlags.NoConstraints && + instantiatedType.flags & TypeFlags.TypeVariable + ) + ) { const apparentType = mapType( instantiatedType, // When obtaining apparent type of *contextual* type we don't want to get apparent type of mapped types. // That would evaluate mapped types with array or tuple type constraints too eagerly // and thus it would prevent `getTypeOfPropertyOfContextualType` from obtaining per-position contextual type for elements of array literal expressions. // Apparent type of other mapped types is already the mapped type itself so we can just avoid calling `getApparentType` here for all mapped types. - t => getObjectFlags(t) & ObjectFlags.Mapped ? t : getApparentType(t), - /*noReductions*/ true, + (t) => + getObjectFlags(t) & ObjectFlags.Mapped + ? t + : getApparentType(t), + /*noReductions*/ true ); - return apparentType.flags & TypeFlags.Union && isObjectLiteralExpression(node) ? discriminateContextualTypeByObjectMembers(node, apparentType as UnionType) : - apparentType.flags & TypeFlags.Union && isJsxAttributes(node) ? discriminateContextualTypeByJSXAttributes(node, apparentType as UnionType) : - apparentType; + return apparentType.flags & TypeFlags.Union && + isObjectLiteralExpression(node) + ? discriminateContextualTypeByObjectMembers( + node, + apparentType as UnionType + ) + : apparentType.flags & TypeFlags.Union && isJsxAttributes(node) + ? discriminateContextualTypeByJSXAttributes( + node, + apparentType as UnionType + ) + : apparentType; } } // If the given contextual type contains instantiable types and if a mapper representing // return type inferences is available, instantiate those types using that mapper. - function instantiateContextualType(contextualType: Type | undefined, node: Node, contextFlags: ContextFlags | undefined): Type | undefined { - if (contextualType && maybeTypeOfKind(contextualType, TypeFlags.Instantiable)) { + function instantiateContextualType( + contextualType: Type | undefined, + node: Node, + contextFlags: ContextFlags | undefined + ): Type | undefined { + if ( + contextualType && + maybeTypeOfKind(contextualType, TypeFlags.Instantiable) + ) { const inferenceContext = getInferenceContext(node); // If no inferences have been made, and none of the type parameters for which we are inferring // specify default types, nothing is gained from instantiating as type parameters would just be // replaced with their constraints similar to the apparent type. - if (inferenceContext && contextFlags! & ContextFlags.Signature && some(inferenceContext.inferences, hasInferenceCandidatesOrDefault)) { + if ( + inferenceContext && + contextFlags! & ContextFlags.Signature && + some( + inferenceContext.inferences, + hasInferenceCandidatesOrDefault + ) + ) { // For contextual signatures we incorporate all inferences made so far, e.g. from return // types as well as arguments to the left in a function call. - return instantiateInstantiableTypes(contextualType, inferenceContext.nonFixingMapper); + return instantiateInstantiableTypes( + contextualType, + inferenceContext.nonFixingMapper + ); } if (inferenceContext?.returnMapper) { // For other purposes (e.g. determining whether to produce literal types) we only // incorporate inferences made from the return type in a function call. We remove // the 'boolean' type from the contextual type such that contextually typed boolean // literals actually end up widening to 'boolean' (see #48363). - const type = instantiateInstantiableTypes(contextualType, inferenceContext.returnMapper); - return type.flags & TypeFlags.Union && containsType((type as UnionType).types, regularFalseType) && containsType((type as UnionType).types, regularTrueType) ? - filterType(type, t => t !== regularFalseType && t !== regularTrueType) : - type; + const type = instantiateInstantiableTypes( + contextualType, + inferenceContext.returnMapper + ); + return type.flags & TypeFlags.Union && + containsType((type as UnionType).types, regularFalseType) && + containsType((type as UnionType).types, regularTrueType) + ? filterType( + type, + (t) => t !== regularFalseType && t !== regularTrueType + ) + : type; } } return contextualType; @@ -32558,15 +57550,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // This function is similar to instantiateType, except that (a) it only instantiates types that // are classified as instantiable (i.e. it doesn't instantiate object types), and (b) it performs // no reductions on instantiated union types. - function instantiateInstantiableTypes(type: Type, mapper: TypeMapper): Type { + function instantiateInstantiableTypes( + type: Type, + mapper: TypeMapper + ): Type { if (type.flags & TypeFlags.Instantiable) { return instantiateType(type, mapper); } if (type.flags & TypeFlags.Union) { - return getUnionType(map((type as UnionType).types, t => instantiateInstantiableTypes(t, mapper)), UnionReduction.None); + return getUnionType( + map((type as UnionType).types, (t) => + instantiateInstantiableTypes(t, mapper) + ), + UnionReduction.None + ); } if (type.flags & TypeFlags.Intersection) { - return getIntersectionType(map((type as IntersectionType).types, t => instantiateInstantiableTypes(t, mapper))); + return getIntersectionType( + map((type as IntersectionType).types, (t) => + instantiateInstantiableTypes(t, mapper) + ) + ); } return type; } @@ -32588,7 +57592,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param node the expression whose contextual type will be returned. * @returns the contextual type of an expression. */ - function getContextualType(node: Expression, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualType( + node: Expression, + contextFlags: ContextFlags | undefined + ): Type | undefined { if (node.flags & NodeFlags.InWithStatement) { // We cannot answer semantic questions within a with block, do not proceed any further return undefined; @@ -32606,79 +57613,157 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: case SyntaxKind.BindingElement: - return getContextualTypeForInitializerExpression(node, contextFlags); + return getContextualTypeForInitializerExpression( + node, + contextFlags + ); case SyntaxKind.ArrowFunction: case SyntaxKind.ReturnStatement: return getContextualTypeForReturnExpression(node, contextFlags); case SyntaxKind.YieldExpression: - return getContextualTypeForYieldOperand(parent as YieldExpression, contextFlags); + return getContextualTypeForYieldOperand( + parent as YieldExpression, + contextFlags + ); case SyntaxKind.AwaitExpression: - return getContextualTypeForAwaitOperand(parent as AwaitExpression, contextFlags); + return getContextualTypeForAwaitOperand( + parent as AwaitExpression, + contextFlags + ); case SyntaxKind.CallExpression: case SyntaxKind.NewExpression: - return getContextualTypeForArgument(parent as CallExpression | NewExpression | Decorator, node); + return getContextualTypeForArgument( + parent as CallExpression | NewExpression | Decorator, + node + ); case SyntaxKind.Decorator: return getContextualTypeForDecorator(parent as Decorator); case SyntaxKind.TypeAssertionExpression: case SyntaxKind.AsExpression: - return isConstTypeReference((parent as AssertionExpression).type) ? getContextualType(parent as AssertionExpression, contextFlags) : getTypeFromTypeNode((parent as AssertionExpression).type); + return isConstTypeReference( + (parent as AssertionExpression).type + ) + ? getContextualType( + parent as AssertionExpression, + contextFlags + ) + : getTypeFromTypeNode((parent as AssertionExpression).type); case SyntaxKind.BinaryExpression: return getContextualTypeForBinaryOperand(node, contextFlags); case SyntaxKind.PropertyAssignment: case SyntaxKind.ShorthandPropertyAssignment: - return getContextualTypeForObjectLiteralElement(parent as PropertyAssignment | ShorthandPropertyAssignment, contextFlags); + return getContextualTypeForObjectLiteralElement( + parent as PropertyAssignment | ShorthandPropertyAssignment, + contextFlags + ); case SyntaxKind.SpreadAssignment: - return getContextualType(parent.parent as ObjectLiteralExpression, contextFlags); + return getContextualType( + parent.parent as ObjectLiteralExpression, + contextFlags + ); case SyntaxKind.ArrayLiteralExpression: { const arrayLiteral = parent as ArrayLiteralExpression; - const type = getApparentTypeOfContextualType(arrayLiteral, contextFlags); + const type = getApparentTypeOfContextualType( + arrayLiteral, + contextFlags + ); const elementIndex = indexOfNode(arrayLiteral.elements, node); - const spreadIndices = getNodeLinks(arrayLiteral).spreadIndices ??= getSpreadIndices(arrayLiteral.elements); - return getContextualTypeForElementExpression(type, elementIndex, arrayLiteral.elements.length, spreadIndices.first, spreadIndices.last); + const spreadIndices = (getNodeLinks( + arrayLiteral + ).spreadIndices ??= getSpreadIndices(arrayLiteral.elements)); + return getContextualTypeForElementExpression( + type, + elementIndex, + arrayLiteral.elements.length, + spreadIndices.first, + spreadIndices.last + ); } case SyntaxKind.ConditionalExpression: - return getContextualTypeForConditionalOperand(node, contextFlags); + return getContextualTypeForConditionalOperand( + node, + contextFlags + ); case SyntaxKind.TemplateSpan: - Debug.assert(parent.parent.kind === SyntaxKind.TemplateExpression); - return getContextualTypeForSubstitutionExpression(parent.parent as TemplateExpression, node); + Debug.assert( + parent.parent.kind === SyntaxKind.TemplateExpression + ); + return getContextualTypeForSubstitutionExpression( + parent.parent as TemplateExpression, + node + ); case SyntaxKind.ParenthesizedExpression: { if (isInJSFile(parent)) { if (isJSDocSatisfiesExpression(parent)) { - return getTypeFromTypeNode(getJSDocSatisfiesExpressionType(parent)); + return getTypeFromTypeNode( + getJSDocSatisfiesExpressionType(parent) + ); } // Like in `checkParenthesizedExpression`, an `/** @type {xyz} */` comment before a parenthesized expression acts as a type cast. const typeTag = getJSDocTypeTag(parent); - if (typeTag && !isConstTypeReference(typeTag.typeExpression.type)) { + if ( + typeTag && + !isConstTypeReference(typeTag.typeExpression.type) + ) { return getTypeFromTypeNode(typeTag.typeExpression.type); } } - return getContextualType(parent as ParenthesizedExpression, contextFlags); + return getContextualType( + parent as ParenthesizedExpression, + contextFlags + ); } case SyntaxKind.NonNullExpression: - return getContextualType(parent as NonNullExpression, contextFlags); + return getContextualType( + parent as NonNullExpression, + contextFlags + ); case SyntaxKind.SatisfiesExpression: - return getTypeFromTypeNode((parent as SatisfiesExpression).type); + return getTypeFromTypeNode( + (parent as SatisfiesExpression).type + ); case SyntaxKind.ExportAssignment: - return tryGetTypeFromEffectiveTypeNode(parent as ExportAssignment); + return tryGetTypeFromEffectiveTypeNode( + parent as ExportAssignment + ); case SyntaxKind.JsxExpression: - return getContextualTypeForJsxExpression(parent as JsxExpression, contextFlags); + return getContextualTypeForJsxExpression( + parent as JsxExpression, + contextFlags + ); case SyntaxKind.JsxAttribute: case SyntaxKind.JsxSpreadAttribute: - return getContextualTypeForJsxAttribute(parent as JsxAttribute | JsxSpreadAttribute, contextFlags); + return getContextualTypeForJsxAttribute( + parent as JsxAttribute | JsxSpreadAttribute, + contextFlags + ); case SyntaxKind.JsxOpeningElement: case SyntaxKind.JsxSelfClosingElement: - return getContextualJsxElementAttributesType(parent as JsxOpeningLikeElement, contextFlags); + return getContextualJsxElementAttributesType( + parent as JsxOpeningLikeElement, + contextFlags + ); case SyntaxKind.ImportAttribute: - return getContextualImportAttributeType(parent as ImportAttribute); + return getContextualImportAttributeType( + parent as ImportAttribute + ); } return undefined; } function pushCachedContextualType(node: Expression) { - pushContextualType(node, getContextualType(node, /*contextFlags*/ undefined), /*isCache*/ true); + pushContextualType( + node, + getContextualType(node, /*contextFlags*/ undefined), + /*isCache*/ true + ); } - function pushContextualType(node: Expression, type: Type | undefined, isCache: boolean) { + function pushContextualType( + node: Expression, + type: Type | undefined, + isCache: boolean + ) { contextualTypeNodes[contextualTypeCount] = node; contextualTypes[contextualTypeCount] = type; contextualIsCache[contextualTypeCount] = isCache; @@ -32691,14 +57776,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function findContextualNode(node: Node, includeCaches: boolean) { for (let i = contextualTypeCount - 1; i >= 0; i--) { - if (node === contextualTypeNodes[i] && (includeCaches || !contextualIsCache[i])) { + if ( + node === contextualTypeNodes[i] && + (includeCaches || !contextualIsCache[i]) + ) { return i; } } return -1; } - function pushInferenceContext(node: Node, inferenceContext: InferenceContext | undefined) { + function pushInferenceContext( + node: Node, + inferenceContext: InferenceContext | undefined + ) { inferenceContextNodes[inferenceContextCount] = node; inferenceContexts[inferenceContextCount] = inferenceContext; inferenceContextCount++; @@ -32742,12 +57833,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getContextualImportAttributeType(node: ImportAttribute) { - return getTypeOfPropertyOfContextualType(getGlobalImportAttributesType(/*reportErrors*/ false), getNameFromImportAttribute(node)); + return getTypeOfPropertyOfContextualType( + getGlobalImportAttributesType(/*reportErrors*/ false), + getNameFromImportAttribute(node) + ); } - function getContextualJsxElementAttributesType(node: JsxOpeningLikeElement, contextFlags: ContextFlags | undefined) { - if (isJsxOpeningElement(node) && contextFlags !== ContextFlags.Completions) { - const index = findContextualNode(node.parent, /*includeCaches*/ !contextFlags); + function getContextualJsxElementAttributesType( + node: JsxOpeningLikeElement, + contextFlags: ContextFlags | undefined + ) { + if ( + isJsxOpeningElement(node) && + contextFlags !== ContextFlags.Completions + ) { + const index = findContextualNode( + node.parent, + /*includeCaches*/ !contextFlags + ); if (index >= 0) { // Contextually applied type is moved from attributes up to the outer jsx attributes so when walking up from the children they get hit // _However_ to hit them from the _attributes_ we must look for them here; otherwise we'll used the declared type @@ -32758,23 +57861,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getContextualTypeForArgumentAtIndex(node, 0); } - function getEffectiveFirstArgumentForJsxSignature(signature: Signature, node: JsxCallLike) { - return isJsxOpeningFragment(node) || getJsxReferenceKind(node) !== JsxReferenceKind.Component + function getEffectiveFirstArgumentForJsxSignature( + signature: Signature, + node: JsxCallLike + ) { + return isJsxOpeningFragment(node) || + getJsxReferenceKind(node) !== JsxReferenceKind.Component ? getJsxPropsTypeFromCallSignature(signature, node) : getJsxPropsTypeFromClassType(signature, node); } - function getJsxPropsTypeFromCallSignature(sig: Signature, context: JsxCallLike) { - let propsType = getTypeOfFirstParameterOfSignatureWithFallback(sig, unknownType); - propsType = getJsxManagedAttributesFromLocatedAttributes(context, getJsxNamespaceAt(context), propsType); - const intrinsicAttribs = getJsxType(JsxNames.IntrinsicAttributes, context); + function getJsxPropsTypeFromCallSignature( + sig: Signature, + context: JsxCallLike + ) { + let propsType = getTypeOfFirstParameterOfSignatureWithFallback( + sig, + unknownType + ); + propsType = getJsxManagedAttributesFromLocatedAttributes( + context, + getJsxNamespaceAt(context), + propsType + ); + const intrinsicAttribs = getJsxType( + JsxNames.IntrinsicAttributes, + context + ); if (!isErrorType(intrinsicAttribs)) { propsType = intersectTypes(intrinsicAttribs, propsType); } return propsType; } - function getJsxPropsTypeForSignatureFromMember(sig: Signature, forcedLookupLocation: __String) { + function getJsxPropsTypeForSignatureFromMember( + sig: Signature, + forcedLookupLocation: __String + ) { if (sig.compositeSignatures) { // JSX Elements using the legacy `props`-field based lookup (eg, react class components) need to treat the `props` member as an input // instead of an output position when resolving the signature. We need to go back to the input signatures of the composite signature, @@ -32787,7 +57910,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isTypeAny(instance)) { return instance; } - const propType = getTypeOfPropertyOfType(instance, forcedLookupLocation); + const propType = getTypeOfPropertyOfType( + instance, + forcedLookupLocation + ); if (!propType) { return; } @@ -32796,33 +57922,54 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getIntersectionType(results); // Same result for both union and intersection signatures } const instanceType = getReturnTypeOfSignature(sig); - return isTypeAny(instanceType) ? instanceType : getTypeOfPropertyOfType(instanceType, forcedLookupLocation); + return isTypeAny(instanceType) + ? instanceType + : getTypeOfPropertyOfType(instanceType, forcedLookupLocation); } function getStaticTypeOfReferencedJsxConstructor(context: JsxCallLike) { if (isJsxOpeningFragment(context)) return getJSXFragmentType(context); if (isJsxIntrinsicTagName(context.tagName)) { - const result = getIntrinsicAttributesTypeFromJsxOpeningLikeElement(context); - const fakeSignature = createSignatureForJSXIntrinsic(context, result); + const result = + getIntrinsicAttributesTypeFromJsxOpeningLikeElement(context); + const fakeSignature = createSignatureForJSXIntrinsic( + context, + result + ); return getOrCreateTypeFromSignature(fakeSignature); } const tagType = checkExpressionCached(context.tagName); if (tagType.flags & TypeFlags.StringLiteral) { - const result = getIntrinsicAttributesTypeFromStringLiteralType(tagType as StringLiteralType, context); + const result = getIntrinsicAttributesTypeFromStringLiteralType( + tagType as StringLiteralType, + context + ); if (!result) { return errorType; } - const fakeSignature = createSignatureForJSXIntrinsic(context, result); + const fakeSignature = createSignatureForJSXIntrinsic( + context, + result + ); return getOrCreateTypeFromSignature(fakeSignature); } return tagType; } - function getJsxManagedAttributesFromLocatedAttributes(context: JsxCallLike, ns: Symbol, attributesType: Type) { + function getJsxManagedAttributesFromLocatedAttributes( + context: JsxCallLike, + ns: Symbol, + attributesType: Type + ) { const managedSym = getJsxLibraryManagedAttributes(ns); if (managedSym) { const ctorType = getStaticTypeOfReferencedJsxConstructor(context); - const result = instantiateAliasOrInterfaceWithDefaults(managedSym, isInJSFile(context), ctorType, attributesType); + const result = instantiateAliasOrInterfaceWithDefaults( + managedSym, + isInJSFile(context), + ctorType, + attributesType + ); if (result) { return result; } @@ -32830,53 +57977,96 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return attributesType; } - function getJsxPropsTypeFromClassType(sig: Signature, context: JsxOpeningLikeElement) { + function getJsxPropsTypeFromClassType( + sig: Signature, + context: JsxOpeningLikeElement + ) { const ns = getJsxNamespaceAt(context); const forcedLookupLocation = getJsxElementPropertiesName(ns); - let attributesType = forcedLookupLocation === undefined - // If there is no type ElementAttributesProperty, return the type of the first parameter of the signature, which should be the props type - ? getTypeOfFirstParameterOfSignatureWithFallback(sig, unknownType) - : forcedLookupLocation === "" - // If there is no e.g. 'props' member in ElementAttributesProperty, use the element class type instead - ? getReturnTypeOfSignature(sig) - // Otherwise get the type of the property on the signature return type - : getJsxPropsTypeForSignatureFromMember(sig, forcedLookupLocation); + let attributesType = + forcedLookupLocation === undefined + ? // If there is no type ElementAttributesProperty, return the type of the first parameter of the signature, which should be the props type + getTypeOfFirstParameterOfSignatureWithFallback( + sig, + unknownType + ) + : forcedLookupLocation === "" + ? // If there is no e.g. 'props' member in ElementAttributesProperty, use the element class type instead + getReturnTypeOfSignature(sig) + : // Otherwise get the type of the property on the signature return type + getJsxPropsTypeForSignatureFromMember( + sig, + forcedLookupLocation + ); if (!attributesType) { // There is no property named 'props' on this instance type - if (!!forcedLookupLocation && !!length(context.attributes.properties)) { - error(context, Diagnostics.JSX_element_class_does_not_support_attributes_because_it_does_not_have_a_0_property, unescapeLeadingUnderscores(forcedLookupLocation)); + if ( + !!forcedLookupLocation && + !!length(context.attributes.properties) + ) { + error( + context, + Diagnostics.JSX_element_class_does_not_support_attributes_because_it_does_not_have_a_0_property, + unescapeLeadingUnderscores(forcedLookupLocation) + ); } return unknownType; } - attributesType = getJsxManagedAttributesFromLocatedAttributes(context, ns, attributesType); + attributesType = getJsxManagedAttributesFromLocatedAttributes( + context, + ns, + attributesType + ); if (isTypeAny(attributesType)) { // Props is of type 'any' or unknown return attributesType; - } - else { + } else { // Normal case -- add in IntrinsicClassElements and IntrinsicElements let apparentAttributesType = attributesType; - const intrinsicClassAttribs = getJsxType(JsxNames.IntrinsicClassAttributes, context); + const intrinsicClassAttribs = getJsxType( + JsxNames.IntrinsicClassAttributes, + context + ); if (!isErrorType(intrinsicClassAttribs)) { - const typeParams = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(intrinsicClassAttribs.symbol); + const typeParams = + getLocalTypeParametersOfClassOrInterfaceOrTypeAlias( + intrinsicClassAttribs.symbol + ); const hostClassType = getReturnTypeOfSignature(sig); let libraryManagedAttributeType: Type; if (typeParams) { // apply JSX.IntrinsicClassElements - const inferredArgs = fillMissingTypeArguments([hostClassType], typeParams, getMinTypeArgumentCount(typeParams), isInJSFile(context)); - libraryManagedAttributeType = instantiateType(intrinsicClassAttribs, createTypeMapper(typeParams, inferredArgs)); + const inferredArgs = fillMissingTypeArguments( + [hostClassType], + typeParams, + getMinTypeArgumentCount(typeParams), + isInJSFile(context) + ); + libraryManagedAttributeType = instantiateType( + intrinsicClassAttribs, + createTypeMapper(typeParams, inferredArgs) + ); } // or JSX.IntrinsicClassElements has no generics. else libraryManagedAttributeType = intrinsicClassAttribs; - apparentAttributesType = intersectTypes(libraryManagedAttributeType, apparentAttributesType); + apparentAttributesType = intersectTypes( + libraryManagedAttributeType, + apparentAttributesType + ); } - const intrinsicAttribs = getJsxType(JsxNames.IntrinsicAttributes, context); + const intrinsicAttribs = getJsxType( + JsxNames.IntrinsicAttributes, + context + ); if (!isErrorType(intrinsicAttribs)) { - apparentAttributesType = intersectTypes(intrinsicAttribs, apparentAttributesType); + apparentAttributesType = intersectTypes( + intrinsicAttribs, + apparentAttributesType + ); } return apparentAttributesType; @@ -32885,90 +58075,159 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getIntersectedSignatures(signatures: readonly Signature[]) { return getStrictOptionValue(compilerOptions, "noImplicitAny") - ? reduceLeft( - signatures, - (left: Signature | undefined, right) => - left === right || !left ? left - : compareTypeParametersIdentical(left.typeParameters, right!.typeParameters) ? combineSignaturesOfIntersectionMembers(left, right!) - : undefined, - ) + ? reduceLeft(signatures, (left: Signature | undefined, right) => + left === right || !left + ? left + : compareTypeParametersIdentical( + left.typeParameters, + right!.typeParameters + ) + ? combineSignaturesOfIntersectionMembers(left, right!) + : undefined + ) : undefined; } - function combineIntersectionThisParam(left: Symbol | undefined, right: Symbol | undefined, mapper: TypeMapper | undefined): Symbol | undefined { + function combineIntersectionThisParam( + left: Symbol | undefined, + right: Symbol | undefined, + mapper: TypeMapper | undefined + ): Symbol | undefined { if (!left || !right) { return left || right; } // A signature `this` type might be a read or a write position... It's very possible that it should be invariant // and we should refuse to merge signatures if there are `this` types and they do not match. However, so as to be // pessimistic when contextual typing, for now, we'll union the `this` types. - const thisType = getUnionType([getTypeOfSymbol(left), instantiateType(getTypeOfSymbol(right), mapper)]); + const thisType = getUnionType([ + getTypeOfSymbol(left), + instantiateType(getTypeOfSymbol(right), mapper), + ]); return createSymbolWithType(left, thisType); } - function combineIntersectionParameters(left: Signature, right: Signature, mapper: TypeMapper | undefined) { + function combineIntersectionParameters( + left: Signature, + right: Signature, + mapper: TypeMapper | undefined + ) { const leftCount = getParameterCount(left); const rightCount = getParameterCount(right); const longest = leftCount >= rightCount ? left : right; const shorter = longest === left ? right : left; const longestCount = longest === left ? leftCount : rightCount; - const eitherHasEffectiveRest = hasEffectiveRestParameter(left) || hasEffectiveRestParameter(right); - const needsExtraRestElement = eitherHasEffectiveRest && !hasEffectiveRestParameter(longest); - const params = new Array(longestCount + (needsExtraRestElement ? 1 : 0)); + const eitherHasEffectiveRest = + hasEffectiveRestParameter(left) || hasEffectiveRestParameter(right); + const needsExtraRestElement = + eitherHasEffectiveRest && !hasEffectiveRestParameter(longest); + const params = new Array( + longestCount + (needsExtraRestElement ? 1 : 0) + ); for (let i = 0; i < longestCount; i++) { let longestParamType = tryGetTypeAtPosition(longest, i)!; if (longest === right) { longestParamType = instantiateType(longestParamType, mapper); } - let shorterParamType = tryGetTypeAtPosition(shorter, i) || unknownType; + let shorterParamType = + tryGetTypeAtPosition(shorter, i) || unknownType; if (shorter === right) { shorterParamType = instantiateType(shorterParamType, mapper); } - const unionParamType = getUnionType([longestParamType, shorterParamType]); - const isRestParam = eitherHasEffectiveRest && !needsExtraRestElement && i === (longestCount - 1); - const isOptional = i >= getMinArgumentCount(longest) && i >= getMinArgumentCount(shorter); - const leftName = i >= leftCount ? undefined : getParameterNameAtPosition(left, i); - const rightName = i >= rightCount ? undefined : getParameterNameAtPosition(right, i); - - const paramName = leftName === rightName ? leftName : - !leftName ? rightName : - !rightName ? leftName : - undefined; + const unionParamType = getUnionType([ + longestParamType, + shorterParamType, + ]); + const isRestParam = + eitherHasEffectiveRest && + !needsExtraRestElement && + i === longestCount - 1; + const isOptional = + i >= getMinArgumentCount(longest) && + i >= getMinArgumentCount(shorter); + const leftName = + i >= leftCount + ? undefined + : getParameterNameAtPosition(left, i); + const rightName = + i >= rightCount + ? undefined + : getParameterNameAtPosition(right, i); + + const paramName = + leftName === rightName + ? leftName + : !leftName + ? rightName + : !rightName + ? leftName + : undefined; const paramSymbol = createSymbol( - SymbolFlags.FunctionScopedVariable | (isOptional && !isRestParam ? SymbolFlags.Optional : 0), - paramName || `arg${i}` as __String, - isRestParam ? CheckFlags.RestParameter : isOptional ? CheckFlags.OptionalParameter : 0, + SymbolFlags.FunctionScopedVariable | + (isOptional && !isRestParam ? SymbolFlags.Optional : 0), + paramName || (`arg${i}` as __String), + isRestParam + ? CheckFlags.RestParameter + : isOptional + ? CheckFlags.OptionalParameter + : 0 ); - paramSymbol.links.type = isRestParam ? createArrayType(unionParamType) : unionParamType; + paramSymbol.links.type = isRestParam + ? createArrayType(unionParamType) + : unionParamType; params[i] = paramSymbol; } if (needsExtraRestElement) { - const restParamSymbol = createSymbol(SymbolFlags.FunctionScopedVariable, "args" as __String, CheckFlags.RestParameter); - restParamSymbol.links.type = createArrayType(getTypeAtPosition(shorter, longestCount)); + const restParamSymbol = createSymbol( + SymbolFlags.FunctionScopedVariable, + "args" as __String, + CheckFlags.RestParameter + ); + restParamSymbol.links.type = createArrayType( + getTypeAtPosition(shorter, longestCount) + ); if (shorter === right) { - restParamSymbol.links.type = instantiateType(restParamSymbol.links.type, mapper); + restParamSymbol.links.type = instantiateType( + restParamSymbol.links.type, + mapper + ); } params[longestCount] = restParamSymbol; } return params; } - function combineSignaturesOfIntersectionMembers(left: Signature, right: Signature): Signature { + function combineSignaturesOfIntersectionMembers( + left: Signature, + right: Signature + ): Signature { const typeParams = left.typeParameters || right.typeParameters; let paramMapper: TypeMapper | undefined; if (left.typeParameters && right.typeParameters) { - paramMapper = createTypeMapper(right.typeParameters, left.typeParameters); + paramMapper = createTypeMapper( + right.typeParameters, + left.typeParameters + ); // We just use the type parameter defaults from the first signature } - let flags = (left.flags | right.flags) & (SignatureFlags.PropagatingFlags & ~SignatureFlags.HasRestParameter); + let flags = + (left.flags | right.flags) & + (SignatureFlags.PropagatingFlags & + ~SignatureFlags.HasRestParameter); const declaration = left.declaration; const params = combineIntersectionParameters(left, right, paramMapper); const lastParam = lastOrUndefined(params); if (lastParam && getCheckFlags(lastParam) & CheckFlags.RestParameter) { flags |= SignatureFlags.HasRestParameter; } - const thisParam = combineIntersectionThisParam(left.thisParameter, right.thisParameter, paramMapper); - const minArgCount = Math.max(left.minArgumentCount, right.minArgumentCount); + const thisParam = combineIntersectionThisParam( + left.thisParameter, + right.thisParameter, + paramMapper + ); + const minArgCount = Math.max( + left.minArgumentCount, + right.minArgumentCount + ); const result = createSignature( declaration, typeParams, @@ -32977,42 +58236,80 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /*resolvedReturnType*/ undefined, /*resolvedTypePredicate*/ undefined, minArgCount, - flags, + flags ); result.compositeKind = TypeFlags.Intersection; - result.compositeSignatures = concatenate(left.compositeKind === TypeFlags.Intersection && left.compositeSignatures || [left], [right]); + result.compositeSignatures = concatenate( + (left.compositeKind === TypeFlags.Intersection && + left.compositeSignatures) || [left], + [right] + ); if (paramMapper) { - result.mapper = left.compositeKind === TypeFlags.Intersection && left.mapper && left.compositeSignatures ? combineTypeMappers(left.mapper, paramMapper) : paramMapper; + result.mapper = + left.compositeKind === TypeFlags.Intersection && + left.mapper && + left.compositeSignatures + ? combineTypeMappers(left.mapper, paramMapper) + : paramMapper; } return result; } // If the given type is an object or union type with a single signature, and if that signature has at // least as many parameters as the given function, return the signature. Otherwise return undefined. - function getContextualCallSignature(type: Type, node: SignatureDeclaration): Signature | undefined { + function getContextualCallSignature( + type: Type, + node: SignatureDeclaration + ): Signature | undefined { const signatures = getSignaturesOfType(type, SignatureKind.Call); - const applicableByArity = filter(signatures, s => !isAritySmaller(s, node)); - return applicableByArity.length === 1 ? applicableByArity[0] : getIntersectedSignatures(applicableByArity); + const applicableByArity = filter( + signatures, + (s) => !isAritySmaller(s, node) + ); + return applicableByArity.length === 1 + ? applicableByArity[0] + : getIntersectedSignatures(applicableByArity); } /** If the contextual signature has fewer parameters than the function expression, do not use it */ - function isAritySmaller(signature: Signature, target: SignatureDeclaration) { + function isAritySmaller( + signature: Signature, + target: SignatureDeclaration + ) { let targetParameterCount = 0; - for (; targetParameterCount < target.parameters.length; targetParameterCount++) { + for ( + ; + targetParameterCount < target.parameters.length; + targetParameterCount++ + ) { const param = target.parameters[targetParameterCount]; - if (param.initializer || param.questionToken || param.dotDotDotToken || isJSDocOptionalParameter(param)) { + if ( + param.initializer || + param.questionToken || + param.dotDotDotToken || + isJSDocOptionalParameter(param) + ) { break; } } - if (target.parameters.length && parameterIsThisKeyword(target.parameters[0])) { + if ( + target.parameters.length && + parameterIsThisKeyword(target.parameters[0]) + ) { targetParameterCount--; } - return !hasEffectiveRestParameter(signature) && getParameterCount(signature) < targetParameterCount; + return ( + !hasEffectiveRestParameter(signature) && + getParameterCount(signature) < targetParameterCount + ); } - function getContextualSignatureForFunctionLikeDeclaration(node: FunctionLikeDeclaration): Signature | undefined { + function getContextualSignatureForFunctionLikeDeclaration( + node: FunctionLikeDeclaration + ): Signature | undefined { // Only function expressions, arrow functions, and object literal methods are contextually typed. - return isFunctionExpressionOrArrowFunction(node) || isObjectLiteralMethod(node) + return isFunctionExpressionOrArrowFunction(node) || + isObjectLiteralMethod(node) ? getContextualSignature(node as FunctionExpression) : undefined; } @@ -33022,13 +58319,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If the contextual type is a union type, get the signature from each type possible and if they are // all identical ignoring their return type, the result is same signature but with return type as // union type of return types from these signatures - function getContextualSignature(node: FunctionExpression | ArrowFunction | MethodDeclaration): Signature | undefined { - Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); + function getContextualSignature( + node: FunctionExpression | ArrowFunction | MethodDeclaration + ): Signature | undefined { + Debug.assert( + node.kind !== SyntaxKind.MethodDeclaration || + isObjectLiteralMethod(node) + ); const typeTagSignature = getSignatureOfTypeTag(node); if (typeTagSignature) { return typeTagSignature; } - const type = getApparentTypeOfContextualType(node, ContextFlags.Signature); + const type = getApparentTypeOfContextualType( + node, + ContextFlags.Signature + ); if (!type) { return undefined; } @@ -33043,12 +58348,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!signatureList) { // This signature will contribute to contextual union signature signatureList = [signature]; - } - else if (!compareSignaturesIdentical(signatureList[0], signature, /*partialMatch*/ false, /*ignoreThisTypes*/ true, /*ignoreReturnTypes*/ true, compareTypesIdentical)) { + } else if ( + !compareSignaturesIdentical( + signatureList[0], + signature, + /*partialMatch*/ false, + /*ignoreThisTypes*/ true, + /*ignoreReturnTypes*/ true, + compareTypesIdentical + ) + ) { // Signatures aren't identical, do not use return undefined; - } - else { + } else { // Use this signature for contextual union signature signatureList.push(signature); } @@ -33056,11 +58368,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Result is union of signatures collected (return type is union of return types of this signature set) if (signatureList) { - return signatureList.length === 1 ? signatureList[0] : createUnionSignature(signatureList[0], signatureList); + return signatureList.length === 1 + ? signatureList[0] + : createUnionSignature(signatureList[0], signatureList); } } - function checkGrammarRegularExpressionLiteral(node: RegularExpressionLiteral) { + function checkGrammarRegularExpressionLiteral( + node: RegularExpressionLiteral + ) { const sourceFile = getSourceFileOfNode(node); if (!hasParseDiagnostics(sourceFile) && !node.isUnterminated) { let lastError: DiagnosticWithLocation | undefined; @@ -33070,22 +58386,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { scanner.setOnError((message, length, arg0) => { // For providing spelling suggestions const start = scanner!.getTokenEnd(); - if (message.category === DiagnosticCategory.Message && lastError && start === lastError.start && length === lastError.length) { - const error = createDetachedDiagnostic(sourceFile.fileName, sourceFile.text, start, length, message, arg0); + if ( + message.category === DiagnosticCategory.Message && + lastError && + start === lastError.start && + length === lastError.length + ) { + const error = createDetachedDiagnostic( + sourceFile.fileName, + sourceFile.text, + start, + length, + message, + arg0 + ); addRelatedInfo(lastError, error); - } - else if (!lastError || start !== lastError.start) { - lastError = createFileDiagnostic(sourceFile, start, length, message, arg0); + } else if (!lastError || start !== lastError.start) { + lastError = createFileDiagnostic( + sourceFile, + start, + length, + message, + arg0 + ); diagnostics.add(lastError); } }); scanner.setText(sourceFile.text, node.pos, node.end - node.pos); try { scanner.scan(); - Debug.assert(scanner.reScanSlashToken(/*reportErrors*/ true) === SyntaxKind.RegularExpressionLiteral, "Expected scanner to rescan RegularExpressionLiteral"); + Debug.assert( + scanner.reScanSlashToken(/*reportErrors*/ true) === + SyntaxKind.RegularExpressionLiteral, + "Expected scanner to rescan RegularExpressionLiteral" + ); return !!lastError; - } - finally { + } finally { scanner.setText(""); scanner.setOnError(/*onError*/ undefined); } @@ -33102,24 +58438,49 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return globalRegExpType; } - function checkSpreadExpression(node: SpreadElement, checkMode?: CheckMode): Type { + function checkSpreadExpression( + node: SpreadElement, + checkMode?: CheckMode + ): Type { if (languageVersion < LanguageFeatureMinimumTarget.SpreadElements) { - checkExternalEmitHelpers(node, compilerOptions.downlevelIteration ? ExternalEmitHelpers.SpreadIncludes : ExternalEmitHelpers.SpreadArray); + checkExternalEmitHelpers( + node, + compilerOptions.downlevelIteration + ? ExternalEmitHelpers.SpreadIncludes + : ExternalEmitHelpers.SpreadArray + ); } const arrayOrIterableType = checkExpression(node.expression, checkMode); - return checkIteratedTypeOrElementType(IterationUse.Spread, arrayOrIterableType, undefinedType, node.expression); + return checkIteratedTypeOrElementType( + IterationUse.Spread, + arrayOrIterableType, + undefinedType, + node.expression + ); } function checkSyntheticExpression(node: SyntheticExpression): Type { - return node.isSpread ? getIndexedAccessType(node.type, numberType) : node.type; + return node.isSpread + ? getIndexedAccessType(node.type, numberType) + : node.type; } - function hasDefaultValue(node: BindingElement | ObjectLiteralElementLike | Expression): boolean { - return node.kind === SyntaxKind.BindingElement && !!(node as BindingElement).initializer || - node.kind === SyntaxKind.PropertyAssignment && hasDefaultValue((node as PropertyAssignment).initializer) || - node.kind === SyntaxKind.ShorthandPropertyAssignment && !!(node as ShorthandPropertyAssignment).objectAssignmentInitializer || - node.kind === SyntaxKind.BinaryExpression && (node as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken; + function hasDefaultValue( + node: BindingElement | ObjectLiteralElementLike | Expression + ): boolean { + return ( + (node.kind === SyntaxKind.BindingElement && + !!(node as BindingElement).initializer) || + (node.kind === SyntaxKind.PropertyAssignment && + hasDefaultValue((node as PropertyAssignment).initializer)) || + (node.kind === SyntaxKind.ShorthandPropertyAssignment && + !!(node as ShorthandPropertyAssignment) + .objectAssignmentInitializer) || + (node.kind === SyntaxKind.BinaryExpression && + (node as BinaryExpression).operatorToken.kind === + SyntaxKind.EqualsToken) + ); } function isSpreadIntoCallOrNew(node: ArrayLiteralExpression) { @@ -33127,7 +58488,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return isSpreadElement(parent) && isCallOrNewExpression(parent.parent); } - function checkArrayLiteral(node: ArrayLiteralExpression, checkMode: CheckMode | undefined, forceTuple: boolean | undefined): Type { + function checkArrayLiteral( + node: ArrayLiteralExpression, + checkMode: CheckMode | undefined, + forceTuple: boolean | undefined + ): Type { const elements = node.elements; const elementCount = elements.length; const elementTypes: Type[] = []; @@ -33135,22 +58500,48 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { pushCachedContextualType(node); const inDestructuringPattern = isAssignmentTarget(node); const inConstContext = isConstContext(node); - const contextualType = getApparentTypeOfContextualType(node, /*contextFlags*/ undefined); - const inTupleContext = isSpreadIntoCallOrNew(node) || !!contextualType && someType(contextualType, t => isTupleLikeType(t) || isGenericMappedType(t) && !t.nameType && !!getHomomorphicTypeVariable(t.target as MappedType || t)); + const contextualType = getApparentTypeOfContextualType( + node, + /*contextFlags*/ undefined + ); + const inTupleContext = + isSpreadIntoCallOrNew(node) || + (!!contextualType && + someType( + contextualType, + (t) => + isTupleLikeType(t) || + (isGenericMappedType(t) && + !t.nameType && + !!getHomomorphicTypeVariable( + (t.target as MappedType) || t + )) + )); let hasOmittedExpression = false; for (let i = 0; i < elementCount; i++) { const e = elements[i]; if (e.kind === SyntaxKind.SpreadElement) { - if (languageVersion < LanguageFeatureMinimumTarget.SpreadElements) { - checkExternalEmitHelpers(e, compilerOptions.downlevelIteration ? ExternalEmitHelpers.SpreadIncludes : ExternalEmitHelpers.SpreadArray); + if ( + languageVersion < + LanguageFeatureMinimumTarget.SpreadElements + ) { + checkExternalEmitHelpers( + e, + compilerOptions.downlevelIteration + ? ExternalEmitHelpers.SpreadIncludes + : ExternalEmitHelpers.SpreadArray + ); } - const spreadType = checkExpression((e as SpreadElement).expression, checkMode, forceTuple); + const spreadType = checkExpression( + (e as SpreadElement).expression, + checkMode, + forceTuple + ); if (isArrayLikeType(spreadType)) { elementTypes.push(spreadType); elementFlags.push(ElementFlags.Variadic); - } - else if (inDestructuringPattern) { + } else if (inDestructuringPattern) { // Given the following situation: // var c: {}; // [...c] = ["", 0]; @@ -33163,27 +58554,61 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // get the contextual element type from it. So we do something similar to // getContextualTypeForElementExpression, which will crucially not error // if there is no index type / iterated type. - const restElementType = getIndexTypeOfType(spreadType, numberType) || - getIteratedTypeOrElementType(IterationUse.Destructuring, spreadType, undefinedType, /*errorNode*/ undefined, /*checkAssignability*/ false) || + const restElementType = + getIndexTypeOfType(spreadType, numberType) || + getIteratedTypeOrElementType( + IterationUse.Destructuring, + spreadType, + undefinedType, + /*errorNode*/ undefined, + /*checkAssignability*/ false + ) || unknownType; elementTypes.push(restElementType); elementFlags.push(ElementFlags.Rest); - } - else { - elementTypes.push(checkIteratedTypeOrElementType(IterationUse.Spread, spreadType, undefinedType, (e as SpreadElement).expression)); + } else { + elementTypes.push( + checkIteratedTypeOrElementType( + IterationUse.Spread, + spreadType, + undefinedType, + (e as SpreadElement).expression + ) + ); elementFlags.push(ElementFlags.Rest); } - } - else if (exactOptionalPropertyTypes && e.kind === SyntaxKind.OmittedExpression) { + } else if ( + exactOptionalPropertyTypes && + e.kind === SyntaxKind.OmittedExpression + ) { hasOmittedExpression = true; elementTypes.push(undefinedOrMissingType); elementFlags.push(ElementFlags.Optional); - } - else { - const type = checkExpressionForMutableLocation(e, checkMode, forceTuple); - elementTypes.push(addOptionality(type, /*isProperty*/ true, hasOmittedExpression)); - elementFlags.push(hasOmittedExpression ? ElementFlags.Optional : ElementFlags.Required); - if (inTupleContext && checkMode && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && isContextSensitive(e)) { + } else { + const type = checkExpressionForMutableLocation( + e, + checkMode, + forceTuple + ); + elementTypes.push( + addOptionality( + type, + /*isProperty*/ true, + hasOmittedExpression + ) + ); + elementFlags.push( + hasOmittedExpression + ? ElementFlags.Optional + : ElementFlags.Required + ); + if ( + inTupleContext && + checkMode && + checkMode & CheckMode.Inferential && + !(checkMode & CheckMode.SkipContextSensitive) && + isContextSensitive(e) + ) { const inferenceContext = getInferenceContext(node); Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context addIntraExpressionInferenceSite(inferenceContext, e, type); @@ -33195,14 +58620,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return createTupleType(elementTypes, elementFlags); } if (forceTuple || inConstContext || inTupleContext) { - return createArrayLiteralType(createTupleType(elementTypes, elementFlags, /*readonly*/ inConstContext && !(contextualType && someType(contextualType, isMutableArrayLikeType)))); + return createArrayLiteralType( + createTupleType( + elementTypes, + elementFlags, + /*readonly*/ inConstContext && + !( + contextualType && + someType(contextualType, isMutableArrayLikeType) + ) + ) + ); } - return createArrayLiteralType(createArrayType( - elementTypes.length ? - getUnionType(sameMap(elementTypes, (t, i) => elementFlags[i] & ElementFlags.Variadic ? getIndexedAccessTypeOrUndefined(t, numberType) || anyType : t), UnionReduction.Subtype) : - strictNullChecks ? implicitNeverType : undefinedWideningType, - inConstContext, - )); + return createArrayLiteralType( + createArrayType( + elementTypes.length + ? getUnionType( + sameMap(elementTypes, (t, i) => + elementFlags[i] & ElementFlags.Variadic + ? getIndexedAccessTypeOrUndefined( + t, + numberType + ) || anyType + : t + ), + UnionReduction.Subtype + ) + : strictNullChecks + ? implicitNeverType + : undefinedWideningType, + inConstContext + ) + ); } function createArrayLiteralType(type: Type) { @@ -33211,8 +58660,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } let literalType = (type as TypeReference).literalType; if (!literalType) { - literalType = (type as TypeReference).literalType = cloneTypeReference(type as TypeReference); - literalType.objectFlags |= ObjectFlags.ArrayLiteral | ObjectFlags.ContainsObjectOrArrayLiteral; + literalType = (type as TypeReference).literalType = + cloneTypeReference(type as TypeReference); + literalType.objectFlags |= + ObjectFlags.ArrayLiteral | + ObjectFlags.ContainsObjectOrArrayLiteral; } return literalType; } @@ -33234,42 +58686,70 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isNumericComputedName(name: ComputedPropertyName): boolean { // It seems odd to consider an expression of type Any to result in a numeric name, // but this behavior is consistent with checkIndexedAccess - return isTypeAssignableToKind(checkComputedPropertyName(name), TypeFlags.NumberLike); + return isTypeAssignableToKind( + checkComputedPropertyName(name), + TypeFlags.NumberLike + ); } function checkComputedPropertyName(node: ComputedPropertyName): Type { const links = getNodeLinks(node.expression); if (!links.resolvedType) { if ( - (isTypeLiteralNode(node.parent.parent) || isClassLike(node.parent.parent) || isInterfaceDeclaration(node.parent.parent)) - && isBinaryExpression(node.expression) && node.expression.operatorToken.kind === SyntaxKind.InKeyword - && node.parent.kind !== SyntaxKind.GetAccessor && node.parent.kind !== SyntaxKind.SetAccessor + (isTypeLiteralNode(node.parent.parent) || + isClassLike(node.parent.parent) || + isInterfaceDeclaration(node.parent.parent)) && + isBinaryExpression(node.expression) && + node.expression.operatorToken.kind === SyntaxKind.InKeyword && + node.parent.kind !== SyntaxKind.GetAccessor && + node.parent.kind !== SyntaxKind.SetAccessor ) { - return links.resolvedType = errorType; + return (links.resolvedType = errorType); } links.resolvedType = checkExpression(node.expression); // The computed property name of a non-static class field within a loop must be stored in a block-scoped binding. // (It needs to be bound at class evaluation time.) - if (isPropertyDeclaration(node.parent) && !hasStaticModifier(node.parent) && isClassExpression(node.parent.parent)) { - const container = getEnclosingBlockScopeContainer(node.parent.parent); - const enclosingIterationStatement = getEnclosingIterationStatement(container); + if ( + isPropertyDeclaration(node.parent) && + !hasStaticModifier(node.parent) && + isClassExpression(node.parent.parent) + ) { + const container = getEnclosingBlockScopeContainer( + node.parent.parent + ); + const enclosingIterationStatement = + getEnclosingIterationStatement(container); if (enclosingIterationStatement) { // The computed field name will use a block scoped binding which can be unique for each iteration of the loop. - getNodeLinks(enclosingIterationStatement).flags |= NodeCheckFlags.LoopWithCapturedBlockScopedBinding; + getNodeLinks(enclosingIterationStatement).flags |= + NodeCheckFlags.LoopWithCapturedBlockScopedBinding; // The generated variable which stores the computed field name must be block-scoped. - getNodeLinks(node).flags |= NodeCheckFlags.BlockScopedBindingInLoop; + getNodeLinks(node).flags |= + NodeCheckFlags.BlockScopedBindingInLoop; // The generated variable which stores the class must be block-scoped. - getNodeLinks(node.parent.parent).flags |= NodeCheckFlags.BlockScopedBindingInLoop; + getNodeLinks(node.parent.parent).flags |= + NodeCheckFlags.BlockScopedBindingInLoop; } } // This will allow types number, string, symbol or any. It will also allow enums, the unknown // type, and any union of these types (like string | number). if ( links.resolvedType.flags & TypeFlags.Nullable || - !isTypeAssignableToKind(links.resolvedType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbolLike) && - !isTypeAssignableTo(links.resolvedType, stringNumberSymbolType) + (!isTypeAssignableToKind( + links.resolvedType, + TypeFlags.StringLike | + TypeFlags.NumberLike | + TypeFlags.ESSymbolLike + ) && + !isTypeAssignableTo( + links.resolvedType, + stringNumberSymbolType + )) ) { - error(node, Diagnostics.A_computed_property_name_must_be_of_type_string_number_symbol_or_any); + error( + node, + Diagnostics.A_computed_property_name_must_be_of_type_string_number_symbol_or_any + ); } } @@ -33278,67 +58758,119 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isSymbolWithNumericName(symbol: Symbol) { const firstDecl = symbol.declarations?.[0]; - return isNumericLiteralName(symbol.escapedName) || (firstDecl && isNamedDeclaration(firstDecl) && isNumericName(firstDecl.name)); + return ( + isNumericLiteralName(symbol.escapedName) || + (firstDecl && + isNamedDeclaration(firstDecl) && + isNumericName(firstDecl.name)) + ); } function isSymbolWithSymbolName(symbol: Symbol) { const firstDecl = symbol.declarations?.[0]; - return isKnownSymbol(symbol) || (firstDecl && isNamedDeclaration(firstDecl) && isComputedPropertyName(firstDecl.name) && - isTypeAssignableToKind(checkComputedPropertyName(firstDecl.name), TypeFlags.ESSymbol)); + return ( + isKnownSymbol(symbol) || + (firstDecl && + isNamedDeclaration(firstDecl) && + isComputedPropertyName(firstDecl.name) && + isTypeAssignableToKind( + checkComputedPropertyName(firstDecl.name), + TypeFlags.ESSymbol + )) + ); } function isSymbolWithComputedName(symbol: Symbol) { const firstDecl = symbol.declarations?.[0]; - return firstDecl && isNamedDeclaration(firstDecl) && isComputedPropertyName(firstDecl.name); + return ( + firstDecl && + isNamedDeclaration(firstDecl) && + isComputedPropertyName(firstDecl.name) + ); } // NOTE: currently does not make pattern literal indexers, eg `${number}px` - function getObjectLiteralIndexInfo(isReadonly: boolean, offset: number, properties: Symbol[], keyType: Type): IndexInfo { + function getObjectLiteralIndexInfo( + isReadonly: boolean, + offset: number, + properties: Symbol[], + keyType: Type + ): IndexInfo { const propTypes: Type[] = []; let components: ElementWithComputedPropertyName[] | undefined; for (let i = offset; i < properties.length; i++) { const prop = properties[i]; if ( - keyType === stringType && !isSymbolWithSymbolName(prop) || - keyType === numberType && isSymbolWithNumericName(prop) || - keyType === esSymbolType && isSymbolWithSymbolName(prop) + (keyType === stringType && !isSymbolWithSymbolName(prop)) || + (keyType === numberType && isSymbolWithNumericName(prop)) || + (keyType === esSymbolType && isSymbolWithSymbolName(prop)) ) { propTypes.push(getTypeOfSymbol(properties[i])); if (isSymbolWithComputedName(properties[i])) { - components = append(components, properties[i].declarations?.[0]! as ElementWithComputedPropertyName); + components = append( + components, + properties[i] + .declarations?.[0]! as ElementWithComputedPropertyName + ); } } } - const unionType = propTypes.length ? getUnionType(propTypes, UnionReduction.Subtype) : undefinedType; - return createIndexInfo(keyType, unionType, isReadonly, /*declaration*/ undefined, components); + const unionType = propTypes.length + ? getUnionType(propTypes, UnionReduction.Subtype) + : undefinedType; + return createIndexInfo( + keyType, + unionType, + isReadonly, + /*declaration*/ undefined, + components + ); } function getImmediateAliasedSymbol(symbol: Symbol): Symbol | undefined { - Debug.assert((symbol.flags & SymbolFlags.Alias) !== 0, "Should only get Alias here."); + Debug.assert( + (symbol.flags & SymbolFlags.Alias) !== 0, + "Should only get Alias here." + ); const links = getSymbolLinks(symbol); if (!links.immediateTarget) { const node = getDeclarationOfAliasSymbol(symbol); if (!node) return Debug.fail(); - links.immediateTarget = getTargetOfAliasDeclaration(node, /*dontRecursivelyResolve*/ true); + links.immediateTarget = getTargetOfAliasDeclaration( + node, + /*dontRecursivelyResolve*/ true + ); } return links.immediateTarget; } - function checkObjectLiteral(node: ObjectLiteralExpression, checkMode: CheckMode = CheckMode.Normal): Type { + function checkObjectLiteral( + node: ObjectLiteralExpression, + checkMode: CheckMode = CheckMode.Normal + ): Type { const inDestructuringPattern = isAssignmentTarget(node); // Grammar checking checkGrammarObjectLiteralExpression(node, inDestructuringPattern); - const allPropertiesTable = strictNullChecks ? createSymbolTable() : undefined; + const allPropertiesTable = strictNullChecks + ? createSymbolTable() + : undefined; let propertiesTable = createSymbolTable(); let propertiesArray: Symbol[] = []; let spread: Type = emptyObjectType; pushCachedContextualType(node); - const contextualType = getApparentTypeOfContextualType(node, /*contextFlags*/ undefined); - const contextualTypeHasPattern = contextualType && contextualType.pattern && - (contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression); + const contextualType = getApparentTypeOfContextualType( + node, + /*contextFlags*/ undefined + ); + const contextualTypeHasPattern = + contextualType && + contextualType.pattern && + (contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || + contextualType.pattern.kind === + SyntaxKind.ObjectLiteralExpression); const inConstContext = isConstContext(node); const checkFlags = inConstContext ? CheckFlags.Readonly : 0; const isInJavascript = isInJSFile(node) && !isInJsonFile(node); @@ -33362,34 +58894,64 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let offset = 0; for (const memberDecl of node.properties) { let member = getSymbolOfDeclaration(memberDecl); - const computedNameType = memberDecl.name && memberDecl.name.kind === SyntaxKind.ComputedPropertyName ? - checkComputedPropertyName(memberDecl.name) : undefined; + const computedNameType = + memberDecl.name && + memberDecl.name.kind === SyntaxKind.ComputedPropertyName + ? checkComputedPropertyName(memberDecl.name) + : undefined; if ( memberDecl.kind === SyntaxKind.PropertyAssignment || memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment || isObjectLiteralMethod(memberDecl) ) { - let type = memberDecl.kind === SyntaxKind.PropertyAssignment ? checkPropertyAssignment(memberDecl, checkMode) : - // avoid resolving the left side of the ShorthandPropertyAssignment outside of the destructuring - // for error recovery purposes. For example, if a user wrote `{ a = 100 }` instead of `{ a: 100 }`. - // we don't want to say "could not find 'a'". - memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment ? checkExpressionForMutableLocation(!inDestructuringPattern && memberDecl.objectAssignmentInitializer ? memberDecl.objectAssignmentInitializer : memberDecl.name, checkMode) : - checkObjectLiteralMethod(memberDecl, checkMode); + let type = + memberDecl.kind === SyntaxKind.PropertyAssignment + ? checkPropertyAssignment(memberDecl, checkMode) + : // avoid resolving the left side of the ShorthandPropertyAssignment outside of the destructuring + // for error recovery purposes. For example, if a user wrote `{ a = 100 }` instead of `{ a: 100 }`. + // we don't want to say "could not find 'a'". + memberDecl.kind === + SyntaxKind.ShorthandPropertyAssignment + ? checkExpressionForMutableLocation( + !inDestructuringPattern && + memberDecl.objectAssignmentInitializer + ? memberDecl.objectAssignmentInitializer + : memberDecl.name, + checkMode + ) + : checkObjectLiteralMethod(memberDecl, checkMode); if (isInJavascript) { - const jsDocType = getTypeForDeclarationFromJSDocComment(memberDecl); + const jsDocType = + getTypeForDeclarationFromJSDocComment(memberDecl); if (jsDocType) { checkTypeAssignableTo(type, jsDocType, memberDecl); type = jsDocType; - } - else if (enumTag && enumTag.typeExpression) { - checkTypeAssignableTo(type, getTypeFromTypeNode(enumTag.typeExpression), memberDecl); + } else if (enumTag && enumTag.typeExpression) { + checkTypeAssignableTo( + type, + getTypeFromTypeNode(enumTag.typeExpression), + memberDecl + ); } } - objectFlags |= getObjectFlags(type) & ObjectFlags.PropagatingFlags; - const nameType = computedNameType && isTypeUsableAsPropertyName(computedNameType) ? computedNameType : undefined; - const prop = nameType ? - createSymbol(SymbolFlags.Property | member.flags, getPropertyNameFromType(nameType), checkFlags | CheckFlags.Late) : - createSymbol(SymbolFlags.Property | member.flags, member.escapedName, checkFlags); + objectFlags |= + getObjectFlags(type) & ObjectFlags.PropagatingFlags; + const nameType = + computedNameType && + isTypeUsableAsPropertyName(computedNameType) + ? computedNameType + : undefined; + const prop = nameType + ? createSymbol( + SymbolFlags.Property | member.flags, + getPropertyNameFromType(nameType), + checkFlags | CheckFlags.Late + ) + : createSymbol( + SymbolFlags.Property | member.flags, + member.escapedName, + checkFlags + ); if (nameType) { prop.links.nameType = nameType; } @@ -33398,16 +58960,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If object literal is an assignment pattern and if the assignment pattern specifies a default value // for the property, make the property optional. prop.flags |= SymbolFlags.Optional; - } - else if (contextualTypeHasPattern && !(getObjectFlags(contextualType) & ObjectFlags.ObjectLiteralPatternWithComputedProperties)) { + } else if ( + contextualTypeHasPattern && + !( + getObjectFlags(contextualType) & + ObjectFlags.ObjectLiteralPatternWithComputedProperties + ) + ) { // If object literal is contextually typed by the implied type of a binding pattern, and if the // binding pattern specifies a default value for the property, make the property optional. - const impliedProp = getPropertyOfType(contextualType, member.escapedName); + const impliedProp = getPropertyOfType( + contextualType, + member.escapedName + ); if (impliedProp) { prop.flags |= impliedProp.flags & SymbolFlags.Optional; - } - else if (!getIndexInfoOfType(contextualType, stringType)) { - error(memberDecl.name, Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1, symbolToString(member), typeToString(contextualType)); + } else if ( + !getIndexInfoOfType(contextualType, stringType) + ) { + error( + memberDecl.name, + Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1, + symbolToString(member), + typeToString(contextualType) + ); } } @@ -33423,72 +58999,122 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { allPropertiesTable?.set(prop.escapedName, prop); if ( - contextualType && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && - (memberDecl.kind === SyntaxKind.PropertyAssignment || memberDecl.kind === SyntaxKind.MethodDeclaration) && isContextSensitive(memberDecl) + contextualType && + checkMode & CheckMode.Inferential && + !(checkMode & CheckMode.SkipContextSensitive) && + (memberDecl.kind === SyntaxKind.PropertyAssignment || + memberDecl.kind === SyntaxKind.MethodDeclaration) && + isContextSensitive(memberDecl) ) { const inferenceContext = getInferenceContext(node); Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context - const inferenceNode = memberDecl.kind === SyntaxKind.PropertyAssignment ? memberDecl.initializer : memberDecl; - addIntraExpressionInferenceSite(inferenceContext, inferenceNode, type); + const inferenceNode = + memberDecl.kind === SyntaxKind.PropertyAssignment + ? memberDecl.initializer + : memberDecl; + addIntraExpressionInferenceSite( + inferenceContext, + inferenceNode, + type + ); } - } - else if (memberDecl.kind === SyntaxKind.SpreadAssignment) { - if (languageVersion < LanguageFeatureMinimumTarget.ObjectAssign) { - checkExternalEmitHelpers(memberDecl, ExternalEmitHelpers.Assign); + } else if (memberDecl.kind === SyntaxKind.SpreadAssignment) { + if ( + languageVersion < LanguageFeatureMinimumTarget.ObjectAssign + ) { + checkExternalEmitHelpers( + memberDecl, + ExternalEmitHelpers.Assign + ); } if (propertiesArray.length > 0) { - spread = getSpreadType(spread, createObjectLiteralType(), node.symbol, objectFlags, inConstContext); + spread = getSpreadType( + spread, + createObjectLiteralType(), + node.symbol, + objectFlags, + inConstContext + ); propertiesArray = []; propertiesTable = createSymbolTable(); hasComputedStringProperty = false; hasComputedNumberProperty = false; hasComputedSymbolProperty = false; } - const type = getReducedType(checkExpression(memberDecl.expression, checkMode & CheckMode.Inferential)); + const type = getReducedType( + checkExpression( + memberDecl.expression, + checkMode & CheckMode.Inferential + ) + ); if (isValidSpreadType(type)) { - const mergedType = tryMergeUnionOfObjectTypeAndEmptyObject(type, inConstContext); + const mergedType = tryMergeUnionOfObjectTypeAndEmptyObject( + type, + inConstContext + ); if (allPropertiesTable) { - checkSpreadPropOverrides(mergedType, allPropertiesTable, memberDecl); + checkSpreadPropOverrides( + mergedType, + allPropertiesTable, + memberDecl + ); } offset = propertiesArray.length; if (isErrorType(spread)) { continue; } - spread = getSpreadType(spread, mergedType, node.symbol, objectFlags, inConstContext); - } - else { - error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types); + spread = getSpreadType( + spread, + mergedType, + node.symbol, + objectFlags, + inConstContext + ); + } else { + error( + memberDecl, + Diagnostics.Spread_types_may_only_be_created_from_object_types + ); spread = errorType; } continue; - } - else { + } else { // TypeScript 1.0 spec (April 2014) // A get accessor declaration is processed in the same manner as // an ordinary function declaration(section 6.1) with no parameters. // A set accessor declaration is processed in the same manner // as an ordinary function declaration with a single parameter and a Void return type. - Debug.assert(memberDecl.kind === SyntaxKind.GetAccessor || memberDecl.kind === SyntaxKind.SetAccessor); + Debug.assert( + memberDecl.kind === SyntaxKind.GetAccessor || + memberDecl.kind === SyntaxKind.SetAccessor + ); checkNodeDeferred(memberDecl); } - if (computedNameType && !(computedNameType.flags & TypeFlags.StringOrNumberLiteralOrUnique)) { - if (isTypeAssignableTo(computedNameType, stringNumberSymbolType)) { + if ( + computedNameType && + !( + computedNameType.flags & + TypeFlags.StringOrNumberLiteralOrUnique + ) + ) { + if ( + isTypeAssignableTo(computedNameType, stringNumberSymbolType) + ) { if (isTypeAssignableTo(computedNameType, numberType)) { hasComputedNumberProperty = true; - } - else if (isTypeAssignableTo(computedNameType, esSymbolType)) { + } else if ( + isTypeAssignableTo(computedNameType, esSymbolType) + ) { hasComputedSymbolProperty = true; - } - else { + } else { hasComputedStringProperty = true; } if (inDestructuringPattern) { patternWithComputedProperties = true; } } - } - else { + } else { propertiesTable.set(member.escapedName, member); } propertiesArray.push(member); @@ -33501,14 +59127,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (spread !== emptyObjectType) { if (propertiesArray.length > 0) { - spread = getSpreadType(spread, createObjectLiteralType(), node.symbol, objectFlags, inConstContext); + spread = getSpreadType( + spread, + createObjectLiteralType(), + node.symbol, + objectFlags, + inConstContext + ); propertiesArray = []; propertiesTable = createSymbolTable(); hasComputedStringProperty = false; hasComputedNumberProperty = false; } // remap the raw emptyObjectType fed in at the top into a fresh empty object literal type, unique to this use site - return mapType(spread, t => t === emptyObjectType ? createObjectLiteralType() : t); + return mapType(spread, (t) => + t === emptyObjectType ? createObjectLiteralType() : t + ); } return createObjectLiteralType(); @@ -33516,16 +59150,50 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function createObjectLiteralType() { const indexInfos = []; const isReadonly = isConstContext(node); - if (hasComputedStringProperty) indexInfos.push(getObjectLiteralIndexInfo(isReadonly, offset, propertiesArray, stringType)); - if (hasComputedNumberProperty) indexInfos.push(getObjectLiteralIndexInfo(isReadonly, offset, propertiesArray, numberType)); - if (hasComputedSymbolProperty) indexInfos.push(getObjectLiteralIndexInfo(isReadonly, offset, propertiesArray, esSymbolType)); - const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, indexInfos); - result.objectFlags |= objectFlags | ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral; + if (hasComputedStringProperty) + indexInfos.push( + getObjectLiteralIndexInfo( + isReadonly, + offset, + propertiesArray, + stringType + ) + ); + if (hasComputedNumberProperty) + indexInfos.push( + getObjectLiteralIndexInfo( + isReadonly, + offset, + propertiesArray, + numberType + ) + ); + if (hasComputedSymbolProperty) + indexInfos.push( + getObjectLiteralIndexInfo( + isReadonly, + offset, + propertiesArray, + esSymbolType + ) + ); + const result = createAnonymousType( + node.symbol, + propertiesTable, + emptyArray, + emptyArray, + indexInfos + ); + result.objectFlags |= + objectFlags | + ObjectFlags.ObjectLiteral | + ObjectFlags.ContainsObjectOrArrayLiteral; if (isJSObjectLiteral) { result.objectFlags |= ObjectFlags.JSLiteral; } if (patternWithComputedProperties) { - result.objectFlags |= ObjectFlags.ObjectLiteralPatternWithComputedProperties; + result.objectFlags |= + ObjectFlags.ObjectLiteralPatternWithComputedProperties; } if (inDestructuringPattern) { result.pattern = node; @@ -33535,16 +59203,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isValidSpreadType(type: Type): boolean { - const t = removeDefinitelyFalsyTypes(mapType(type, getBaseConstraintOrType)); - return !!(t.flags & (TypeFlags.Any | TypeFlags.NonPrimitive | TypeFlags.Object | TypeFlags.InstantiableNonPrimitive) || - t.flags & TypeFlags.UnionOrIntersection && every((t as UnionOrIntersectionType).types, isValidSpreadType)); + const t = removeDefinitelyFalsyTypes( + mapType(type, getBaseConstraintOrType) + ); + return !!( + t.flags & + (TypeFlags.Any | + TypeFlags.NonPrimitive | + TypeFlags.Object | + TypeFlags.InstantiableNonPrimitive) || + (t.flags & TypeFlags.UnionOrIntersection && + every((t as UnionOrIntersectionType).types, isValidSpreadType)) + ); } function checkJsxSelfClosingElementDeferred(node: JsxSelfClosingElement) { checkJsxOpeningLikeElementOrOpeningFragment(node); } - function checkJsxSelfClosingElement(node: JsxSelfClosingElement, _checkMode: CheckMode | undefined): Type { + function checkJsxSelfClosingElement( + node: JsxSelfClosingElement, + _checkMode: CheckMode | undefined + ): Type { checkNodeDeferred(node); return getJsxElementTypeAt(node) || anyType; } @@ -33556,15 +59236,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Perform resolution on the closing tag so that rename/go to definition/etc work if (isJsxIntrinsicTagName(node.closingElement.tagName)) { getIntrinsicTagSymbol(node.closingElement); - } - else { + } else { checkExpression(node.closingElement.tagName); } checkJsxChildren(node); } - function checkJsxElement(node: JsxElement, _checkMode: CheckMode | undefined): Type { + function checkJsxElement( + node: JsxElement, + _checkMode: CheckMode | undefined + ): Type { checkNodeDeferred(node); return getJsxElementTypeAt(node) || anyType; @@ -33577,14 +59259,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // if jsxFactory compiler option is provided, ensure jsxFragmentFactory compiler option or @jsxFrag pragma is provided too const nodeSourceFile = getSourceFileOfNode(node); if ( - getJSXTransformEnabled(compilerOptions) && (compilerOptions.jsxFactory || nodeSourceFile.pragmas.has("jsx")) - && !compilerOptions.jsxFragmentFactory && !nodeSourceFile.pragmas.has("jsxfrag") + getJSXTransformEnabled(compilerOptions) && + (compilerOptions.jsxFactory || nodeSourceFile.pragmas.has("jsx")) && + !compilerOptions.jsxFragmentFactory && + !nodeSourceFile.pragmas.has("jsxfrag") ) { error( node, compilerOptions.jsxFactory ? Diagnostics.The_jsxFragmentFactory_compiler_option_must_be_provided_to_use_JSX_fragments_with_the_jsxFactory_compiler_option - : Diagnostics.An_jsxFrag_pragma_is_required_when_using_an_jsx_pragma_with_JSX_fragments, + : Diagnostics.An_jsxFrag_pragma_is_required_when_using_an_jsx_pragma_with_JSX_fragments ); } @@ -33600,8 +59284,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** * Returns true iff React would emit this tag name as a string rather than an identifier or qualified name */ - function isJsxIntrinsicTagName(tagName: Node): tagName is Identifier | JsxNamespacedName { - return isIdentifier(tagName) && isIntrinsicJsxName(tagName.escapedText) || isJsxNamespacedName(tagName); + function isJsxIntrinsicTagName( + tagName: Node + ): tagName is Identifier | JsxNamespacedName { + return ( + (isIdentifier(tagName) && + isIntrinsicJsxName(tagName.escapedText)) || + isJsxNamespacedName(tagName) + ); } function checkJsxAttribute(node: JsxAttribute, checkMode?: CheckMode) { @@ -33619,15 +59309,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @remarks Because this function calls getSpreadType, it needs to use the same checks as checkObjectLiteral, * which also calls getSpreadType. */ - function createJsxAttributesTypeFromAttributesProperty(openingLikeElement: JsxCallLike, checkMode: CheckMode = CheckMode.Normal) { - const allAttributesTable = strictNullChecks ? createSymbolTable() : undefined; + function createJsxAttributesTypeFromAttributesProperty( + openingLikeElement: JsxCallLike, + checkMode: CheckMode = CheckMode.Normal + ) { + const allAttributesTable = strictNullChecks + ? createSymbolTable() + : undefined; let attributesTable = createSymbolTable(); let spread: Type = emptyJsxObjectType; let hasSpreadAnyType = false; let typeToIntersect: Type | undefined; let explicitlySpecifyChildrenAttribute = false; let objectFlags: ObjectFlags = ObjectFlags.JsxAttributes; - const jsxChildrenPropertyName = getJsxElementChildrenPropertyName(getJsxNamespaceAt(openingLikeElement)); + const jsxChildrenPropertyName = getJsxElementChildrenPropertyName( + getJsxNamespaceAt(openingLikeElement) + ); const isJsxOpenFragment = isJsxOpeningFragment(openingLikeElement); @@ -33637,65 +59334,141 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const attributes = openingLikeElement.attributes; attributesSymbol = attributes.symbol; attributeParent = attributes; - const contextualType = getContextualType(attributes, ContextFlags.None); + const contextualType = getContextualType( + attributes, + ContextFlags.None + ); for (const attributeDecl of attributes.properties) { const member = attributeDecl.symbol; if (isJsxAttribute(attributeDecl)) { - const exprType = checkJsxAttribute(attributeDecl, checkMode); - objectFlags |= getObjectFlags(exprType) & ObjectFlags.PropagatingFlags; + const exprType = checkJsxAttribute( + attributeDecl, + checkMode + ); + objectFlags |= + getObjectFlags(exprType) & ObjectFlags.PropagatingFlags; - const attributeSymbol = createSymbol(SymbolFlags.Property | member.flags, member.escapedName); + const attributeSymbol = createSymbol( + SymbolFlags.Property | member.flags, + member.escapedName + ); attributeSymbol.declarations = member.declarations; attributeSymbol.parent = member.parent; if (member.valueDeclaration) { - attributeSymbol.valueDeclaration = member.valueDeclaration; + attributeSymbol.valueDeclaration = + member.valueDeclaration; } attributeSymbol.links.type = exprType; attributeSymbol.links.target = member; - attributesTable.set(attributeSymbol.escapedName, attributeSymbol); - allAttributesTable?.set(attributeSymbol.escapedName, attributeSymbol); - if (getEscapedTextOfJsxAttributeName(attributeDecl.name) === jsxChildrenPropertyName) { + attributesTable.set( + attributeSymbol.escapedName, + attributeSymbol + ); + allAttributesTable?.set( + attributeSymbol.escapedName, + attributeSymbol + ); + if ( + getEscapedTextOfJsxAttributeName(attributeDecl.name) === + jsxChildrenPropertyName + ) { explicitlySpecifyChildrenAttribute = true; } if (contextualType) { - const prop = getPropertyOfType(contextualType, member.escapedName); - if (prop && prop.declarations && isDeprecatedSymbol(prop) && isIdentifier(attributeDecl.name)) { - addDeprecatedSuggestion(attributeDecl.name, prop.declarations, attributeDecl.name.escapedText as string); + const prop = getPropertyOfType( + contextualType, + member.escapedName + ); + if ( + prop && + prop.declarations && + isDeprecatedSymbol(prop) && + isIdentifier(attributeDecl.name) + ) { + addDeprecatedSuggestion( + attributeDecl.name, + prop.declarations, + attributeDecl.name.escapedText as string + ); } } - if (contextualType && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && isContextSensitive(attributeDecl)) { - const inferenceContext = getInferenceContext(attributes); + if ( + contextualType && + checkMode & CheckMode.Inferential && + !(checkMode & CheckMode.SkipContextSensitive) && + isContextSensitive(attributeDecl) + ) { + const inferenceContext = + getInferenceContext(attributes); Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context - const inferenceNode = (attributeDecl.initializer as JsxExpression).expression!; - addIntraExpressionInferenceSite(inferenceContext, inferenceNode, exprType); + const inferenceNode = ( + attributeDecl.initializer as JsxExpression + ).expression!; + addIntraExpressionInferenceSite( + inferenceContext, + inferenceNode, + exprType + ); } - } - else { - Debug.assert(attributeDecl.kind === SyntaxKind.JsxSpreadAttribute); + } else { + Debug.assert( + attributeDecl.kind === SyntaxKind.JsxSpreadAttribute + ); if (attributesTable.size > 0) { - spread = getSpreadType(spread, createJsxAttributesTypeHelper(), attributes.symbol, objectFlags, /*readonly*/ false); + spread = getSpreadType( + spread, + createJsxAttributesTypeHelper(), + attributes.symbol, + objectFlags, + /*readonly*/ false + ); attributesTable = createSymbolTable(); } - const exprType = getReducedType(checkExpression(attributeDecl.expression, checkMode & CheckMode.Inferential)); + const exprType = getReducedType( + checkExpression( + attributeDecl.expression, + checkMode & CheckMode.Inferential + ) + ); if (isTypeAny(exprType)) { hasSpreadAnyType = true; } if (isValidSpreadType(exprType)) { - spread = getSpreadType(spread, exprType, attributes.symbol, objectFlags, /*readonly*/ false); + spread = getSpreadType( + spread, + exprType, + attributes.symbol, + objectFlags, + /*readonly*/ false + ); if (allAttributesTable) { - checkSpreadPropOverrides(exprType, allAttributesTable, attributeDecl); + checkSpreadPropOverrides( + exprType, + allAttributesTable, + attributeDecl + ); } - } - else { - error(attributeDecl.expression, Diagnostics.Spread_types_may_only_be_created_from_object_types); - typeToIntersect = typeToIntersect ? getIntersectionType([typeToIntersect, exprType]) : exprType; + } else { + error( + attributeDecl.expression, + Diagnostics.Spread_types_may_only_be_created_from_object_types + ); + typeToIntersect = typeToIntersect + ? getIntersectionType([typeToIntersect, exprType]) + : exprType; } } } if (!hasSpreadAnyType) { if (attributesTable.size > 0) { - spread = getSpreadType(spread, createJsxAttributesTypeHelper(), attributes.symbol, objectFlags, /*readonly*/ false); + spread = getSpreadType( + spread, + createJsxAttributesTypeHelper(), + attributes.symbol, + objectFlags, + /*readonly*/ false + ); } } } @@ -33704,33 +59477,79 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const parent = openingLikeElement.parent; // We have to check that openingElement of the parent is the one we are visiting as this may not be true for selfClosingElement if ( - (isJsxElement(parent) && parent.openingElement === openingLikeElement || isJsxFragment(parent) && parent.openingFragment === openingLikeElement) && + ((isJsxElement(parent) && + parent.openingElement === openingLikeElement) || + (isJsxFragment(parent) && + parent.openingFragment === openingLikeElement)) && getSemanticJsxChildren(parent.children).length > 0 ) { const childrenTypes: Type[] = checkJsxChildren(parent, checkMode); - if (!hasSpreadAnyType && jsxChildrenPropertyName && jsxChildrenPropertyName !== "") { + if ( + !hasSpreadAnyType && + jsxChildrenPropertyName && + jsxChildrenPropertyName !== "" + ) { // Error if there is a attribute named "children" explicitly specified and children element. // This is because children element will overwrite the value from attributes. // Note: we will not warn "children" attribute overwritten if "children" attribute is specified in object spread. if (explicitlySpecifyChildrenAttribute) { - error(attributeParent, Diagnostics._0_are_specified_twice_The_attribute_named_0_will_be_overwritten, unescapeLeadingUnderscores(jsxChildrenPropertyName)); + error( + attributeParent, + Diagnostics._0_are_specified_twice_The_attribute_named_0_will_be_overwritten, + unescapeLeadingUnderscores(jsxChildrenPropertyName) + ); } - const contextualType = isJsxOpeningElement(openingLikeElement) ? getApparentTypeOfContextualType(openingLikeElement.attributes, /*contextFlags*/ undefined) : undefined; - const childrenContextualType = contextualType && getTypeOfPropertyOfContextualType(contextualType, jsxChildrenPropertyName); + const contextualType = isJsxOpeningElement(openingLikeElement) + ? getApparentTypeOfContextualType( + openingLikeElement.attributes, + /*contextFlags*/ undefined + ) + : undefined; + const childrenContextualType = + contextualType && + getTypeOfPropertyOfContextualType( + contextualType, + jsxChildrenPropertyName + ); // 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 - const childrenPropSymbol = createSymbol(SymbolFlags.Property, jsxChildrenPropertyName); - childrenPropSymbol.links.type = childrenTypes.length === 1 ? childrenTypes[0] : - childrenContextualType && someType(childrenContextualType, isTupleLikeType) ? createTupleType(childrenTypes) : - createArrayType(getUnionType(childrenTypes)); + const childrenPropSymbol = createSymbol( + SymbolFlags.Property, + jsxChildrenPropertyName + ); + childrenPropSymbol.links.type = + childrenTypes.length === 1 + ? childrenTypes[0] + : childrenContextualType && + someType(childrenContextualType, isTupleLikeType) + ? createTupleType(childrenTypes) + : createArrayType(getUnionType(childrenTypes)); // Fake up a property declaration for the children - childrenPropSymbol.valueDeclaration = factory.createPropertySignature(/*modifiers*/ undefined, unescapeLeadingUnderscores(jsxChildrenPropertyName), /*questionToken*/ undefined, /*type*/ undefined); + childrenPropSymbol.valueDeclaration = + factory.createPropertySignature( + /*modifiers*/ undefined, + unescapeLeadingUnderscores(jsxChildrenPropertyName), + /*questionToken*/ undefined, + /*type*/ undefined + ); setParent(childrenPropSymbol.valueDeclaration, attributeParent); childrenPropSymbol.valueDeclaration.symbol = childrenPropSymbol; const childPropMap = createSymbolTable(); childPropMap.set(jsxChildrenPropertyName, childrenPropSymbol); - spread = getSpreadType(spread, createAnonymousType(attributesSymbol, childPropMap, emptyArray, emptyArray, emptyArray), attributesSymbol, objectFlags, /*readonly*/ false); + spread = getSpreadType( + spread, + createAnonymousType( + attributesSymbol, + childPropMap, + emptyArray, + emptyArray, + emptyArray + ), + attributesSymbol, + objectFlags, + /*readonly*/ false + ); } } @@ -33740,11 +59559,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (typeToIntersect && spread !== emptyJsxObjectType) { return getIntersectionType([typeToIntersect, spread]); } - return typeToIntersect || (spread === emptyJsxObjectType ? createJsxAttributesTypeHelper() : spread); + return ( + typeToIntersect || + (spread === emptyJsxObjectType + ? createJsxAttributesTypeHelper() + : spread) + ); function createJsxAttributesTypeHelper() { objectFlags |= ObjectFlags.FreshLiteral; - return createJsxAttributesType(objectFlags, attributesSymbol, attributesTable); + return createJsxAttributesType( + objectFlags, + attributesSymbol, + attributesTable + ); } } /** @@ -33752,13 +59580,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param symbol a symbol of JsxAttributes containing attributes corresponding to attributesTable * @param attributesTable a symbol table of attributes property */ - function createJsxAttributesType(objectFlags: ObjectFlags, attributesSymbol: Symbol | undefined, attributesTable: SymbolTable): Type { - const result = createAnonymousType(attributesSymbol, attributesTable, emptyArray, emptyArray, emptyArray); - result.objectFlags |= objectFlags | ObjectFlags.FreshLiteral | ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral; + function createJsxAttributesType( + objectFlags: ObjectFlags, + attributesSymbol: Symbol | undefined, + attributesTable: SymbolTable + ): Type { + const result = createAnonymousType( + attributesSymbol, + attributesTable, + emptyArray, + emptyArray, + emptyArray + ); + result.objectFlags |= + objectFlags | + ObjectFlags.FreshLiteral | + ObjectFlags.ObjectLiteral | + ObjectFlags.ContainsObjectOrArrayLiteral; return result; } - function checkJsxChildren(node: JsxElement | JsxFragment, checkMode?: CheckMode) { + function checkJsxChildren( + node: JsxElement | JsxFragment, + checkMode?: CheckMode + ) { const childrenTypes: Type[] = []; for (const child of node.children) { // In React, JSX text that contains only whitespaces will be ignored so we don't want to type-check that @@ -33767,24 +59612,41 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!child.containsOnlyTriviaWhiteSpaces) { childrenTypes.push(stringType); } - } - else if (child.kind === SyntaxKind.JsxExpression && !child.expression) { + } else if ( + child.kind === SyntaxKind.JsxExpression && + !child.expression + ) { continue; // empty jsx expressions don't *really* count as present children - } - else { - childrenTypes.push(checkExpressionForMutableLocation(child, checkMode)); + } else { + childrenTypes.push( + checkExpressionForMutableLocation(child, checkMode) + ); } } return childrenTypes; } - function checkSpreadPropOverrides(type: Type, props: SymbolTable, spread: SpreadAssignment | JsxSpreadAttribute) { + function checkSpreadPropOverrides( + type: Type, + props: SymbolTable, + spread: SpreadAssignment | JsxSpreadAttribute + ) { for (const right of getPropertiesOfType(type)) { if (!(right.flags & SymbolFlags.Optional)) { const left = props.get(right.escapedName); if (left) { - const diagnostic = error(left.valueDeclaration, Diagnostics._0_is_specified_more_than_once_so_this_usage_will_be_overwritten, unescapeLeadingUnderscores(left.escapedName)); - addRelatedInfo(diagnostic, createDiagnosticForNode(spread, Diagnostics.This_spread_always_overwrites_this_property)); + const diagnostic = error( + left.valueDeclaration, + Diagnostics._0_is_specified_more_than_once_so_this_usage_will_be_overwritten, + unescapeLeadingUnderscores(left.escapedName) + ); + addRelatedInfo( + diagnostic, + createDiagnosticForNode( + spread, + Diagnostics.This_spread_always_overwrites_this_property + ) + ); } } } @@ -33795,14 +59657,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * (See "checkApplicableSignatureForJsxOpeningLikeElement" for how the function is used) * @param node a JSXAttributes to be resolved of its type */ - function checkJsxAttributes(node: JsxAttributes, checkMode: CheckMode | undefined) { - return createJsxAttributesTypeFromAttributesProperty(node.parent, checkMode); + function checkJsxAttributes( + node: JsxAttributes, + checkMode: CheckMode | undefined + ) { + return createJsxAttributesTypeFromAttributesProperty( + node.parent, + checkMode + ); } function getJsxType(name: __String, location: Node | undefined) { const namespace = getJsxNamespaceAt(location); const exports = namespace && getExportsOfSymbol(namespace); - const typeSymbol = exports && getSymbol(exports, name, SymbolFlags.Type); + const typeSymbol = + exports && getSymbol(exports, name, SymbolFlags.Type); return typeSymbol ? getDeclaredTypeOfSymbol(typeSymbol) : errorType; } @@ -33812,47 +59681,80 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * string index signature (in which case nodeLinks.jsxFlags will be IntrinsicIndexedElement). * May also return unknownSymbol if both of these lookups fail. */ - function getIntrinsicTagSymbol(node: JsxOpeningLikeElement | JsxClosingElement): Symbol { + function getIntrinsicTagSymbol( + node: JsxOpeningLikeElement | JsxClosingElement + ): Symbol { const links = getNodeLinks(node); if (!links.resolvedSymbol) { - const intrinsicElementsType = getJsxType(JsxNames.IntrinsicElements, node); + const intrinsicElementsType = getJsxType( + JsxNames.IntrinsicElements, + node + ); if (!isErrorType(intrinsicElementsType)) { // Property case - if (!isIdentifier(node.tagName) && !isJsxNamespacedName(node.tagName)) return Debug.fail(); - const propName = isJsxNamespacedName(node.tagName) ? getEscapedTextOfJsxNamespacedName(node.tagName) : node.tagName.escapedText; - const intrinsicProp = getPropertyOfType(intrinsicElementsType, propName); + if ( + !isIdentifier(node.tagName) && + !isJsxNamespacedName(node.tagName) + ) + return Debug.fail(); + const propName = isJsxNamespacedName(node.tagName) + ? getEscapedTextOfJsxNamespacedName(node.tagName) + : node.tagName.escapedText; + const intrinsicProp = getPropertyOfType( + intrinsicElementsType, + propName + ); if (intrinsicProp) { links.jsxFlags |= JsxFlags.IntrinsicNamedElement; - return links.resolvedSymbol = intrinsicProp; + return (links.resolvedSymbol = intrinsicProp); } // Intrinsic string indexer case - const indexSymbol = getApplicableIndexSymbol(intrinsicElementsType, getStringLiteralType(unescapeLeadingUnderscores(propName))); + const indexSymbol = getApplicableIndexSymbol( + intrinsicElementsType, + getStringLiteralType(unescapeLeadingUnderscores(propName)) + ); if (indexSymbol) { links.jsxFlags |= JsxFlags.IntrinsicIndexedElement; - return links.resolvedSymbol = indexSymbol; + return (links.resolvedSymbol = indexSymbol); } - if (getTypeOfPropertyOrIndexSignatureOfType(intrinsicElementsType, propName)) { + if ( + getTypeOfPropertyOrIndexSignatureOfType( + intrinsicElementsType, + propName + ) + ) { links.jsxFlags |= JsxFlags.IntrinsicIndexedElement; - return links.resolvedSymbol = intrinsicElementsType.symbol; + return (links.resolvedSymbol = + intrinsicElementsType.symbol); } // Wasn't found - error(node, Diagnostics.Property_0_does_not_exist_on_type_1, intrinsicTagNameToString(node.tagName), "JSX." + JsxNames.IntrinsicElements); - return links.resolvedSymbol = unknownSymbol; - } - else { + error( + node, + Diagnostics.Property_0_does_not_exist_on_type_1, + intrinsicTagNameToString(node.tagName), + "JSX." + JsxNames.IntrinsicElements + ); + return (links.resolvedSymbol = unknownSymbol); + } else { if (noImplicitAny) { - error(node, Diagnostics.JSX_element_implicitly_has_type_any_because_no_interface_JSX_0_exists, unescapeLeadingUnderscores(JsxNames.IntrinsicElements)); + error( + node, + Diagnostics.JSX_element_implicitly_has_type_any_because_no_interface_JSX_0_exists, + unescapeLeadingUnderscores(JsxNames.IntrinsicElements) + ); } - return links.resolvedSymbol = unknownSymbol; + return (links.resolvedSymbol = unknownSymbol); } } return links.resolvedSymbol; } - function getJsxNamespaceContainerForImplicitImport(location: Node | undefined): Symbol | undefined { + function getJsxNamespaceContainerForImplicitImport( + location: Node | undefined + ): Symbol | undefined { const file = location && getSourceFileOfNode(location); const links = file && getNodeLinks(file); if (links && links.jsxImplicitImportContainer === false) { @@ -33861,17 +59763,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (links && links.jsxImplicitImportContainer) { return links.jsxImplicitImportContainer; } - const runtimeImportSpecifier = getJSXRuntimeImport(getJSXImplicitImportBase(compilerOptions, file), compilerOptions); + const runtimeImportSpecifier = getJSXRuntimeImport( + getJSXImplicitImportBase(compilerOptions, file), + compilerOptions + ); if (!runtimeImportSpecifier) { return undefined; } - const isClassic = getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Classic; + const isClassic = + getEmitModuleResolutionKind(compilerOptions) === + ModuleResolutionKind.Classic; const errorMessage = isClassic ? Diagnostics.Cannot_find_module_0_Did_you_mean_to_set_the_moduleResolution_option_to_nodenext_or_to_add_aliases_to_the_paths_option : Diagnostics.This_JSX_tag_requires_the_module_path_0_to_exist_but_none_could_be_found_Make_sure_you_have_types_for_the_appropriate_package_installed; - const specifier = getJSXRuntimeImportSpecifier(file, runtimeImportSpecifier); - const mod = resolveExternalModule(specifier || location!, runtimeImportSpecifier, errorMessage, location); - const result = mod && mod !== unknownSymbol ? getMergedSymbol(resolveSymbol(mod)) : undefined; + const specifier = getJSXRuntimeImportSpecifier( + file, + runtimeImportSpecifier + ); + const mod = resolveExternalModule( + specifier || location!, + runtimeImportSpecifier, + errorMessage, + location + ); + const result = + mod && mod !== unknownSymbol + ? getMergedSymbol(resolveSymbol(mod)) + : undefined; if (links) { links.jsxImplicitImportContainer = result || false; } @@ -33884,15 +59802,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return links.jsxNamespace; } if (!links || links.jsxNamespace !== false) { - let resolvedNamespace = getJsxNamespaceContainerForImplicitImport(location); + let resolvedNamespace = + getJsxNamespaceContainerForImplicitImport(location); if (!resolvedNamespace || resolvedNamespace === unknownSymbol) { const namespaceName = getJsxNamespace(location); - resolvedNamespace = resolveName(location, namespaceName, SymbolFlags.Namespace, /*nameNotFoundMessage*/ undefined, /*isUse*/ false); + resolvedNamespace = resolveName( + location, + namespaceName, + SymbolFlags.Namespace, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ false + ); } if (resolvedNamespace) { - const candidate = resolveSymbol(getSymbol(getExportsOfSymbol(resolveSymbol(resolvedNamespace)), JsxNames.JSX, SymbolFlags.Namespace)); + const candidate = resolveSymbol( + getSymbol( + getExportsOfSymbol(resolveSymbol(resolvedNamespace)), + JsxNames.JSX, + SymbolFlags.Namespace + ) + ); if (candidate && candidate !== unknownSymbol) { if (links) { links.jsxNamespace = candidate; @@ -33905,7 +59836,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } // JSX global fallback - const s = resolveSymbol(getGlobalSymbol(JsxNames.JSX, SymbolFlags.Namespace, /*diagnostic*/ undefined)); + const s = resolveSymbol( + getGlobalSymbol( + JsxNames.JSX, + SymbolFlags.Namespace, + /*diagnostic*/ undefined + ) + ); if (s === unknownSymbol) { return undefined!; // TODO: GH#18217 } @@ -33919,13 +59856,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param nameOfAttribPropContainer a string of value JsxNames.ElementAttributesPropertyNameContainer or JsxNames.ElementChildrenAttributeNameContainer * if other string is given or the container doesn't exist, return undefined. */ - function getNameFromJsxElementAttributesContainer(nameOfAttribPropContainer: __String, jsxNamespace: Symbol): __String | undefined { + function getNameFromJsxElementAttributesContainer( + nameOfAttribPropContainer: __String, + jsxNamespace: Symbol + ): __String | undefined { // JSX.ElementAttributesProperty | JSX.ElementChildrenAttribute [symbol] - const jsxElementAttribPropInterfaceSym = jsxNamespace && getSymbol(jsxNamespace.exports!, nameOfAttribPropContainer, SymbolFlags.Type); + const jsxElementAttribPropInterfaceSym = + jsxNamespace && + getSymbol( + jsxNamespace.exports!, + nameOfAttribPropContainer, + SymbolFlags.Type + ); // JSX.ElementAttributesProperty | JSX.ElementChildrenAttribute [type] - const jsxElementAttribPropInterfaceType = jsxElementAttribPropInterfaceSym && getDeclaredTypeOfSymbol(jsxElementAttribPropInterfaceSym); + const jsxElementAttribPropInterfaceType = + jsxElementAttribPropInterfaceSym && + getDeclaredTypeOfSymbol(jsxElementAttribPropInterfaceSym); // The properties of JSX.ElementAttributesProperty | JSX.ElementChildrenAttribute - const propertiesOfJsxElementAttribPropInterface = jsxElementAttribPropInterfaceType && getPropertiesOfType(jsxElementAttribPropInterfaceType); + const propertiesOfJsxElementAttribPropInterface = + jsxElementAttribPropInterfaceType && + getPropertiesOfType(jsxElementAttribPropInterfaceType); if (propertiesOfJsxElementAttribPropInterface) { // Element Attributes has zero properties, so the element attributes type will be the class instance type if (propertiesOfJsxElementAttribPropInterface.length === 0) { @@ -33935,10 +59885,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // property of the class instance type else if (propertiesOfJsxElementAttribPropInterface.length === 1) { return propertiesOfJsxElementAttribPropInterface[0].escapedName; - } - else if (propertiesOfJsxElementAttribPropInterface.length > 1 && jsxElementAttribPropInterfaceSym.declarations) { + } else if ( + propertiesOfJsxElementAttribPropInterface.length > 1 && + jsxElementAttribPropInterfaceSym.declarations + ) { // More than one property on ElementAttributesProperty is an error - error(jsxElementAttribPropInterfaceSym.declarations[0], Diagnostics.The_global_type_JSX_0_may_not_have_more_than_one_property, unescapeLeadingUnderscores(nameOfAttribPropContainer)); + error( + jsxElementAttribPropInterfaceSym.declarations[0], + Diagnostics.The_global_type_JSX_0_may_not_have_more_than_one_property, + unescapeLeadingUnderscores(nameOfAttribPropContainer) + ); } } return undefined; @@ -33946,12 +59902,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getJsxLibraryManagedAttributes(jsxNamespace: Symbol) { // JSX.LibraryManagedAttributes [symbol] - return jsxNamespace && getSymbol(jsxNamespace.exports!, JsxNames.LibraryManagedAttributes, SymbolFlags.Type); + return ( + jsxNamespace && + getSymbol( + jsxNamespace.exports!, + JsxNames.LibraryManagedAttributes, + SymbolFlags.Type + ) + ); } function getJsxElementTypeSymbol(jsxNamespace: Symbol) { // JSX.ElementType [symbol] - return jsxNamespace && getSymbol(jsxNamespace.exports!, JsxNames.ElementType, SymbolFlags.Type); + return ( + jsxNamespace && + getSymbol( + jsxNamespace.exports!, + JsxNames.ElementType, + SymbolFlags.Type + ) + ); } /// e.g. "props" for React.d.ts, @@ -33960,59 +59930,108 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /// or '' if it has 0 properties (which means every /// non-intrinsic elements' attributes type is the element instance type) function getJsxElementPropertiesName(jsxNamespace: Symbol) { - return getNameFromJsxElementAttributesContainer(JsxNames.ElementAttributesPropertyNameContainer, jsxNamespace); + return getNameFromJsxElementAttributesContainer( + JsxNames.ElementAttributesPropertyNameContainer, + jsxNamespace + ); } - function getJsxElementChildrenPropertyName(jsxNamespace: Symbol): __String | undefined { - if (compilerOptions.jsx === JsxEmit.ReactJSX || compilerOptions.jsx === JsxEmit.ReactJSXDev) { + function getJsxElementChildrenPropertyName( + jsxNamespace: Symbol + ): __String | undefined { + if ( + compilerOptions.jsx === JsxEmit.ReactJSX || + compilerOptions.jsx === JsxEmit.ReactJSXDev + ) { // In these JsxEmit modes the children property is fixed to 'children' return "children" as __String; } - return getNameFromJsxElementAttributesContainer(JsxNames.ElementChildrenAttributeNameContainer, jsxNamespace); + return getNameFromJsxElementAttributesContainer( + JsxNames.ElementChildrenAttributeNameContainer, + jsxNamespace + ); } - function getUninstantiatedJsxSignaturesOfType(elementType: Type, caller: JsxCallLike): readonly Signature[] { + function getUninstantiatedJsxSignaturesOfType( + elementType: Type, + caller: JsxCallLike + ): readonly Signature[] { if (elementType.flags & TypeFlags.String) { return [anySignature]; - } - else if (elementType.flags & TypeFlags.StringLiteral) { - const intrinsicType = getIntrinsicAttributesTypeFromStringLiteralType(elementType as StringLiteralType, caller); + } else if (elementType.flags & TypeFlags.StringLiteral) { + const intrinsicType = + getIntrinsicAttributesTypeFromStringLiteralType( + elementType as StringLiteralType, + caller + ); if (!intrinsicType) { - error(caller, Diagnostics.Property_0_does_not_exist_on_type_1, (elementType as StringLiteralType).value, "JSX." + JsxNames.IntrinsicElements); + error( + caller, + Diagnostics.Property_0_does_not_exist_on_type_1, + (elementType as StringLiteralType).value, + "JSX." + JsxNames.IntrinsicElements + ); return emptyArray; - } - else { - const fakeSignature = createSignatureForJSXIntrinsic(caller, intrinsicType); + } else { + const fakeSignature = createSignatureForJSXIntrinsic( + caller, + intrinsicType + ); return [fakeSignature]; } } const apparentElemType = getApparentType(elementType); // Resolve the signatures, preferring constructor - let signatures = getSignaturesOfType(apparentElemType, SignatureKind.Construct); + let signatures = getSignaturesOfType( + apparentElemType, + SignatureKind.Construct + ); if (signatures.length === 0) { // No construct signatures, try call signatures - signatures = getSignaturesOfType(apparentElemType, SignatureKind.Call); + signatures = getSignaturesOfType( + apparentElemType, + SignatureKind.Call + ); } - if (signatures.length === 0 && apparentElemType.flags & TypeFlags.Union) { + if ( + signatures.length === 0 && + apparentElemType.flags & TypeFlags.Union + ) { // If each member has some combination of new/call signatures; make a union signature list for those - signatures = getUnionSignatures(map((apparentElemType as UnionType).types, t => getUninstantiatedJsxSignaturesOfType(t, caller))); + signatures = getUnionSignatures( + map((apparentElemType as UnionType).types, (t) => + getUninstantiatedJsxSignaturesOfType(t, caller) + ) + ); } return signatures; } - function getIntrinsicAttributesTypeFromStringLiteralType(type: StringLiteralType, location: Node): Type | undefined { + function getIntrinsicAttributesTypeFromStringLiteralType( + type: StringLiteralType, + location: Node + ): Type | undefined { // 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 // For example: // var CustomTag: "h1" = "h1"; // Hello World - const intrinsicElementsType = getJsxType(JsxNames.IntrinsicElements, location); + const intrinsicElementsType = getJsxType( + JsxNames.IntrinsicElements, + location + ); if (!isErrorType(intrinsicElementsType)) { const stringLiteralTypeName = type.value; - const intrinsicProp = getPropertyOfType(intrinsicElementsType, escapeLeadingUnderscores(stringLiteralTypeName)); + const intrinsicProp = getPropertyOfType( + intrinsicElementsType, + escapeLeadingUnderscores(stringLiteralTypeName) + ); if (intrinsicProp) { return getTypeOfSymbol(intrinsicProp); } - const indexSignatureType = getIndexTypeOfType(intrinsicElementsType, stringType); + const indexSignatureType = getIndexTypeOfType( + intrinsicElementsType, + stringType + ); if (indexSignatureType) { return indexSignatureType; } @@ -34022,33 +60041,68 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return anyType; } - function checkJsxReturnAssignableToAppropriateBound(refKind: JsxReferenceKind, elemInstanceType: Type, openingLikeElement: JsxOpeningLikeElement) { + function checkJsxReturnAssignableToAppropriateBound( + refKind: JsxReferenceKind, + elemInstanceType: Type, + openingLikeElement: JsxOpeningLikeElement + ) { if (refKind === JsxReferenceKind.Function) { - const sfcReturnConstraint = getJsxStatelessElementTypeAt(openingLikeElement); + const sfcReturnConstraint = + getJsxStatelessElementTypeAt(openingLikeElement); if (sfcReturnConstraint) { - checkTypeRelatedTo(elemInstanceType, sfcReturnConstraint, assignableRelation, openingLikeElement.tagName, Diagnostics.Its_return_type_0_is_not_a_valid_JSX_element, generateInitialErrorChain); + checkTypeRelatedTo( + elemInstanceType, + sfcReturnConstraint, + assignableRelation, + openingLikeElement.tagName, + Diagnostics.Its_return_type_0_is_not_a_valid_JSX_element, + generateInitialErrorChain + ); } - } - else if (refKind === JsxReferenceKind.Component) { - const classConstraint = getJsxElementClassTypeAt(openingLikeElement); + } else if (refKind === JsxReferenceKind.Component) { + const classConstraint = + getJsxElementClassTypeAt(openingLikeElement); if (classConstraint) { // Issue an error if this return type isn't assignable to JSX.ElementClass, failing that - checkTypeRelatedTo(elemInstanceType, classConstraint, assignableRelation, openingLikeElement.tagName, Diagnostics.Its_instance_type_0_is_not_a_valid_JSX_element, generateInitialErrorChain); + checkTypeRelatedTo( + elemInstanceType, + classConstraint, + assignableRelation, + openingLikeElement.tagName, + Diagnostics.Its_instance_type_0_is_not_a_valid_JSX_element, + generateInitialErrorChain + ); } - } - else { // Mixed - const sfcReturnConstraint = getJsxStatelessElementTypeAt(openingLikeElement); - const classConstraint = getJsxElementClassTypeAt(openingLikeElement); + } else { + // Mixed + const sfcReturnConstraint = + getJsxStatelessElementTypeAt(openingLikeElement); + const classConstraint = + getJsxElementClassTypeAt(openingLikeElement); if (!sfcReturnConstraint || !classConstraint) { return; } - const combined = getUnionType([sfcReturnConstraint, classConstraint]); - checkTypeRelatedTo(elemInstanceType, combined, assignableRelation, openingLikeElement.tagName, Diagnostics.Its_element_type_0_is_not_a_valid_JSX_element, generateInitialErrorChain); + const combined = getUnionType([ + sfcReturnConstraint, + classConstraint, + ]); + checkTypeRelatedTo( + elemInstanceType, + combined, + assignableRelation, + openingLikeElement.tagName, + Diagnostics.Its_element_type_0_is_not_a_valid_JSX_element, + generateInitialErrorChain + ); } function generateInitialErrorChain(): DiagnosticMessageChain { const componentName = getTextOfNode(openingLikeElement.tagName); - return chainDiagnosticMessages(/*details*/ undefined, Diagnostics._0_cannot_be_used_as_a_JSX_component, componentName); + return chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics._0_cannot_be_used_as_a_JSX_component, + componentName + ); } } @@ -34057,20 +60111,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * The function is intended to be called from a function which has checked that the opening element is an intrinsic element. * @param node an intrinsic JSX opening-like element */ - function getIntrinsicAttributesTypeFromJsxOpeningLikeElement(node: JsxOpeningLikeElement): Type { + function getIntrinsicAttributesTypeFromJsxOpeningLikeElement( + node: JsxOpeningLikeElement + ): Type { Debug.assert(isJsxIntrinsicTagName(node.tagName)); const links = getNodeLinks(node); if (!links.resolvedJsxElementAttributesType) { const symbol = getIntrinsicTagSymbol(node); if (links.jsxFlags & JsxFlags.IntrinsicNamedElement) { - return links.resolvedJsxElementAttributesType = getTypeOfSymbol(symbol) || errorType; - } - else if (links.jsxFlags & JsxFlags.IntrinsicIndexedElement) { - const propName = isJsxNamespacedName(node.tagName) ? getEscapedTextOfJsxNamespacedName(node.tagName) : node.tagName.escapedText; - return links.resolvedJsxElementAttributesType = getApplicableIndexInfoForName(getJsxType(JsxNames.IntrinsicElements, node), propName)?.type || errorType; - } - else { - return links.resolvedJsxElementAttributesType = errorType; + return (links.resolvedJsxElementAttributesType = + getTypeOfSymbol(symbol) || errorType); + } else if (links.jsxFlags & JsxFlags.IntrinsicIndexedElement) { + const propName = isJsxNamespacedName(node.tagName) + ? getEscapedTextOfJsxNamespacedName(node.tagName) + : node.tagName.escapedText; + return (links.resolvedJsxElementAttributesType = + getApplicableIndexInfoForName( + getJsxType(JsxNames.IntrinsicElements, node), + propName + )?.type || errorType); + } else { + return (links.resolvedJsxElementAttributesType = errorType); } } return links.resolvedJsxElementAttributesType; @@ -34098,23 +60159,48 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!ns) return undefined; const sym = getJsxElementTypeSymbol(ns); if (!sym) return undefined; - const type = instantiateAliasOrInterfaceWithDefaults(sym, isInJSFile(location)); + const type = instantiateAliasOrInterfaceWithDefaults( + sym, + isInJSFile(location) + ); if (!type || isErrorType(type)) return undefined; return type; } - function instantiateAliasOrInterfaceWithDefaults(managedSym: Symbol, inJs: boolean, ...typeArguments: Type[]) { + function instantiateAliasOrInterfaceWithDefaults( + managedSym: Symbol, + inJs: boolean, + ...typeArguments: Type[] + ) { const declaredManagedType = getDeclaredTypeOfSymbol(managedSym); // fetches interface type, or initializes symbol links type parmaeters if (managedSym.flags & SymbolFlags.TypeAlias) { const params = getSymbolLinks(managedSym).typeParameters; if (length(params) >= typeArguments.length) { - const args = fillMissingTypeArguments(typeArguments, params, typeArguments.length, inJs); - return length(args) === 0 ? declaredManagedType : getTypeAliasInstantiation(managedSym, args); + const args = fillMissingTypeArguments( + typeArguments, + params, + typeArguments.length, + inJs + ); + return length(args) === 0 + ? declaredManagedType + : getTypeAliasInstantiation(managedSym, args); } } - if (length((declaredManagedType as GenericType).typeParameters) >= typeArguments.length) { - const args = fillMissingTypeArguments(typeArguments, (declaredManagedType as GenericType).typeParameters, typeArguments.length, inJs); - return createTypeReference(declaredManagedType as GenericType, args); + if ( + length((declaredManagedType as GenericType).typeParameters) >= + typeArguments.length + ) { + const args = fillMissingTypeArguments( + typeArguments, + (declaredManagedType as GenericType).typeParameters, + typeArguments.length, + inJs + ); + return createTypeReference( + declaredManagedType as GenericType, + args + ); } return undefined; } @@ -34130,17 +60216,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkJsxPreconditions(errorNode: Node) { // Preconditions for using JSX if ((compilerOptions.jsx || JsxEmit.None) === JsxEmit.None) { - error(errorNode, Diagnostics.Cannot_use_JSX_unless_the_jsx_flag_is_provided); + error( + errorNode, + Diagnostics.Cannot_use_JSX_unless_the_jsx_flag_is_provided + ); } if (getJsxElementTypeAt(errorNode) === undefined) { if (noImplicitAny) { - error(errorNode, Diagnostics.JSX_element_implicitly_has_type_any_because_the_global_type_JSX_Element_does_not_exist); + error( + errorNode, + Diagnostics.JSX_element_implicitly_has_type_any_because_the_global_type_JSX_Element_does_not_exist + ); } } } - function checkJsxOpeningLikeElementOrOpeningFragment(node: JsxOpeningLikeElement | JsxOpeningFragment) { + function checkJsxOpeningLikeElementOrOpeningFragment( + node: JsxOpeningLikeElement | JsxOpeningFragment + ) { const isNodeOpeningLikeElement = isJsxOpeningLikeElement(node); if (isNodeOpeningLikeElement) { @@ -34156,19 +60250,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isNodeOpeningLikeElement) { const jsxOpeningLikeNode = node; - const elementTypeConstraint = getJsxElementTypeTypeAt(jsxOpeningLikeNode); + const elementTypeConstraint = + getJsxElementTypeTypeAt(jsxOpeningLikeNode); if (elementTypeConstraint !== undefined) { const tagName = jsxOpeningLikeNode.tagName; const tagType = isJsxIntrinsicTagName(tagName) ? getStringLiteralType(intrinsicTagNameToString(tagName)) : checkExpression(tagName); - checkTypeRelatedTo(tagType, elementTypeConstraint, assignableRelation, tagName, Diagnostics.Its_type_0_is_not_a_valid_JSX_element_type, () => { - const componentName = getTextOfNode(tagName); - return chainDiagnosticMessages(/*details*/ undefined, Diagnostics._0_cannot_be_used_as_a_JSX_component, componentName); - }); - } - else { - checkJsxReturnAssignableToAppropriateBound(getJsxReferenceKind(jsxOpeningLikeNode), getReturnTypeOfSignature(sig), jsxOpeningLikeNode); + checkTypeRelatedTo( + tagType, + elementTypeConstraint, + assignableRelation, + tagName, + Diagnostics.Its_type_0_is_not_a_valid_JSX_element_type, + () => { + const componentName = getTextOfNode(tagName); + return chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics._0_cannot_be_used_as_a_JSX_component, + componentName + ); + } + ); + } else { + checkJsxReturnAssignableToAppropriateBound( + getJsxReferenceKind(jsxOpeningLikeNode), + getReturnTypeOfSignature(sig), + jsxOpeningLikeNode + ); } } } @@ -34186,7 +60295,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param name a property name to search * @param isComparingJsxAttributes a boolean flag indicating whether we are searching in JsxAttributesType */ - function isKnownProperty(targetType: Type, name: __String, isComparingJsxAttributes: boolean): boolean { + function isKnownProperty( + targetType: Type, + name: __String, + isComparingJsxAttributes: boolean + ): boolean { if (targetType.flags & TypeFlags.Object) { // For backwards compatibility a symbol-named property is satisfied by a string index signature. This // is incorrect and inconsistent with element access expressions, where it is an error, so eventually @@ -34194,17 +60307,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if ( getPropertyOfObjectType(targetType, name) || getApplicableIndexInfoForName(targetType, name) || - isLateBoundName(name) && getIndexInfoOfType(targetType, stringType) || - isComparingJsxAttributes && isHyphenatedJsxName(name) + (isLateBoundName(name) && + getIndexInfoOfType(targetType, stringType)) || + (isComparingJsxAttributes && isHyphenatedJsxName(name)) ) { // For JSXAttributes, if the attribute has a hyphenated name, consider that the attribute to be known. return true; } } if (targetType.flags & TypeFlags.Substitution) { - return isKnownProperty((targetType as SubstitutionType).baseType, name, isComparingJsxAttributes); + return isKnownProperty( + (targetType as SubstitutionType).baseType, + name, + isComparingJsxAttributes + ); } - if (targetType.flags & TypeFlags.UnionOrIntersection && isExcessPropertyCheckTarget(targetType)) { + if ( + targetType.flags & TypeFlags.UnionOrIntersection && + isExcessPropertyCheckTarget(targetType) + ) { for (const t of (targetType as UnionOrIntersectionType).types) { if (isKnownProperty(t, name, isComparingJsxAttributes)) { return true; @@ -34215,11 +60336,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isExcessPropertyCheckTarget(type: Type): boolean { - return !!(type.flags & TypeFlags.Object && !(getObjectFlags(type) & ObjectFlags.ObjectLiteralPatternWithComputedProperties) || + return !!( + (type.flags & TypeFlags.Object && + !( + getObjectFlags(type) & + ObjectFlags.ObjectLiteralPatternWithComputedProperties + )) || type.flags & TypeFlags.NonPrimitive || - type.flags & TypeFlags.Substitution && isExcessPropertyCheckTarget((type as SubstitutionType).baseType) || - type.flags & TypeFlags.Union && some((type as UnionType).types, isExcessPropertyCheckTarget) || - type.flags & TypeFlags.Intersection && every((type as IntersectionType).types, isExcessPropertyCheckTarget)); + (type.flags & TypeFlags.Substitution && + isExcessPropertyCheckTarget( + (type as SubstitutionType).baseType + )) || + (type.flags & TypeFlags.Union && + some((type as UnionType).types, isExcessPropertyCheckTarget)) || + (type.flags & TypeFlags.Intersection && + every( + (type as IntersectionType).types, + isExcessPropertyCheckTarget + )) + ); } function checkJsxExpression(node: JsxExpression, checkMode?: CheckMode) { @@ -34230,14 +60365,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { error(node, Diagnostics.JSX_spread_child_must_be_an_array_type); } return type; - } - else { + } else { return errorType; } } function getDeclarationNodeFlagsFromSymbol(s: Symbol): NodeFlags { - return s.valueDeclaration ? getCombinedNodeFlagsCached(s.valueDeclaration) : 0; + return s.valueDeclaration + ? getCombinedNodeFlagsCached(s.valueDeclaration) + : 0; } /** @@ -34245,13 +60381,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Note that this is not tracked well within the compiler, so the answer may be incorrect. */ function isPrototypeProperty(symbol: Symbol) { - if (symbol.flags & SymbolFlags.Method || getCheckFlags(symbol) & CheckFlags.SyntheticMethod) { + if ( + symbol.flags & SymbolFlags.Method || + getCheckFlags(symbol) & CheckFlags.SyntheticMethod + ) { return true; } if (isInJSFile(symbol.valueDeclaration)) { const parent = symbol.valueDeclaration!.parent; - return parent && isBinaryExpression(parent) && - getAssignmentDeclarationKind(parent) === AssignmentDeclarationKind.PrototypeProperty; + return ( + parent && + isBinaryExpression(parent) && + getAssignmentDeclarationKind(parent) === + AssignmentDeclarationKind.PrototypeProperty + ); } } @@ -34264,19 +60407,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param prop The symbol for the property being accessed. */ function checkPropertyAccessibility( - node: PropertyAccessExpression | QualifiedName | PropertyAccessExpression | VariableDeclaration | ParameterDeclaration | ImportTypeNode | PropertyAssignment | ShorthandPropertyAssignment | BindingElement, + node: + | PropertyAccessExpression + | QualifiedName + | PropertyAccessExpression + | VariableDeclaration + | ParameterDeclaration + | ImportTypeNode + | PropertyAssignment + | ShorthandPropertyAssignment + | BindingElement, isSuper: boolean, writing: boolean, type: Type, prop: Symbol, - reportError = true, + reportError = true ): boolean { - const errorNode = !reportError ? undefined : - node.kind === SyntaxKind.QualifiedName ? node.right : - node.kind === SyntaxKind.ImportType ? node : - node.kind === SyntaxKind.BindingElement && node.propertyName ? node.propertyName : node.name; - - return checkPropertyAccessibilityAtLocation(node, isSuper, writing, type, prop, errorNode); + const errorNode = !reportError + ? undefined + : node.kind === SyntaxKind.QualifiedName + ? node.right + : node.kind === SyntaxKind.ImportType + ? node + : node.kind === SyntaxKind.BindingElement && node.propertyName + ? node.propertyName + : node.name; + + return checkPropertyAccessibilityAtLocation( + node, + isSuper, + writing, + type, + prop, + errorNode + ); } /** @@ -34289,7 +60453,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param prop The symbol for the property being accessed. * @param errorNode The node where we should report an invalid property access error, or undefined if we should not report errors. */ - function checkPropertyAccessibilityAtLocation(location: Node, isSuper: boolean, writing: boolean, containingType: Type, prop: Symbol, errorNode?: Node): boolean { + function checkPropertyAccessibilityAtLocation( + location: Node, + isSuper: boolean, + writing: boolean, + containingType: Type, + prop: Symbol, + errorNode?: Node + ): boolean { const flags = getDeclarationModifierFlagsFromSymbol(prop, writing); if (isSuper) { @@ -34303,7 +60474,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (languageVersion < ScriptTarget.ES2015) { if (symbolHasNonMethodDeclaration(prop)) { if (errorNode) { - error(errorNode, Diagnostics.Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword); + error( + errorNode, + Diagnostics.Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword + ); } return false; } @@ -34314,15 +60488,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // cannot simultaneously be private and abstract, so this will trigger an // additional error elsewhere. if (errorNode) { - error(errorNode, Diagnostics.Abstract_method_0_in_class_1_cannot_be_accessed_via_super_expression, symbolToString(prop), typeToString(getDeclaringClass(prop)!)); + error( + errorNode, + Diagnostics.Abstract_method_0_in_class_1_cannot_be_accessed_via_super_expression, + symbolToString(prop), + typeToString(getDeclaringClass(prop)!) + ); } return false; } // A class field cannot be accessed via super.* from a derived class. // This is true for both [[Set]] (old) and [[Define]] (ES spec) semantics. - if (!(flags & ModifierFlags.Static) && prop.declarations?.some(isClassInstanceProperty)) { + if ( + !(flags & ModifierFlags.Static) && + prop.declarations?.some(isClassInstanceProperty) + ) { if (errorNode) { - error(errorNode, Diagnostics.Class_field_0_defined_by_the_parent_class_is_not_accessible_in_the_child_class_via_super, symbolToString(prop)); + error( + errorNode, + Diagnostics.Class_field_0_defined_by_the_parent_class_is_not_accessible_in_the_child_class_via_super, + symbolToString(prop) + ); } return false; } @@ -34330,13 +60516,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Referencing abstract properties within their own constructors is not allowed if ( - (flags & ModifierFlags.Abstract) && symbolHasNonMethodDeclaration(prop) && - (isThisProperty(location) || isThisInitializedObjectBindingExpression(location) || isObjectBindingPattern(location.parent) && isThisInitializedDeclaration(location.parent.parent)) + flags & ModifierFlags.Abstract && + symbolHasNonMethodDeclaration(prop) && + (isThisProperty(location) || + isThisInitializedObjectBindingExpression(location) || + (isObjectBindingPattern(location.parent) && + isThisInitializedDeclaration(location.parent.parent))) ) { - const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(getParentOfSymbol(prop)!); - if (declaringClassDeclaration && isNodeUsedDuringClassInitialization(location)) { + const declaringClassDeclaration = getClassLikeDeclarationOfSymbol( + getParentOfSymbol(prop)! + ); + if ( + declaringClassDeclaration && + isNodeUsedDuringClassInitialization(location) + ) { if (errorNode) { - error(errorNode, Diagnostics.Abstract_property_0_in_class_1_cannot_be_accessed_in_the_constructor, symbolToString(prop), getTextOfIdentifierOrLiteral(declaringClassDeclaration.name!)); + error( + errorNode, + Diagnostics.Abstract_property_0_in_class_1_cannot_be_accessed_in_the_constructor, + symbolToString(prop), + getTextOfIdentifierOrLiteral( + declaringClassDeclaration.name! + ) + ); } return false; } @@ -34351,10 +60553,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Private property is accessible if the property is within the declaring class if (flags & ModifierFlags.Private) { - const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(getParentOfSymbol(prop)!)!; + const declaringClassDeclaration = getClassLikeDeclarationOfSymbol( + getParentOfSymbol(prop)! + )!; if (!isNodeWithinClass(location, declaringClassDeclaration)) { if (errorNode) { - error(errorNode, Diagnostics.Property_0_is_private_and_only_accessible_within_class_1, symbolToString(prop), typeToString(getDeclaringClass(prop)!)); + error( + errorNode, + Diagnostics.Property_0_is_private_and_only_accessible_within_class_1, + symbolToString(prop), + typeToString(getDeclaringClass(prop)!) + ); } return false; } @@ -34370,19 +60579,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Find the first enclosing class that has the declaring classes of the protected constituents // of the property as base classes - let enclosingClass = forEachEnclosingClass(location, enclosingDeclaration => { - const enclosingClass = getDeclaredTypeOfSymbol(getSymbolOfDeclaration(enclosingDeclaration)) as InterfaceType; - return isClassDerivedFromDeclaringClasses(enclosingClass, prop, writing); - }); + let enclosingClass = forEachEnclosingClass( + location, + (enclosingDeclaration) => { + const enclosingClass = getDeclaredTypeOfSymbol( + getSymbolOfDeclaration(enclosingDeclaration) + ) as InterfaceType; + return isClassDerivedFromDeclaringClasses( + enclosingClass, + prop, + writing + ); + } + ); // A protected property is accessible if the property is within the declaring class or classes derived from it if (!enclosingClass) { // allow PropertyAccessibility if context is in function with this parameter // static member access is disallowed enclosingClass = getEnclosingClassFromThisParameter(location); - enclosingClass = enclosingClass && isClassDerivedFromDeclaringClasses(enclosingClass, prop, writing); + enclosingClass = + enclosingClass && + isClassDerivedFromDeclaringClasses( + enclosingClass, + prop, + writing + ); if (flags & ModifierFlags.Static || !enclosingClass) { if (errorNode) { - error(errorNode, Diagnostics.Property_0_is_protected_and_only_accessible_within_class_1_and_its_subclasses, symbolToString(prop), typeToString(getDeclaringClass(prop) || containingType)); + error( + errorNode, + Diagnostics.Property_0_is_protected_and_only_accessible_within_class_1_and_its_subclasses, + symbolToString(prop), + typeToString(getDeclaringClass(prop) || containingType) + ); } return false; } @@ -34393,48 +60622,77 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (containingType.flags & TypeFlags.TypeParameter) { // get the original type -- represented as the type constraint of the 'this' type - 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 + 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 } if (!containingType || !hasBaseType(containingType, enclosingClass)) { if (errorNode) { - error(errorNode, Diagnostics.Property_0_is_protected_and_only_accessible_through_an_instance_of_class_1_This_is_an_instance_of_class_2, symbolToString(prop), typeToString(enclosingClass), typeToString(containingType)); + error( + errorNode, + Diagnostics.Property_0_is_protected_and_only_accessible_through_an_instance_of_class_1_This_is_an_instance_of_class_2, + symbolToString(prop), + typeToString(enclosingClass), + typeToString(containingType) + ); } return false; } return true; } - function getEnclosingClassFromThisParameter(node: Node): InterfaceType | undefined { + function getEnclosingClassFromThisParameter( + node: Node + ): InterfaceType | undefined { // 'this' type for a node comes from, in priority order... // 1. The type of a syntactic 'this' parameter in the enclosing function scope const thisParameter = getThisParameterFromNodeContext(node); - let thisType = thisParameter?.type && getTypeFromTypeNode(thisParameter.type); + let thisType = + thisParameter?.type && getTypeFromTypeNode(thisParameter.type); if (thisType) { // 2. The constraint of a type parameter used for an explicit 'this' parameter if (thisType.flags & TypeFlags.TypeParameter) { - thisType = getConstraintOfTypeParameter(thisType as TypeParameter); + thisType = getConstraintOfTypeParameter( + thisType as TypeParameter + ); } - } - else { + } else { // 3. The 'this' parameter of a contextual type - const thisContainer = getThisContainer(node, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); + const thisContainer = getThisContainer( + node, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false + ); if (isFunctionLike(thisContainer)) { thisType = getContextualThisParameterType(thisContainer); } } - if (thisType && getObjectFlags(thisType) & (ObjectFlags.ClassOrInterface | ObjectFlags.Reference)) { + if ( + thisType && + getObjectFlags(thisType) & + (ObjectFlags.ClassOrInterface | ObjectFlags.Reference) + ) { return getTargetType(thisType) as InterfaceType; } return undefined; } function getThisParameterFromNodeContext(node: Node) { - const thisContainer = getThisContainer(node, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); - return thisContainer && isFunctionLike(thisContainer) ? getThisParameter(thisContainer) : undefined; + const thisContainer = getThisContainer( + node, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false + ); + return thisContainer && isFunctionLike(thisContainer) + ? getThisParameter(thisContainer) + : undefined; } function symbolHasNonMethodDeclaration(symbol: Symbol) { - return !!forEachProperty(symbol, prop => !(prop.flags & SymbolFlags.Method)); + return !!forEachProperty( + symbol, + (prop) => !(prop.flags & SymbolFlags.Method) + ); } function checkNonNullExpression(node: Expression | QualifiedName) { @@ -34449,51 +60707,65 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return isNullableType(type) ? getNonNullableType(type) : type; } - function reportObjectPossiblyNullOrUndefinedError(node: Node, facts: TypeFacts) { - const nodeText = isEntityNameExpression(node) ? entityNameToString(node) : undefined; + function reportObjectPossiblyNullOrUndefinedError( + node: Node, + facts: TypeFacts + ) { + const nodeText = isEntityNameExpression(node) + ? entityNameToString(node) + : undefined; if (node.kind === SyntaxKind.NullKeyword) { error(node, Diagnostics.The_value_0_cannot_be_used_here, "null"); return; } if (nodeText !== undefined && nodeText.length < 100) { if (isIdentifier(node) && nodeText === "undefined") { - error(node, Diagnostics.The_value_0_cannot_be_used_here, "undefined"); + error( + node, + Diagnostics.The_value_0_cannot_be_used_here, + "undefined" + ); return; } error( node, - facts & TypeFacts.IsUndefined ? facts & TypeFacts.IsNull ? - Diagnostics._0_is_possibly_null_or_undefined : - Diagnostics._0_is_possibly_undefined : - Diagnostics._0_is_possibly_null, - nodeText, + facts & TypeFacts.IsUndefined + ? facts & TypeFacts.IsNull + ? Diagnostics._0_is_possibly_null_or_undefined + : Diagnostics._0_is_possibly_undefined + : Diagnostics._0_is_possibly_null, + nodeText ); - } - else { + } else { error( node, - facts & TypeFacts.IsUndefined ? facts & TypeFacts.IsNull ? - Diagnostics.Object_is_possibly_null_or_undefined : - Diagnostics.Object_is_possibly_undefined : - Diagnostics.Object_is_possibly_null, + facts & TypeFacts.IsUndefined + ? facts & TypeFacts.IsNull + ? Diagnostics.Object_is_possibly_null_or_undefined + : Diagnostics.Object_is_possibly_undefined + : Diagnostics.Object_is_possibly_null ); } } - function reportCannotInvokePossiblyNullOrUndefinedError(node: Node, facts: TypeFacts) { + function reportCannotInvokePossiblyNullOrUndefinedError( + node: Node, + facts: TypeFacts + ) { error( node, - facts & TypeFacts.IsUndefined ? facts & TypeFacts.IsNull ? - Diagnostics.Cannot_invoke_an_object_which_is_possibly_null_or_undefined : - Diagnostics.Cannot_invoke_an_object_which_is_possibly_undefined : - Diagnostics.Cannot_invoke_an_object_which_is_possibly_null, + facts & TypeFacts.IsUndefined + ? facts & TypeFacts.IsNull + ? Diagnostics.Cannot_invoke_an_object_which_is_possibly_null_or_undefined + : Diagnostics.Cannot_invoke_an_object_which_is_possibly_undefined + : Diagnostics.Cannot_invoke_an_object_which_is_possibly_null ); } function checkNonNullTypeWithReporter( type: Type, node: Node, - reportError: (node: Node, facts: TypeFacts) => void, + reportError: (node: Node, facts: TypeFacts) => void ): Type { if (strictNullChecks && type.flags & TypeFlags.Unknown) { if (isEntityNameExpression(node)) { @@ -34510,13 +60782,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (facts & TypeFacts.IsUndefinedOrNull) { reportError(node, facts); const t = getNonNullableType(type); - return t.flags & (TypeFlags.Nullable | TypeFlags.Never) ? errorType : t; + return t.flags & (TypeFlags.Nullable | TypeFlags.Never) + ? errorType + : t; } return type; } function checkNonNullType(type: Type, node: Node) { - return checkNonNullTypeWithReporter(type, node, reportObjectPossiblyNullOrUndefinedError); + return checkNonNullTypeWithReporter( + type, + node, + reportObjectPossiblyNullOrUndefinedError + ); } function checkNonNullNonVoidType(type: Type, node: Node): Type { @@ -34525,7 +60803,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isEntityNameExpression(node)) { const nodeText = entityNameToString(node); if (isIdentifier(node) && nodeText === "undefined") { - error(node, Diagnostics.The_value_0_cannot_be_used_here, nodeText); + error( + node, + Diagnostics.The_value_0_cannot_be_used_here, + nodeText + ); return nonNullType; } if (nodeText.length < 100) { @@ -34538,54 +60820,124 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return nonNullType; } - function checkPropertyAccessExpression(node: PropertyAccessExpression, checkMode: CheckMode | undefined, writeOnly?: boolean) { - return node.flags & NodeFlags.OptionalChain ? checkPropertyAccessChain(node as PropertyAccessChain, checkMode) : - checkPropertyAccessExpressionOrQualifiedName(node, node.expression, checkNonNullExpression(node.expression), node.name, checkMode, writeOnly); - } - - function checkPropertyAccessChain(node: PropertyAccessChain, checkMode: CheckMode | undefined) { + function checkPropertyAccessExpression( + node: PropertyAccessExpression, + checkMode: CheckMode | undefined, + writeOnly?: boolean + ) { + return node.flags & NodeFlags.OptionalChain + ? checkPropertyAccessChain(node as PropertyAccessChain, checkMode) + : checkPropertyAccessExpressionOrQualifiedName( + node, + node.expression, + checkNonNullExpression(node.expression), + node.name, + checkMode, + writeOnly + ); + } + + function checkPropertyAccessChain( + node: PropertyAccessChain, + checkMode: CheckMode | undefined + ) { const leftType = checkExpression(node.expression); - const nonOptionalType = getOptionalExpressionType(leftType, node.expression); - return propagateOptionalTypeMarker(checkPropertyAccessExpressionOrQualifiedName(node, node.expression, checkNonNullType(nonOptionalType, node.expression), node.name, checkMode), node, nonOptionalType !== leftType); + const nonOptionalType = getOptionalExpressionType( + leftType, + node.expression + ); + return propagateOptionalTypeMarker( + checkPropertyAccessExpressionOrQualifiedName( + node, + node.expression, + checkNonNullType(nonOptionalType, node.expression), + node.name, + checkMode + ), + node, + nonOptionalType !== leftType + ); } - function checkQualifiedName(node: QualifiedName, checkMode: CheckMode | undefined) { - const leftType = isPartOfTypeQuery(node) && isThisIdentifier(node.left) ? checkNonNullType(checkThisExpression(node.left), node.left) : checkNonNullExpression(node.left); - return checkPropertyAccessExpressionOrQualifiedName(node, node.left, leftType, node.right, checkMode); + function checkQualifiedName( + node: QualifiedName, + checkMode: CheckMode | undefined + ) { + const leftType = + isPartOfTypeQuery(node) && isThisIdentifier(node.left) + ? checkNonNullType(checkThisExpression(node.left), node.left) + : checkNonNullExpression(node.left); + return checkPropertyAccessExpressionOrQualifiedName( + node, + node.left, + leftType, + node.right, + checkMode + ); } function isMethodAccessForCall(node: Node) { while (node.parent.kind === SyntaxKind.ParenthesizedExpression) { node = node.parent; } - return isCallOrNewExpression(node.parent) && node.parent.expression === node; + return ( + isCallOrNewExpression(node.parent) && + node.parent.expression === node + ); } // Lookup the private identifier lexically. - function lookupSymbolForPrivateIdentifierDeclaration(propName: __String, location: Node): Symbol | undefined { - for (let containingClass = getContainingClassExcludingClassDecorators(location); !!containingClass; containingClass = getContainingClass(containingClass)) { + function lookupSymbolForPrivateIdentifierDeclaration( + propName: __String, + location: Node + ): Symbol | undefined { + for ( + let containingClass = + getContainingClassExcludingClassDecorators(location); + !!containingClass; + containingClass = getContainingClass(containingClass) + ) { const { symbol } = containingClass; const name = getSymbolNameForPrivateIdentifier(symbol, propName); - const prop = (symbol.members && symbol.members.get(name)) || (symbol.exports && symbol.exports.get(name)); + const prop = + (symbol.members && symbol.members.get(name)) || + (symbol.exports && symbol.exports.get(name)); if (prop) { return prop; } } } - function checkGrammarPrivateIdentifierExpression(privId: PrivateIdentifier): boolean { + function checkGrammarPrivateIdentifierExpression( + privId: PrivateIdentifier + ): boolean { if (!getContainingClass(privId)) { - return grammarErrorOnNode(privId, Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies); + return grammarErrorOnNode( + privId, + Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies + ); } if (!isForInStatement(privId.parent)) { if (!isExpressionNode(privId)) { - 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); + 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 + ); } - const isInOperation = isBinaryExpression(privId.parent) && privId.parent.operatorToken.kind === SyntaxKind.InKeyword; - if (!getSymbolForPrivateIdentifierExpression(privId) && !isInOperation) { - return grammarErrorOnNode(privId, Diagnostics.Cannot_find_name_0, idText(privId)); + const isInOperation = + isBinaryExpression(privId.parent) && + privId.parent.operatorToken.kind === SyntaxKind.InKeyword; + if ( + !getSymbolForPrivateIdentifierExpression(privId) && + !isInOperation + ) { + return grammarErrorOnNode( + privId, + Diagnostics.Cannot_find_name_0, + idText(privId) + ); } } @@ -34596,28 +60948,47 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkGrammarPrivateIdentifierExpression(privId); const symbol = getSymbolForPrivateIdentifierExpression(privId); if (symbol) { - markPropertyAsReferenced(symbol, /*nodeForCheckWriteOnly*/ undefined, /*isSelfTypeAccess*/ false); + markPropertyAsReferenced( + symbol, + /*nodeForCheckWriteOnly*/ undefined, + /*isSelfTypeAccess*/ false + ); } return anyType; } - function getSymbolForPrivateIdentifierExpression(privId: PrivateIdentifier): Symbol | undefined { + function getSymbolForPrivateIdentifierExpression( + privId: PrivateIdentifier + ): Symbol | undefined { if (!isExpressionNode(privId)) { return undefined; } const links = getNodeLinks(privId); if (links.resolvedSymbol === undefined) { - links.resolvedSymbol = lookupSymbolForPrivateIdentifierDeclaration(privId.escapedText, privId); + links.resolvedSymbol = lookupSymbolForPrivateIdentifierDeclaration( + privId.escapedText, + privId + ); } return links.resolvedSymbol; } - function getPrivateIdentifierPropertyOfType(leftType: Type, lexicallyScopedIdentifier: Symbol): Symbol | undefined { - return getPropertyOfType(leftType, lexicallyScopedIdentifier.escapedName); + function getPrivateIdentifierPropertyOfType( + leftType: Type, + lexicallyScopedIdentifier: Symbol + ): Symbol | undefined { + return getPropertyOfType( + leftType, + lexicallyScopedIdentifier.escapedName + ); } - function checkPrivateIdentifierPropertyAccess(leftType: Type, right: PrivateIdentifier, lexicallyScopedIdentifier: Symbol | undefined): boolean { + function checkPrivateIdentifierPropertyAccess( + leftType: Type, + right: PrivateIdentifier, + lexicallyScopedIdentifier: Symbol | undefined + ): boolean { // Either the identifier could not be looked up in the lexical scope OR the lexically scoped identifier did not exist on the type. // Find a private identifier with the same description on the type. let propertyOnType: Symbol | undefined; @@ -34625,7 +60996,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (properties) { forEach(properties, (symbol: Symbol) => { const decl = symbol.valueDeclaration; - if (decl && isNamedDeclaration(decl) && isPrivateIdentifier(decl.name) && decl.name.escapedText === right.escapedText) { + if ( + decl && + isNamedDeclaration(decl) && + isPrivateIdentifier(decl.name) && + decl.name.escapedText === right.escapedText + ) { propertyOnType = symbol; return true; } @@ -34633,22 +61009,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const diagName = diagnosticName(right); if (propertyOnType) { - const typeValueDecl = Debug.checkDefined(propertyOnType.valueDeclaration); - const typeClass = Debug.checkDefined(getContainingClass(typeValueDecl)); + const typeValueDecl = Debug.checkDefined( + propertyOnType.valueDeclaration + ); + const typeClass = Debug.checkDefined( + getContainingClass(typeValueDecl) + ); // We found a private identifier property with the same description. // Either: // - There is a lexically scoped private identifier AND it shadows the one we found on the type. // - It is an attempt to access the private identifier outside of the class. if (lexicallyScopedIdentifier?.valueDeclaration) { - const lexicalValueDecl = lexicallyScopedIdentifier.valueDeclaration; + const lexicalValueDecl = + lexicallyScopedIdentifier.valueDeclaration; const lexicalClass = getContainingClass(lexicalValueDecl); Debug.assert(!!lexicalClass); - if (findAncestor(lexicalClass, n => typeClass === n)) { + if (findAncestor(lexicalClass, (n) => typeClass === n)) { const diagnostic = error( right, 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, diagName, - typeToString(leftType), + typeToString(leftType) ); addRelatedInfo( @@ -34656,13 +61037,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { createDiagnosticForNode( lexicalValueDecl, Diagnostics.The_shadowing_declaration_of_0_is_defined_here, - diagName, + diagName ), createDiagnosticForNode( typeValueDecl, Diagnostics.The_declaration_of_0_that_you_probably_intended_to_use_is_defined_here, - diagName, - ), + diagName + ) ); return true; } @@ -34671,137 +61052,326 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { right, Diagnostics.Property_0_is_not_accessible_outside_class_1_because_it_has_a_private_identifier, diagName, - diagnosticName(typeClass.name || anon), + diagnosticName(typeClass.name || anon) ); return true; } return false; } - function isThisPropertyAccessInConstructor(node: ElementAccessExpression | PropertyAccessExpression | QualifiedName, prop: Symbol) { - return (isConstructorDeclaredProperty(prop) || isThisProperty(node) && isAutoTypedProperty(prop)) - && getThisContainer(node, /*includeArrowFunctions*/ true, /*includeClassComputedPropertyName*/ false) === getDeclaringConstructor(prop); + function isThisPropertyAccessInConstructor( + node: + | ElementAccessExpression + | PropertyAccessExpression + | QualifiedName, + prop: Symbol + ) { + return ( + (isConstructorDeclaredProperty(prop) || + (isThisProperty(node) && isAutoTypedProperty(prop))) && + getThisContainer( + node, + /*includeArrowFunctions*/ true, + /*includeClassComputedPropertyName*/ false + ) === getDeclaringConstructor(prop) + ); } - function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, leftType: Type, right: Identifier | PrivateIdentifier, checkMode: CheckMode | undefined, writeOnly?: boolean) { + function checkPropertyAccessExpressionOrQualifiedName( + node: PropertyAccessExpression | QualifiedName, + left: Expression | QualifiedName, + leftType: Type, + right: Identifier | PrivateIdentifier, + checkMode: CheckMode | undefined, + writeOnly?: boolean + ) { const parentSymbol = getNodeLinks(left).resolvedSymbol; const assignmentKind = getAssignmentTargetKind(node); - const apparentType = getApparentType(assignmentKind !== AssignmentKind.None || isMethodAccessForCall(node) ? getWidenedType(leftType) : leftType); - const isAnyLike = isTypeAny(apparentType) || apparentType === silentNeverType; + const apparentType = getApparentType( + assignmentKind !== AssignmentKind.None || + isMethodAccessForCall(node) + ? getWidenedType(leftType) + : leftType + ); + const isAnyLike = + isTypeAny(apparentType) || apparentType === silentNeverType; let prop: Symbol | undefined; if (isPrivateIdentifier(right)) { if ( - languageVersion < LanguageFeatureMinimumTarget.PrivateNamesAndClassStaticBlocks || - languageVersion < LanguageFeatureMinimumTarget.ClassAndClassElementDecorators || + languageVersion < + LanguageFeatureMinimumTarget.PrivateNamesAndClassStaticBlocks || + languageVersion < + LanguageFeatureMinimumTarget.ClassAndClassElementDecorators || !useDefineForClassFields ) { if (assignmentKind !== AssignmentKind.None) { - checkExternalEmitHelpers(node, ExternalEmitHelpers.ClassPrivateFieldSet); + checkExternalEmitHelpers( + node, + ExternalEmitHelpers.ClassPrivateFieldSet + ); } if (assignmentKind !== AssignmentKind.Definite) { - checkExternalEmitHelpers(node, ExternalEmitHelpers.ClassPrivateFieldGet); + checkExternalEmitHelpers( + node, + ExternalEmitHelpers.ClassPrivateFieldGet + ); } } - const lexicallyScopedSymbol = lookupSymbolForPrivateIdentifierDeclaration(right.escapedText, right); - if (assignmentKind && lexicallyScopedSymbol && lexicallyScopedSymbol.valueDeclaration && isMethodDeclaration(lexicallyScopedSymbol.valueDeclaration)) { - grammarErrorOnNode(right, Diagnostics.Cannot_assign_to_private_method_0_Private_methods_are_not_writable, idText(right)); + const lexicallyScopedSymbol = + lookupSymbolForPrivateIdentifierDeclaration( + right.escapedText, + right + ); + if ( + assignmentKind && + lexicallyScopedSymbol && + lexicallyScopedSymbol.valueDeclaration && + isMethodDeclaration(lexicallyScopedSymbol.valueDeclaration) + ) { + grammarErrorOnNode( + right, + Diagnostics.Cannot_assign_to_private_method_0_Private_methods_are_not_writable, + idText(right) + ); } if (isAnyLike) { if (lexicallyScopedSymbol) { return isErrorType(apparentType) ? errorType : apparentType; } - if (getContainingClassExcludingClassDecorators(right) === undefined) { - grammarErrorOnNode(right, Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies); + if ( + getContainingClassExcludingClassDecorators(right) === + undefined + ) { + grammarErrorOnNode( + right, + Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies + ); return anyType; } } - prop = lexicallyScopedSymbol && getPrivateIdentifierPropertyOfType(leftType, lexicallyScopedSymbol); + prop = + lexicallyScopedSymbol && + getPrivateIdentifierPropertyOfType( + leftType, + lexicallyScopedSymbol + ); if (prop === undefined) { // Check for private-identifier-specific shadowing and lexical-scoping errors. - if (checkPrivateIdentifierPropertyAccess(leftType, right, lexicallyScopedSymbol)) { + if ( + checkPrivateIdentifierPropertyAccess( + leftType, + right, + lexicallyScopedSymbol + ) + ) { return errorType; } - const containingClass = getContainingClassExcludingClassDecorators(right); - if (containingClass && isPlainJsFile(getSourceFileOfNode(containingClass), compilerOptions.checkJs)) { - grammarErrorOnNode(right, Diagnostics.Private_field_0_must_be_declared_in_an_enclosing_class, idText(right)); + const containingClass = + getContainingClassExcludingClassDecorators(right); + if ( + containingClass && + isPlainJsFile( + getSourceFileOfNode(containingClass), + compilerOptions.checkJs + ) + ) { + grammarErrorOnNode( + right, + Diagnostics.Private_field_0_must_be_declared_in_an_enclosing_class, + idText(right) + ); } - } - else { - const isSetonlyAccessor = prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor); - if (isSetonlyAccessor && assignmentKind !== AssignmentKind.Definite) { - error(node, Diagnostics.Private_accessor_was_defined_without_a_getter); + } else { + const isSetonlyAccessor = + prop.flags & SymbolFlags.SetAccessor && + !(prop.flags & SymbolFlags.GetAccessor); + if ( + isSetonlyAccessor && + assignmentKind !== AssignmentKind.Definite + ) { + error( + node, + Diagnostics.Private_accessor_was_defined_without_a_getter + ); } } - } - else { + } else { if (isAnyLike) { if (isIdentifier(left) && parentSymbol) { - markLinkedReferences(node, ReferenceHint.Property, /*propSymbol*/ undefined, leftType); + markLinkedReferences( + node, + ReferenceHint.Property, + /*propSymbol*/ undefined, + leftType + ); } return isErrorType(apparentType) ? errorType : apparentType; } - prop = getPropertyOfType(apparentType, right.escapedText, /*skipObjectFunctionPropertyAugment*/ isConstEnumObjectType(apparentType), /*includeTypeOnlyMembers*/ node.kind === SyntaxKind.QualifiedName); + prop = getPropertyOfType( + apparentType, + right.escapedText, + /*skipObjectFunctionPropertyAugment*/ isConstEnumObjectType( + apparentType + ), + /*includeTypeOnlyMembers*/ node.kind === + SyntaxKind.QualifiedName + ); } markLinkedReferences(node, ReferenceHint.Property, prop, leftType); let propType: Type; if (!prop) { - const indexInfo = !isPrivateIdentifier(right) && (assignmentKind === AssignmentKind.None || !isGenericObjectType(leftType) || isThisTypeParameter(leftType)) ? - getApplicableIndexInfoForName(apparentType, right.escapedText) : undefined; + const indexInfo = + !isPrivateIdentifier(right) && + (assignmentKind === AssignmentKind.None || + !isGenericObjectType(leftType) || + isThisTypeParameter(leftType)) + ? getApplicableIndexInfoForName( + apparentType, + right.escapedText + ) + : undefined; if (!(indexInfo && indexInfo.type)) { - const isUncheckedJS = isUncheckedJSSuggestion(node, leftType.symbol, /*excludeClasses*/ true); + const isUncheckedJS = isUncheckedJSSuggestion( + node, + leftType.symbol, + /*excludeClasses*/ true + ); if (!isUncheckedJS && isJSLiteralType(leftType)) { return anyType; } if (leftType.symbol === globalThisSymbol) { - if (globalThisSymbol.exports!.has(right.escapedText) && (globalThisSymbol.exports!.get(right.escapedText)!.flags & SymbolFlags.BlockScoped)) { - error(right, Diagnostics.Property_0_does_not_exist_on_type_1, unescapeLeadingUnderscores(right.escapedText), typeToString(leftType)); - } - else if (noImplicitAny) { - error(right, Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature, typeToString(leftType)); + if ( + globalThisSymbol.exports!.has(right.escapedText) && + globalThisSymbol.exports!.get(right.escapedText)! + .flags & SymbolFlags.BlockScoped + ) { + error( + right, + Diagnostics.Property_0_does_not_exist_on_type_1, + unescapeLeadingUnderscores(right.escapedText), + typeToString(leftType) + ); + } else if (noImplicitAny) { + error( + right, + Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature, + typeToString(leftType) + ); } return anyType; } - if (right.escapedText && !checkAndReportErrorForExtendingInterface(node)) { - reportNonexistentProperty(right, isThisTypeParameter(leftType) ? apparentType : leftType, isUncheckedJS); + if ( + right.escapedText && + !checkAndReportErrorForExtendingInterface(node) + ) { + reportNonexistentProperty( + right, + isThisTypeParameter(leftType) ? apparentType : leftType, + isUncheckedJS + ); } return errorType; } - if (indexInfo.isReadonly && (isAssignmentTarget(node) || isDeleteTarget(node))) { - error(node, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(apparentType)); + if ( + indexInfo.isReadonly && + (isAssignmentTarget(node) || isDeleteTarget(node)) + ) { + error( + node, + Diagnostics.Index_signature_in_type_0_only_permits_reading, + typeToString(apparentType) + ); } propType = indexInfo.type; - if (compilerOptions.noUncheckedIndexedAccess && getAssignmentTargetKind(node) !== AssignmentKind.Definite) { + if ( + compilerOptions.noUncheckedIndexedAccess && + getAssignmentTargetKind(node) !== AssignmentKind.Definite + ) { propType = getUnionType([propType, missingType]); } - if (compilerOptions.noPropertyAccessFromIndexSignature && isPropertyAccessExpression(node)) { - error(right, Diagnostics.Property_0_comes_from_an_index_signature_so_it_must_be_accessed_with_0, unescapeLeadingUnderscores(right.escapedText)); + if ( + compilerOptions.noPropertyAccessFromIndexSignature && + isPropertyAccessExpression(node) + ) { + error( + right, + Diagnostics.Property_0_comes_from_an_index_signature_so_it_must_be_accessed_with_0, + unescapeLeadingUnderscores(right.escapedText) + ); } - if (indexInfo.declaration && isDeprecatedDeclaration(indexInfo.declaration)) { - addDeprecatedSuggestion(right, [indexInfo.declaration], right.escapedText as string); + if ( + indexInfo.declaration && + isDeprecatedDeclaration(indexInfo.declaration) + ) { + addDeprecatedSuggestion( + right, + [indexInfo.declaration], + right.escapedText as string + ); } - } - else { - const targetPropSymbol = resolveAliasWithDeprecationCheck(prop, right); - if (isDeprecatedSymbol(targetPropSymbol) && isUncalledFunctionReference(node, targetPropSymbol) && targetPropSymbol.declarations) { - addDeprecatedSuggestion(right, targetPropSymbol.declarations, right.escapedText as string); + } else { + const targetPropSymbol = resolveAliasWithDeprecationCheck( + prop, + right + ); + if ( + isDeprecatedSymbol(targetPropSymbol) && + isUncalledFunctionReference(node, targetPropSymbol) && + targetPropSymbol.declarations + ) { + addDeprecatedSuggestion( + right, + targetPropSymbol.declarations, + right.escapedText as string + ); } checkPropertyNotUsedBeforeDeclaration(prop, node, right); - markPropertyAsReferenced(prop, node, isSelfTypeAccess(left, parentSymbol)); + markPropertyAsReferenced( + prop, + node, + isSelfTypeAccess(left, parentSymbol) + ); getNodeLinks(node).resolvedSymbol = prop; - checkPropertyAccessibility(node, left.kind === SyntaxKind.SuperKeyword, isWriteAccess(node), apparentType, prop); - if (isAssignmentToReadonlyEntity(node as Expression, prop, assignmentKind)) { - error(right, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, idText(right)); + checkPropertyAccessibility( + node, + left.kind === SyntaxKind.SuperKeyword, + isWriteAccess(node), + apparentType, + prop + ); + if ( + isAssignmentToReadonlyEntity( + node as Expression, + prop, + assignmentKind + ) + ) { + error( + right, + Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, + idText(right) + ); return errorType; } - propType = isThisPropertyAccessInConstructor(node, prop) ? autoType : writeOnly || isWriteOnlyAccess(node) ? getWriteTypeOfSymbol(prop) : getTypeOfSymbol(prop); + propType = isThisPropertyAccessInConstructor(node, prop) + ? autoType + : writeOnly || isWriteOnlyAccess(node) + ? getWriteTypeOfSymbol(prop) + : getTypeOfSymbol(prop); } - return getFlowTypeOfAccessExpression(node, prop, propType, right, checkMode); + return getFlowTypeOfAccessExpression( + node, + prop, + propType, + right, + checkMode + ); } /** @@ -34811,36 +61381,89 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * - Is from a global file that is different from the reference file, or * - (optionally) Is a class, or is a this.x property access expression */ - function isUncheckedJSSuggestion(node: Node | undefined, suggestion: Symbol | undefined, excludeClasses: boolean): boolean { + function isUncheckedJSSuggestion( + node: Node | undefined, + suggestion: Symbol | undefined, + excludeClasses: boolean + ): boolean { const file = getSourceFileOfNode(node); if (file) { - if (compilerOptions.checkJs === undefined && file.checkJsDirective === undefined && (file.scriptKind === ScriptKind.JS || file.scriptKind === ScriptKind.JSX)) { - const declarationFile = forEach(suggestion?.declarations, getSourceFileOfNode); - const suggestionHasNoExtendsOrDecorators = !suggestion?.valueDeclaration - || !isClassLike(suggestion.valueDeclaration) - || suggestion.valueDeclaration.heritageClauses?.length - || classOrConstructorParameterIsDecorated(/*useLegacyDecorators*/ false, suggestion.valueDeclaration); - return !(file !== declarationFile && !!declarationFile && isGlobalSourceFile(declarationFile)) - && !(excludeClasses && suggestion && suggestion.flags & SymbolFlags.Class && suggestionHasNoExtendsOrDecorators) - && !(!!node && excludeClasses && isPropertyAccessExpression(node) && node.expression.kind === SyntaxKind.ThisKeyword && suggestionHasNoExtendsOrDecorators); + if ( + compilerOptions.checkJs === undefined && + file.checkJsDirective === undefined && + (file.scriptKind === ScriptKind.JS || + file.scriptKind === ScriptKind.JSX) + ) { + const declarationFile = forEach( + suggestion?.declarations, + getSourceFileOfNode + ); + const suggestionHasNoExtendsOrDecorators = + !suggestion?.valueDeclaration || + !isClassLike(suggestion.valueDeclaration) || + suggestion.valueDeclaration.heritageClauses?.length || + classOrConstructorParameterIsDecorated( + /*useLegacyDecorators*/ false, + suggestion.valueDeclaration + ); + return ( + !( + file !== declarationFile && + !!declarationFile && + isGlobalSourceFile(declarationFile) + ) && + !( + excludeClasses && + suggestion && + suggestion.flags & SymbolFlags.Class && + suggestionHasNoExtendsOrDecorators + ) && + !( + !!node && + excludeClasses && + isPropertyAccessExpression(node) && + node.expression.kind === SyntaxKind.ThisKeyword && + suggestionHasNoExtendsOrDecorators + ) + ); } } return false; } - function getFlowTypeOfAccessExpression(node: ElementAccessExpression | PropertyAccessExpression | QualifiedName, prop: Symbol | undefined, propType: Type, errorNode: Node, checkMode: CheckMode | undefined) { + function getFlowTypeOfAccessExpression( + node: + | ElementAccessExpression + | PropertyAccessExpression + | QualifiedName, + prop: Symbol | undefined, + propType: Type, + errorNode: Node, + checkMode: CheckMode | undefined + ) { // Only compute control flow type if this is a property access expression that isn't an // assignment target, and the referenced property was declared as a variable, property, // accessor, or optional method. const assignmentKind = getAssignmentTargetKind(node); if (assignmentKind === AssignmentKind.Definite) { - return removeMissingType(propType, !!(prop && prop.flags & SymbolFlags.Optional)); + return removeMissingType( + propType, + !!(prop && prop.flags & SymbolFlags.Optional) + ); } if ( prop && - !(prop.flags & (SymbolFlags.Variable | SymbolFlags.Property | SymbolFlags.Accessor)) - && !(prop.flags & SymbolFlags.Method && propType.flags & TypeFlags.Union) - && !isDuplicatedCommonJSExport(prop.declarations) + !( + prop.flags & + (SymbolFlags.Variable | + SymbolFlags.Property | + SymbolFlags.Accessor) + ) && + !( + prop.flags & SymbolFlags.Method && + propType.flags & TypeFlags.Union + ) && + !isDuplicatedCommonJSExport(prop.declarations) ) { return propType; } @@ -34853,35 +61476,62 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // and if we are in a constructor of the same class as the property declaration, assume that // the property is uninitialized at the top of the control flow. let assumeUninitialized = false; - if (strictNullChecks && strictPropertyInitialization && isAccessExpression(node) && node.expression.kind === SyntaxKind.ThisKeyword) { + if ( + strictNullChecks && + strictPropertyInitialization && + isAccessExpression(node) && + node.expression.kind === SyntaxKind.ThisKeyword + ) { const declaration = prop && prop.valueDeclaration; if (declaration && isPropertyWithoutInitializer(declaration)) { if (!isStatic(declaration)) { const flowContainer = getControlFlowContainer(node); - if (flowContainer.kind === SyntaxKind.Constructor && flowContainer.parent === declaration.parent && !(declaration.flags & NodeFlags.Ambient)) { + if ( + flowContainer.kind === SyntaxKind.Constructor && + flowContainer.parent === declaration.parent && + !(declaration.flags & NodeFlags.Ambient) + ) { assumeUninitialized = true; } } } - } - else if ( - strictNullChecks && prop && prop.valueDeclaration && + } else if ( + strictNullChecks && + prop && + prop.valueDeclaration && isPropertyAccessExpression(prop.valueDeclaration) && getAssignmentDeclarationPropertyAccessKind(prop.valueDeclaration) && - getControlFlowContainer(node) === getControlFlowContainer(prop.valueDeclaration) + getControlFlowContainer(node) === + getControlFlowContainer(prop.valueDeclaration) ) { assumeUninitialized = true; } - const flowType = getFlowTypeOfReference(node, propType, assumeUninitialized ? getOptionalType(propType) : propType); - if (assumeUninitialized && !containsUndefinedType(propType) && containsUndefinedType(flowType)) { - error(errorNode, Diagnostics.Property_0_is_used_before_being_assigned, symbolToString(prop!)); // TODO: GH#18217 + const flowType = getFlowTypeOfReference( + node, + propType, + assumeUninitialized ? getOptionalType(propType) : propType + ); + if ( + assumeUninitialized && + !containsUndefinedType(propType) && + containsUndefinedType(flowType) + ) { + error( + errorNode, + Diagnostics.Property_0_is_used_before_being_assigned, + symbolToString(prop!) + ); // TODO: GH#18217 // Return the declared type to reduce follow-on errors return propType; } return assignmentKind ? getBaseTypeOfLiteralType(flowType) : flowType; } - function checkPropertyNotUsedBeforeDeclaration(prop: Symbol, node: PropertyAccessExpression | QualifiedName, right: Identifier | PrivateIdentifier): void { + function checkPropertyNotUsedBeforeDeclaration( + prop: Symbol, + node: PropertyAccessExpression | QualifiedName, + right: Identifier | PrivateIdentifier + ): void { const { valueDeclaration } = prop; if (!valueDeclaration || getSourceFileOfNode(node).isDeclarationFile) { return; @@ -34890,31 +61540,55 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let diagnosticMessage; const declarationName = idText(right); if ( - isInPropertyInitializerOrClassStaticBlock(node) - && !isOptionalPropertyDeclaration(valueDeclaration) - && !(isAccessExpression(node) && isAccessExpression(node.expression)) - && !isBlockScopedNameDeclaredBeforeUse(valueDeclaration, right) - && !(isMethodDeclaration(valueDeclaration) && getCombinedModifierFlagsCached(valueDeclaration) & ModifierFlags.Static) - && (useDefineForClassFields || !isPropertyDeclaredInAncestorClass(prop)) + isInPropertyInitializerOrClassStaticBlock(node) && + !isOptionalPropertyDeclaration(valueDeclaration) && + !( + isAccessExpression(node) && isAccessExpression(node.expression) + ) && + !isBlockScopedNameDeclaredBeforeUse(valueDeclaration, right) && + !( + isMethodDeclaration(valueDeclaration) && + getCombinedModifierFlagsCached(valueDeclaration) & + ModifierFlags.Static + ) && + (useDefineForClassFields || + !isPropertyDeclaredInAncestorClass(prop)) ) { - diagnosticMessage = error(right, Diagnostics.Property_0_is_used_before_its_initialization, declarationName); - } - else if ( + diagnosticMessage = error( + right, + Diagnostics.Property_0_is_used_before_its_initialization, + declarationName + ); + } else if ( valueDeclaration.kind === SyntaxKind.ClassDeclaration && node.parent.kind !== SyntaxKind.TypeReference && !(valueDeclaration.flags & NodeFlags.Ambient) && !isBlockScopedNameDeclaredBeforeUse(valueDeclaration, right) ) { - diagnosticMessage = error(right, Diagnostics.Class_0_used_before_its_declaration, declarationName); + diagnosticMessage = error( + right, + Diagnostics.Class_0_used_before_its_declaration, + declarationName + ); } if (diagnosticMessage) { - addRelatedInfo(diagnosticMessage, createDiagnosticForNode(valueDeclaration, Diagnostics._0_is_declared_here, declarationName)); + addRelatedInfo( + diagnosticMessage, + createDiagnosticForNode( + valueDeclaration, + Diagnostics._0_is_declared_here, + declarationName + ) + ); } } - function isInPropertyInitializerOrClassStaticBlock(node: Node, ignoreArrowFunctions?: boolean): boolean { - return !!findAncestor(node, node => { + function isInPropertyInitializerOrClassStaticBlock( + node: Node, + ignoreArrowFunctions?: boolean + ): boolean { + return !!findAncestor(node, (node) => { switch (node.kind) { case SyntaxKind.PropertyDeclaration: case SyntaxKind.ClassStaticBlockDeclaration: @@ -34925,7 +61599,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ArrowFunction: return ignoreArrowFunctions ? false : "quit"; case SyntaxKind.Block: - return isFunctionLikeDeclaration(node.parent) && node.parent.kind !== SyntaxKind.ArrowFunction ? "quit" : false; + return isFunctionLikeDeclaration(node.parent) && + node.parent.kind !== SyntaxKind.ArrowFunction + ? "quit" + : false; default: return false; } @@ -34940,13 +61617,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!(prop.parent!.flags & SymbolFlags.Class)) { return false; } - let classType: InterfaceType | undefined = getTypeOfSymbol(prop.parent!) as InterfaceType; + let classType: InterfaceType | undefined = getTypeOfSymbol( + prop.parent! + ) as InterfaceType; while (true) { - classType = classType.symbol && getSuperClass(classType) as InterfaceType | undefined; + classType = + classType.symbol && + (getSuperClass(classType) as InterfaceType | undefined); if (!classType) { return false; } - const superProperty = getPropertyOfType(classType, prop.escapedName); + const superProperty = getPropertyOfType( + classType, + prop.escapedName + ); if (superProperty && superProperty.valueDeclaration) { return true; } @@ -34961,7 +61645,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getIntersectionType(x); } - function reportNonexistentProperty(propNode: Identifier | PrivateIdentifier, containingType: Type, isUncheckedJS: boolean) { + function reportNonexistentProperty( + propNode: Identifier | PrivateIdentifier, + containingType: Type, + isUncheckedJS: boolean + ) { const links = getNodeLinks(propNode); const cache = (links.nonExistentPropCheckCache ||= new Set()); const key = `${getTypeId(containingType)}|${isUncheckedJS}`; @@ -34971,10 +61659,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { cache.add(key); let errorInfo: DiagnosticMessageChain | undefined; let relatedInfo: Diagnostic | undefined; - if (!isPrivateIdentifier(propNode) && containingType.flags & TypeFlags.Union && !(containingType.flags & TypeFlags.Primitive)) { + if ( + !isPrivateIdentifier(propNode) && + containingType.flags & TypeFlags.Union && + !(containingType.flags & TypeFlags.Primitive) + ) { for (const subtype of (containingType as UnionType).types) { - if (!getPropertyOfType(subtype, propNode.escapedText) && !getApplicableIndexInfoForName(subtype, propNode.escapedText)) { - errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(propNode), typeToString(subtype)); + if ( + !getPropertyOfType(subtype, propNode.escapedText) && + !getApplicableIndexInfoForName( + subtype, + propNode.escapedText + ) + ) { + errorInfo = chainDiagnosticMessages( + errorInfo, + Diagnostics.Property_0_does_not_exist_on_type_1, + declarationNameToString(propNode), + typeToString(subtype) + ); break; } } @@ -34982,54 +61685,132 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (typeHasStaticProperty(propNode.escapedText, containingType)) { const propName = declarationNameToString(propNode); const typeName = typeToString(containingType); - 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); - } - else { + 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 + ); + } else { const promisedType = getPromisedTypeOfPromise(containingType); - if (promisedType && getPropertyOfType(promisedType, propNode.escapedText)) { - errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(propNode), typeToString(containingType)); - relatedInfo = createDiagnosticForNode(propNode, Diagnostics.Did_you_forget_to_use_await); - } - else { + if ( + promisedType && + getPropertyOfType(promisedType, propNode.escapedText) + ) { + errorInfo = chainDiagnosticMessages( + errorInfo, + Diagnostics.Property_0_does_not_exist_on_type_1, + declarationNameToString(propNode), + typeToString(containingType) + ); + relatedInfo = createDiagnosticForNode( + propNode, + Diagnostics.Did_you_forget_to_use_await + ); + } else { const missingProperty = declarationNameToString(propNode); const container = typeToString(containingType); - const libSuggestion = getSuggestedLibForNonExistentProperty(missingProperty, containingType); + const libSuggestion = getSuggestedLibForNonExistentProperty( + missingProperty, + containingType + ); if (libSuggestion !== undefined) { - 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); - } - else { - const suggestion = getSuggestedSymbolForNonexistentProperty(propNode, containingType); + 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 + ); + } else { + const suggestion = getSuggestedSymbolForNonexistentProperty( + propNode, + containingType + ); if (suggestion !== undefined) { const suggestedName = symbolName(suggestion); - 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; - errorInfo = chainDiagnosticMessages(errorInfo, message, missingProperty, container, suggestedName); - relatedInfo = suggestion.valueDeclaration && createDiagnosticForNode(suggestion.valueDeclaration, Diagnostics._0_is_declared_here, suggestedName); - } - else { - const diagnostic = containerSeemsToBeEmptyDomElement(containingType) + 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; + errorInfo = chainDiagnosticMessages( + errorInfo, + message, + missingProperty, + container, + suggestedName + ); + relatedInfo = + suggestion.valueDeclaration && + createDiagnosticForNode( + suggestion.valueDeclaration, + Diagnostics._0_is_declared_here, + suggestedName + ); + } else { + const diagnostic = containerSeemsToBeEmptyDomElement( + containingType + ) ? Diagnostics.Property_0_does_not_exist_on_type_1_Try_changing_the_lib_compiler_option_to_include_dom : Diagnostics.Property_0_does_not_exist_on_type_1; - errorInfo = chainDiagnosticMessages(elaborateNeverIntersection(errorInfo, containingType), diagnostic, missingProperty, container); + errorInfo = chainDiagnosticMessages( + elaborateNeverIntersection( + errorInfo, + containingType + ), + diagnostic, + missingProperty, + container + ); } } } } - const resultDiagnostic = createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(propNode), propNode, errorInfo); + const resultDiagnostic = createDiagnosticForNodeFromMessageChain( + getSourceFileOfNode(propNode), + propNode, + errorInfo + ); if (relatedInfo) { addRelatedInfo(resultDiagnostic, relatedInfo); } - addErrorOrSuggestion(!isUncheckedJS || errorInfo.code !== Diagnostics.Property_0_may_not_exist_on_type_1_Did_you_mean_2.code, resultDiagnostic); + addErrorOrSuggestion( + !isUncheckedJS || + errorInfo.code !== + Diagnostics + .Property_0_may_not_exist_on_type_1_Did_you_mean_2.code, + resultDiagnostic + ); } function containerSeemsToBeEmptyDomElement(containingType: Type) { - return (compilerOptions.lib && !compilerOptions.lib.includes("lib.dom.d.ts")) && - everyContainedType(containingType, type => type.symbol && /^(?:EventTarget|Node|(?:HTML[a-zA-Z]*)?Element)$/.test(unescapeLeadingUnderscores(type.symbol.escapedName))) && - isEmptyObjectType(containingType); + return ( + compilerOptions.lib && + !compilerOptions.lib.includes("lib.dom.d.ts") && + everyContainedType( + containingType, + (type) => + type.symbol && + /^(?:EventTarget|Node|(?:HTML[a-zA-Z]*)?Element)$/.test( + unescapeLeadingUnderscores(type.symbol.escapedName) + ) + ) && + isEmptyObjectType(containingType) + ); } - function typeHasStaticProperty(propName: __String, containingType: Type): boolean { - const prop = containingType.symbol && getPropertyOfType(getTypeOfSymbol(containingType.symbol), propName); - return prop !== undefined && !!prop.valueDeclaration && isStatic(prop.valueDeclaration); + function typeHasStaticProperty( + propName: __String, + containingType: Type + ): boolean { + const prop = + containingType.symbol && + getPropertyOfType(getTypeOfSymbol(containingType.symbol), propName); + return ( + prop !== undefined && + !!prop.valueDeclaration && + isStatic(prop.valueDeclaration) + ); } function getSuggestedLibForNonExistentName(name: __String | Identifier) { @@ -35039,7 +61820,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return typeFeatures && firstIterator(typeFeatures.keys()); } - function getSuggestedLibForNonExistentProperty(missingProperty: string, containingType: Type) { + function getSuggestedLibForNonExistentProperty( + missingProperty: string, + containingType: Type + ) { const container = getApparentType(containingType).symbol; if (!container) { return undefined; @@ -35056,37 +61840,72 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getSuggestedSymbolForNonexistentClassMember(name: string, baseType: Type): Symbol | undefined { - return getSpellingSuggestionForName(name, getPropertiesOfType(baseType), SymbolFlags.ClassMember); + function getSuggestedSymbolForNonexistentClassMember( + name: string, + baseType: Type + ): Symbol | undefined { + return getSpellingSuggestionForName( + name, + getPropertiesOfType(baseType), + SymbolFlags.ClassMember + ); } - function getSuggestedSymbolForNonexistentProperty(name: Identifier | PrivateIdentifier | string, containingType: Type): Symbol | undefined { + function getSuggestedSymbolForNonexistentProperty( + name: Identifier | PrivateIdentifier | string, + containingType: Type + ): Symbol | undefined { let props = getPropertiesOfType(containingType); if (typeof name !== "string") { const parent = name.parent; if (isPropertyAccessExpression(parent)) { - props = filter(props, prop => isValidPropertyAccessForCompletions(parent, containingType, prop)); + props = filter(props, (prop) => + isValidPropertyAccessForCompletions( + parent, + containingType, + prop + ) + ); } name = idText(name); } return getSpellingSuggestionForName(name, props, SymbolFlags.Value); } - function getSuggestedSymbolForNonexistentJSXAttribute(name: Identifier | PrivateIdentifier | string, containingType: Type): Symbol | undefined { + function getSuggestedSymbolForNonexistentJSXAttribute( + name: Identifier | PrivateIdentifier | string, + containingType: Type + ): Symbol | undefined { const strName = isString(name) ? name : idText(name); const properties = getPropertiesOfType(containingType); - const jsxSpecific = strName === "for" ? find(properties, x => symbolName(x) === "htmlFor") - : strName === "class" ? find(properties, x => symbolName(x) === "className") - : undefined; - return jsxSpecific ?? getSpellingSuggestionForName(strName, properties, SymbolFlags.Value); + const jsxSpecific = + strName === "for" + ? find(properties, (x) => symbolName(x) === "htmlFor") + : strName === "class" + ? find(properties, (x) => symbolName(x) === "className") + : undefined; + return ( + jsxSpecific ?? + getSpellingSuggestionForName(strName, properties, SymbolFlags.Value) + ); } - function getSuggestionForNonexistentProperty(name: Identifier | PrivateIdentifier | string, containingType: Type): string | undefined { - const suggestion = getSuggestedSymbolForNonexistentProperty(name, containingType); + function getSuggestionForNonexistentProperty( + name: Identifier | PrivateIdentifier | string, + containingType: Type + ): string | undefined { + const suggestion = getSuggestedSymbolForNonexistentProperty( + name, + containingType + ); return suggestion && symbolName(suggestion); } - function getSuggestionForSymbolNameLookup(symbols: SymbolTable, name: __String, meaning: SymbolFlags) { + function getSuggestionForSymbolNameLookup( + symbols: SymbolTable, + name: __String, + meaning: SymbolFlags + ) { const symbol = getSymbol(symbols, name, meaning); // 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 // So the table *contains* `x` but `x` isn't actually in scope. @@ -35096,34 +61915,75 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (symbols === globals) { const primitives = mapDefined( ["string", "number", "boolean", "object", "bigint", "symbol"], - s => symbols.has((s.charAt(0).toUpperCase() + s.slice(1)) as __String) - ? createSymbol(SymbolFlags.TypeAlias, s as __String) as Symbol - : undefined, + (s) => + symbols.has( + (s.charAt(0).toUpperCase() + s.slice(1)) as __String + ) + ? (createSymbol( + SymbolFlags.TypeAlias, + s as __String + ) as Symbol) + : undefined ); candidates = primitives.concat(arrayFrom(symbols.values())); - } - else { + } else { candidates = arrayFrom(symbols.values()); } - return getSpellingSuggestionForName(unescapeLeadingUnderscores(name), candidates, meaning); + return getSpellingSuggestionForName( + unescapeLeadingUnderscores(name), + candidates, + meaning + ); } - function getSuggestedSymbolForNonexistentSymbol(location: Node | undefined, outerName: __String, meaning: SymbolFlags): Symbol | undefined { - Debug.assert(outerName !== undefined, "outername should always be defined"); - const result = resolveNameForSymbolSuggestion(location, outerName, meaning, /*nameNotFoundMessage*/ undefined, /*isUse*/ false, /*excludeGlobals*/ false); + function getSuggestedSymbolForNonexistentSymbol( + location: Node | undefined, + outerName: __String, + meaning: SymbolFlags + ): Symbol | undefined { + Debug.assert( + outerName !== undefined, + "outername should always be defined" + ); + const result = resolveNameForSymbolSuggestion( + location, + outerName, + meaning, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ false, + /*excludeGlobals*/ false + ); return result; } - function getSuggestedSymbolForNonexistentModule(name: Identifier, targetModule: Symbol): Symbol | undefined { - return targetModule.exports && getSpellingSuggestionForName(idText(name), getExportsOfModuleAsArray(targetModule), SymbolFlags.ModuleMember); + function getSuggestedSymbolForNonexistentModule( + name: Identifier, + targetModule: Symbol + ): Symbol | undefined { + return ( + targetModule.exports && + getSpellingSuggestionForName( + idText(name), + getExportsOfModuleAsArray(targetModule), + SymbolFlags.ModuleMember + ) + ); } - function getSuggestionForNonexistentIndexSignature(objectType: Type, expr: ElementAccessExpression, keyedType: Type): string | undefined { + function getSuggestionForNonexistentIndexSignature( + objectType: Type, + expr: ElementAccessExpression, + keyedType: Type + ): string | undefined { // check if object type has setter or getter function hasProp(name: "set" | "get") { const prop = getPropertyOfObjectType(objectType, name as __String); if (prop) { const s = getSingleCallSignature(getTypeOfSymbol(prop)); - return !!s && getMinArgumentCount(s) >= 1 && isTypeAssignableTo(keyedType, getTypeAtPosition(s, 0)); + return ( + !!s && + getMinArgumentCount(s) >= 1 && + isTypeAssignableTo(keyedType, getTypeAtPosition(s, 0)) + ); } return false; } @@ -35133,20 +61993,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - let suggestion = tryGetPropertyAccessOrIdentifierToString(expr.expression); + let suggestion = tryGetPropertyAccessOrIdentifierToString( + expr.expression + ); if (suggestion === undefined) { suggestion = suggestedMethod; - } - else { + } else { suggestion += "." + suggestedMethod; } return suggestion; } - function getSuggestedTypeForNonexistentStringLiteralType(source: StringLiteralType, target: UnionType): StringLiteralType | undefined { - const candidates = target.types.filter((type): type is StringLiteralType => !!(type.flags & TypeFlags.StringLiteral)); - return getSpellingSuggestion(source.value, candidates, type => type.value); + function getSuggestedTypeForNonexistentStringLiteralType( + source: StringLiteralType, + target: UnionType + ): StringLiteralType | undefined { + const candidates = target.types.filter( + (type): type is StringLiteralType => + !!(type.flags & TypeFlags.StringLiteral) + ); + return getSpellingSuggestion( + source.value, + candidates, + (type) => type.value + ); } /** @@ -35164,7 +62035,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * (0.4 allows 1 substitution/transposition for every 5 characters, * and 1 insertion/deletion at 3 characters) */ - function getSpellingSuggestionForName(name: string, symbols: Symbol[], meaning: SymbolFlags): Symbol | undefined { + function getSpellingSuggestionForName( + name: string, + symbols: Symbol[], + meaning: SymbolFlags + ): Symbol | undefined { return getSpellingSuggestion(name, symbols, getCandidateName); function getCandidateName(candidate: Symbol) { @@ -35188,43 +62063,90 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function markPropertyAsReferenced(prop: Symbol, nodeForCheckWriteOnly: Node | undefined, isSelfTypeAccess: boolean) { - const valueDeclaration = prop && (prop.flags & SymbolFlags.ClassMember) && prop.valueDeclaration; + function markPropertyAsReferenced( + prop: Symbol, + nodeForCheckWriteOnly: Node | undefined, + isSelfTypeAccess: boolean + ) { + const valueDeclaration = + prop && + prop.flags & SymbolFlags.ClassMember && + prop.valueDeclaration; if (!valueDeclaration) { return; } - const hasPrivateModifier = hasEffectiveModifier(valueDeclaration, ModifierFlags.Private); - const hasPrivateIdentifier = prop.valueDeclaration && isNamedDeclaration(prop.valueDeclaration) && isPrivateIdentifier(prop.valueDeclaration.name); + const hasPrivateModifier = hasEffectiveModifier( + valueDeclaration, + ModifierFlags.Private + ); + const hasPrivateIdentifier = + prop.valueDeclaration && + isNamedDeclaration(prop.valueDeclaration) && + isPrivateIdentifier(prop.valueDeclaration.name); if (!hasPrivateModifier && !hasPrivateIdentifier) { return; } - if (nodeForCheckWriteOnly && isWriteOnlyAccess(nodeForCheckWriteOnly) && !(prop.flags & SymbolFlags.SetAccessor)) { + if ( + nodeForCheckWriteOnly && + isWriteOnlyAccess(nodeForCheckWriteOnly) && + !(prop.flags & SymbolFlags.SetAccessor) + ) { return; } if (isSelfTypeAccess) { // Find any FunctionLikeDeclaration because those create a new 'this' binding. But this should only matter for methods (or getters/setters). - const containingMethod = findAncestor(nodeForCheckWriteOnly, isFunctionLikeDeclaration); + const containingMethod = findAncestor( + nodeForCheckWriteOnly, + isFunctionLikeDeclaration + ); if (containingMethod && containingMethod.symbol === prop) { return; } } - (getCheckFlags(prop) & CheckFlags.Instantiated ? getSymbolLinks(prop).target : prop)!.isReferenced = SymbolFlags.All; + (getCheckFlags(prop) & CheckFlags.Instantiated + ? getSymbolLinks(prop).target + : prop)!.isReferenced = SymbolFlags.All; } - function isSelfTypeAccess(name: Expression | QualifiedName, parent: Symbol | undefined) { - return name.kind === SyntaxKind.ThisKeyword - || !!parent && isEntityNameExpression(name) && parent === getResolvedSymbol(getFirstIdentifier(name)); + function isSelfTypeAccess( + name: Expression | QualifiedName, + parent: Symbol | undefined + ) { + return ( + name.kind === SyntaxKind.ThisKeyword || + (!!parent && + isEntityNameExpression(name) && + parent === getResolvedSymbol(getFirstIdentifier(name))) + ); } - function isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName | ImportTypeNode, propertyName: __String): boolean { + function isValidPropertyAccess( + node: PropertyAccessExpression | QualifiedName | ImportTypeNode, + propertyName: __String + ): boolean { switch (node.kind) { case SyntaxKind.PropertyAccessExpression: - return isValidPropertyAccessWithType(node, node.expression.kind === SyntaxKind.SuperKeyword, propertyName, getWidenedType(checkExpression(node.expression))); + return isValidPropertyAccessWithType( + node, + node.expression.kind === SyntaxKind.SuperKeyword, + propertyName, + getWidenedType(checkExpression(node.expression)) + ); case SyntaxKind.QualifiedName: - return isValidPropertyAccessWithType(node, /*isSuper*/ false, propertyName, getWidenedType(checkExpression(node.left))); + return isValidPropertyAccessWithType( + node, + /*isSuper*/ false, + propertyName, + getWidenedType(checkExpression(node.left)) + ); case SyntaxKind.ImportType: - return isValidPropertyAccessWithType(node, /*isSuper*/ false, propertyName, getTypeFromTypeNode(node)); + return isValidPropertyAccessWithType( + node, + /*isSuper*/ false, + propertyName, + getTypeFromTypeNode(node) + ); } } @@ -35238,8 +62160,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param type the type whose property we are checking. * @param property the accessed property's symbol. */ - function isValidPropertyAccessForCompletions(node: PropertyAccessExpression | ImportTypeNode | QualifiedName, type: Type, property: Symbol): boolean { - return isPropertyAccessible(node, node.kind === SyntaxKind.PropertyAccessExpression && node.expression.kind === SyntaxKind.SuperKeyword, /*isWrite*/ false, type, property); + function isValidPropertyAccessForCompletions( + node: PropertyAccessExpression | ImportTypeNode | QualifiedName, + type: Type, + property: Symbol + ): boolean { + return isPropertyAccessible( + node, + node.kind === SyntaxKind.PropertyAccessExpression && + node.expression.kind === SyntaxKind.SuperKeyword, + /*isWrite*/ false, + type, + property + ); // Previously we validated the 'this' type of methods but this adversely affected performance. See #31377 for more context. } @@ -35247,7 +62180,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { node: PropertyAccessExpression | QualifiedName | ImportTypeNode, isSuper: boolean, propertyName: __String, - type: Type, + type: Type ): boolean { // Short-circuiting for improved performance. if (isTypeAny(type)) { @@ -35255,7 +62188,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const prop = getPropertyOfType(type, propertyName); - return !!prop && isPropertyAccessible(node, isSuper, /*isWrite*/ false, type, prop); + return ( + !!prop && + isPropertyAccessible(node, isSuper, /*isWrite*/ false, type, prop) + ); } /** @@ -35273,7 +62209,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { isSuper: boolean, isWrite: boolean, containingType: Type, - property: Symbol, + property: Symbol ): boolean { // Short-circuiting for improved performance. if (isTypeAny(containingType)) { @@ -35282,12 +62218,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // A #private property access in an optional chain is an error dealt with by the parser. // The checker does not check for it, so we need to do our own check here. - if (property.valueDeclaration && isPrivateIdentifierClassElementDeclaration(property.valueDeclaration)) { + if ( + property.valueDeclaration && + isPrivateIdentifierClassElementDeclaration( + property.valueDeclaration + ) + ) { const declClass = getContainingClass(property.valueDeclaration); - return !isOptionalChain(node) && !!findAncestor(node, parent => parent === declClass); + return ( + !isOptionalChain(node) && + !!findAncestor(node, (parent) => parent === declClass) + ); } - return checkPropertyAccessibilityAtLocation(node, isSuper, isWrite, containingType, property); + return checkPropertyAccessibilityAtLocation( + node, + isSuper, + isWrite, + containingType, + property + ); } /** @@ -35296,12 +62246,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getForInVariableSymbol(node: ForInStatement): Symbol | undefined { const initializer = node.initializer; if (initializer.kind === SyntaxKind.VariableDeclarationList) { - const variable = (initializer as VariableDeclarationList).declarations[0]; + const variable = (initializer as VariableDeclarationList) + .declarations[0]; if (variable && !isBindingPattern(variable.name)) { return getSymbolOfDeclaration(variable); } - } - else if (initializer.kind === SyntaxKind.Identifier) { + } else if (initializer.kind === SyntaxKind.Identifier) { return getResolvedSymbol(initializer as Identifier); } return undefined; @@ -35311,7 +62261,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Return true if the given type is considered to have numeric property names. */ function hasNumericPropertyNames(type: Type) { - return getIndexInfosOfType(type).length === 1 && !!getIndexInfoOfType(type, numberType); + return ( + getIndexInfosOfType(type).length === 1 && + !!getIndexInfoOfType(type, numberType) + ); } /** @@ -35329,8 +62282,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if ( node.kind === SyntaxKind.ForInStatement && child === (node as ForInStatement).statement && - getForInVariableSymbol(node as ForInStatement) === symbol && - hasNumericPropertyNames(getTypeOfExpression((node as ForInStatement).expression)) + getForInVariableSymbol(node as ForInStatement) === + symbol && + hasNumericPropertyNames( + getTypeOfExpression( + (node as ForInStatement).expression + ) + ) ) { return true; } @@ -35342,19 +62300,49 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function checkIndexedAccess(node: ElementAccessExpression, checkMode: CheckMode | undefined): Type { - return node.flags & NodeFlags.OptionalChain ? checkElementAccessChain(node as ElementAccessChain, checkMode) : - checkElementAccessExpression(node, checkNonNullExpression(node.expression), checkMode); - } - - function checkElementAccessChain(node: ElementAccessChain, checkMode: CheckMode | undefined) { + function checkIndexedAccess( + node: ElementAccessExpression, + checkMode: CheckMode | undefined + ): Type { + return node.flags & NodeFlags.OptionalChain + ? checkElementAccessChain(node as ElementAccessChain, checkMode) + : checkElementAccessExpression( + node, + checkNonNullExpression(node.expression), + checkMode + ); + } + + function checkElementAccessChain( + node: ElementAccessChain, + checkMode: CheckMode | undefined + ) { const exprType = checkExpression(node.expression); - const nonOptionalType = getOptionalExpressionType(exprType, node.expression); - return propagateOptionalTypeMarker(checkElementAccessExpression(node, checkNonNullType(nonOptionalType, node.expression), checkMode), node, nonOptionalType !== exprType); + const nonOptionalType = getOptionalExpressionType( + exprType, + node.expression + ); + return propagateOptionalTypeMarker( + checkElementAccessExpression( + node, + checkNonNullType(nonOptionalType, node.expression), + checkMode + ), + node, + nonOptionalType !== exprType + ); } - function checkElementAccessExpression(node: ElementAccessExpression, exprType: Type, checkMode: CheckMode | undefined): Type { - const objectType = getAssignmentTargetKind(node) !== AssignmentKind.None || isMethodAccessForCall(node) ? getWidenedType(exprType) : exprType; + function checkElementAccessExpression( + node: ElementAccessExpression, + exprType: Type, + checkMode: CheckMode | undefined + ): Type { + const objectType = + getAssignmentTargetKind(node) !== AssignmentKind.None || + isMethodAccessForCall(node) + ? getWidenedType(exprType) + : exprType; const indexExpression = node.argumentExpression; const indexType = checkExpression(indexExpression); @@ -35362,29 +62350,68 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return objectType; } - if (isConstEnumObjectType(objectType) && !isStringLiteralLike(indexExpression)) { - error(indexExpression, Diagnostics.A_const_enum_member_can_only_be_accessed_using_a_string_literal); + if ( + isConstEnumObjectType(objectType) && + !isStringLiteralLike(indexExpression) + ) { + error( + indexExpression, + Diagnostics.A_const_enum_member_can_only_be_accessed_using_a_string_literal + ); return errorType; } - const effectiveIndexType = isForInVariableForNumericPropertyNames(indexExpression) ? numberType : indexType; + const effectiveIndexType = isForInVariableForNumericPropertyNames( + indexExpression + ) + ? numberType + : indexType; const assignmentTargetKind = getAssignmentTargetKind(node); let accessFlags: AccessFlags; if (assignmentTargetKind === AssignmentKind.None) { accessFlags = AccessFlags.ExpressionPosition; - } - else { - accessFlags = AccessFlags.Writing | (isGenericObjectType(objectType) && !isThisTypeParameter(objectType) ? AccessFlags.NoIndexSignatures : 0); + } else { + accessFlags = + AccessFlags.Writing | + (isGenericObjectType(objectType) && + !isThisTypeParameter(objectType) + ? AccessFlags.NoIndexSignatures + : 0); if (assignmentTargetKind === AssignmentKind.Compound) { accessFlags |= AccessFlags.ExpressionPosition; } } - const indexedAccessType = getIndexedAccessTypeOrUndefined(objectType, effectiveIndexType, accessFlags, node) || errorType; - return checkIndexedAccessIndexType(getFlowTypeOfAccessExpression(node, getNodeLinks(node).resolvedSymbol, indexedAccessType, indexExpression, checkMode), node); + const indexedAccessType = + getIndexedAccessTypeOrUndefined( + objectType, + effectiveIndexType, + accessFlags, + node + ) || errorType; + return checkIndexedAccessIndexType( + getFlowTypeOfAccessExpression( + node, + getNodeLinks(node).resolvedSymbol, + indexedAccessType, + indexExpression, + checkMode + ), + node + ); } - function callLikeExpressionMayHaveTypeArguments(node: CallLikeExpression): node is CallExpression | NewExpression | TaggedTemplateExpression | JsxOpeningElement { - return isCallOrNewExpression(node) || isTaggedTemplateExpression(node) || isJsxOpeningLikeElement(node); + function callLikeExpressionMayHaveTypeArguments( + node: CallLikeExpression + ): node is + | CallExpression + | NewExpression + | TaggedTemplateExpression + | JsxOpeningElement { + return ( + isCallOrNewExpression(node) || + isTaggedTemplateExpression(node) || + isJsxOpeningLikeElement(node) + ); } function resolveUntypedCall(node: CallLikeExpression): Signature { @@ -35396,15 +62423,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (node.kind === SyntaxKind.TaggedTemplateExpression) { checkExpression(node.template); - } - else if (isJsxOpeningLikeElement(node)) { + } else if (isJsxOpeningLikeElement(node)) { checkExpression(node.attributes); - } - else if (isBinaryExpression(node)) { + } else if (isBinaryExpression(node)) { checkExpression(node.left); - } - else if (isCallOrNewExpression(node)) { - forEach(node.arguments, argument => { + } else if (isCallOrNewExpression(node)) { + forEach(node.arguments, (argument) => { checkExpression(argument); }); } @@ -35424,7 +62448,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // interface B extends A { (x: 'foo'): string } // const b: B; // b('foo') // <- here overloads should be processed as [(x:'foo'): string, (x: string): void] - function reorderCandidates(signatures: readonly Signature[], result: Signature[], callChainFlags: SignatureFlags): void { + function reorderCandidates( + signatures: readonly Signature[], + result: Signature[], + callChainFlags: SignatureFlags + ): void { let lastParent: Node | undefined; let lastSymbol: Symbol | undefined; let cutoffIndex = 0; @@ -35433,18 +62461,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let spliceIndex: number; Debug.assert(!result.length); for (const signature of signatures) { - const symbol = signature.declaration && getSymbolOfDeclaration(signature.declaration); - const parent = signature.declaration && signature.declaration.parent; + const symbol = + signature.declaration && + getSymbolOfDeclaration(signature.declaration); + const parent = + signature.declaration && signature.declaration.parent; if (!lastSymbol || symbol === lastSymbol) { if (lastParent && parent === lastParent) { index = index! + 1; - } - else { + } else { lastParent = parent; index = cutoffIndex; } - } - else { + } else { // current declaration belongs to a different symbol // set cutoffIndex so re-orderings in the future won't change result set from 0 to cutoffIndex index = cutoffIndex = result.length; @@ -35461,17 +62490,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // in order to prevent non-specialized signatures from being added before a specialized // signature. cutoffIndex++; - } - else { + } else { spliceIndex = index; } - result.splice(spliceIndex, 0, callChainFlags ? getOptionalCallSignature(signature, callChainFlags) : signature); + result.splice( + spliceIndex, + 0, + callChainFlags + ? getOptionalCallSignature(signature, callChainFlags) + : signature + ); } } function isSpreadArgument(arg: Expression | undefined): arg is Expression { - return !!arg && (arg.kind === SyntaxKind.SpreadElement || arg.kind === SyntaxKind.SyntheticExpression && (arg as SyntheticExpression).isSpread); + return ( + !!arg && + (arg.kind === SyntaxKind.SpreadElement || + (arg.kind === SyntaxKind.SyntheticExpression && + (arg as SyntheticExpression).isSpread)) + ); } function getSpreadArgumentIndex(args: readonly Expression[]): number { @@ -35483,10 +62522,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function acceptsVoidUndefinedUnknownOrAny(t: Type): boolean { - return !!(t.flags & (TypeFlags.Void | TypeFlags.Undefined | TypeFlags.Unknown | TypeFlags.Any)); + return !!( + t.flags & + (TypeFlags.Void | + TypeFlags.Undefined | + TypeFlags.Unknown | + TypeFlags.Any) + ); } - function hasCorrectArity(node: CallLikeExpression, args: readonly Expression[], signature: Signature, signatureHelpTrailingComma = false) { + function hasCorrectArity( + node: CallLikeExpression, + args: readonly Expression[], + signature: Signature, + signatureHelpTrailingComma = false + ) { if (isJsxOpeningFragment(node)) return true; let argCount: number; @@ -35500,39 +62550,41 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If a tagged template expression lacks a tail literal, the call is incomplete. // Specifically, a template only can end in a TemplateTail or a Missing literal. const lastSpan = last(node.template.templateSpans); // we should always have at least one span. - callIsIncomplete = nodeIsMissing(lastSpan.literal) || !!lastSpan.literal.isUnterminated; - } - else { + callIsIncomplete = + nodeIsMissing(lastSpan.literal) || + !!lastSpan.literal.isUnterminated; + } else { // If the template didn't end in a backtick, or its beginning occurred right prior to EOF, // then this might actually turn out to be a TemplateHead in the future; // so we consider the call to be incomplete. const templateLiteral = node.template as LiteralExpression; - Debug.assert(templateLiteral.kind === SyntaxKind.NoSubstitutionTemplateLiteral); + Debug.assert( + templateLiteral.kind === + SyntaxKind.NoSubstitutionTemplateLiteral + ); callIsIncomplete = !!templateLiteral.isUnterminated; } - } - else if (node.kind === SyntaxKind.Decorator) { + } else if (node.kind === SyntaxKind.Decorator) { argCount = getDecoratorArgumentCount(node, signature); - } - else if (node.kind === SyntaxKind.BinaryExpression) { + } else if (node.kind === SyntaxKind.BinaryExpression) { argCount = 1; - } - else if (isJsxOpeningLikeElement(node)) { + } else if (isJsxOpeningLikeElement(node)) { callIsIncomplete = node.attributes.end === node.end; if (callIsIncomplete) { return true; } argCount = effectiveMinimumArguments === 0 ? args.length : 1; - effectiveParameterCount = args.length === 0 ? effectiveParameterCount : 1; // class may have argumentless ctor functions - still resolve ctor and compare vs props member type + effectiveParameterCount = + args.length === 0 ? effectiveParameterCount : 1; // class may have argumentless ctor functions - still resolve ctor and compare vs props member type effectiveMinimumArguments = Math.min(effectiveMinimumArguments, 1); // sfc may specify context argument - handled by framework and not typechecked - } - else if (!node.arguments) { + } else if (!node.arguments) { // This only happens when we have something of the form: 'new C' Debug.assert(node.kind === SyntaxKind.NewExpression); return getMinArgumentCount(signature) === 0; - } - else { - argCount = signatureHelpTrailingComma ? args.length + 1 : args.length; + } else { + argCount = signatureHelpTrailingComma + ? args.length + 1 + : args.length; // If we are missing the close parenthesis, the call is incomplete. callIsIncomplete = node.arguments.end === node.end; @@ -35540,12 +62592,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If a spread argument is present, check that it corresponds to a rest parameter or at least that it's in the valid range. const spreadArgIndex = getSpreadArgumentIndex(args); if (spreadArgIndex >= 0) { - return spreadArgIndex >= getMinArgumentCount(signature) && (hasEffectiveRestParameter(signature) || spreadArgIndex < getParameterCount(signature)); + return ( + spreadArgIndex >= getMinArgumentCount(signature) && + (hasEffectiveRestParameter(signature) || + spreadArgIndex < getParameterCount(signature)) + ); } } // Too many arguments implies incorrect arity. - if (!hasEffectiveRestParameter(signature) && argCount > effectiveParameterCount) { + if ( + !hasEffectiveRestParameter(signature) && + argCount > effectiveParameterCount + ) { return false; } @@ -35556,45 +62615,96 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } for (let i = argCount; i < effectiveMinimumArguments; i++) { const type = getTypeAtPosition(signature, i); - if (filterType(type, isInJSFile(node) && !strictNullChecks ? acceptsVoidUndefinedUnknownOrAny : acceptsVoid).flags & TypeFlags.Never) { + if ( + filterType( + type, + isInJSFile(node) && !strictNullChecks + ? acceptsVoidUndefinedUnknownOrAny + : acceptsVoid + ).flags & TypeFlags.Never + ) { return false; } } return true; } - function hasCorrectTypeArgumentArity(signature: Signature, typeArguments: NodeArray | undefined) { + function hasCorrectTypeArgumentArity( + signature: Signature, + typeArguments: NodeArray | undefined + ) { // If the user supplied type arguments, but the number of type arguments does not match // the declared number of type parameters, the call has an incorrect arity. const numTypeParameters = length(signature.typeParameters); - const minTypeArgumentCount = getMinTypeArgumentCount(signature.typeParameters); - return !some(typeArguments) || - (typeArguments.length >= minTypeArgumentCount && typeArguments.length <= numTypeParameters); + const minTypeArgumentCount = getMinTypeArgumentCount( + signature.typeParameters + ); + return ( + !some(typeArguments) || + (typeArguments.length >= minTypeArgumentCount && + typeArguments.length <= numTypeParameters) + ); } function isInstantiatedGenericParameter(signature: Signature, pos: number) { let type; - return !!(signature.target && (type = tryGetTypeAtPosition(signature.target, pos)) && isGenericType(type)); + return !!( + signature.target && + (type = tryGetTypeAtPosition(signature.target, pos)) && + isGenericType(type) + ); } // If type has a single call signature and no other members, return that signature. Otherwise, return undefined. function getSingleCallSignature(type: Type): Signature | undefined { - return getSingleSignature(type, SignatureKind.Call, /*allowMembers*/ false); + return getSingleSignature( + type, + SignatureKind.Call, + /*allowMembers*/ false + ); } - function getSingleCallOrConstructSignature(type: Type): Signature | undefined { - return getSingleSignature(type, SignatureKind.Call, /*allowMembers*/ false) || - getSingleSignature(type, SignatureKind.Construct, /*allowMembers*/ false); + function getSingleCallOrConstructSignature( + type: Type + ): Signature | undefined { + return ( + getSingleSignature( + type, + SignatureKind.Call, + /*allowMembers*/ false + ) || + getSingleSignature( + type, + SignatureKind.Construct, + /*allowMembers*/ false + ) + ); } - function getSingleSignature(type: Type, kind: SignatureKind, allowMembers: boolean): Signature | undefined { + function getSingleSignature( + type: Type, + kind: SignatureKind, + allowMembers: boolean + ): Signature | undefined { if (type.flags & TypeFlags.Object) { const resolved = resolveStructuredTypeMembers(type as ObjectType); - if (allowMembers || resolved.properties.length === 0 && resolved.indexInfos.length === 0) { - if (kind === SignatureKind.Call && resolved.callSignatures.length === 1 && resolved.constructSignatures.length === 0) { + if ( + allowMembers || + (resolved.properties.length === 0 && + resolved.indexInfos.length === 0) + ) { + if ( + kind === SignatureKind.Call && + resolved.callSignatures.length === 1 && + resolved.constructSignatures.length === 0 + ) { return resolved.callSignatures[0]; } - if (kind === SignatureKind.Construct && resolved.constructSignatures.length === 1 && resolved.callSignatures.length === 0) { + if ( + kind === SignatureKind.Construct && + resolved.constructSignatures.length === 1 && + resolved.callSignatures.length === 0 + ) { return resolved.constructSignatures[0]; } } @@ -35603,29 +62713,71 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Instantiate a generic signature in the context of a non-generic signature (section 3.8.5 in TypeScript spec) - function instantiateSignatureInContextOf(signature: Signature, contextualSignature: Signature, inferenceContext?: InferenceContext, compareTypes?: TypeComparer): Signature { - const context = createInferenceContext(getTypeParametersForMapper(signature)!, signature, InferenceFlags.None, compareTypes); + function instantiateSignatureInContextOf( + signature: Signature, + contextualSignature: Signature, + inferenceContext?: InferenceContext, + compareTypes?: TypeComparer + ): Signature { + const context = createInferenceContext( + getTypeParametersForMapper(signature)!, + signature, + InferenceFlags.None, + compareTypes + ); // We clone the inferenceContext to avoid fixing. For example, when the source signature is (x: T) => T[] and // the contextual signature is (...args: A) => B, we want to infer the element type of A's constraint (say 'any') // for T but leave it possible to later infer '[any]' back to A. const restType = getEffectiveRestType(contextualSignature); - const mapper = inferenceContext && (restType && restType.flags & TypeFlags.TypeParameter ? inferenceContext.nonFixingMapper : inferenceContext.mapper); - const sourceSignature = mapper ? instantiateSignature(contextualSignature, mapper) : contextualSignature; + const mapper = + inferenceContext && + (restType && restType.flags & TypeFlags.TypeParameter + ? inferenceContext.nonFixingMapper + : inferenceContext.mapper); + const sourceSignature = mapper + ? instantiateSignature(contextualSignature, mapper) + : contextualSignature; applyToParameterTypes(sourceSignature, signature, (source, target) => { // Type parameters from outer context referenced by source type are fixed by instantiation of the source type inferTypes(context.inferences, source, target); }); if (!inferenceContext) { - applyToReturnTypes(contextualSignature, signature, (source, target) => { - inferTypes(context.inferences, source, target, InferencePriority.ReturnType); - }); + applyToReturnTypes( + contextualSignature, + signature, + (source, target) => { + inferTypes( + context.inferences, + source, + target, + InferencePriority.ReturnType + ); + } + ); } - return getSignatureInstantiation(signature, getInferredTypes(context), isInJSFile(contextualSignature.declaration)); + return getSignatureInstantiation( + signature, + getInferredTypes(context), + isInJSFile(contextualSignature.declaration) + ); } - function inferJsxTypeArguments(node: JsxOpeningLikeElement, signature: Signature, checkMode: CheckMode, context: InferenceContext): Type[] { - const paramType = getEffectiveFirstArgumentForJsxSignature(signature, node); - const checkAttrType = checkExpressionWithContextualType(node.attributes, paramType, context, checkMode); + function inferJsxTypeArguments( + node: JsxOpeningLikeElement, + signature: Signature, + checkMode: CheckMode, + context: InferenceContext + ): Type[] { + const paramType = getEffectiveFirstArgumentForJsxSignature( + signature, + node + ); + const checkAttrType = checkExpressionWithContextualType( + node.attributes, + paramType, + context, + checkMode + ); inferTypes(context.inferences, checkAttrType, paramType); return getInferredTypes(context); } @@ -35635,13 +62787,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return voidType; } const thisArgumentType = checkExpression(thisArgumentNode); - return isRightSideOfInstanceofExpression(thisArgumentNode) ? thisArgumentType : - isOptionalChainRoot(thisArgumentNode.parent) ? getNonNullableType(thisArgumentType) : - isOptionalChain(thisArgumentNode.parent) ? removeOptionalTypeMarker(thisArgumentType) : - thisArgumentType; + return isRightSideOfInstanceofExpression(thisArgumentNode) + ? thisArgumentType + : isOptionalChainRoot(thisArgumentNode.parent) + ? getNonNullableType(thisArgumentType) + : isOptionalChain(thisArgumentNode.parent) + ? removeOptionalTypeMarker(thisArgumentType) + : thisArgumentType; } - function inferTypeArguments(node: CallLikeExpression, signature: Signature, args: readonly Expression[], checkMode: CheckMode, context: InferenceContext): Type[] { + function inferTypeArguments( + node: CallLikeExpression, + signature: Signature, + args: readonly Expression[], + checkMode: CheckMode, + context: InferenceContext + ): Type[] { if (isJsxOpeningLikeElement(node)) { return inferJsxTypeArguments(node, signature, checkMode, context); } @@ -35650,14 +62811,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // example, given a 'function wrap(cb: (x: T) => U): (x: T) => U' and a call expression // 'let f: (x: string) => number = wrap(s => s.length)', we infer from the declared type of 'f' to the // return type of 'wrap'. - if (node.kind !== SyntaxKind.Decorator && node.kind !== SyntaxKind.BinaryExpression) { - const skipBindingPatterns = every(signature.typeParameters, p => !!getDefaultFromTypeParameter(p)); - const contextualType = getContextualType(node, skipBindingPatterns ? ContextFlags.SkipBindingPatterns : ContextFlags.None); + if ( + node.kind !== SyntaxKind.Decorator && + node.kind !== SyntaxKind.BinaryExpression + ) { + const skipBindingPatterns = every( + signature.typeParameters, + (p) => !!getDefaultFromTypeParameter(p) + ); + const contextualType = getContextualType( + node, + skipBindingPatterns + ? ContextFlags.SkipBindingPatterns + : ContextFlags.None + ); if (contextualType) { const inferenceTargetType = getReturnTypeOfSignature(signature); if (couldContainTypeVariables(inferenceTargetType)) { const outerContext = getInferenceContext(node); - const isFromBindingPattern = !skipBindingPatterns && getContextualType(node, ContextFlags.SkipBindingPatterns) !== contextualType; + const isFromBindingPattern = + !skipBindingPatterns && + getContextualType( + node, + ContextFlags.SkipBindingPatterns + ) !== contextualType; // A return type inference from a binding pattern can be used in instantiating the contextual // type of an argument later in inference, but cannot stand on its own as the final return type. // It is incorporated into `context.returnMapper` which is used in `instantiateContextualType`, @@ -35672,8 +62849,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We clone the inference context to avoid disturbing a resolution in progress for an // outer call expression. Effectively we just want a snapshot of whatever has been // inferred for any outer call expression so far. - const outerMapper = getMapperFromContext(cloneInferenceContext(outerContext, InferenceFlags.NoDefault)); - const instantiatedType = instantiateType(contextualType, outerMapper); + const outerMapper = getMapperFromContext( + cloneInferenceContext( + outerContext, + InferenceFlags.NoDefault + ) + ); + const instantiatedType = instantiateType( + contextualType, + outerMapper + ); // If the contextual type is a generic function type with a single call signature, we // instantiate the type with its own type parameters and type arguments. This ensures that // the type parameters are not erased to type any during type inference such that they can @@ -35681,12 +62866,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // declare function arrayMap(f: (x: T) => U): (a: T[]) => U[]; // const boxElements: (a: A[]) => { value: A }[] = arrayMap(value => ({ value })); // Above, the type of the 'value' parameter is inferred to be 'A'. - const contextualSignature = getSingleCallSignature(instantiatedType); - const inferenceSourceType = contextualSignature && contextualSignature.typeParameters ? - getOrCreateTypeFromSignature(getSignatureInstantiationWithoutFillingInTypeArguments(contextualSignature, contextualSignature.typeParameters)) : - instantiatedType; + const contextualSignature = + getSingleCallSignature(instantiatedType); + const inferenceSourceType = + contextualSignature && + contextualSignature.typeParameters + ? getOrCreateTypeFromSignature( + getSignatureInstantiationWithoutFillingInTypeArguments( + contextualSignature, + contextualSignature.typeParameters + ) + ) + : instantiatedType; // Inferences made from return types have lower priority than all other inferences. - inferTypes(context.inferences, inferenceSourceType, inferenceTargetType, InferencePriority.ReturnType); + inferTypes( + context.inferences, + inferenceSourceType, + inferenceTargetType, + InferencePriority.ReturnType + ); } // Create a type mapper for instantiating generic contextual types using the inferences made // from the return type. We need a separate inference pass here because (a) instantiation of @@ -35696,27 +62894,57 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // replaced with inferences produced from the outer return type or preceding outer arguments. // This protects against circular inferences, i.e. avoiding situations where inferences reference // type parameters for which the inferences are being made. - const returnContext = createInferenceContext(signature.typeParameters!, signature, context.flags); - const returnSourceType = instantiateType(contextualType, outerContext && createOuterReturnMapper(outerContext)); - inferTypes(returnContext.inferences, returnSourceType, inferenceTargetType); - context.returnMapper = some(returnContext.inferences, hasInferenceCandidates) ? getMapperFromContext(cloneInferredPartOfContext(returnContext)) : undefined; + const returnContext = createInferenceContext( + signature.typeParameters!, + signature, + context.flags + ); + const returnSourceType = instantiateType( + contextualType, + outerContext && createOuterReturnMapper(outerContext) + ); + inferTypes( + returnContext.inferences, + returnSourceType, + inferenceTargetType + ); + context.returnMapper = some( + returnContext.inferences, + hasInferenceCandidates + ) + ? getMapperFromContext( + cloneInferredPartOfContext(returnContext) + ) + : undefined; } } } const restType = getNonArrayRestType(signature); - const argCount = restType ? Math.min(getParameterCount(signature) - 1, args.length) : args.length; + const argCount = restType + ? Math.min(getParameterCount(signature) - 1, args.length) + : args.length; if (restType && restType.flags & TypeFlags.TypeParameter) { - const info = find(context.inferences, info => info.typeParameter === restType); + const info = find( + context.inferences, + (info) => info.typeParameter === restType + ); if (info) { - info.impliedArity = findIndex(args, isSpreadArgument, argCount) < 0 ? args.length - argCount : undefined; + info.impliedArity = + findIndex(args, isSpreadArgument, argCount) < 0 + ? args.length - argCount + : undefined; } } const thisType = getThisTypeOfSignature(signature); if (thisType && couldContainTypeVariables(thisType)) { const thisArgumentNode = getThisArgumentOfCall(node); - inferTypes(context.inferences, getThisArgumentType(thisArgumentNode), thisType); + inferTypes( + context.inferences, + getThisArgumentType(thisArgumentNode), + thisType + ); } for (let i = 0; i < argCount; i++) { @@ -35724,14 +62952,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (arg.kind !== SyntaxKind.OmittedExpression) { const paramType = getTypeAtPosition(signature, i); if (couldContainTypeVariables(paramType)) { - const argType = checkExpressionWithContextualType(arg, paramType, context, checkMode); + const argType = checkExpressionWithContextualType( + arg, + paramType, + context, + checkMode + ); inferTypes(context.inferences, argType, paramType); } } } if (restType && couldContainTypeVariables(restType)) { - const spreadType = getSpreadArgumentType(args, argCount, args.length, restType, context, checkMode); + const spreadType = getSpreadArgumentType( + args, + argCount, + args.length, + restType, + context, + checkMode + ); inferTypes(context.inferences, spreadType, restType); } @@ -35739,13 +62979,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getMutableArrayOrTupleType(type: Type) { - return type.flags & TypeFlags.Union ? mapType(type, getMutableArrayOrTupleType) : - type.flags & TypeFlags.Any || isMutableArrayOrTuple(getBaseConstraintOfType(type) || type) ? type : - isTupleType(type) ? createTupleType(getElementTypes(type), type.target.elementFlags, /*readonly*/ false, type.target.labeledElementDeclarations) : - createTupleType([type], [ElementFlags.Variadic]); - } - - function getSpreadArgumentType(args: readonly Expression[], index: number, argCount: number, restType: Type, context: InferenceContext | undefined, checkMode: CheckMode) { + return type.flags & TypeFlags.Union + ? mapType(type, getMutableArrayOrTupleType) + : type.flags & TypeFlags.Any || + isMutableArrayOrTuple(getBaseConstraintOfType(type) || type) + ? type + : isTupleType(type) + ? createTupleType( + getElementTypes(type), + type.target.elementFlags, + /*readonly*/ false, + type.target.labeledElementDeclarations + ) + : createTupleType([type], [ElementFlags.Variadic]); + } + + function getSpreadArgumentType( + args: readonly Expression[], + index: number, + argCount: number, + restType: Type, + context: InferenceContext | undefined, + checkMode: CheckMode + ) { const inConstContext = isConstTypeVariable(restType); if (index >= argCount - 1) { @@ -35753,14 +63009,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isSpreadArgument(arg)) { // We are inferring from a spread expression in the last argument position, i.e. both the parameter // and the argument are ...x forms. - const spreadType = arg.kind === SyntaxKind.SyntheticExpression ? (arg as SyntheticExpression).type : - checkExpressionWithContextualType((arg as SpreadElement).expression, restType, context, checkMode); + const spreadType = + arg.kind === SyntaxKind.SyntheticExpression + ? (arg as SyntheticExpression).type + : checkExpressionWithContextualType( + (arg as SpreadElement).expression, + restType, + context, + checkMode + ); if (isArrayLikeType(spreadType)) { return getMutableArrayOrTupleType(spreadType); } - return createArrayType(checkIteratedTypeOrElementType(IterationUse.Spread, spreadType, undefinedType, arg.kind === SyntaxKind.SpreadElement ? (arg as SpreadElement).expression : arg), inConstContext); + return createArrayType( + checkIteratedTypeOrElementType( + IterationUse.Spread, + spreadType, + undefinedType, + arg.kind === SyntaxKind.SpreadElement + ? (arg as SpreadElement).expression + : arg + ), + inConstContext + ); } } const types = []; @@ -35769,57 +63042,127 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (let i = index; i < argCount; i++) { const arg = args[i]; if (isSpreadArgument(arg)) { - const spreadType = arg.kind === SyntaxKind.SyntheticExpression ? (arg as SyntheticExpression).type : checkExpression((arg as SpreadElement).expression); + const spreadType = + arg.kind === SyntaxKind.SyntheticExpression + ? (arg as SyntheticExpression).type + : checkExpression((arg as SpreadElement).expression); if (isArrayLikeType(spreadType)) { types.push(spreadType); flags.push(ElementFlags.Variadic); - } - else { - types.push(checkIteratedTypeOrElementType(IterationUse.Spread, spreadType, undefinedType, arg.kind === SyntaxKind.SpreadElement ? (arg as SpreadElement).expression : arg)); + } else { + types.push( + checkIteratedTypeOrElementType( + IterationUse.Spread, + spreadType, + undefinedType, + arg.kind === SyntaxKind.SpreadElement + ? (arg as SpreadElement).expression + : arg + ) + ); flags.push(ElementFlags.Rest); } - } - else { - const contextualType = isTupleType(restType) ? - getContextualTypeForElementExpression(restType, i - index, argCount - index) || unknownType : - getIndexedAccessType(restType, getNumberLiteralType(i - index), AccessFlags.Contextual); - const argType = checkExpressionWithContextualType(arg, contextualType, context, checkMode); - const hasPrimitiveContextualType = inConstContext || maybeTypeOfKind(contextualType, TypeFlags.Primitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping); - types.push(hasPrimitiveContextualType ? getRegularTypeOfLiteralType(argType) : getWidenedLiteralType(argType)); + } else { + const contextualType = isTupleType(restType) + ? getContextualTypeForElementExpression( + restType, + i - index, + argCount - index + ) || unknownType + : getIndexedAccessType( + restType, + getNumberLiteralType(i - index), + AccessFlags.Contextual + ); + const argType = checkExpressionWithContextualType( + arg, + contextualType, + context, + checkMode + ); + const hasPrimitiveContextualType = + inConstContext || + maybeTypeOfKind( + contextualType, + TypeFlags.Primitive | + TypeFlags.Index | + TypeFlags.TemplateLiteral | + TypeFlags.StringMapping + ); + types.push( + hasPrimitiveContextualType + ? getRegularTypeOfLiteralType(argType) + : getWidenedLiteralType(argType) + ); flags.push(ElementFlags.Required); } - if (arg.kind === SyntaxKind.SyntheticExpression && (arg as SyntheticExpression).tupleNameSource) { + if ( + arg.kind === SyntaxKind.SyntheticExpression && + (arg as SyntheticExpression).tupleNameSource + ) { names.push((arg as SyntheticExpression).tupleNameSource!); - } - else { + } else { names.push(undefined); } } - return createTupleType(types, flags, inConstContext && !someType(restType, isMutableArrayLikeType), names); + return createTupleType( + types, + flags, + inConstContext && !someType(restType, isMutableArrayLikeType), + names + ); } - function checkTypeArguments(signature: Signature, typeArgumentNodes: readonly TypeNode[], reportErrors: boolean, headMessage?: DiagnosticMessage): Type[] | undefined { + function checkTypeArguments( + signature: Signature, + typeArgumentNodes: readonly TypeNode[], + reportErrors: boolean, + headMessage?: DiagnosticMessage + ): Type[] | undefined { const isJavascript = isInJSFile(signature.declaration); const typeParameters = signature.typeParameters!; - const typeArgumentTypes = fillMissingTypeArguments(map(typeArgumentNodes, getTypeFromTypeNode), typeParameters, getMinTypeArgumentCount(typeParameters), isJavascript); + const typeArgumentTypes = fillMissingTypeArguments( + map(typeArgumentNodes, getTypeFromTypeNode), + typeParameters, + getMinTypeArgumentCount(typeParameters), + isJavascript + ); let mapper: TypeMapper | undefined; for (let i = 0; i < typeArgumentNodes.length; i++) { - Debug.assert(typeParameters[i] !== undefined, "Should not call checkTypeArguments with too many type arguments"); + Debug.assert( + typeParameters[i] !== undefined, + "Should not call checkTypeArguments with too many type arguments" + ); const constraint = getConstraintOfTypeParameter(typeParameters[i]); if (constraint) { - const errorInfo = reportErrors && headMessage ? (() => chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Type_0_does_not_satisfy_the_constraint_1)) : undefined; - const typeArgumentHeadMessage = headMessage || Diagnostics.Type_0_does_not_satisfy_the_constraint_1; + const errorInfo = + reportErrors && headMessage + ? () => + chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Type_0_does_not_satisfy_the_constraint_1 + ) + : undefined; + const typeArgumentHeadMessage = + headMessage || + Diagnostics.Type_0_does_not_satisfy_the_constraint_1; if (!mapper) { - mapper = createTypeMapper(typeParameters, typeArgumentTypes); + mapper = createTypeMapper( + typeParameters, + typeArgumentTypes + ); } const typeArgument = typeArgumentTypes[i]; if ( !checkTypeAssignableTo( typeArgument, - getTypeWithThisArgument(instantiateType(constraint, mapper), typeArgument), + getTypeWithThisArgument( + instantiateType(constraint, mapper), + typeArgument + ), reportErrors ? typeArgumentNodes[i] : undefined, typeArgumentHeadMessage, - errorInfo, + errorInfo ) ) { return undefined; @@ -35829,7 +63172,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return typeArgumentTypes; } - function getJsxReferenceKind(node: JsxOpeningLikeElement): JsxReferenceKind { + function getJsxReferenceKind( + node: JsxOpeningLikeElement + ): JsxReferenceKind { if (isJsxIntrinsicTagName(node.tagName)) { return JsxReferenceKind.Mixed; } @@ -35855,24 +63200,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { relation: Map, checkMode: CheckMode, reportErrors: boolean, - containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, - errorOutputContainer: ErrorOutputContainer, + containingMessageChain: + | (() => DiagnosticMessageChain | undefined) + | undefined, + errorOutputContainer: ErrorOutputContainer ) { // Stateless function components can have maximum of three arguments: "props", "context", and "updater". // However "context" and "updater" are implicit and can't be specify by users. Only the first parameter, props, // can be specified by users through attributes property. - const paramType = getEffectiveFirstArgumentForJsxSignature(signature, node); - const attributesType = isJsxOpeningFragment(node) ? createJsxAttributesTypeFromAttributesProperty(node) : checkExpressionWithContextualType(node.attributes, paramType, /*inferenceContext*/ undefined, checkMode); - const checkAttributesType = checkMode & CheckMode.SkipContextSensitive ? getRegularTypeOfObjectLiteral(attributesType) : attributesType; - return checkTagNameDoesNotExpectTooManyArguments() && checkTypeRelatedToAndOptionallyElaborate( - checkAttributesType, - paramType, - relation, - reportErrors ? isJsxOpeningFragment(node) ? node : node.tagName : undefined, - isJsxOpeningFragment(node) ? undefined : node.attributes, - /*headMessage*/ undefined, - containingMessageChain, - errorOutputContainer, + const paramType = getEffectiveFirstArgumentForJsxSignature( + signature, + node + ); + const attributesType = isJsxOpeningFragment(node) + ? createJsxAttributesTypeFromAttributesProperty(node) + : checkExpressionWithContextualType( + node.attributes, + paramType, + /*inferenceContext*/ undefined, + checkMode + ); + const checkAttributesType = + checkMode & CheckMode.SkipContextSensitive + ? getRegularTypeOfObjectLiteral(attributesType) + : attributesType; + return ( + checkTagNameDoesNotExpectTooManyArguments() && + checkTypeRelatedToAndOptionallyElaborate( + checkAttributesType, + paramType, + relation, + reportErrors + ? isJsxOpeningFragment(node) + ? node + : node.tagName + : undefined, + isJsxOpeningFragment(node) ? undefined : node.attributes, + /*headMessage*/ undefined, + containingMessageChain, + errorOutputContainer + ) ); function checkTagNameDoesNotExpectTooManyArguments(): boolean { @@ -35881,11 +63248,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // We assume fragments have the correct arity since the node does not have attributes - const tagType = (isJsxOpeningElement(node) || isJsxSelfClosingElement(node)) && !(isJsxIntrinsicTagName(node.tagName) || isJsxNamespacedName(node.tagName)) ? checkExpression(node.tagName) : undefined; + const tagType = + (isJsxOpeningElement(node) || isJsxSelfClosingElement(node)) && + !( + isJsxIntrinsicTagName(node.tagName) || + isJsxNamespacedName(node.tagName) + ) + ? checkExpression(node.tagName) + : undefined; if (!tagType) { return true; } - const tagCallSignatures = getSignaturesOfType(tagType, SignatureKind.Call); + const tagCallSignatures = getSignaturesOfType( + tagType, + SignatureKind.Call + ); if (!length(tagCallSignatures)) { return true; } @@ -35893,13 +63270,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!factory) { return true; } - const factorySymbol = resolveEntityName(factory, SymbolFlags.Value, /*ignoreErrors*/ true, /*dontResolveAlias*/ false, node); + const factorySymbol = resolveEntityName( + factory, + SymbolFlags.Value, + /*ignoreErrors*/ true, + /*dontResolveAlias*/ false, + node + ); if (!factorySymbol) { return true; } const factoryType = getTypeOfSymbol(factorySymbol); - const callSignatures = getSignaturesOfType(factoryType, SignatureKind.Call); + const callSignatures = getSignaturesOfType( + factoryType, + SignatureKind.Call + ); if (!length(callSignatures)) { return true; } @@ -35909,7 +63295,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Check that _some_ first parameter expects a FC-like thing, and that some overload of the SFC expects an acceptable number of arguments for (const sig of callSignatures) { const firstparam = getTypeAtPosition(sig, 0); - const signaturesOfParam = getSignaturesOfType(firstparam, SignatureKind.Call); + const signaturesOfParam = getSignaturesOfType( + firstparam, + SignatureKind.Call + ); if (!length(signaturesOfParam)) continue; for (const paramSig of signaturesOfParam) { hasFirstParamSignatures = true; @@ -35940,14 +63329,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (reportErrors) { // We will not report errors in this function for fragments, since we do not check them in this function - const tagName = (node as JsxOpeningElement | JsxSelfClosingElement).tagName; - const diag = createDiagnosticForNode(tagName, Diagnostics.Tag_0_expects_at_least_1_arguments_but_the_JSX_factory_2_provides_at_most_3, entityNameToString(tagName), absoluteMinArgCount, entityNameToString(factory), maxParamCount); - const tagNameDeclaration = getSymbolAtLocation(tagName)?.valueDeclaration; + const tagName = ( + node as JsxOpeningElement | JsxSelfClosingElement + ).tagName; + const diag = createDiagnosticForNode( + tagName, + Diagnostics.Tag_0_expects_at_least_1_arguments_but_the_JSX_factory_2_provides_at_most_3, + entityNameToString(tagName), + absoluteMinArgCount, + entityNameToString(factory), + maxParamCount + ); + const tagNameDeclaration = + getSymbolAtLocation(tagName)?.valueDeclaration; if (tagNameDeclaration) { - addRelatedInfo(diag, createDiagnosticForNode(tagNameDeclaration, Diagnostics._0_is_declared_here, entityNameToString(tagName))); + addRelatedInfo( + diag, + createDiagnosticForNode( + tagNameDeclaration, + Diagnostics._0_is_declared_here, + entityNameToString(tagName) + ) + ); } if (errorOutputContainer && errorOutputContainer.skipLogging) { - (errorOutputContainer.errors || (errorOutputContainer.errors = [])).push(diag); + ( + errorOutputContainer.errors || + (errorOutputContainer.errors = []) + ).push(diag); } if (!errorOutputContainer.skipLogging) { diagnostics.add(diag); @@ -35959,7 +63368,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getEffectiveCheckNode(argument: Expression): Expression { const flags = isInJSFile(argument) - ? OuterExpressionKinds.Parentheses | OuterExpressionKinds.Satisfies | OuterExpressionKinds.ExcludeJSDocTypeAssertion + ? OuterExpressionKinds.Parentheses | + OuterExpressionKinds.Satisfies | + OuterExpressionKinds.ExcludeJSDocTypeAssertion : OuterExpressionKinds.Parentheses | OuterExpressionKinds.Satisfies; return skipOuterExpressions(argument, flags); } @@ -35971,74 +63382,185 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { relation: Map, checkMode: CheckMode, reportErrors: boolean, - containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, + containingMessageChain: + | (() => DiagnosticMessageChain | undefined) + | undefined ): readonly Diagnostic[] | undefined { - const errorOutputContainer: ErrorOutputContainer = { errors: undefined, skipLogging: true }; + const errorOutputContainer: ErrorOutputContainer = { + errors: undefined, + skipLogging: true, + }; if (isJsxCallLike(node)) { - if (!checkApplicableSignatureForJsxCallLikeElement(node, signature, relation, checkMode, reportErrors, containingMessageChain, errorOutputContainer)) { - Debug.assert(!reportErrors || !!errorOutputContainer.errors, "jsx should have errors when reporting errors"); + if ( + !checkApplicableSignatureForJsxCallLikeElement( + node, + signature, + relation, + checkMode, + reportErrors, + containingMessageChain, + errorOutputContainer + ) + ) { + Debug.assert( + !reportErrors || !!errorOutputContainer.errors, + "jsx should have errors when reporting errors" + ); return errorOutputContainer.errors || emptyArray; } return undefined; } const thisType = getThisTypeOfSignature(signature); - if (thisType && thisType !== voidType && !(isNewExpression(node) || isCallExpression(node) && isSuperProperty(node.expression))) { + if ( + thisType && + thisType !== voidType && + !( + isNewExpression(node) || + (isCallExpression(node) && isSuperProperty(node.expression)) + ) + ) { // If the called expression is not of the form `x.f` or `x["f"]`, then sourceType = voidType // If the signature's 'this' type is voidType, then the check is skipped -- anything is compatible. // If the expression is a new expression or super call expression, then the check is skipped. const thisArgumentNode = getThisArgumentOfCall(node); const thisArgumentType = getThisArgumentType(thisArgumentNode); - const errorNode = reportErrors ? (thisArgumentNode || node) : undefined; - const headMessage = Diagnostics.The_this_context_of_type_0_is_not_assignable_to_method_s_this_of_type_1; - if (!checkTypeRelatedTo(thisArgumentType, thisType, relation, errorNode, headMessage, containingMessageChain, errorOutputContainer)) { - Debug.assert(!reportErrors || !!errorOutputContainer.errors, "this parameter should have errors when reporting errors"); + const errorNode = reportErrors + ? thisArgumentNode || node + : undefined; + const headMessage = + Diagnostics.The_this_context_of_type_0_is_not_assignable_to_method_s_this_of_type_1; + if ( + !checkTypeRelatedTo( + thisArgumentType, + thisType, + relation, + errorNode, + headMessage, + containingMessageChain, + errorOutputContainer + ) + ) { + Debug.assert( + !reportErrors || !!errorOutputContainer.errors, + "this parameter should have errors when reporting errors" + ); return errorOutputContainer.errors || emptyArray; } } - const headMessage = Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1; + const headMessage = + Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1; const restType = getNonArrayRestType(signature); - const argCount = restType ? Math.min(getParameterCount(signature) - 1, args.length) : args.length; + const argCount = restType + ? Math.min(getParameterCount(signature) - 1, args.length) + : args.length; for (let i = 0; i < argCount; i++) { const arg = args[i]; if (arg.kind !== SyntaxKind.OmittedExpression) { const paramType = getTypeAtPosition(signature, i); - const argType = checkExpressionWithContextualType(arg, paramType, /*inferenceContext*/ undefined, checkMode); + const argType = checkExpressionWithContextualType( + arg, + paramType, + /*inferenceContext*/ undefined, + checkMode + ); // If one or more arguments are still excluded (as indicated by CheckMode.SkipContextSensitive), // we obtain the regular type of any object literal arguments because we may not have inferred complete // parameter types yet and therefore excess property checks may yield false positives (see #17041). - const checkArgType = checkMode & CheckMode.SkipContextSensitive ? getRegularTypeOfObjectLiteral(argType) : argType; + const checkArgType = + checkMode & CheckMode.SkipContextSensitive + ? getRegularTypeOfObjectLiteral(argType) + : argType; const effectiveCheckArgumentNode = getEffectiveCheckNode(arg); - if (!checkTypeRelatedToAndOptionallyElaborate(checkArgType, paramType, relation, reportErrors ? effectiveCheckArgumentNode : undefined, effectiveCheckArgumentNode, headMessage, containingMessageChain, errorOutputContainer)) { - Debug.assert(!reportErrors || !!errorOutputContainer.errors, "parameter should have errors when reporting errors"); + if ( + !checkTypeRelatedToAndOptionallyElaborate( + checkArgType, + paramType, + relation, + reportErrors ? effectiveCheckArgumentNode : undefined, + effectiveCheckArgumentNode, + headMessage, + containingMessageChain, + errorOutputContainer + ) + ) { + Debug.assert( + !reportErrors || !!errorOutputContainer.errors, + "parameter should have errors when reporting errors" + ); maybeAddMissingAwaitInfo(arg, checkArgType, paramType); return errorOutputContainer.errors || emptyArray; } } } if (restType) { - const spreadType = getSpreadArgumentType(args, argCount, args.length, restType, /*context*/ undefined, checkMode); + const spreadType = getSpreadArgumentType( + args, + argCount, + args.length, + restType, + /*context*/ undefined, + checkMode + ); const restArgCount = args.length - argCount; - const errorNode = !reportErrors ? undefined : - restArgCount === 0 ? node : - restArgCount === 1 ? getEffectiveCheckNode(args[argCount]) : - setTextRangePosEnd(createSyntheticExpression(node, spreadType), args[argCount].pos, args[args.length - 1].end); - if (!checkTypeRelatedTo(spreadType, restType, relation, errorNode, headMessage, /*containingMessageChain*/ undefined, errorOutputContainer)) { - Debug.assert(!reportErrors || !!errorOutputContainer.errors, "rest parameter should have errors when reporting errors"); + const errorNode = !reportErrors + ? undefined + : restArgCount === 0 + ? node + : restArgCount === 1 + ? getEffectiveCheckNode(args[argCount]) + : setTextRangePosEnd( + createSyntheticExpression(node, spreadType), + args[argCount].pos, + args[args.length - 1].end + ); + if ( + !checkTypeRelatedTo( + spreadType, + restType, + relation, + errorNode, + headMessage, + /*containingMessageChain*/ undefined, + errorOutputContainer + ) + ) { + Debug.assert( + !reportErrors || !!errorOutputContainer.errors, + "rest parameter should have errors when reporting errors" + ); maybeAddMissingAwaitInfo(errorNode, spreadType, restType); return errorOutputContainer.errors || emptyArray; } } return undefined; - function maybeAddMissingAwaitInfo(errorNode: Node | undefined, source: Type, target: Type) { - if (errorNode && reportErrors && errorOutputContainer.errors && errorOutputContainer.errors.length) { + function maybeAddMissingAwaitInfo( + errorNode: Node | undefined, + source: Type, + target: Type + ) { + if ( + errorNode && + reportErrors && + errorOutputContainer.errors && + errorOutputContainer.errors.length + ) { // Bail if target is Promise-like---something else is wrong if (getAwaitedTypeOfPromise(target)) { return; } const awaitedTypeOfSource = getAwaitedTypeOfPromise(source); - if (awaitedTypeOfSource && isTypeRelatedTo(awaitedTypeOfSource, target, relation)) { - addRelatedInfo(errorOutputContainer.errors[0], createDiagnosticForNode(errorNode, Diagnostics.Did_you_forget_to_use_await)); + if ( + awaitedTypeOfSource && + isTypeRelatedTo(awaitedTypeOfSource, target, relation) + ) { + addRelatedInfo( + errorOutputContainer.errors[0], + createDiagnosticForNode( + errorNode, + Diagnostics.Did_you_forget_to_use_await + ) + ); } } } @@ -36047,15 +63569,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** * Returns the this argument in calls like x.f(...) and x[f](...). Undefined otherwise. */ - function getThisArgumentOfCall(node: CallLikeExpression): Expression | undefined { + function getThisArgumentOfCall( + node: CallLikeExpression + ): Expression | undefined { if (node.kind === SyntaxKind.BinaryExpression) { return node.right; } - const expression = node.kind === SyntaxKind.CallExpression ? node.expression : - node.kind === SyntaxKind.TaggedTemplateExpression ? node.tag : - node.kind === SyntaxKind.Decorator && !legacyDecorators ? node.expression : - undefined; + const expression = + node.kind === SyntaxKind.CallExpression + ? node.expression + : node.kind === SyntaxKind.TaggedTemplateExpression + ? node.tag + : node.kind === SyntaxKind.Decorator && !legacyDecorators + ? node.expression + : undefined; if (expression) { const callee = skipOuterExpressions(expression); if (isAccessExpression(callee)) { @@ -36064,8 +63592,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function createSyntheticExpression(parent: Node, type: Type, isSpread?: boolean, tupleNameSource?: ParameterDeclaration | NamedTupleMember) { - const result = parseNodeFactory.createSyntheticExpression(type, isSpread, tupleNameSource); + function createSyntheticExpression( + parent: Node, + type: Type, + isSpread?: boolean, + tupleNameSource?: ParameterDeclaration | NamedTupleMember + ) { + const result = parseNodeFactory.createSyntheticExpression( + type, + isSpread, + tupleNameSource + ); setTextRangeWorker(result, parent); setParent(result, parent); return result; @@ -36074,7 +63611,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** * Returns the effective arguments for an expression that works like a function invocation. */ - function getEffectiveCallArguments(node: CallLikeExpression): readonly Expression[] { + function getEffectiveCallArguments( + node: CallLikeExpression + ): readonly Expression[] { if (isJsxOpeningFragment(node)) { // This attributes Type does not include a children property yet, the same way a fragment created with does not at this stage return [createSyntheticExpression(node, emptyFreshJsxObjectType)]; @@ -36082,9 +63621,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (node.kind === SyntaxKind.TaggedTemplateExpression) { const template = node.template; - const args: Expression[] = [createSyntheticExpression(template, getGlobalTemplateStringsArrayType())]; + const args: Expression[] = [ + createSyntheticExpression( + template, + getGlobalTemplateStringsArrayType() + ), + ]; if (template.kind === SyntaxKind.TemplateExpression) { - forEach(template.templateSpans, span => { + forEach(template.templateSpans, (span) => { args.push(span.expression); }); } @@ -36097,7 +63641,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return [node.left]; } if (isJsxOpeningLikeElement(node)) { - return node.attributes.properties.length > 0 || (isJsxOpeningElement(node) && node.parent.children.length > 0) ? [node.attributes] : emptyArray; + return node.attributes.properties.length > 0 || + (isJsxOpeningElement(node) && node.parent.children.length > 0) + ? [node.attributes] + : emptyArray; } const args = node.arguments || emptyArray; const spreadIndex = getSpreadArgumentIndex(args); @@ -36107,15 +63654,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (let i = spreadIndex; i < args.length; i++) { const arg = args[i]; // We can call checkExpressionCached because spread expressions never have a contextual type. - const spreadType = arg.kind === SyntaxKind.SpreadElement && (flowLoopCount ? checkExpression((arg as SpreadElement).expression) : checkExpressionCached((arg as SpreadElement).expression)); + const spreadType = + arg.kind === SyntaxKind.SpreadElement && + (flowLoopCount + ? checkExpression((arg as SpreadElement).expression) + : checkExpressionCached( + (arg as SpreadElement).expression + )); if (spreadType && isTupleType(spreadType)) { forEach(getElementTypes(spreadType), (t, i) => { const flags = spreadType.target.elementFlags[i]; - const syntheticArg = createSyntheticExpression(arg, flags & ElementFlags.Rest ? createArrayType(t) : t, !!(flags & ElementFlags.Variable), spreadType.target.labeledElementDeclarations?.[i]); + const syntheticArg = createSyntheticExpression( + arg, + flags & ElementFlags.Rest ? createArrayType(t) : t, + !!(flags & ElementFlags.Variable), + spreadType.target.labeledElementDeclarations?.[i] + ); effectiveArgs.push(syntheticArg); }); - } - else { + } else { effectiveArgs.push(arg); } } @@ -36127,7 +63684,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** * Returns the synthetic argument list for a decorator invocation. */ - function getEffectiveDecoratorArguments(node: Decorator): readonly Expression[] { + function getEffectiveDecoratorArguments( + node: Decorator + ): readonly Expression[] { const expr = node.expression; const signature = getDecoratorCallSignature(node); if (signature) { @@ -36145,16 +63704,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Returns the argument count for a decorator node that works like a function invocation. */ function getDecoratorArgumentCount(node: Decorator, signature: Signature) { - return compilerOptions.experimentalDecorators ? - getLegacyDecoratorArgumentCount(node, signature) : - // Allow the runtime to oversupply arguments to an ES decorator as long as there's at least one parameter. - Math.min(Math.max(getParameterCount(signature), 1), 2); + return compilerOptions.experimentalDecorators + ? getLegacyDecoratorArgumentCount(node, signature) + : // Allow the runtime to oversupply arguments to an ES decorator as long as there's at least one parameter. + Math.min(Math.max(getParameterCount(signature), 1), 2); } /** * Returns the argument count for a decorator node that works like a function invocation. */ - function getLegacyDecoratorArgumentCount(node: Decorator, signature: Signature) { + function getLegacyDecoratorArgumentCount( + node: Decorator, + signature: Signature + ) { switch (node.parent.kind) { case SyntaxKind.ClassDeclaration: case SyntaxKind.ClassExpression: @@ -36175,32 +63737,55 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getDiagnosticSpanForCallNode(node: CallExpression) { const sourceFile = getSourceFileOfNode(node); - const { start, length } = getErrorSpanForNode(sourceFile, isPropertyAccessExpression(node.expression) ? node.expression.name : node.expression); + const { start, length } = getErrorSpanForNode( + sourceFile, + isPropertyAccessExpression(node.expression) + ? node.expression.name + : node.expression + ); return { start, length, sourceFile }; } - function getDiagnosticForCallNode(node: CallLikeExpression, message: DiagnosticMessage | DiagnosticMessageChain, ...args: DiagnosticArguments): DiagnosticWithLocation { + function getDiagnosticForCallNode( + node: CallLikeExpression, + message: DiagnosticMessage | DiagnosticMessageChain, + ...args: DiagnosticArguments + ): DiagnosticWithLocation { if (isCallExpression(node)) { - const { sourceFile, start, length } = getDiagnosticSpanForCallNode(node); - if ("message" in message) { // eslint-disable-line local/no-in-operator - return createFileDiagnostic(sourceFile, start, length, message, ...args); + const { sourceFile, start, length } = + getDiagnosticSpanForCallNode(node); + if ("message" in message) { + return createFileDiagnostic( + sourceFile, + start, + length, + message, + ...args + ); } return createDiagnosticForFileFromMessageChain(sourceFile, message); - } - else { - if ("message" in message) { // eslint-disable-line local/no-in-operator + } else { + if ("message" in message) { return createDiagnosticForNode(node, message, ...args); } - return createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(node), node, message); + return createDiagnosticForNodeFromMessageChain( + getSourceFileOfNode(node), + node, + message + ); } } function getErrorNodeForCallNode(callLike: CallLikeExpression): Node { if (isCallOrNewExpression(callLike)) { - return isPropertyAccessExpression(callLike.expression) ? callLike.expression.name : callLike.expression; + return isPropertyAccessExpression(callLike.expression) + ? callLike.expression.name + : callLike.expression; } if (isTaggedTemplateExpression(callLike)) { - return isPropertyAccessExpression(callLike.tag) ? callLike.tag.name : callLike.tag; + return isPropertyAccessExpression(callLike.tag) + ? callLike.tag.name + : callLike.tag; } if (isJsxOpeningLikeElement(callLike)) { return callLike.tagName; @@ -36209,25 +63794,51 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isPromiseResolveArityError(node: CallLikeExpression) { - if (!isCallExpression(node) || !isIdentifier(node.expression)) return false; + if (!isCallExpression(node) || !isIdentifier(node.expression)) + return false; - const symbol = resolveName(node.expression, node.expression.escapedText, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*isUse*/ false); + const symbol = resolveName( + node.expression, + node.expression.escapedText, + SymbolFlags.Value, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ false + ); const decl = symbol?.valueDeclaration; - if (!decl || !isParameter(decl) || !isFunctionExpressionOrArrowFunction(decl.parent) || !isNewExpression(decl.parent.parent) || !isIdentifier(decl.parent.parent.expression)) { + if ( + !decl || + !isParameter(decl) || + !isFunctionExpressionOrArrowFunction(decl.parent) || + !isNewExpression(decl.parent.parent) || + !isIdentifier(decl.parent.parent.expression) + ) { return false; } - const globalPromiseSymbol = getGlobalPromiseConstructorSymbol(/*reportErrors*/ false); + const globalPromiseSymbol = getGlobalPromiseConstructorSymbol( + /*reportErrors*/ false + ); if (!globalPromiseSymbol) return false; - const constructorSymbol = getSymbolAtLocation(decl.parent.parent.expression, /*ignoreErrors*/ true); + const constructorSymbol = getSymbolAtLocation( + decl.parent.parent.expression, + /*ignoreErrors*/ true + ); return constructorSymbol === globalPromiseSymbol; } - function getArgumentArityError(node: CallLikeExpression, signatures: readonly Signature[], args: readonly Expression[], headMessage?: DiagnosticMessage) { + function getArgumentArityError( + node: CallLikeExpression, + signatures: readonly Signature[], + args: readonly Expression[], + headMessage?: DiagnosticMessage + ) { const spreadIndex = getSpreadArgumentIndex(args); if (spreadIndex > -1) { - return createDiagnosticForNode(args[spreadIndex], Diagnostics.A_spread_argument_must_either_have_a_tuple_type_or_be_passed_to_a_rest_parameter); + return createDiagnosticForNode( + args[spreadIndex], + Diagnostics.A_spread_argument_must_either_have_a_tuple_type_or_be_passed_to_a_rest_parameter + ); } let min = Number.POSITIVE_INFINITY; // smallest parameter count let max = Number.NEGATIVE_INFINITY; // largest parameter count @@ -36245,55 +63856,110 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } max = Math.max(max, maxParameter); // shortest parameter count *longer than the call*/longest parameter count *shorter than the call* - if (minParameter < args.length && minParameter > maxBelow) maxBelow = minParameter; - if (args.length < maxParameter && maxParameter < minAbove) minAbove = maxParameter; + if (minParameter < args.length && minParameter > maxBelow) + maxBelow = minParameter; + if (args.length < maxParameter && maxParameter < minAbove) + minAbove = maxParameter; } const hasRestParameter = some(signatures, hasEffectiveRestParameter); - const parameterRange = hasRestParameter ? min - : min < max ? min + "-" + max + const parameterRange = hasRestParameter + ? min + : min < max + ? min + "-" + max : min; - const isVoidPromiseError = !hasRestParameter && parameterRange === 1 && args.length === 0 && isPromiseResolveArityError(node); + const isVoidPromiseError = + !hasRestParameter && + parameterRange === 1 && + args.length === 0 && + isPromiseResolveArityError(node); if (isVoidPromiseError && isInJSFile(node)) { - 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); + 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 + ); } - const error = isDecorator(node) ? - hasRestParameter ? Diagnostics.The_runtime_will_invoke_the_decorator_with_1_arguments_but_the_decorator_expects_at_least_0 : - Diagnostics.The_runtime_will_invoke_the_decorator_with_1_arguments_but_the_decorator_expects_0 : - hasRestParameter ? Diagnostics.Expected_at_least_0_arguments_but_got_1 : - isVoidPromiseError ? Diagnostics.Expected_0_arguments_but_got_1_Did_you_forget_to_include_void_in_your_type_argument_to_Promise : - Diagnostics.Expected_0_arguments_but_got_1; + const error = isDecorator(node) + ? hasRestParameter + ? Diagnostics.The_runtime_will_invoke_the_decorator_with_1_arguments_but_the_decorator_expects_at_least_0 + : Diagnostics.The_runtime_will_invoke_the_decorator_with_1_arguments_but_the_decorator_expects_0 + : hasRestParameter + ? Diagnostics.Expected_at_least_0_arguments_but_got_1 + : isVoidPromiseError + ? Diagnostics.Expected_0_arguments_but_got_1_Did_you_forget_to_include_void_in_your_type_argument_to_Promise + : Diagnostics.Expected_0_arguments_but_got_1; if (min < args.length && args.length < max) { // between min and max, but with no matching overload if (headMessage) { - let chain = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.No_overload_expects_0_arguments_but_overloads_do_exist_that_expect_either_1_or_2_arguments, args.length, maxBelow, minAbove); + let chain = chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.No_overload_expects_0_arguments_but_overloads_do_exist_that_expect_either_1_or_2_arguments, + args.length, + maxBelow, + minAbove + ); chain = chainDiagnosticMessages(chain, headMessage); return getDiagnosticForCallNode(node, chain); } - return getDiagnosticForCallNode(node, Diagnostics.No_overload_expects_0_arguments_but_overloads_do_exist_that_expect_either_1_or_2_arguments, args.length, maxBelow, minAbove); - } - else if (args.length < min) { + return getDiagnosticForCallNode( + node, + Diagnostics.No_overload_expects_0_arguments_but_overloads_do_exist_that_expect_either_1_or_2_arguments, + args.length, + maxBelow, + minAbove + ); + } else if (args.length < min) { // too short: put the error span on the call expression, not any of the args let diagnostic: Diagnostic; if (headMessage) { - let chain = chainDiagnosticMessages(/*details*/ undefined, error, parameterRange, args.length); + let chain = chainDiagnosticMessages( + /*details*/ undefined, + error, + parameterRange, + args.length + ); chain = chainDiagnosticMessages(chain, headMessage); diagnostic = getDiagnosticForCallNode(node, chain); + } else { + diagnostic = getDiagnosticForCallNode( + node, + error, + parameterRange, + args.length + ); } - else { - diagnostic = getDiagnosticForCallNode(node, error, parameterRange, args.length); - } - const parameter = closestSignature?.declaration?.parameters[closestSignature.thisParameter ? args.length + 1 : args.length]; + const parameter = + closestSignature?.declaration?.parameters[ + closestSignature.thisParameter + ? args.length + 1 + : args.length + ]; if (parameter) { - const messageAndArgs: DiagnosticAndArguments = isBindingPattern(parameter.name) ? [Diagnostics.An_argument_matching_this_binding_pattern_was_not_provided] - : isRestParameter(parameter) ? [Diagnostics.Arguments_for_the_rest_parameter_0_were_not_provided, idText(getFirstIdentifier(parameter.name))] - : [Diagnostics.An_argument_for_0_was_not_provided, !parameter.name ? args.length : idText(getFirstIdentifier(parameter.name))]; - const parameterError = createDiagnosticForNode(parameter, ...messageAndArgs); + const messageAndArgs: DiagnosticAndArguments = isBindingPattern( + parameter.name + ) + ? [ + Diagnostics.An_argument_matching_this_binding_pattern_was_not_provided, + ] + : isRestParameter(parameter) + ? [ + Diagnostics.Arguments_for_the_rest_parameter_0_were_not_provided, + idText(getFirstIdentifier(parameter.name)), + ] + : [ + Diagnostics.An_argument_for_0_was_not_provided, + !parameter.name + ? args.length + : idText(getFirstIdentifier(parameter.name)), + ]; + const parameterError = createDiagnosticForNode( + parameter, + ...messageAndArgs + ); return addRelatedInfo(diagnostic, parameterError); } return diagnostic; - } - else { + } else { // too long; error goes on the excess parameters const errorSpan = factory.createNodeArray(args.slice(max)); const pos = first(errorSpan).pos; @@ -36303,15 +63969,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } setTextRangePosEnd(errorSpan, pos, end); if (headMessage) { - let chain = chainDiagnosticMessages(/*details*/ undefined, error, parameterRange, args.length); + let chain = chainDiagnosticMessages( + /*details*/ undefined, + error, + parameterRange, + args.length + ); chain = chainDiagnosticMessages(chain, headMessage); - return createDiagnosticForNodeArrayFromMessageChain(getSourceFileOfNode(node), errorSpan, chain); + return createDiagnosticForNodeArrayFromMessageChain( + getSourceFileOfNode(node), + errorSpan, + chain + ); } - return createDiagnosticForNodeArray(getSourceFileOfNode(node), errorSpan, error, parameterRange, args.length); + return createDiagnosticForNodeArray( + getSourceFileOfNode(node), + errorSpan, + error, + parameterRange, + args.length + ); } } - function getTypeArgumentArityError(node: Node, signatures: readonly Signature[], typeArguments: NodeArray, headMessage?: DiagnosticMessage) { + function getTypeArgumentArityError( + node: Node, + signatures: readonly Signature[], + typeArguments: NodeArray, + headMessage?: DiagnosticMessage + ) { const argCount = typeArguments.length; // No overloads exist if (signatures.length === 1) { @@ -36319,11 +64005,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const min = getMinTypeArgumentCount(sig.typeParameters); const max = length(sig.typeParameters); if (headMessage) { - let chain = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Expected_0_type_arguments_but_got_1, min < max ? min + "-" + max : min, argCount); + let chain = chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Expected_0_type_arguments_but_got_1, + min < max ? min + "-" + max : min, + argCount + ); chain = chainDiagnosticMessages(chain, headMessage); - return createDiagnosticForNodeArrayFromMessageChain(getSourceFileOfNode(node), typeArguments, chain); + return createDiagnosticForNodeArrayFromMessageChain( + getSourceFileOfNode(node), + typeArguments, + chain + ); } - return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, min < max ? min + "-" + max : min, argCount); + return createDiagnosticForNodeArray( + getSourceFileOfNode(node), + typeArguments, + Diagnostics.Expected_0_type_arguments_but_got_1, + min < max ? min + "-" + max : min, + argCount + ); } // Overloads exist let belowArgCount = -Infinity; @@ -36333,34 +64034,74 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const max = length(sig.typeParameters); if (min > argCount) { aboveArgCount = Math.min(aboveArgCount, min); - } - else if (max < argCount) { + } else if (max < argCount) { belowArgCount = Math.max(belowArgCount, max); } } if (belowArgCount !== -Infinity && aboveArgCount !== Infinity) { if (headMessage) { - let chain = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.No_overload_expects_0_type_arguments_but_overloads_do_exist_that_expect_either_1_or_2_type_arguments, argCount, belowArgCount, aboveArgCount); + let chain = chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.No_overload_expects_0_type_arguments_but_overloads_do_exist_that_expect_either_1_or_2_type_arguments, + argCount, + belowArgCount, + aboveArgCount + ); chain = chainDiagnosticMessages(chain, headMessage); - return createDiagnosticForNodeArrayFromMessageChain(getSourceFileOfNode(node), typeArguments, chain); + return createDiagnosticForNodeArrayFromMessageChain( + getSourceFileOfNode(node), + typeArguments, + chain + ); } - 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); + 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 + ); } if (headMessage) { - let chain = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Expected_0_type_arguments_but_got_1, belowArgCount === -Infinity ? aboveArgCount : belowArgCount, argCount); + let chain = chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Expected_0_type_arguments_but_got_1, + belowArgCount === -Infinity ? aboveArgCount : belowArgCount, + argCount + ); chain = chainDiagnosticMessages(chain, headMessage); - return createDiagnosticForNodeArrayFromMessageChain(getSourceFileOfNode(node), typeArguments, chain); + return createDiagnosticForNodeArrayFromMessageChain( + getSourceFileOfNode(node), + typeArguments, + chain + ); } - return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, belowArgCount === -Infinity ? aboveArgCount : belowArgCount, argCount); + return createDiagnosticForNodeArray( + getSourceFileOfNode(node), + typeArguments, + Diagnostics.Expected_0_type_arguments_but_got_1, + belowArgCount === -Infinity ? aboveArgCount : belowArgCount, + argCount + ); } - function resolveCall(node: CallLikeExpression, signatures: readonly Signature[], candidatesOutArray: Signature[] | undefined, checkMode: CheckMode, callChainFlags: SignatureFlags, headMessage?: DiagnosticMessage): Signature { - const isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression; + function resolveCall( + node: CallLikeExpression, + signatures: readonly Signature[], + candidatesOutArray: Signature[] | undefined, + checkMode: CheckMode, + callChainFlags: SignatureFlags, + headMessage?: DiagnosticMessage + ): Signature { + const isTaggedTemplate = + node.kind === SyntaxKind.TaggedTemplateExpression; const isDecorator = node.kind === SyntaxKind.Decorator; const isJsxOpeningOrSelfClosingElement = isJsxOpeningLikeElement(node); const isJsxOpenFragment = isJsxOpeningFragment(node); const isInstanceof = node.kind === SyntaxKind.BinaryExpression; - const reportErrors = !isInferencePartiallyBlocked && !candidatesOutArray; + const reportErrors = + !isInferencePartiallyBlocked && !candidatesOutArray; // The following variables are captured and modified by calls to chooseOverload. // If overload resolution or type argument inference fails, we want to report the @@ -36391,11 +64132,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let candidates: Signature[] = []; let typeArguments: NodeArray | undefined; - if (!isDecorator && !isInstanceof && !isSuperCall(node) && !isJsxOpenFragment) { + if ( + !isDecorator && + !isInstanceof && + !isSuperCall(node) && + !isJsxOpenFragment + ) { typeArguments = (node as CallExpression).typeArguments; // We already perform checking on the type arguments on the class declaration itself. - if (isTaggedTemplate || isJsxOpeningOrSelfClosingElement || (node as CallExpression).expression.kind !== SyntaxKind.SuperKeyword) { + if ( + isTaggedTemplate || + isJsxOpeningOrSelfClosingElement || + (node as CallExpression).expression.kind !== + SyntaxKind.SuperKeyword + ) { forEach(typeArguments, checkSourceElement); } } @@ -36404,7 +64155,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // reorderCandidates fills up the candidates array directly reorderCandidates(signatures, candidates, callChainFlags); if (!isJsxOpenFragment) { - Debug.assert(candidates.length, "Revert #54442 and add a testcase with whatever triggered this"); + Debug.assert( + candidates.length, + "Revert #54442 and add a testcase with whatever triggered this" + ); } const args = getEffectiveCallArguments(node); @@ -36420,14 +64174,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // // For a decorator, no arguments are susceptible to contextual typing due to the fact // decorators are applied to a declaration by the emitter, and not to an expression. - const isSingleNonGenericCandidate = candidates.length === 1 && !candidates[0].typeParameters; - if (!isDecorator && !isSingleNonGenericCandidate && some(args, isContextSensitive)) { + const isSingleNonGenericCandidate = + candidates.length === 1 && !candidates[0].typeParameters; + if ( + !isDecorator && + !isSingleNonGenericCandidate && + some(args, isContextSensitive) + ) { argCheckMode = CheckMode.SkipContextSensitive; } // If we are in signature help, a trailing comma indicates that we intend to provide another argument, // so we will only accept overloads with arity at least 1 higher than the current number of provided arguments. - const signatureHelpTrailingComma = !!(checkMode & CheckMode.IsForSignatureHelp) && node.kind === SyntaxKind.CallExpression && node.arguments.hasTrailingComma; + const signatureHelpTrailingComma = + !!(checkMode & CheckMode.IsForSignatureHelp) && + node.kind === SyntaxKind.CallExpression && + node.arguments.hasTrailingComma; // Section 4.12.1: // if the candidate list contains one or more signatures for which the type of each argument @@ -36440,13 +64202,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // is just important for choosing the best signature. So in the case where there is only one // signature, the subtype pass is useless. So skipping it is an optimization. if (candidates.length > 1) { - result = chooseOverload(candidates, subtypeRelation, isSingleNonGenericCandidate, signatureHelpTrailingComma); + result = chooseOverload( + candidates, + subtypeRelation, + isSingleNonGenericCandidate, + signatureHelpTrailingComma + ); } if (!result) { - result = chooseOverload(candidates, assignableRelation, isSingleNonGenericCandidate, signatureHelpTrailingComma); + result = chooseOverload( + candidates, + assignableRelation, + isSingleNonGenericCandidate, + signatureHelpTrailingComma + ); } const links = getNodeLinks(node); - if (links.resolvedSignature !== resolvingSignature && !candidatesOutArray) { + if ( + links.resolvedSignature !== resolvingSignature && + !candidatesOutArray + ) { // There are 2 situations in which it's good to preemptively return the cached result here: // // 1. if the signature resolution originated on a node that itself depends on the contextual type @@ -36467,7 +64242,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (result) { return result; } - result = getCandidateForOverloadFailure(node, candidates, args, !!candidatesOutArray, checkMode); + result = getCandidateForOverloadFailure( + node, + candidates, + args, + !!candidatesOutArray, + checkMode + ); // Preemptively cache the result; getResolvedSignature will do this after we return, but // we need to ensure that the result is present for the error checks below so that if // this signature is encountered again, we handle the circularity (rather than producing a @@ -36486,42 +64267,86 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // message when reporting diagnostics that explains how we got to `right[Symbol.hasInstance](left)` from // `left instanceof right`, as it pertains to "Argument" related messages reported for the call. if (!headMessage && isInstanceof) { - headMessage = Diagnostics.The_left_hand_side_of_an_instanceof_expression_must_be_assignable_to_the_first_argument_of_the_right_hand_side_s_Symbol_hasInstance_method; + headMessage = + Diagnostics.The_left_hand_side_of_an_instanceof_expression_must_be_assignable_to_the_first_argument_of_the_right_hand_side_s_Symbol_hasInstance_method; } if (candidatesForArgumentError) { - if (candidatesForArgumentError.length === 1 || candidatesForArgumentError.length > 3) { - const last = candidatesForArgumentError[candidatesForArgumentError.length - 1]; + if ( + candidatesForArgumentError.length === 1 || + candidatesForArgumentError.length > 3 + ) { + const last = + candidatesForArgumentError[ + candidatesForArgumentError.length - 1 + ]; let chain: DiagnosticMessageChain | undefined; if (candidatesForArgumentError.length > 3) { - chain = chainDiagnosticMessages(chain, Diagnostics.The_last_overload_gave_the_following_error); - chain = chainDiagnosticMessages(chain, Diagnostics.No_overload_matches_this_call); + chain = chainDiagnosticMessages( + chain, + Diagnostics.The_last_overload_gave_the_following_error + ); + chain = chainDiagnosticMessages( + chain, + Diagnostics.No_overload_matches_this_call + ); } if (headMessage) { chain = chainDiagnosticMessages(chain, headMessage); } - const diags = getSignatureApplicabilityError(node, args, last, assignableRelation, CheckMode.Normal, /*reportErrors*/ true, () => chain); + const diags = getSignatureApplicabilityError( + node, + args, + last, + assignableRelation, + CheckMode.Normal, + /*reportErrors*/ true, + () => chain + ); if (diags) { for (const d of diags) { - if (last.declaration && candidatesForArgumentError.length > 3) { - addRelatedInfo(d, createDiagnosticForNode(last.declaration, Diagnostics.The_last_overload_is_declared_here)); + if ( + last.declaration && + candidatesForArgumentError.length > 3 + ) { + addRelatedInfo( + d, + createDiagnosticForNode( + last.declaration, + Diagnostics.The_last_overload_is_declared_here + ) + ); } addImplementationSuccessElaboration(last, d); diagnostics.add(d); } - } - else { + } else { Debug.fail("No error for last overload signature"); } - } - else { - const allDiagnostics: (readonly DiagnosticRelatedInformation[])[] = []; + } else { + const allDiagnostics: (readonly DiagnosticRelatedInformation[])[] = + []; let max = 0; let min = Number.MAX_VALUE; let minIndex = 0; let i = 0; for (const c of candidatesForArgumentError) { - const chain = () => chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Overload_0_of_1_2_gave_the_following_error, i + 1, candidates.length, signatureToString(c)); - const diags = getSignatureApplicabilityError(node, args, c, assignableRelation, CheckMode.Normal, /*reportErrors*/ true, chain); + const chain = () => + chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Overload_0_of_1_2_gave_the_following_error, + i + 1, + candidates.length, + signatureToString(c) + ); + const diags = getSignatureApplicabilityError( + node, + args, + c, + assignableRelation, + CheckMode.Normal, + /*reportErrors*/ true, + chain + ); if (diags) { if (diags.length <= min) { min = diags.length; @@ -36529,69 +64354,160 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } max = Math.max(max, diags.length); allDiagnostics.push(diags); - } - else { - Debug.fail("No error for 3 or fewer overload signatures"); + } else { + Debug.fail( + "No error for 3 or fewer overload signatures" + ); } i++; } - const diags = max > 1 ? allDiagnostics[minIndex] : flatten(allDiagnostics); - Debug.assert(diags.length > 0, "No errors reported for 3 or fewer overload signatures"); + const diags = + max > 1 + ? allDiagnostics[minIndex] + : flatten(allDiagnostics); + Debug.assert( + diags.length > 0, + "No errors reported for 3 or fewer overload signatures" + ); let chain = chainDiagnosticMessages( map(diags, createDiagnosticMessageChainFromDiagnostic), - Diagnostics.No_overload_matches_this_call, + Diagnostics.No_overload_matches_this_call ); if (headMessage) { chain = chainDiagnosticMessages(chain, headMessage); } // 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 // arrays and the emptyArray singleton where possible, which is decidedly not what we want while we're still constructing this diagnostic - const related = [...flatMap(diags, d => (d as Diagnostic).relatedInformation) as DiagnosticRelatedInformation[]]; + const related = [ + ...(flatMap( + diags, + (d) => (d as Diagnostic).relatedInformation + ) as DiagnosticRelatedInformation[]), + ]; let diag: Diagnostic; - if (every(diags, d => d.start === diags[0].start && d.length === diags[0].length && d.file === diags[0].file)) { + if ( + every( + diags, + (d) => + d.start === diags[0].start && + d.length === diags[0].length && + d.file === diags[0].file + ) + ) { const { file, start, length } = diags[0]; - diag = { file, start, length, code: chain.code, category: chain.category, messageText: chain, relatedInformation: related }; - } - else { - diag = createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(node), getErrorNodeForCallNode(node), chain, related); + diag = { + file, + start, + length, + code: chain.code, + category: chain.category, + messageText: chain, + relatedInformation: related, + }; + } else { + diag = createDiagnosticForNodeFromMessageChain( + getSourceFileOfNode(node), + getErrorNodeForCallNode(node), + chain, + related + ); } - addImplementationSuccessElaboration(candidatesForArgumentError[0], diag); + addImplementationSuccessElaboration( + candidatesForArgumentError[0], + diag + ); diagnostics.add(diag); } - } - else if (candidateForArgumentArityError) { - diagnostics.add(getArgumentArityError(node, [candidateForArgumentArityError], args, headMessage)); - } - else if (candidateForTypeArgumentError) { - checkTypeArguments(candidateForTypeArgumentError, (node as CallExpression | TaggedTemplateExpression | JsxOpeningLikeElement).typeArguments!, /*reportErrors*/ true, headMessage); - } - else if (!isJsxOpenFragment) { - const signaturesWithCorrectTypeArgumentArity = filter(signatures, s => hasCorrectTypeArgumentArity(s, typeArguments)); + } else if (candidateForArgumentArityError) { + diagnostics.add( + getArgumentArityError( + node, + [candidateForArgumentArityError], + args, + headMessage + ) + ); + } else if (candidateForTypeArgumentError) { + checkTypeArguments( + candidateForTypeArgumentError, + ( + node as + | CallExpression + | TaggedTemplateExpression + | JsxOpeningLikeElement + ).typeArguments!, + /*reportErrors*/ true, + headMessage + ); + } else if (!isJsxOpenFragment) { + const signaturesWithCorrectTypeArgumentArity = filter( + signatures, + (s) => hasCorrectTypeArgumentArity(s, typeArguments) + ); if (signaturesWithCorrectTypeArgumentArity.length === 0) { - diagnostics.add(getTypeArgumentArityError(node, signatures, typeArguments!, headMessage)); - } - else { - diagnostics.add(getArgumentArityError(node, signaturesWithCorrectTypeArgumentArity, args, headMessage)); + diagnostics.add( + getTypeArgumentArityError( + node, + signatures, + typeArguments!, + headMessage + ) + ); + } else { + diagnostics.add( + getArgumentArityError( + node, + signaturesWithCorrectTypeArgumentArity, + args, + headMessage + ) + ); } } } return result; - function addImplementationSuccessElaboration(failed: Signature, diagnostic: Diagnostic) { + function addImplementationSuccessElaboration( + failed: Signature, + diagnostic: Diagnostic + ) { const oldCandidatesForArgumentError = candidatesForArgumentError; - const oldCandidateForArgumentArityError = candidateForArgumentArityError; - const oldCandidateForTypeArgumentError = candidateForTypeArgumentError; + const oldCandidateForArgumentArityError = + candidateForArgumentArityError; + const oldCandidateForTypeArgumentError = + candidateForTypeArgumentError; - const failedSignatureDeclarations = failed.declaration?.symbol?.declarations || emptyArray; + const failedSignatureDeclarations = + failed.declaration?.symbol?.declarations || emptyArray; const isOverload = failedSignatureDeclarations.length > 1; - const implDecl = isOverload ? find(failedSignatureDeclarations, d => isFunctionLikeDeclaration(d) && nodeIsPresent(d.body)) : undefined; + const implDecl = isOverload + ? find( + failedSignatureDeclarations, + (d) => + isFunctionLikeDeclaration(d) && nodeIsPresent(d.body) + ) + : undefined; if (implDecl) { - const candidate = getSignatureFromDeclaration(implDecl as FunctionLikeDeclaration); + const candidate = getSignatureFromDeclaration( + implDecl as FunctionLikeDeclaration + ); const isSingleNonGenericCandidate = !candidate.typeParameters; - if (chooseOverload([candidate], assignableRelation, isSingleNonGenericCandidate)) { - addRelatedInfo(diagnostic, createDiagnosticForNode(implDecl, Diagnostics.The_call_would_have_succeeded_against_this_implementation_but_implementation_signatures_of_overloads_are_not_externally_visible)); + if ( + chooseOverload( + [candidate], + assignableRelation, + isSingleNonGenericCandidate + ) + ) { + addRelatedInfo( + diagnostic, + createDiagnosticForNode( + implDecl, + Diagnostics.The_call_would_have_succeeded_against_this_implementation_but_implementation_signatures_of_overloads_are_not_externally_visible + ) + ); } } @@ -36600,26 +64516,61 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { candidateForTypeArgumentError = oldCandidateForTypeArgumentError; } - function chooseOverload(candidates: Signature[], relation: Map, isSingleNonGenericCandidate: boolean, signatureHelpTrailingComma = false) { + function chooseOverload( + candidates: Signature[], + relation: Map, + isSingleNonGenericCandidate: boolean, + signatureHelpTrailingComma = false + ) { candidatesForArgumentError = undefined; candidateForArgumentArityError = undefined; candidateForTypeArgumentError = undefined; if (isSingleNonGenericCandidate) { const candidate = candidates[0]; - if (some(typeArguments) || !hasCorrectArity(node, args, candidate, signatureHelpTrailingComma)) { + if ( + some(typeArguments) || + !hasCorrectArity( + node, + args, + candidate, + signatureHelpTrailingComma + ) + ) { return undefined; } - if (getSignatureApplicabilityError(node, args, candidate, relation, CheckMode.Normal, /*reportErrors*/ false, /*containingMessageChain*/ undefined)) { + if ( + getSignatureApplicabilityError( + node, + args, + candidate, + relation, + CheckMode.Normal, + /*reportErrors*/ false, + /*containingMessageChain*/ undefined + ) + ) { candidatesForArgumentError = [candidate]; return undefined; } return candidate; } - for (let candidateIndex = 0; candidateIndex < candidates.length; candidateIndex++) { + for ( + let candidateIndex = 0; + candidateIndex < candidates.length; + candidateIndex++ + ) { const candidate = candidates[candidateIndex]; - if (!hasCorrectTypeArgumentArity(candidate, typeArguments) || !hasCorrectArity(node, args, candidate, signatureHelpTrailingComma)) { + if ( + !hasCorrectTypeArgumentArity(candidate, typeArguments) || + !hasCorrectArity( + node, + args, + candidate, + signatureHelpTrailingComma + ) + ) { continue; } @@ -36629,31 +64580,76 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (candidate.typeParameters) { let typeArgumentTypes: Type[] | undefined; if (some(typeArguments)) { - typeArgumentTypes = checkTypeArguments(candidate, typeArguments, /*reportErrors*/ false); + typeArgumentTypes = checkTypeArguments( + candidate, + typeArguments, + /*reportErrors*/ false + ); if (!typeArgumentTypes) { candidateForTypeArgumentError = candidate; continue; } - } - else { - inferenceContext = createInferenceContext(candidate.typeParameters, candidate, /*flags*/ isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None); - typeArgumentTypes = inferTypeArguments(node, candidate, args, argCheckMode | CheckMode.SkipGenericFunctions, inferenceContext); - argCheckMode |= inferenceContext.flags & InferenceFlags.SkippedGenericFunction ? CheckMode.SkipGenericFunctions : CheckMode.Normal; - } - checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration), inferenceContext && inferenceContext.inferredTypeParameters); + } else { + inferenceContext = createInferenceContext( + candidate.typeParameters, + candidate, + /*flags*/ isInJSFile(node) + ? InferenceFlags.AnyDefault + : InferenceFlags.None + ); + typeArgumentTypes = inferTypeArguments( + node, + candidate, + args, + argCheckMode | CheckMode.SkipGenericFunctions, + inferenceContext + ); + argCheckMode |= + inferenceContext.flags & + InferenceFlags.SkippedGenericFunction + ? CheckMode.SkipGenericFunctions + : CheckMode.Normal; + } + checkCandidate = getSignatureInstantiation( + candidate, + typeArgumentTypes, + isInJSFile(candidate.declaration), + inferenceContext && + inferenceContext.inferredTypeParameters + ); // If the original signature has a generic rest type, instantiation may produce a // signature with different arity and we need to perform another arity check. - if (getNonArrayRestType(candidate) && !hasCorrectArity(node, args, checkCandidate, signatureHelpTrailingComma)) { + if ( + getNonArrayRestType(candidate) && + !hasCorrectArity( + node, + args, + checkCandidate, + signatureHelpTrailingComma + ) + ) { candidateForArgumentArityError = checkCandidate; continue; } - } - else { + } else { checkCandidate = candidate; } - if (getSignatureApplicabilityError(node, args, checkCandidate, relation, argCheckMode, /*reportErrors*/ false, /*containingMessageChain*/ undefined)) { + if ( + getSignatureApplicabilityError( + node, + args, + checkCandidate, + relation, + argCheckMode, + /*reportErrors*/ false, + /*containingMessageChain*/ undefined + ) + ) { // Give preference to error candidates that have no rest parameters (as they are more specific) - (candidatesForArgumentError || (candidatesForArgumentError = [])).push(checkCandidate); + ( + candidatesForArgumentError || + (candidatesForArgumentError = []) + ).push(checkCandidate); continue; } if (argCheckMode) { @@ -36662,18 +64658,50 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // round of type inference and applicability checking for this particular candidate. argCheckMode = CheckMode.Normal; if (inferenceContext) { - const typeArgumentTypes = inferTypeArguments(node, candidate, args, argCheckMode, inferenceContext); - checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration), inferenceContext.inferredTypeParameters); + const typeArgumentTypes = inferTypeArguments( + node, + candidate, + args, + argCheckMode, + inferenceContext + ); + checkCandidate = getSignatureInstantiation( + candidate, + typeArgumentTypes, + isInJSFile(candidate.declaration), + inferenceContext.inferredTypeParameters + ); // If the original signature has a generic rest type, instantiation may produce a // signature with different arity and we need to perform another arity check. - if (getNonArrayRestType(candidate) && !hasCorrectArity(node, args, checkCandidate, signatureHelpTrailingComma)) { + if ( + getNonArrayRestType(candidate) && + !hasCorrectArity( + node, + args, + checkCandidate, + signatureHelpTrailingComma + ) + ) { candidateForArgumentArityError = checkCandidate; continue; } } - if (getSignatureApplicabilityError(node, args, checkCandidate, relation, argCheckMode, /*reportErrors*/ false, /*containingMessageChain*/ undefined)) { + if ( + getSignatureApplicabilityError( + node, + args, + checkCandidate, + relation, + argCheckMode, + /*reportErrors*/ false, + /*containingMessageChain*/ undefined + ) + ) { // Give preference to error candidates that have no rest parameters (as they are more specific) - (candidatesForArgumentError || (candidatesForArgumentError = [])).push(checkCandidate); + ( + candidatesForArgumentError || + (candidatesForArgumentError = []) + ).push(checkCandidate); continue; } } @@ -36691,39 +64719,73 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { candidates: Signature[], args: readonly Expression[], hasCandidatesOutArray: boolean, - checkMode: CheckMode, + checkMode: CheckMode ): Signature { Debug.assert(candidates.length > 0); // Else should not have called this. checkNodeDeferred(node); // Normally we will combine overloads. Skip this if they have type parameters since that's hard to combine. // Don't do this if there is a `candidatesOutArray`, // because then we want the chosen best candidate to be one of the overloads, not a combination. - return hasCandidatesOutArray || candidates.length === 1 || candidates.some(c => !!c.typeParameters) + return hasCandidatesOutArray || + candidates.length === 1 || + candidates.some((c) => !!c.typeParameters) ? pickLongestCandidateSignature(node, candidates, args, checkMode) : createUnionOfSignaturesForOverloadFailure(candidates); } - function createUnionOfSignaturesForOverloadFailure(candidates: readonly Signature[]): Signature { - const thisParameters = mapDefined(candidates, c => c.thisParameter); + function createUnionOfSignaturesForOverloadFailure( + candidates: readonly Signature[] + ): Signature { + const thisParameters = mapDefined(candidates, (c) => c.thisParameter); let thisParameter: Symbol | undefined; if (thisParameters.length) { - thisParameter = createCombinedSymbolFromTypes(thisParameters, thisParameters.map(getTypeOfParameter)); + thisParameter = createCombinedSymbolFromTypes( + thisParameters, + thisParameters.map(getTypeOfParameter) + ); } - const { min: minArgumentCount, max: maxNonRestParam } = minAndMax(candidates, getNumNonRestParameters); + const { min: minArgumentCount, max: maxNonRestParam } = minAndMax( + candidates, + getNumNonRestParameters + ); const parameters: Symbol[] = []; for (let i = 0; i < maxNonRestParam; i++) { - const symbols = mapDefined(candidates, s => - signatureHasRestParameter(s) ? - i < s.parameters.length - 1 ? s.parameters[i] : last(s.parameters) : - i < s.parameters.length ? s.parameters[i] : undefined); + const symbols = mapDefined(candidates, (s) => + signatureHasRestParameter(s) + ? i < s.parameters.length - 1 + ? s.parameters[i] + : last(s.parameters) + : i < s.parameters.length + ? s.parameters[i] + : undefined + ); Debug.assert(symbols.length !== 0); - parameters.push(createCombinedSymbolFromTypes(symbols, mapDefined(candidates, candidate => tryGetTypeAtPosition(candidate, i)))); + parameters.push( + createCombinedSymbolFromTypes( + symbols, + mapDefined(candidates, (candidate) => + tryGetTypeAtPosition(candidate, i) + ) + ) + ); } - const restParameterSymbols = mapDefined(candidates, c => signatureHasRestParameter(c) ? last(c.parameters) : undefined); + const restParameterSymbols = mapDefined(candidates, (c) => + signatureHasRestParameter(c) ? last(c.parameters) : undefined + ); let flags = SignatureFlags.IsSignatureCandidateForOverloadFailure; if (restParameterSymbols.length !== 0) { - const type = createArrayType(getUnionType(mapDefined(candidates, tryGetRestTypeOfSignature), UnionReduction.Subtype)); - parameters.push(createCombinedSymbolForOverloadFailure(restParameterSymbols, type)); + const type = createArrayType( + getUnionType( + mapDefined(candidates, tryGetRestTypeOfSignature), + UnionReduction.Subtype + ) + ); + parameters.push( + createCombinedSymbolForOverloadFailure( + restParameterSymbols, + type + ) + ); flags |= SignatureFlags.HasRestParameter; } if (candidates.some(signatureHasLiteralTypes)) { @@ -36734,10 +64796,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /*typeParameters*/ undefined, // Before calling this we tested for `!candidates.some(c => !!c.typeParameters)`. thisParameter, parameters, - /*resolvedReturnType*/ getIntersectionType(candidates.map(getReturnTypeOfSignature)), + /*resolvedReturnType*/ getIntersectionType( + candidates.map(getReturnTypeOfSignature) + ), /*resolvedTypePredicate*/ undefined, minArgumentCount, - flags, + flags ); } @@ -36746,62 +64810,135 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return signatureHasRestParameter(signature) ? numParams - 1 : numParams; } - function createCombinedSymbolFromTypes(sources: readonly Symbol[], types: Type[]): Symbol { - return createCombinedSymbolForOverloadFailure(sources, getUnionType(types, UnionReduction.Subtype)); + function createCombinedSymbolFromTypes( + sources: readonly Symbol[], + types: Type[] + ): Symbol { + return createCombinedSymbolForOverloadFailure( + sources, + getUnionType(types, UnionReduction.Subtype) + ); } - function createCombinedSymbolForOverloadFailure(sources: readonly Symbol[], type: Type): Symbol { + function createCombinedSymbolForOverloadFailure( + sources: readonly Symbol[], + type: Type + ): Symbol { // This function is currently only used for erroneous overloads, so it's good enough to just use the first source. return createSymbolWithType(first(sources), type); } - function pickLongestCandidateSignature(node: CallLikeExpression, candidates: Signature[], args: readonly Expression[], checkMode: CheckMode): Signature { + function pickLongestCandidateSignature( + node: CallLikeExpression, + candidates: Signature[], + args: readonly Expression[], + checkMode: CheckMode + ): Signature { // Pick the longest signature. This way we can get a contextual type for cases like: // declare function f(a: { xa: number; xb: number; }, b: number); // f({ | // Also, use explicitly-supplied type arguments if they are provided, so we can get a contextual signature in cases like: // declare function f(k: keyof T); // f(" - const bestIndex = getLongestCandidateIndex(candidates, apparentArgumentCount === undefined ? args.length : apparentArgumentCount); + const bestIndex = getLongestCandidateIndex( + candidates, + apparentArgumentCount === undefined + ? args.length + : apparentArgumentCount + ); const candidate = candidates[bestIndex]; const { typeParameters } = candidate; if (!typeParameters) { return candidate; } - const typeArgumentNodes: readonly TypeNode[] | undefined = callLikeExpressionMayHaveTypeArguments(node) ? node.typeArguments : undefined; + const typeArgumentNodes: readonly TypeNode[] | undefined = + callLikeExpressionMayHaveTypeArguments(node) + ? node.typeArguments + : undefined; const instantiated = typeArgumentNodes - ? createSignatureInstantiation(candidate, getTypeArgumentsFromNodes(typeArgumentNodes, typeParameters, isInJSFile(node))) - : inferSignatureInstantiationForOverloadFailure(node, typeParameters, candidate, args, checkMode); + ? createSignatureInstantiation( + candidate, + getTypeArgumentsFromNodes( + typeArgumentNodes, + typeParameters, + isInJSFile(node) + ) + ) + : inferSignatureInstantiationForOverloadFailure( + node, + typeParameters, + candidate, + args, + checkMode + ); candidates[bestIndex] = instantiated; return instantiated; } - function getTypeArgumentsFromNodes(typeArgumentNodes: readonly TypeNode[], typeParameters: readonly TypeParameter[], isJs: boolean): readonly Type[] { + function getTypeArgumentsFromNodes( + typeArgumentNodes: readonly TypeNode[], + typeParameters: readonly TypeParameter[], + isJs: boolean + ): readonly Type[] { const typeArguments = typeArgumentNodes.map(getTypeOfNode); while (typeArguments.length > typeParameters.length) { typeArguments.pop(); } while (typeArguments.length < typeParameters.length) { - typeArguments.push(getDefaultFromTypeParameter(typeParameters[typeArguments.length]) || getConstraintOfTypeParameter(typeParameters[typeArguments.length]) || getDefaultTypeArgumentType(isJs)); + typeArguments.push( + getDefaultFromTypeParameter( + typeParameters[typeArguments.length] + ) || + getConstraintOfTypeParameter( + typeParameters[typeArguments.length] + ) || + getDefaultTypeArgumentType(isJs) + ); } return typeArguments; } - function inferSignatureInstantiationForOverloadFailure(node: CallLikeExpression, typeParameters: readonly TypeParameter[], candidate: Signature, args: readonly Expression[], checkMode: CheckMode): Signature { - const inferenceContext = createInferenceContext(typeParameters, candidate, /*flags*/ isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None); - const typeArgumentTypes = inferTypeArguments(node, candidate, args, checkMode | CheckMode.SkipContextSensitive | CheckMode.SkipGenericFunctions, inferenceContext); + function inferSignatureInstantiationForOverloadFailure( + node: CallLikeExpression, + typeParameters: readonly TypeParameter[], + candidate: Signature, + args: readonly Expression[], + checkMode: CheckMode + ): Signature { + const inferenceContext = createInferenceContext( + typeParameters, + candidate, + /*flags*/ isInJSFile(node) + ? InferenceFlags.AnyDefault + : InferenceFlags.None + ); + const typeArgumentTypes = inferTypeArguments( + node, + candidate, + args, + checkMode | + CheckMode.SkipContextSensitive | + CheckMode.SkipGenericFunctions, + inferenceContext + ); return createSignatureInstantiation(candidate, typeArgumentTypes); } - function getLongestCandidateIndex(candidates: Signature[], argsCount: number): number { + function getLongestCandidateIndex( + candidates: Signature[], + argsCount: number + ): number { let maxParamsIndex = -1; let maxParams = -1; for (let i = 0; i < candidates.length; i++) { const candidate = candidates[i]; const paramCount = getParameterCount(candidate); - if (hasEffectiveRestParameter(candidate) || paramCount >= argsCount) { + if ( + hasEffectiveRestParameter(candidate) || + paramCount >= argsCount + ) { return i; } if (paramCount > maxParams) { @@ -36813,7 +64950,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return maxParamsIndex; } - function resolveCallExpression(node: CallExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { + function resolveCallExpression( + node: CallExpression, + candidatesOutArray: Signature[] | undefined, + checkMode: CheckMode + ): Signature { if (node.expression.kind === SyntaxKind.SuperKeyword) { const superType = checkSuperExpression(node.expression); if (isTypeAny(superType)) { @@ -36825,10 +64966,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!isErrorType(superType)) { // In super call, the candidate signatures are the matching arity signatures of the base constructor function instantiated // with the type arguments specified in the extends clause. - const baseTypeNode = getEffectiveBaseTypeNode(getContainingClass(node)!); + const baseTypeNode = getEffectiveBaseTypeNode( + getContainingClass(node)! + ); if (baseTypeNode) { - const baseConstructors = getInstantiatedConstructorsForTypeArguments(superType, baseTypeNode.typeArguments, baseTypeNode); - return resolveCall(node, baseConstructors, candidatesOutArray, checkMode, SignatureFlags.None); + const baseConstructors = + getInstantiatedConstructorsForTypeArguments( + superType, + baseTypeNode.typeArguments, + baseTypeNode + ); + return resolveCall( + node, + baseConstructors, + candidatesOutArray, + checkMode, + SignatureFlags.None + ); } } return resolveUntypedCall(node); @@ -36837,20 +64991,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let callChainFlags: SignatureFlags; let funcType = checkExpression(node.expression); if (isCallChain(node)) { - const nonOptionalType = getOptionalExpressionType(funcType, node.expression); - callChainFlags = nonOptionalType === funcType ? SignatureFlags.None : - isOutermostOptionalChain(node) ? SignatureFlags.IsOuterCallChain : - SignatureFlags.IsInnerCallChain; + const nonOptionalType = getOptionalExpressionType( + funcType, + node.expression + ); + callChainFlags = + nonOptionalType === funcType + ? SignatureFlags.None + : isOutermostOptionalChain(node) + ? SignatureFlags.IsOuterCallChain + : SignatureFlags.IsInnerCallChain; funcType = nonOptionalType; - } - else { + } else { callChainFlags = SignatureFlags.None; } funcType = checkNonNullTypeWithReporter( funcType, node.expression, - reportCannotInvokePossiblyNullOrUndefinedError, + reportCannotInvokePossiblyNullOrUndefinedError ); if (funcType === silentNeverType) { @@ -36867,17 +65026,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // but we are not including call signatures that may have been added to the Object or // Function interface, since they have none by default. This is a bit of a leap of faith // that the user will not add any. - const callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call); - const numConstructSignatures = getSignaturesOfType(apparentType, SignatureKind.Construct).length; + const callSignatures = getSignaturesOfType( + apparentType, + SignatureKind.Call + ); + const numConstructSignatures = getSignaturesOfType( + apparentType, + SignatureKind.Construct + ).length; // TS 1.0 Spec: 4.12 // In an untyped function call no TypeArgs are permitted, Args can be any argument list, no contextual // types are provided for the argument expressions, and the result is always of type Any. - if (isUntypedFunctionCall(funcType, apparentType, callSignatures.length, numConstructSignatures)) { + if ( + isUntypedFunctionCall( + funcType, + apparentType, + callSignatures.length, + numConstructSignatures + ) + ) { // The unknownType indicates that an error already occurred (and was reported). No // need to report another error in this case. if (!isErrorType(funcType) && node.typeArguments) { - error(node, Diagnostics.Untyped_function_calls_may_not_accept_type_arguments); + error( + node, + Diagnostics.Untyped_function_calls_may_not_accept_type_arguments + ); } return resolveUntypedCall(node); } @@ -36886,17 +65061,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // with multiple call signatures. if (!callSignatures.length) { if (numConstructSignatures) { - error(node, Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new, typeToString(funcType)); - } - else { - let relatedInformation: DiagnosticRelatedInformation | undefined; + error( + node, + Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new, + typeToString(funcType) + ); + } else { + let relatedInformation: + | DiagnosticRelatedInformation + | undefined; if (node.arguments.length === 1) { const text = getSourceFileOfNode(node).text; - if (isLineBreak(text.charCodeAt(skipTrivia(text, node.expression.end, /*stopAfterLineBreak*/ true) - 1))) { - relatedInformation = createDiagnosticForNode(node.expression, Diagnostics.Are_you_missing_a_semicolon); + if ( + isLineBreak( + text.charCodeAt( + skipTrivia( + text, + node.expression.end, + /*stopAfterLineBreak*/ true + ) - 1 + ) + ) + ) { + relatedInformation = createDiagnosticForNode( + node.expression, + Diagnostics.Are_you_missing_a_semicolon + ); } } - invocationError(node.expression, apparentType, SignatureKind.Call, relatedInformation); + invocationError( + node.expression, + apparentType, + SignatureKind.Call, + relatedInformation + ); } return resolveErrorCall(node); } @@ -36912,21 +65110,44 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // use the resolvingSignature singleton to indicate that we deferred processing. This result will be // propagated out and eventually turned into silentNeverType (a type that is assignable to anything and // from which we never make inferences). - if (checkMode & CheckMode.SkipGenericFunctions && !node.typeArguments && callSignatures.some(isGenericFunctionReturningFunction)) { + if ( + checkMode & CheckMode.SkipGenericFunctions && + !node.typeArguments && + callSignatures.some(isGenericFunctionReturningFunction) + ) { skippedGenericFunction(node, checkMode); return resolvingSignature; } // If the function is explicitly marked with `@class`, then it must be constructed. - if (callSignatures.some(sig => isInJSFile(sig.declaration) && !!getJSDocClassTag(sig.declaration!))) { - error(node, Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new, typeToString(funcType)); + if ( + callSignatures.some( + (sig) => + isInJSFile(sig.declaration) && + !!getJSDocClassTag(sig.declaration!) + ) + ) { + error( + node, + Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new, + typeToString(funcType) + ); return resolveErrorCall(node); } - return resolveCall(node, callSignatures, candidatesOutArray, checkMode, callChainFlags); + return resolveCall( + node, + callSignatures, + candidatesOutArray, + checkMode, + callChainFlags + ); } function isGenericFunctionReturningFunction(signature: Signature) { - return !!(signature.typeParameters && isFunctionType(getReturnTypeOfSignature(signature))); + return !!( + signature.typeParameters && + isFunctionType(getReturnTypeOfSignature(signature)) + ); } /** @@ -36934,13 +65155,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * If FuncExpr is of type Any, or of an object type that has no call or construct signatures * but is a subtype of the Function interface, the call is an untyped function call. */ - function isUntypedFunctionCall(funcType: Type, apparentFuncType: Type, numCallSignatures: number, numConstructSignatures: number): boolean { + function isUntypedFunctionCall( + funcType: Type, + apparentFuncType: Type, + numCallSignatures: number, + numConstructSignatures: number + ): boolean { // We exclude union types because we may have a union of function types that happen to have no common signatures. - return isTypeAny(funcType) || isTypeAny(apparentFuncType) && !!(funcType.flags & TypeFlags.TypeParameter) || - !numCallSignatures && !numConstructSignatures && !(apparentFuncType.flags & TypeFlags.Union) && !(getReducedType(apparentFuncType).flags & TypeFlags.Never) && isTypeAssignableTo(funcType, globalFunctionType); + return ( + isTypeAny(funcType) || + (isTypeAny(apparentFuncType) && + !!(funcType.flags & TypeFlags.TypeParameter)) || + (!numCallSignatures && + !numConstructSignatures && + !(apparentFuncType.flags & TypeFlags.Union) && + !(getReducedType(apparentFuncType).flags & TypeFlags.Never) && + isTypeAssignableTo(funcType, globalFunctionType)) + ); } - function resolveNewExpression(node: NewExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { + function resolveNewExpression( + node: NewExpression, + candidatesOutArray: Signature[] | undefined, + checkMode: CheckMode + ): Signature { let expressionType = checkNonNullExpression(node.expression); if (expressionType === silentNeverType) { return silentNeverSignature; @@ -36962,7 +65200,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // list and the result of the operation is of type Any. if (isTypeAny(expressionType)) { if (node.typeArguments) { - error(node, Diagnostics.Untyped_function_calls_may_not_accept_type_arguments); + error( + node, + Diagnostics.Untyped_function_calls_may_not_accept_type_arguments + ); } return resolveUntypedCall(node); } @@ -36971,7 +65212,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // but we are not including construct signatures that may have been added to the Object or // Function interface, since they have none by default. This is a bit of a leap of faith // that the user will not add any. - const constructSignatures = getSignaturesOfType(expressionType, SignatureKind.Construct); + const constructSignatures = getSignaturesOfType( + expressionType, + SignatureKind.Construct + ); if (constructSignatures.length) { if (!isConstructorAccessible(node, constructSignatures[0])) { return resolveErrorCall(node); @@ -36980,49 +65224,102 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // then it cannot be instantiated. // In the case of a merged class-module or class-interface declaration, // only the class declaration node will have the Abstract flag set. - if (someSignature(constructSignatures, signature => !!(signature.flags & SignatureFlags.Abstract))) { - error(node, Diagnostics.Cannot_create_an_instance_of_an_abstract_class); + if ( + someSignature( + constructSignatures, + (signature) => !!(signature.flags & SignatureFlags.Abstract) + ) + ) { + error( + node, + Diagnostics.Cannot_create_an_instance_of_an_abstract_class + ); return resolveErrorCall(node); } - const valueDecl = expressionType.symbol && getClassLikeDeclarationOfSymbol(expressionType.symbol); - if (valueDecl && hasSyntacticModifier(valueDecl, ModifierFlags.Abstract)) { - error(node, Diagnostics.Cannot_create_an_instance_of_an_abstract_class); + const valueDecl = + expressionType.symbol && + getClassLikeDeclarationOfSymbol(expressionType.symbol); + if ( + valueDecl && + hasSyntacticModifier(valueDecl, ModifierFlags.Abstract) + ) { + error( + node, + Diagnostics.Cannot_create_an_instance_of_an_abstract_class + ); return resolveErrorCall(node); } - return resolveCall(node, constructSignatures, candidatesOutArray, checkMode, SignatureFlags.None); + return resolveCall( + node, + constructSignatures, + candidatesOutArray, + checkMode, + SignatureFlags.None + ); } // If expressionType's apparent type is an object type with no construct signatures but // one or more call signatures, the expression is processed as a function call. A compile-time // error occurs if the result of the function call is not Void. The type of the result of the // operation is Any. It is an error to have a Void this type. - const callSignatures = getSignaturesOfType(expressionType, SignatureKind.Call); + const callSignatures = getSignaturesOfType( + expressionType, + SignatureKind.Call + ); if (callSignatures.length) { - const signature = resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None); + const signature = resolveCall( + node, + callSignatures, + candidatesOutArray, + checkMode, + SignatureFlags.None + ); if (!noImplicitAny) { - if (signature.declaration && !isJSConstructor(signature.declaration) && getReturnTypeOfSignature(signature) !== voidType) { - error(node, Diagnostics.Only_a_void_function_can_be_called_with_the_new_keyword); + if ( + signature.declaration && + !isJSConstructor(signature.declaration) && + getReturnTypeOfSignature(signature) !== voidType + ) { + error( + node, + Diagnostics.Only_a_void_function_can_be_called_with_the_new_keyword + ); } if (getThisTypeOfSignature(signature) === voidType) { - error(node, Diagnostics.A_function_that_is_called_with_the_new_keyword_cannot_have_a_this_type_that_is_void); + error( + node, + Diagnostics.A_function_that_is_called_with_the_new_keyword_cannot_have_a_this_type_that_is_void + ); } } return signature; } - invocationError(node.expression, expressionType, SignatureKind.Construct); + invocationError( + node.expression, + expressionType, + SignatureKind.Construct + ); return resolveErrorCall(node); } - function someSignature(signatures: Signature | readonly Signature[], f: (s: Signature) => boolean): boolean { + function someSignature( + signatures: Signature | readonly Signature[], + f: (s: Signature) => boolean + ): boolean { if (isArray(signatures)) { - return some(signatures, signature => someSignature(signature, f)); + return some(signatures, (signature) => someSignature(signature, f)); } - return signatures.compositeKind === TypeFlags.Union ? some(signatures.compositeSignatures, f) : f(signatures); + return signatures.compositeKind === TypeFlags.Union + ? some(signatures.compositeSignatures, f) + : f(signatures); } - function typeHasProtectedAccessibleBase(target: Symbol, type: InterfaceType): boolean { + function typeHasProtectedAccessibleBase( + target: Symbol, + type: InterfaceType + ): boolean { const baseTypes = getBaseTypes(type); if (!length(baseTypes)) { return false; @@ -37032,14 +65329,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const types = (firstBase as IntersectionType).types; const mixinFlags = findMixins(types); let i = 0; - for (const intersectionMember of (firstBase as IntersectionType).types) { + for (const intersectionMember of (firstBase as IntersectionType) + .types) { // We want to ignore mixin ctors if (!mixinFlags[i]) { - if (getObjectFlags(intersectionMember) & (ObjectFlags.Class | ObjectFlags.Interface)) { + if ( + getObjectFlags(intersectionMember) & + (ObjectFlags.Class | ObjectFlags.Interface) + ) { if (intersectionMember.symbol === target) { return true; } - if (typeHasProtectedAccessibleBase(target, intersectionMember as InterfaceType)) { + if ( + typeHasProtectedAccessibleBase( + target, + intersectionMember as InterfaceType + ) + ) { return true; } } @@ -37051,39 +65357,65 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (firstBase.symbol === target) { return true; } - return typeHasProtectedAccessibleBase(target, firstBase as InterfaceType); + return typeHasProtectedAccessibleBase( + target, + firstBase as InterfaceType + ); } - function isConstructorAccessible(node: NewExpression, signature: Signature) { + function isConstructorAccessible( + node: NewExpression, + signature: Signature + ) { if (!signature || !signature.declaration) { return true; } const declaration = signature.declaration; - const modifiers = getSelectedEffectiveModifierFlags(declaration, ModifierFlags.NonPublicAccessibilityModifier); + const modifiers = getSelectedEffectiveModifierFlags( + declaration, + ModifierFlags.NonPublicAccessibilityModifier + ); // (1) Public constructors and (2) constructor functions are always accessible. if (!modifiers || declaration.kind !== SyntaxKind.Constructor) { return true; } - const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(declaration.parent.symbol)!; - const declaringClass = getDeclaredTypeOfSymbol(declaration.parent.symbol) as InterfaceType; + const declaringClassDeclaration = getClassLikeDeclarationOfSymbol( + declaration.parent.symbol + )!; + const declaringClass = getDeclaredTypeOfSymbol( + declaration.parent.symbol + ) as InterfaceType; // A private or protected constructor can only be instantiated within its own class (or a subclass, for protected) if (!isNodeWithinClass(node, declaringClassDeclaration)) { const containingClass = getContainingClass(node); if (containingClass && modifiers & ModifierFlags.Protected) { const containingType = getTypeOfNode(containingClass); - if (typeHasProtectedAccessibleBase(declaration.parent.symbol, containingType as InterfaceType)) { + if ( + typeHasProtectedAccessibleBase( + declaration.parent.symbol, + containingType as InterfaceType + ) + ) { return true; } } if (modifiers & ModifierFlags.Private) { - error(node, Diagnostics.Constructor_of_class_0_is_private_and_only_accessible_within_the_class_declaration, typeToString(declaringClass)); + error( + node, + Diagnostics.Constructor_of_class_0_is_private_and_only_accessible_within_the_class_declaration, + typeToString(declaringClass) + ); } if (modifiers & ModifierFlags.Protected) { - error(node, Diagnostics.Constructor_of_class_0_is_protected_and_only_accessible_within_the_class_declaration, typeToString(declaringClass)); + error( + node, + Diagnostics.Constructor_of_class_0_is_protected_and_only_accessible_within_the_class_declaration, + typeToString(declaringClass) + ); } return false; } @@ -37091,11 +65423,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; } - function invocationErrorDetails(errorTarget: Node, apparentType: Type, kind: SignatureKind): { messageChain: DiagnosticMessageChain; relatedMessage: DiagnosticMessage | undefined; } { + function invocationErrorDetails( + errorTarget: Node, + apparentType: Type, + kind: SignatureKind + ): { + messageChain: DiagnosticMessageChain; + relatedMessage: DiagnosticMessage | undefined; + } { let errorInfo: DiagnosticMessageChain | undefined; const isCall = kind === SignatureKind.Call; const awaitedType = getAwaitedType(apparentType); - const maybeMissingAwait = awaitedType && getSignaturesOfType(awaitedType, kind).length > 0; + const maybeMissingAwait = + awaitedType && getSignaturesOfType(awaitedType, kind).length > 0; if (apparentType.flags & TypeFlags.Union) { const types = (apparentType as UnionType).types; let hasSignatures = false; @@ -37107,23 +65447,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Bail early if we already have an error, no chance of "No constituent of type is callable" break; } - } - else { + } else { // Error on the first non callable constituent only if (!errorInfo) { errorInfo = chainDiagnosticMessages( errorInfo, - isCall ? - Diagnostics.Type_0_has_no_call_signatures : - Diagnostics.Type_0_has_no_construct_signatures, - typeToString(constituent), + isCall + ? Diagnostics.Type_0_has_no_call_signatures + : Diagnostics.Type_0_has_no_construct_signatures, + typeToString(constituent) ); errorInfo = chainDiagnosticMessages( errorInfo, - isCall ? - Diagnostics.Not_all_constituents_of_type_0_are_callable : - Diagnostics.Not_all_constituents_of_type_0_are_constructable, - typeToString(apparentType), + isCall + ? Diagnostics.Not_all_constituents_of_type_0_are_callable + : Diagnostics.Not_all_constituents_of_type_0_are_constructable, + typeToString(apparentType) ); } if (hasSignatures) { @@ -37135,78 +65474,128 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!hasSignatures) { errorInfo = chainDiagnosticMessages( /*details*/ undefined, - isCall ? - Diagnostics.No_constituent_of_type_0_is_callable : - Diagnostics.No_constituent_of_type_0_is_constructable, - typeToString(apparentType), + isCall + ? Diagnostics.No_constituent_of_type_0_is_callable + : Diagnostics.No_constituent_of_type_0_is_constructable, + typeToString(apparentType) ); } if (!errorInfo) { errorInfo = chainDiagnosticMessages( errorInfo, - isCall ? - Diagnostics.Each_member_of_the_union_type_0_has_signatures_but_none_of_those_signatures_are_compatible_with_each_other : - Diagnostics.Each_member_of_the_union_type_0_has_construct_signatures_but_none_of_those_signatures_are_compatible_with_each_other, - typeToString(apparentType), + isCall + ? Diagnostics.Each_member_of_the_union_type_0_has_signatures_but_none_of_those_signatures_are_compatible_with_each_other + : Diagnostics.Each_member_of_the_union_type_0_has_construct_signatures_but_none_of_those_signatures_are_compatible_with_each_other, + typeToString(apparentType) ); } - } - else { + } else { errorInfo = chainDiagnosticMessages( errorInfo, - isCall ? - Diagnostics.Type_0_has_no_call_signatures : - Diagnostics.Type_0_has_no_construct_signatures, - typeToString(apparentType), + isCall + ? Diagnostics.Type_0_has_no_call_signatures + : Diagnostics.Type_0_has_no_construct_signatures, + typeToString(apparentType) ); } - let headMessage = isCall ? Diagnostics.This_expression_is_not_callable : Diagnostics.This_expression_is_not_constructable; + let headMessage = isCall + ? Diagnostics.This_expression_is_not_callable + : Diagnostics.This_expression_is_not_constructable; // Diagnose get accessors incorrectly called as functions - if (isCallExpression(errorTarget.parent) && errorTarget.parent.arguments.length === 0) { + if ( + isCallExpression(errorTarget.parent) && + errorTarget.parent.arguments.length === 0 + ) { const { resolvedSymbol } = getNodeLinks(errorTarget); - if (resolvedSymbol && resolvedSymbol.flags & SymbolFlags.GetAccessor) { - headMessage = Diagnostics.This_expression_is_not_callable_because_it_is_a_get_accessor_Did_you_mean_to_use_it_without; + if ( + resolvedSymbol && + resolvedSymbol.flags & SymbolFlags.GetAccessor + ) { + headMessage = + Diagnostics.This_expression_is_not_callable_because_it_is_a_get_accessor_Did_you_mean_to_use_it_without; } } return { messageChain: chainDiagnosticMessages(errorInfo, headMessage), - relatedMessage: maybeMissingAwait ? Diagnostics.Did_you_forget_to_use_await : undefined, + relatedMessage: maybeMissingAwait + ? Diagnostics.Did_you_forget_to_use_await + : undefined, }; } - function invocationError(errorTarget: Node, apparentType: Type, kind: SignatureKind, relatedInformation?: DiagnosticRelatedInformation) { - const { messageChain, relatedMessage: relatedInfo } = invocationErrorDetails(errorTarget, apparentType, kind); - const diagnostic = createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(errorTarget), errorTarget, messageChain); + function invocationError( + errorTarget: Node, + apparentType: Type, + kind: SignatureKind, + relatedInformation?: DiagnosticRelatedInformation + ) { + const { messageChain, relatedMessage: relatedInfo } = + invocationErrorDetails(errorTarget, apparentType, kind); + const diagnostic = createDiagnosticForNodeFromMessageChain( + getSourceFileOfNode(errorTarget), + errorTarget, + messageChain + ); if (relatedInfo) { - addRelatedInfo(diagnostic, createDiagnosticForNode(errorTarget, relatedInfo)); + addRelatedInfo( + diagnostic, + createDiagnosticForNode(errorTarget, relatedInfo) + ); } if (isCallExpression(errorTarget.parent)) { - const { start, length } = getDiagnosticSpanForCallNode(errorTarget.parent); + const { start, length } = getDiagnosticSpanForCallNode( + errorTarget.parent + ); diagnostic.start = start; diagnostic.length = length; } diagnostics.add(diagnostic); - invocationErrorRecovery(apparentType, kind, relatedInformation ? addRelatedInfo(diagnostic, relatedInformation) : diagnostic); + invocationErrorRecovery( + apparentType, + kind, + relatedInformation + ? addRelatedInfo(diagnostic, relatedInformation) + : diagnostic + ); } - function invocationErrorRecovery(apparentType: Type, kind: SignatureKind, diagnostic: Diagnostic) { + function invocationErrorRecovery( + apparentType: Type, + kind: SignatureKind, + diagnostic: Diagnostic + ) { if (!apparentType.symbol) { return; } - const importNode = getSymbolLinks(apparentType.symbol).originatingImport; + const importNode = getSymbolLinks( + apparentType.symbol + ).originatingImport; // Create a diagnostic on the originating import if possible onto which we can attach a quickfix // 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 if (importNode && !isImportCall(importNode)) { - const sigs = getSignaturesOfType(getTypeOfSymbol(getSymbolLinks(apparentType.symbol).target!), kind); + const sigs = getSignaturesOfType( + getTypeOfSymbol(getSymbolLinks(apparentType.symbol).target!), + kind + ); if (!sigs || !sigs.length) return; - addRelatedInfo(diagnostic, 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)); + addRelatedInfo( + diagnostic, + 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 + ) + ); } } - function resolveTaggedTemplateExpression(node: TaggedTemplateExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { + function resolveTaggedTemplateExpression( + node: TaggedTemplateExpression, + candidatesOutArray: Signature[] | undefined, + checkMode: CheckMode + ): Signature { const tagType = checkExpression(node.tag); const apparentType = getApparentType(tagType); @@ -37215,16 +65604,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return resolveErrorCall(node); } - const callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call); - const numConstructSignatures = getSignaturesOfType(apparentType, SignatureKind.Construct).length; + const callSignatures = getSignaturesOfType( + apparentType, + SignatureKind.Call + ); + const numConstructSignatures = getSignaturesOfType( + apparentType, + SignatureKind.Construct + ).length; - if (isUntypedFunctionCall(tagType, apparentType, callSignatures.length, numConstructSignatures)) { + if ( + isUntypedFunctionCall( + tagType, + apparentType, + callSignatures.length, + numConstructSignatures + ) + ) { return resolveUntypedCall(node); } if (!callSignatures.length) { if (isArrayLiteralExpression(node.parent)) { - 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); + 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 + ); diagnostics.add(diagnostic); return resolveErrorCall(node); } @@ -37233,7 +65638,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return resolveErrorCall(node); } - return resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None); + return resolveCall( + node, + callSignatures, + candidatesOutArray, + checkMode, + SignatureFlags.None + ); } /** @@ -37264,50 +65675,128 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** * Resolves a decorator as if it were a call expression. */ - function resolveDecorator(node: Decorator, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { + function resolveDecorator( + node: Decorator, + candidatesOutArray: Signature[] | undefined, + checkMode: CheckMode + ): Signature { const funcType = checkExpression(node.expression); const apparentType = getApparentType(funcType); if (isErrorType(apparentType)) { return resolveErrorCall(node); } - const callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call); - const numConstructSignatures = getSignaturesOfType(apparentType, SignatureKind.Construct).length; - if (isUntypedFunctionCall(funcType, apparentType, callSignatures.length, numConstructSignatures)) { + const callSignatures = getSignaturesOfType( + apparentType, + SignatureKind.Call + ); + const numConstructSignatures = getSignaturesOfType( + apparentType, + SignatureKind.Construct + ).length; + if ( + isUntypedFunctionCall( + funcType, + apparentType, + callSignatures.length, + numConstructSignatures + ) + ) { return resolveUntypedCall(node); } - if (isPotentiallyUncalledDecorator(node, callSignatures) && !isParenthesizedExpression(node.expression)) { - const nodeStr = getTextOfNode(node.expression, /*includeTrivia*/ false); - 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); + if ( + isPotentiallyUncalledDecorator(node, callSignatures) && + !isParenthesizedExpression(node.expression) + ) { + const nodeStr = getTextOfNode( + node.expression, + /*includeTrivia*/ false + ); + 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 + ); return resolveErrorCall(node); } - const headMessage = getDiagnosticHeadMessageForDecoratorResolution(node); + const headMessage = + getDiagnosticHeadMessageForDecoratorResolution(node); if (!callSignatures.length) { - const errorDetails = invocationErrorDetails(node.expression, apparentType, SignatureKind.Call); - const messageChain = chainDiagnosticMessages(errorDetails.messageChain, headMessage); - const diag = createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(node.expression), node.expression, messageChain); + const errorDetails = invocationErrorDetails( + node.expression, + apparentType, + SignatureKind.Call + ); + const messageChain = chainDiagnosticMessages( + errorDetails.messageChain, + headMessage + ); + const diag = createDiagnosticForNodeFromMessageChain( + getSourceFileOfNode(node.expression), + node.expression, + messageChain + ); if (errorDetails.relatedMessage) { - addRelatedInfo(diag, createDiagnosticForNode(node.expression, errorDetails.relatedMessage)); + addRelatedInfo( + diag, + createDiagnosticForNode( + node.expression, + errorDetails.relatedMessage + ) + ); } diagnostics.add(diag); invocationErrorRecovery(apparentType, SignatureKind.Call, diag); return resolveErrorCall(node); } - return resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None, headMessage); + return resolveCall( + node, + callSignatures, + candidatesOutArray, + checkMode, + SignatureFlags.None, + headMessage + ); } - function createSignatureForJSXIntrinsic(node: JsxCallLike, result: Type): Signature { + function createSignatureForJSXIntrinsic( + node: JsxCallLike, + result: Type + ): Signature { const namespace = getJsxNamespaceAt(node); const exports = namespace && getExportsOfSymbol(namespace); // We fake up a SFC signature for each intrinsic, however a more specific per-element signature drawn from the JSX declaration // file would probably be preferable. - const typeSymbol = exports && getSymbol(exports, JsxNames.Element, SymbolFlags.Type); - const returnNode = typeSymbol && nodeBuilder.symbolToEntityName(typeSymbol, SymbolFlags.Type, node); - const declaration = factory.createFunctionTypeNode(/*typeParameters*/ undefined, [factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "props", /*questionToken*/ undefined, nodeBuilder.typeToTypeNode(result, node))], returnNode ? factory.createTypeReferenceNode(returnNode, /*typeArguments*/ undefined) : factory.createKeywordTypeNode(SyntaxKind.AnyKeyword)); - const parameterSymbol = createSymbol(SymbolFlags.FunctionScopedVariable, "props" as __String); + const typeSymbol = + exports && getSymbol(exports, JsxNames.Element, SymbolFlags.Type); + const returnNode = + typeSymbol && + nodeBuilder.symbolToEntityName(typeSymbol, SymbolFlags.Type, node); + const declaration = factory.createFunctionTypeNode( + /*typeParameters*/ undefined, + [ + factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + "props", + /*questionToken*/ undefined, + nodeBuilder.typeToTypeNode(result, node) + ), + ], + returnNode + ? factory.createTypeReferenceNode( + returnNode, + /*typeArguments*/ undefined + ) + : factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) + ); + const parameterSymbol = createSymbol( + SymbolFlags.FunctionScopedVariable, + "props" as __String + ); parameterSymbol.links.type = result; return createSignature( declaration, @@ -37317,110 +65806,219 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { typeSymbol ? getDeclaredTypeOfSymbol(typeSymbol) : errorType, /*resolvedTypePredicate*/ undefined, 1, - SignatureFlags.None, + SignatureFlags.None ); } function getJSXFragmentType(node: JsxOpeningFragment): Type { // An opening fragment is required in order for `getJsxNamespace` to give the fragment factory const sourceFileLinks = getNodeLinks(getSourceFileOfNode(node)); - if (sourceFileLinks.jsxFragmentType !== undefined) return sourceFileLinks.jsxFragmentType; + if (sourceFileLinks.jsxFragmentType !== undefined) + return sourceFileLinks.jsxFragmentType; const jsxFragmentFactoryName = getJsxNamespace(node); // #38720/60122, allow null as jsxFragmentFactory - const shouldResolveFactoryReference = (compilerOptions.jsx === JsxEmit.React || compilerOptions.jsxFragmentFactory !== undefined) && jsxFragmentFactoryName !== "null"; - if (!shouldResolveFactoryReference) return sourceFileLinks.jsxFragmentType = anyType; - - const shouldModuleRefErr = compilerOptions.jsx !== JsxEmit.Preserve && compilerOptions.jsx !== JsxEmit.ReactNative; - const jsxFactoryRefErr = diagnostics ? Diagnostics.Using_JSX_fragments_requires_fragment_factory_0_to_be_in_scope_but_it_could_not_be_found : undefined; - const jsxFactorySymbol = getJsxNamespaceContainerForImplicitImport(node) ?? + const shouldResolveFactoryReference = + (compilerOptions.jsx === JsxEmit.React || + compilerOptions.jsxFragmentFactory !== undefined) && + jsxFragmentFactoryName !== "null"; + if (!shouldResolveFactoryReference) + return (sourceFileLinks.jsxFragmentType = anyType); + + const shouldModuleRefErr = + compilerOptions.jsx !== JsxEmit.Preserve && + compilerOptions.jsx !== JsxEmit.ReactNative; + const jsxFactoryRefErr = diagnostics + ? Diagnostics.Using_JSX_fragments_requires_fragment_factory_0_to_be_in_scope_but_it_could_not_be_found + : undefined; + const jsxFactorySymbol = + getJsxNamespaceContainerForImplicitImport(node) ?? resolveName( node, jsxFragmentFactoryName, - shouldModuleRefErr ? SymbolFlags.Value : SymbolFlags.Value & ~SymbolFlags.Enum, + shouldModuleRefErr + ? SymbolFlags.Value + : SymbolFlags.Value & ~SymbolFlags.Enum, /*nameNotFoundMessage*/ jsxFactoryRefErr, - /*isUse*/ true, + /*isUse*/ true ); - if (jsxFactorySymbol === undefined) return sourceFileLinks.jsxFragmentType = errorType; - if (jsxFactorySymbol.escapedName === ReactNames.Fragment) return sourceFileLinks.jsxFragmentType = getTypeOfSymbol(jsxFactorySymbol); - - const resolvedAlias = (jsxFactorySymbol.flags & SymbolFlags.Alias) === 0 ? jsxFactorySymbol : resolveAlias(jsxFactorySymbol); - const reactExports = jsxFactorySymbol && getExportsOfSymbol(resolvedAlias); - const typeSymbol = reactExports && getSymbol(reactExports, ReactNames.Fragment, SymbolFlags.BlockScopedVariable); + if (jsxFactorySymbol === undefined) + return (sourceFileLinks.jsxFragmentType = errorType); + if (jsxFactorySymbol.escapedName === ReactNames.Fragment) + return (sourceFileLinks.jsxFragmentType = + getTypeOfSymbol(jsxFactorySymbol)); + + const resolvedAlias = + (jsxFactorySymbol.flags & SymbolFlags.Alias) === 0 + ? jsxFactorySymbol + : resolveAlias(jsxFactorySymbol); + const reactExports = + jsxFactorySymbol && getExportsOfSymbol(resolvedAlias); + const typeSymbol = + reactExports && + getSymbol( + reactExports, + ReactNames.Fragment, + SymbolFlags.BlockScopedVariable + ); const type = typeSymbol && getTypeOfSymbol(typeSymbol); - return sourceFileLinks.jsxFragmentType = type === undefined ? errorType : type; + return (sourceFileLinks.jsxFragmentType = + type === undefined ? errorType : type); } - function resolveJsxOpeningLikeElement(node: JsxCallLike, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { + function resolveJsxOpeningLikeElement( + node: JsxCallLike, + candidatesOutArray: Signature[] | undefined, + checkMode: CheckMode + ): Signature { const isJsxOpenFragment = isJsxOpeningFragment(node); let exprTypes: Type; if (!isJsxOpenFragment) { if (isJsxIntrinsicTagName(node.tagName)) { - const result = getIntrinsicAttributesTypeFromJsxOpeningLikeElement(node); - const fakeSignature = createSignatureForJSXIntrinsic(node, result); - checkTypeAssignableToAndOptionallyElaborate(checkExpressionWithContextualType(node.attributes, getEffectiveFirstArgumentForJsxSignature(fakeSignature, node), /*inferenceContext*/ undefined, CheckMode.Normal), result, node.tagName, node.attributes); + const result = + getIntrinsicAttributesTypeFromJsxOpeningLikeElement(node); + const fakeSignature = createSignatureForJSXIntrinsic( + node, + result + ); + checkTypeAssignableToAndOptionallyElaborate( + checkExpressionWithContextualType( + node.attributes, + getEffectiveFirstArgumentForJsxSignature( + fakeSignature, + node + ), + /*inferenceContext*/ undefined, + CheckMode.Normal + ), + result, + node.tagName, + node.attributes + ); if (length(node.typeArguments)) { forEach(node.typeArguments, checkSourceElement); - diagnostics.add(createDiagnosticForNodeArray(getSourceFileOfNode(node), node.typeArguments!, Diagnostics.Expected_0_type_arguments_but_got_1, 0, length(node.typeArguments))); + diagnostics.add( + createDiagnosticForNodeArray( + getSourceFileOfNode(node), + node.typeArguments!, + Diagnostics.Expected_0_type_arguments_but_got_1, + 0, + length(node.typeArguments) + ) + ); } return fakeSignature; } exprTypes = checkExpression(node.tagName); - } - else { + } else { exprTypes = getJSXFragmentType(node); } const apparentType = getApparentType(exprTypes); if (isErrorType(apparentType)) { return resolveErrorCall(node); } - const signatures = getUninstantiatedJsxSignaturesOfType(exprTypes, node); - if (isUntypedFunctionCall(exprTypes, apparentType, signatures.length, /*constructSignatures*/ 0)) { + const signatures = getUninstantiatedJsxSignaturesOfType( + exprTypes, + node + ); + if ( + isUntypedFunctionCall( + exprTypes, + apparentType, + signatures.length, + /*constructSignatures*/ 0 + ) + ) { return resolveUntypedCall(node); } if (signatures.length === 0) { // We found no signatures at all, which is an error if (isJsxOpenFragment) { - error(node, Diagnostics.JSX_element_type_0_does_not_have_any_construct_or_call_signatures, getTextOfNode(node)); - } - else { - error(node.tagName, Diagnostics.JSX_element_type_0_does_not_have_any_construct_or_call_signatures, getTextOfNode(node.tagName)); + error( + node, + Diagnostics.JSX_element_type_0_does_not_have_any_construct_or_call_signatures, + getTextOfNode(node) + ); + } else { + error( + node.tagName, + Diagnostics.JSX_element_type_0_does_not_have_any_construct_or_call_signatures, + getTextOfNode(node.tagName) + ); } return resolveErrorCall(node); } - return resolveCall(node, signatures, candidatesOutArray, checkMode, SignatureFlags.None); + return resolveCall( + node, + signatures, + candidatesOutArray, + checkMode, + SignatureFlags.None + ); } - function resolveInstanceofExpression(node: InstanceofExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { + function resolveInstanceofExpression( + node: InstanceofExpression, + candidatesOutArray: Signature[] | undefined, + checkMode: CheckMode + ): Signature { // if rightType is an object type with a custom `[Symbol.hasInstance]` method, then it is potentially // valid on the right-hand side of the `instanceof` operator. This allows normal `object` types to // participate in `instanceof`, as per Step 2 of https://tc39.es/ecma262/#sec-instanceofoperator. const rightType = checkExpression(node.right); if (!isTypeAny(rightType)) { - const hasInstanceMethodType = getSymbolHasInstanceMethodOfObjectType(rightType); + const hasInstanceMethodType = + getSymbolHasInstanceMethodOfObjectType(rightType); if (hasInstanceMethodType) { const apparentType = getApparentType(hasInstanceMethodType); if (isErrorType(apparentType)) { return resolveErrorCall(node); } - const callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call); - const constructSignatures = getSignaturesOfType(apparentType, SignatureKind.Construct); - if (isUntypedFunctionCall(hasInstanceMethodType, apparentType, callSignatures.length, constructSignatures.length)) { + const callSignatures = getSignaturesOfType( + apparentType, + SignatureKind.Call + ); + const constructSignatures = getSignaturesOfType( + apparentType, + SignatureKind.Construct + ); + if ( + isUntypedFunctionCall( + hasInstanceMethodType, + apparentType, + callSignatures.length, + constructSignatures.length + ) + ) { return resolveUntypedCall(node); } if (callSignatures.length) { - return resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None); + return resolveCall( + node, + callSignatures, + candidatesOutArray, + checkMode, + SignatureFlags.None + ); } } // NOTE: do not raise error if right is unknown as related error was already reported - else if (!(typeHasCallOrConstructSignatures(rightType) || isTypeSubtypeOf(rightType, globalFunctionType))) { - error(node.right, Diagnostics.The_right_hand_side_of_an_instanceof_expression_must_be_either_of_type_any_a_class_function_or_other_type_assignable_to_the_Function_interface_type_or_an_object_type_with_a_Symbol_hasInstance_method); + else if ( + !( + typeHasCallOrConstructSignatures(rightType) || + isTypeSubtypeOf(rightType, globalFunctionType) + ) + ) { + error( + node.right, + Diagnostics.The_right_hand_side_of_an_instanceof_expression_must_be_either_of_type_any_a_class_function_or_other_type_assignable_to_the_Function_interface_type_or_an_object_type_with_a_Symbol_hasInstance_method + ); return resolveErrorCall(node); } } @@ -37433,31 +66031,68 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * but is receiving too many arguments as part of the decorator invocation. * In those cases, a user may have meant to *call* the expression before using it as a decorator. */ - function isPotentiallyUncalledDecorator(decorator: Decorator, signatures: readonly Signature[]) { - return signatures.length && every(signatures, signature => - signature.minArgumentCount === 0 && - !signatureHasRestParameter(signature) && - signature.parameters.length < getDecoratorArgumentCount(decorator, signature)); + function isPotentiallyUncalledDecorator( + decorator: Decorator, + signatures: readonly Signature[] + ) { + return ( + signatures.length && + every( + signatures, + (signature) => + signature.minArgumentCount === 0 && + !signatureHasRestParameter(signature) && + signature.parameters.length < + getDecoratorArgumentCount(decorator, signature) + ) + ); } - function resolveSignature(node: CallLikeExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { + function resolveSignature( + node: CallLikeExpression, + candidatesOutArray: Signature[] | undefined, + checkMode: CheckMode + ): Signature { switch (node.kind) { case SyntaxKind.CallExpression: - return resolveCallExpression(node, candidatesOutArray, checkMode); + return resolveCallExpression( + node, + candidatesOutArray, + checkMode + ); case SyntaxKind.NewExpression: - return resolveNewExpression(node, candidatesOutArray, checkMode); + return resolveNewExpression( + node, + candidatesOutArray, + checkMode + ); case SyntaxKind.TaggedTemplateExpression: - return resolveTaggedTemplateExpression(node, candidatesOutArray, checkMode); + return resolveTaggedTemplateExpression( + node, + candidatesOutArray, + checkMode + ); case SyntaxKind.Decorator: return resolveDecorator(node, candidatesOutArray, checkMode); case SyntaxKind.JsxOpeningFragment: case SyntaxKind.JsxOpeningElement: case SyntaxKind.JsxSelfClosingElement: - return resolveJsxOpeningLikeElement(node, candidatesOutArray, checkMode); + return resolveJsxOpeningLikeElement( + node, + candidatesOutArray, + checkMode + ); case SyntaxKind.BinaryExpression: - return resolveInstanceofExpression(node, candidatesOutArray, checkMode); + return resolveInstanceofExpression( + node, + candidatesOutArray, + checkMode + ); } - Debug.assertNever(node, "Branch in 'resolveSignature' should be unreachable."); + Debug.assertNever( + node, + "Branch in 'resolveSignature' should be unreachable." + ); } /** @@ -37467,7 +66102,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * the function will fill it up with appropriate candidate signatures * @return a signature of the call-like expression or undefined if one can't be found */ - function getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[] | undefined, checkMode?: CheckMode): Signature { + function getResolvedSignature( + node: CallLikeExpression, + candidatesOutArray?: Signature[] | undefined, + checkMode?: CheckMode + ): Signature { const links = getNodeLinks(node); // If getResolvedSignature has already been called, we will have cached the resolvedSignature. // However, it is possible that either candidatesOutArray was not passed in the first time, @@ -37488,7 +66127,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { resolutionStart = resolutionTargets.length; } links.resolvedSignature = resolvingSignature; - const result = resolveSignature(node, candidatesOutArray, checkMode || CheckMode.Normal); + const result = resolveSignature( + node, + candidatesOutArray, + checkMode || CheckMode.Normal + ); resolutionStart = saveResolutionStart; // When CheckMode.SkipGenericFunctions is set we use resolvingSignature to indicate that call // resolution should be deferred. @@ -37496,7 +66139,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If signature resolution originated in control flow type analysis (for example to compute the // assigned type in a flow assignment) we don't cache the result as it may be based on temporary // types from the control flow analysis. - links.resolvedSignature = flowLoopStart === flowLoopCount ? result : cached; + links.resolvedSignature = + flowLoopStart === flowLoopCount ? result : cached; } return result; } @@ -37505,19 +66149,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Indicates whether a declaration can be treated as a constructor in a JavaScript * file. */ - function isJSConstructor(node: Node | undefined): node is FunctionDeclaration | FunctionExpression { + function isJSConstructor( + node: Node | undefined + ): node is FunctionDeclaration | FunctionExpression { if (!node || !isInJSFile(node)) { return false; } - const func = isFunctionDeclaration(node) || isFunctionExpression(node) ? node : - (isVariableDeclaration(node) || isPropertyAssignment(node)) && node.initializer && isFunctionExpression(node.initializer) ? node.initializer : - undefined; + const func = + isFunctionDeclaration(node) || isFunctionExpression(node) + ? node + : (isVariableDeclaration(node) || isPropertyAssignment(node)) && + node.initializer && + isFunctionExpression(node.initializer) + ? node.initializer + : undefined; if (func) { // If the node has a @class or @constructor tag, treat it like a constructor. if (getJSDocClassTag(node)) return true; // If the node is a property of an object literal. - if (isPropertyAssignment(walkUpParenthesizedExpressions(func.parent))) return false; + if ( + isPropertyAssignment( + walkUpParenthesizedExpressions(func.parent) + ) + ) + return false; // If the symbol of the node has members, treat it like a constructor. const symbol = getSymbolOfDeclaration(func); @@ -37529,8 +66185,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function mergeJSSymbols(target: Symbol, source: Symbol | undefined) { if (source) { const links = getSymbolLinks(source); - if (!links.inferredClassSymbol || !links.inferredClassSymbol.has(getSymbolId(target))) { - const inferred = isTransientSymbol(target) ? target : cloneSymbol(target); + if ( + !links.inferredClassSymbol || + !links.inferredClassSymbol.has(getSymbolId(target)) + ) { + const inferred = isTransientSymbol(target) + ? target + : cloneSymbol(target); inferred.exports = inferred.exports || createSymbolTable(); inferred.members = inferred.members || createSymbolTable(); inferred.flags |= source.flags & SymbolFlags.Class; @@ -37540,7 +66201,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (source.members?.size) { mergeSymbolTable(inferred.members, source.members); } - (links.inferredClassSymbol || (links.inferredClassSymbol = new Map())).set(getSymbolId(inferred), inferred); + ( + links.inferredClassSymbol || + (links.inferredClassSymbol = new Map()) + ).set(getSymbolId(inferred), inferred); return inferred; } return links.inferredClassSymbol.get(getSymbolId(target)); @@ -37548,53 +66212,89 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getAssignedClassSymbol(decl: Declaration): Symbol | undefined { - const assignmentSymbol = decl && getSymbolOfExpando(decl, /*allowDeclaration*/ true); - const prototype = assignmentSymbol?.exports?.get("prototype" as __String); - const init = prototype?.valueDeclaration && getAssignedJSPrototype(prototype.valueDeclaration); + const assignmentSymbol = + decl && getSymbolOfExpando(decl, /*allowDeclaration*/ true); + const prototype = assignmentSymbol?.exports?.get( + "prototype" as __String + ); + const init = + prototype?.valueDeclaration && + getAssignedJSPrototype(prototype.valueDeclaration); return init ? getSymbolOfDeclaration(init) : undefined; } - function getSymbolOfExpando(node: Node, allowDeclaration: boolean): Symbol | undefined { + function getSymbolOfExpando( + node: Node, + allowDeclaration: boolean + ): Symbol | undefined { if (!node.parent) { return undefined; } let name: Expression | BindingName | undefined; let decl: Node | undefined; - if (isVariableDeclaration(node.parent) && node.parent.initializer === node) { - if (!isInJSFile(node) && !(isVarConstLike(node.parent) && isFunctionLikeDeclaration(node))) { + if ( + isVariableDeclaration(node.parent) && + node.parent.initializer === node + ) { + if ( + !isInJSFile(node) && + !( + isVarConstLike(node.parent) && + isFunctionLikeDeclaration(node) + ) + ) { return undefined; } name = node.parent.name; decl = node.parent; - } - else if (isBinaryExpression(node.parent)) { + } else if (isBinaryExpression(node.parent)) { const parentNode = node.parent; const parentNodeOperator = node.parent.operatorToken.kind; - if (parentNodeOperator === SyntaxKind.EqualsToken && (allowDeclaration || parentNode.right === node)) { + if ( + parentNodeOperator === SyntaxKind.EqualsToken && + (allowDeclaration || parentNode.right === node) + ) { name = parentNode.left; decl = name; - } - else if (parentNodeOperator === SyntaxKind.BarBarToken || parentNodeOperator === SyntaxKind.QuestionQuestionToken) { - if (isVariableDeclaration(parentNode.parent) && parentNode.parent.initializer === parentNode) { + } else if ( + parentNodeOperator === SyntaxKind.BarBarToken || + parentNodeOperator === SyntaxKind.QuestionQuestionToken + ) { + if ( + isVariableDeclaration(parentNode.parent) && + parentNode.parent.initializer === parentNode + ) { name = parentNode.parent.name; decl = parentNode.parent; - } - else if (isBinaryExpression(parentNode.parent) && parentNode.parent.operatorToken.kind === SyntaxKind.EqualsToken && (allowDeclaration || parentNode.parent.right === parentNode)) { + } else if ( + isBinaryExpression(parentNode.parent) && + parentNode.parent.operatorToken.kind === + SyntaxKind.EqualsToken && + (allowDeclaration || parentNode.parent.right === parentNode) + ) { name = parentNode.parent.left; decl = name; } - if (!name || !isBindableStaticNameExpression(name) || !isSameEntityName(name, parentNode.left)) { + if ( + !name || + !isBindableStaticNameExpression(name) || + !isSameEntityName(name, parentNode.left) + ) { return undefined; } } - } - else if (allowDeclaration && isFunctionDeclaration(node)) { + } else if (allowDeclaration && isFunctionDeclaration(node)) { name = node.name; decl = node; } - if (!decl || !name || (!allowDeclaration && !getExpandoInitializer(node, isPrototypeAccess(name)))) { + if ( + !decl || + !name || + (!allowDeclaration && + !getExpandoInitializer(node, isPrototypeAccess(name))) + ) { return undefined; } return getSymbolOfNode(decl); @@ -37608,7 +66308,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { while (parent && parent.kind === SyntaxKind.PropertyAccessExpression) { parent = parent.parent; } - if (parent && isBinaryExpression(parent) && isPrototypeAccess(parent.left) && parent.operatorToken.kind === SyntaxKind.EqualsToken) { + if ( + parent && + isBinaryExpression(parent) && + isPrototypeAccess(parent.left) && + parent.operatorToken.kind === SyntaxKind.EqualsToken + ) { const right = getInitializerOfBinaryExpression(parent); return isObjectLiteralExpression(right) && right; } @@ -37619,10 +66324,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param node The call/new expression to be checked. * @returns On success, the expression's signature's return type. On failure, anyType. */ - function checkCallExpression(node: CallExpression | NewExpression, checkMode?: CheckMode): Type { + function checkCallExpression( + node: CallExpression | NewExpression, + checkMode?: CheckMode + ): Type { checkGrammarTypeArguments(node, node.typeArguments); - const signature = getResolvedSignature(node, /*candidatesOutArray*/ undefined, checkMode); + const signature = getResolvedSignature( + node, + /*candidatesOutArray*/ undefined, + checkMode + ); if (signature === resolvingSignature) { // CheckMode.SkipGenericFunctions is enabled and this is a call to a generic function that // returns a function type. We defer checking and return silentNeverType. @@ -37643,13 +66355,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { declaration.kind !== SyntaxKind.Constructor && declaration.kind !== SyntaxKind.ConstructSignature && declaration.kind !== SyntaxKind.ConstructorType && - !(isJSDocSignature(declaration) && getJSDocRoot(declaration)?.parent?.kind === SyntaxKind.Constructor) && + !( + isJSDocSignature(declaration) && + getJSDocRoot(declaration)?.parent?.kind === + SyntaxKind.Constructor + ) && !isJSDocConstructSignature(declaration) && !isJSConstructor(declaration) ) { // When resolved signature is a call signature (and not a construct signature) the result type is any if (noImplicitAny) { - error(node, Diagnostics.new_expression_whose_target_lacks_a_construct_signature_implicitly_has_an_any_type); + error( + node, + Diagnostics.new_expression_whose_target_lacks_a_construct_signature_implicitly_has_an_any_type + ); } return anyType; } @@ -37657,32 +66376,56 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // In JavaScript files, calls to any identifier 'require' are treated as external module imports if (isInJSFile(node) && isCommonJsRequire(node)) { - return resolveExternalModuleTypeByLiteral(node.arguments![0] as StringLiteral); + return resolveExternalModuleTypeByLiteral( + node.arguments![0] as StringLiteral + ); } const returnType = getReturnTypeOfSignature(signature); // Treat any call to the global 'Symbol' function that is part of a const variable or readonly property // as a fresh unique symbol literal type. - if (returnType.flags & TypeFlags.ESSymbolLike && isSymbolOrSymbolForCall(node)) { - return getESSymbolLikeTypeForNode(walkUpParenthesizedExpressions(node.parent)); + if ( + returnType.flags & TypeFlags.ESSymbolLike && + isSymbolOrSymbolForCall(node) + ) { + return getESSymbolLikeTypeForNode( + walkUpParenthesizedExpressions(node.parent) + ); } if ( - node.kind === SyntaxKind.CallExpression && !node.questionDotToken && node.parent.kind === SyntaxKind.ExpressionStatement && - returnType.flags & TypeFlags.Void && getTypePredicateOfSignature(signature) + node.kind === SyntaxKind.CallExpression && + !node.questionDotToken && + node.parent.kind === SyntaxKind.ExpressionStatement && + returnType.flags & TypeFlags.Void && + getTypePredicateOfSignature(signature) ) { if (!isDottedName(node.expression)) { - error(node.expression, Diagnostics.Assertions_require_the_call_target_to_be_an_identifier_or_qualified_name); - } - else if (!getEffectsSignature(node)) { - const diagnostic = error(node.expression, Diagnostics.Assertions_require_every_name_in_the_call_target_to_be_declared_with_an_explicit_type_annotation); + error( + node.expression, + Diagnostics.Assertions_require_the_call_target_to_be_an_identifier_or_qualified_name + ); + } else if (!getEffectsSignature(node)) { + const diagnostic = error( + node.expression, + Diagnostics.Assertions_require_every_name_in_the_call_target_to_be_declared_with_an_explicit_type_annotation + ); getTypeOfDottedName(node.expression, diagnostic); } } if (isInJSFile(node)) { - const jsSymbol = getSymbolOfExpando(node, /*allowDeclaration*/ false); + const jsSymbol = getSymbolOfExpando( + node, + /*allowDeclaration*/ false + ); if (jsSymbol?.exports?.size) { - const jsAssignmentType = createAnonymousType(jsSymbol, jsSymbol.exports, emptyArray, emptyArray, emptyArray); + const jsAssignmentType = createAnonymousType( + jsSymbol, + jsSymbol.exports, + emptyArray, + emptyArray, + emptyArray + ); jsAssignmentType.objectFlags |= ObjectFlags.JSLiteral; return getIntersectionType([returnType, jsAssignmentType]); } @@ -37691,12 +66434,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return returnType; } - function checkDeprecatedSignature(signature: Signature, node: CallLikeExpression) { - if (signature.flags & SignatureFlags.IsSignatureCandidateForOverloadFailure) return; - if (signature.declaration && signature.declaration.flags & NodeFlags.Deprecated) { + function checkDeprecatedSignature( + signature: Signature, + node: CallLikeExpression + ) { + if ( + signature.flags & + SignatureFlags.IsSignatureCandidateForOverloadFailure + ) + return; + if ( + signature.declaration && + signature.declaration.flags & NodeFlags.Deprecated + ) { const suggestionNode = getDeprecatedSuggestionNode(node); - const name = tryGetPropertyAccessOrIdentifierToString(getInvokedExpression(node)); - addDeprecatedSuggestionWithSignature(suggestionNode, signature.declaration, name, signatureToString(signature)); + const name = tryGetPropertyAccessOrIdentifierToString( + getInvokedExpression(node) + ); + addDeprecatedSuggestionWithSignature( + suggestionNode, + signature.declaration, + name, + signatureToString(signature) + ); } } @@ -37706,19 +66466,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.CallExpression: case SyntaxKind.Decorator: case SyntaxKind.NewExpression: - return getDeprecatedSuggestionNode((node as Decorator | CallExpression | NewExpression).expression); + return getDeprecatedSuggestionNode( + (node as Decorator | CallExpression | NewExpression) + .expression + ); case SyntaxKind.TaggedTemplateExpression: - return getDeprecatedSuggestionNode((node as TaggedTemplateExpression).tag); + return getDeprecatedSuggestionNode( + (node as TaggedTemplateExpression).tag + ); case SyntaxKind.JsxOpeningElement: case SyntaxKind.JsxSelfClosingElement: - return getDeprecatedSuggestionNode((node as JsxOpeningLikeElement).tagName); + return getDeprecatedSuggestionNode( + (node as JsxOpeningLikeElement).tagName + ); case SyntaxKind.ElementAccessExpression: return (node as ElementAccessExpression).argumentExpression; case SyntaxKind.PropertyAccessExpression: return (node as PropertyAccessExpression).name; case SyntaxKind.TypeReference: const typeReference = node as TypeReferenceNode; - return isQualifiedName(typeReference.typeName) ? typeReference.typeName.right : typeReference; + return isQualifiedName(typeReference.typeName) + ? typeReference.typeName.right + : typeReference; default: return node; } @@ -37727,7 +66496,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isSymbolOrSymbolForCall(node: Node) { if (!isCallExpression(node)) return false; let left = node.expression; - if (isPropertyAccessExpression(left) && left.name.escapedText === "for") { + if ( + isPropertyAccessExpression(left) && + left.name.escapedText === "for" + ) { left = left.expression; } if (!isIdentifier(left) || left.escapedText !== "Symbol") { @@ -37735,12 +66507,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // make sure `Symbol` is the global symbol - const globalESSymbol = getGlobalESSymbolConstructorSymbol(/*reportErrors*/ false); + const globalESSymbol = getGlobalESSymbolConstructorSymbol( + /*reportErrors*/ false + ); if (!globalESSymbol) { return false; } - return globalESSymbol === resolveName(left, "Symbol" as __String, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*isUse*/ false); + return ( + globalESSymbol === + resolveName( + left, + "Symbol" as __String, + SymbolFlags.Value, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ false + ) + ); } function checkImportCallExpression(node: ImportCall): Type { @@ -37753,54 +66536,107 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const specifier = node.arguments[0]; const specifierType = checkExpressionCached(specifier); - const optionsType = node.arguments.length > 1 ? checkExpressionCached(node.arguments[1]) : undefined; + const optionsType = + node.arguments.length > 1 + ? checkExpressionCached(node.arguments[1]) + : undefined; // Even though multiple arguments is grammatically incorrect, type-check extra arguments for completion for (let i = 2; i < node.arguments.length; ++i) { checkExpressionCached(node.arguments[i]); } - if (specifierType.flags & TypeFlags.Undefined || specifierType.flags & TypeFlags.Null || !isTypeAssignableTo(specifierType, stringType)) { - error(specifier, Diagnostics.Dynamic_import_s_specifier_must_be_of_type_string_but_here_has_type_0, typeToString(specifierType)); + if ( + specifierType.flags & TypeFlags.Undefined || + specifierType.flags & TypeFlags.Null || + !isTypeAssignableTo(specifierType, stringType) + ) { + error( + specifier, + Diagnostics.Dynamic_import_s_specifier_must_be_of_type_string_but_here_has_type_0, + typeToString(specifierType) + ); } if (optionsType) { - const importCallOptionsType = getGlobalImportCallOptionsType(/*reportErrors*/ true); + const importCallOptionsType = getGlobalImportCallOptionsType( + /*reportErrors*/ true + ); if (importCallOptionsType !== emptyObjectType) { - checkTypeAssignableTo(optionsType, getNullableType(importCallOptionsType, TypeFlags.Undefined), node.arguments[1]); + checkTypeAssignableTo( + optionsType, + getNullableType(importCallOptionsType, TypeFlags.Undefined), + node.arguments[1] + ); } } // resolveExternalModuleName will return undefined if the moduleReferenceExpression is not a string literal const moduleSymbol = resolveExternalModuleName(node, specifier); if (moduleSymbol) { - const esModuleSymbol = resolveESModuleSymbol(moduleSymbol, specifier, /*dontResolveAlias*/ true, /*suppressInteropError*/ false); + const esModuleSymbol = resolveESModuleSymbol( + moduleSymbol, + specifier, + /*dontResolveAlias*/ true, + /*suppressInteropError*/ false + ); if (esModuleSymbol) { return createPromiseReturnType( node, - getTypeWithSyntheticDefaultOnly(getTypeOfSymbol(esModuleSymbol), esModuleSymbol, moduleSymbol, specifier) || - getTypeWithSyntheticDefaultImportType(getTypeOfSymbol(esModuleSymbol), esModuleSymbol, moduleSymbol, specifier), + getTypeWithSyntheticDefaultOnly( + getTypeOfSymbol(esModuleSymbol), + esModuleSymbol, + moduleSymbol, + specifier + ) || + getTypeWithSyntheticDefaultImportType( + getTypeOfSymbol(esModuleSymbol), + esModuleSymbol, + moduleSymbol, + specifier + ) ); } } return createPromiseReturnType(node, anyType); } - function createDefaultPropertyWrapperForModule(symbol: Symbol, originalSymbol: Symbol | undefined, anonymousSymbol?: Symbol | undefined) { + function createDefaultPropertyWrapperForModule( + symbol: Symbol, + originalSymbol: Symbol | undefined, + anonymousSymbol?: Symbol | undefined + ) { const memberTable = createSymbolTable(); - const newSymbol = createSymbol(SymbolFlags.Alias, InternalSymbolName.Default); + const newSymbol = createSymbol( + SymbolFlags.Alias, + InternalSymbolName.Default + ); newSymbol.parent = originalSymbol; newSymbol.links.nameType = getStringLiteralType("default"); newSymbol.links.aliasTarget = resolveSymbol(symbol); memberTable.set(InternalSymbolName.Default, newSymbol); - return createAnonymousType(anonymousSymbol, memberTable, emptyArray, emptyArray, emptyArray); + return createAnonymousType( + anonymousSymbol, + memberTable, + emptyArray, + emptyArray, + emptyArray + ); } - function getTypeWithSyntheticDefaultOnly(type: Type, symbol: Symbol, originalSymbol: Symbol, moduleSpecifier: Expression) { + function getTypeWithSyntheticDefaultOnly( + type: Type, + symbol: Symbol, + originalSymbol: Symbol, + moduleSpecifier: Expression + ) { const hasDefaultOnly = isOnlyImportableAsDefault(moduleSpecifier); if (hasDefaultOnly && type && !isErrorType(type)) { const synthType = type as SyntheticDefaultModuleType; if (!synthType.defaultOnlyType) { - const type = createDefaultPropertyWrapperForModule(symbol, originalSymbol); + const type = createDefaultPropertyWrapperForModule( + symbol, + originalSymbol + ); synthType.defaultOnlyType = type; } return synthType.defaultOnlyType; @@ -37808,19 +66644,44 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - function getTypeWithSyntheticDefaultImportType(type: Type, symbol: Symbol, originalSymbol: Symbol, moduleSpecifier: Expression): Type { + function getTypeWithSyntheticDefaultImportType( + type: Type, + symbol: Symbol, + originalSymbol: Symbol, + moduleSpecifier: Expression + ): Type { if (allowSyntheticDefaultImports && type && !isErrorType(type)) { const synthType = type as SyntheticDefaultModuleType; if (!synthType.syntheticType) { const file = originalSymbol.declarations?.find(isSourceFile); - const hasSyntheticDefault = canHaveSyntheticDefault(file, originalSymbol, /*dontResolveAlias*/ false, moduleSpecifier); + const hasSyntheticDefault = canHaveSyntheticDefault( + file, + originalSymbol, + /*dontResolveAlias*/ false, + moduleSpecifier + ); if (hasSyntheticDefault) { - const anonymousSymbol = createSymbol(SymbolFlags.TypeLiteral, InternalSymbolName.Type); - const defaultContainingObject = createDefaultPropertyWrapperForModule(symbol, originalSymbol, anonymousSymbol); + const anonymousSymbol = createSymbol( + SymbolFlags.TypeLiteral, + InternalSymbolName.Type + ); + const defaultContainingObject = + createDefaultPropertyWrapperForModule( + symbol, + originalSymbol, + anonymousSymbol + ); anonymousSymbol.links.type = defaultContainingObject; - synthType.syntheticType = isValidSpreadType(type) ? getSpreadType(type, defaultContainingObject, anonymousSymbol, /*objectFlags*/ 0, /*readonly*/ false) : defaultContainingObject; - } - else { + synthType.syntheticType = isValidSpreadType(type) + ? getSpreadType( + type, + defaultContainingObject, + anonymousSymbol, + /*objectFlags*/ 0, + /*readonly*/ false + ) + : defaultContainingObject; + } else { synthType.syntheticType = type; } } @@ -37836,7 +66697,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Make sure require is not a local function if (!isIdentifier(node.expression)) return Debug.fail(); - const resolvedRequire = resolveName(node.expression, node.expression.escapedText, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*isUse*/ true)!; // TODO: GH#18217 + const resolvedRequire = resolveName( + node.expression, + node.expression.escapedText, + SymbolFlags.Value, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ true + )!; // TODO: GH#18217 if (resolvedRequire === requireSymbol) { return true; } @@ -37845,39 +66712,68 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - const targetDeclarationKind = resolvedRequire.flags & SymbolFlags.Function - ? SyntaxKind.FunctionDeclaration - : resolvedRequire.flags & SymbolFlags.Variable - ? SyntaxKind.VariableDeclaration - : SyntaxKind.Unknown; + const targetDeclarationKind = + resolvedRequire.flags & SymbolFlags.Function + ? SyntaxKind.FunctionDeclaration + : resolvedRequire.flags & SymbolFlags.Variable + ? SyntaxKind.VariableDeclaration + : SyntaxKind.Unknown; if (targetDeclarationKind !== SyntaxKind.Unknown) { - const decl = getDeclarationOfKind(resolvedRequire, targetDeclarationKind)!; + const decl = getDeclarationOfKind( + resolvedRequire, + targetDeclarationKind + )!; // function/variable declaration should be ambient return !!decl && !!(decl.flags & NodeFlags.Ambient); } return false; } - function checkTaggedTemplateExpression(node: TaggedTemplateExpression): Type { - if (!checkGrammarTaggedTemplateChain(node)) checkGrammarTypeArguments(node, node.typeArguments); + function checkTaggedTemplateExpression( + node: TaggedTemplateExpression + ): Type { + if (!checkGrammarTaggedTemplateChain(node)) + checkGrammarTypeArguments(node, node.typeArguments); if (languageVersion < LanguageFeatureMinimumTarget.TaggedTemplates) { - checkExternalEmitHelpers(node, ExternalEmitHelpers.MakeTemplateObject); + checkExternalEmitHelpers( + node, + ExternalEmitHelpers.MakeTemplateObject + ); } const signature = getResolvedSignature(node); checkDeprecatedSignature(signature, node); return getReturnTypeOfSignature(signature); } - function checkAssertion(node: AssertionExpression, checkMode: CheckMode | undefined) { + function checkAssertion( + node: AssertionExpression, + checkMode: CheckMode | undefined + ) { if (node.kind === SyntaxKind.TypeAssertionExpression) { const file = getSourceFileOfNode(node); - if (file && fileExtensionIsOneOf(file.fileName, [Extension.Cts, Extension.Mts])) { - grammarErrorOnNode(node, Diagnostics.This_syntax_is_reserved_in_files_with_the_mts_or_cts_extension_Use_an_as_expression_instead); + if ( + file && + fileExtensionIsOneOf(file.fileName, [ + Extension.Cts, + Extension.Mts, + ]) + ) { + grammarErrorOnNode( + node, + Diagnostics.This_syntax_is_reserved_in_files_with_the_mts_or_cts_extension_Use_an_as_expression_instead + ); } if (compilerOptions.erasableSyntaxOnly) { const start = skipTrivia(file.text, node.pos); const end = node.expression.pos; - diagnostics.add(createFileDiagnostic(file, start, end - start, Diagnostics.This_syntax_is_not_allowed_when_erasableSyntaxOnly_is_enabled)); + diagnostics.add( + createFileDiagnostic( + file, + start, + end - start, + Diagnostics.This_syntax_is_not_allowed_when_erasableSyntaxOnly_is_enabled + ) + ); } } return checkAssertionWorker(node, checkMode); @@ -37896,27 +66792,49 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.TemplateExpression: return true; case SyntaxKind.ParenthesizedExpression: - return isValidConstAssertionArgument((node as ParenthesizedExpression).expression); + return isValidConstAssertionArgument( + (node as ParenthesizedExpression).expression + ); case SyntaxKind.PrefixUnaryExpression: const op = (node as PrefixUnaryExpression).operator; const arg = (node as PrefixUnaryExpression).operand; - return op === SyntaxKind.MinusToken && (arg.kind === SyntaxKind.NumericLiteral || arg.kind === SyntaxKind.BigIntLiteral) || - op === SyntaxKind.PlusToken && arg.kind === SyntaxKind.NumericLiteral; + return ( + (op === SyntaxKind.MinusToken && + (arg.kind === SyntaxKind.NumericLiteral || + arg.kind === SyntaxKind.BigIntLiteral)) || + (op === SyntaxKind.PlusToken && + arg.kind === SyntaxKind.NumericLiteral) + ); case SyntaxKind.PropertyAccessExpression: case SyntaxKind.ElementAccessExpression: - const expr = skipParentheses((node as PropertyAccessExpression | ElementAccessExpression).expression); - const symbol = isEntityNameExpression(expr) ? resolveEntityName(expr, SymbolFlags.Value, /*ignoreErrors*/ true) : undefined; + const expr = skipParentheses( + (node as PropertyAccessExpression | ElementAccessExpression) + .expression + ); + const symbol = isEntityNameExpression(expr) + ? resolveEntityName( + expr, + SymbolFlags.Value, + /*ignoreErrors*/ true + ) + : undefined; return !!(symbol && symbol.flags & SymbolFlags.Enum); } return false; } - function checkAssertionWorker(node: JSDocTypeAssertion | AssertionExpression, checkMode: CheckMode | undefined) { + function checkAssertionWorker( + node: JSDocTypeAssertion | AssertionExpression, + checkMode: CheckMode | undefined + ) { const { type, expression } = getAssertionTypeAndExpression(node); const exprType = checkExpression(expression, checkMode); if (isConstTypeReference(type)) { if (!isValidConstAssertionArgument(expression)) { - error(expression, Diagnostics.A_const_assertions_can_only_be_applied_to_references_to_enum_members_or_string_number_boolean_array_or_object_literals); + error( + expression, + Diagnostics.A_const_assertions_can_only_be_applied_to_references_to_enum_members_or_string_number_boolean_array_or_object_literals + ); } return getRegularTypeOfLiteralType(exprType); } @@ -37927,7 +66845,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getTypeFromTypeNode(type); } - function getAssertionTypeAndExpression(node: JSDocTypeAssertion | AssertionExpression) { + function getAssertionTypeAndExpression( + node: JSDocTypeAssertion | AssertionExpression + ) { let type: TypeNode; let expression: Expression; switch (node.kind) { @@ -37945,18 +66865,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return { type, expression }; } - function checkAssertionDeferred(node: JSDocTypeAssertion | AssertionExpression) { + function checkAssertionDeferred( + node: JSDocTypeAssertion | AssertionExpression + ) { const { type } = getAssertionTypeAndExpression(node); const errNode = isParenthesizedExpression(node) ? type : node; const links = getNodeLinks(node); Debug.assertIsDefined(links.assertionExpressionType); - const exprType = getRegularTypeOfObjectLiteral(getBaseTypeOfLiteralType(links.assertionExpressionType)); + const exprType = getRegularTypeOfObjectLiteral( + getBaseTypeOfLiteralType(links.assertionExpressionType) + ); const targetType = getTypeFromTypeNode(type); if (!isErrorType(targetType)) { addLazyDiagnostic(() => { const widenedType = getWidenedType(exprType); if (!isTypeComparableTo(targetType, widenedType)) { - checkTypeComparableTo(exprType, targetType, errNode, 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); + checkTypeComparableTo( + exprType, + targetType, + errNode, + 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 + ); } }); } @@ -37964,33 +66893,61 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkNonNullChain(node: NonNullChain) { const leftType = checkExpression(node.expression); - const nonOptionalType = getOptionalExpressionType(leftType, node.expression); - return propagateOptionalTypeMarker(getNonNullableType(nonOptionalType), node, nonOptionalType !== leftType); + const nonOptionalType = getOptionalExpressionType( + leftType, + node.expression + ); + return propagateOptionalTypeMarker( + getNonNullableType(nonOptionalType), + node, + nonOptionalType !== leftType + ); } function checkNonNullAssertion(node: NonNullExpression) { - return node.flags & NodeFlags.OptionalChain ? checkNonNullChain(node as NonNullChain) : - getNonNullableType(checkExpression(node.expression)); + return node.flags & NodeFlags.OptionalChain + ? checkNonNullChain(node as NonNullChain) + : getNonNullableType(checkExpression(node.expression)); } - function checkExpressionWithTypeArguments(node: ExpressionWithTypeArguments | TypeQueryNode) { + function checkExpressionWithTypeArguments( + node: ExpressionWithTypeArguments | TypeQueryNode + ) { checkGrammarExpressionWithTypeArguments(node); forEach(node.typeArguments, checkSourceElement); if (node.kind === SyntaxKind.ExpressionWithTypeArguments) { const parent = walkUpParenthesizedExpressions(node.parent); - if (parent.kind === SyntaxKind.BinaryExpression && (parent as BinaryExpression).operatorToken.kind === SyntaxKind.InstanceOfKeyword && isNodeDescendantOf(node, (parent as BinaryExpression).right)) { - error(node, Diagnostics.The_right_hand_side_of_an_instanceof_expression_must_not_be_an_instantiation_expression); + if ( + parent.kind === SyntaxKind.BinaryExpression && + (parent as BinaryExpression).operatorToken.kind === + SyntaxKind.InstanceOfKeyword && + isNodeDescendantOf(node, (parent as BinaryExpression).right) + ) { + error( + node, + Diagnostics.The_right_hand_side_of_an_instanceof_expression_must_not_be_an_instantiation_expression + ); } } - const exprType = node.kind === SyntaxKind.ExpressionWithTypeArguments ? checkExpression(node.expression) : - isThisIdentifier(node.exprName) ? checkThisExpression(node.exprName) : - checkExpression(node.exprName); + const exprType = + node.kind === SyntaxKind.ExpressionWithTypeArguments + ? checkExpression(node.expression) + : isThisIdentifier(node.exprName) + ? checkThisExpression(node.exprName) + : checkExpression(node.exprName); return getInstantiationExpressionType(exprType, node); } - function getInstantiationExpressionType(exprType: Type, node: NodeWithTypeArguments) { + function getInstantiationExpressionType( + exprType: Type, + node: NodeWithTypeArguments + ) { const typeArguments = node.typeArguments; - if (exprType === silentNeverType || isErrorType(exprType) || !some(typeArguments)) { + if ( + exprType === silentNeverType || + isErrorType(exprType) || + !some(typeArguments) + ) { return exprType; } const links = getNodeLinks(node); @@ -38004,9 +66961,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let nonApplicableType: Type | undefined; const result = getInstantiatedType(exprType); links.instantiationExpressionTypes.set(exprType.id, result); - const errorType = hasSomeApplicableSignature ? nonApplicableType : exprType; + const errorType = hasSomeApplicableSignature + ? nonApplicableType + : exprType; if (errorType) { - diagnostics.add(createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Type_0_has_no_signatures_for_which_the_type_argument_list_is_applicable, typeToString(errorType))); + diagnostics.add( + createDiagnosticForNodeArray( + getSourceFileOfNode(node), + typeArguments, + Diagnostics.Type_0_has_no_signatures_for_which_the_type_argument_list_is_applicable, + typeToString(errorType) + ) + ); } return result; @@ -38022,42 +66988,83 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getInstantiatedTypePart(type: Type): Type { if (type.flags & TypeFlags.Object) { - const resolved = resolveStructuredTypeMembers(type as ObjectType); - const callSignatures = getInstantiatedSignatures(resolved.callSignatures); - const constructSignatures = getInstantiatedSignatures(resolved.constructSignatures); - hasSignatures ||= resolved.callSignatures.length !== 0 || resolved.constructSignatures.length !== 0; - hasApplicableSignature ||= callSignatures.length !== 0 || constructSignatures.length !== 0; - if (callSignatures !== resolved.callSignatures || constructSignatures !== resolved.constructSignatures) { - const result = createAnonymousType(createSymbol(SymbolFlags.None, InternalSymbolName.InstantiationExpression), resolved.members, callSignatures, constructSignatures, resolved.indexInfos) as ResolvedType & InstantiationExpressionType; - result.objectFlags |= ObjectFlags.InstantiationExpressionType; + const resolved = resolveStructuredTypeMembers( + type as ObjectType + ); + const callSignatures = getInstantiatedSignatures( + resolved.callSignatures + ); + const constructSignatures = getInstantiatedSignatures( + resolved.constructSignatures + ); + hasSignatures ||= + resolved.callSignatures.length !== 0 || + resolved.constructSignatures.length !== 0; + hasApplicableSignature ||= + callSignatures.length !== 0 || + constructSignatures.length !== 0; + if ( + callSignatures !== resolved.callSignatures || + constructSignatures !== resolved.constructSignatures + ) { + const result = createAnonymousType( + createSymbol( + SymbolFlags.None, + InternalSymbolName.InstantiationExpression + ), + resolved.members, + callSignatures, + constructSignatures, + resolved.indexInfos + ) as ResolvedType & InstantiationExpressionType; + result.objectFlags |= + ObjectFlags.InstantiationExpressionType; result.node = node; return result; } - } - else if (type.flags & TypeFlags.InstantiableNonPrimitive) { + } else if (type.flags & TypeFlags.InstantiableNonPrimitive) { const constraint = getBaseConstraintOfType(type); if (constraint) { - const instantiated = getInstantiatedTypePart(constraint); + const instantiated = + getInstantiatedTypePart(constraint); if (instantiated !== constraint) { return instantiated; } } - } - else if (type.flags & TypeFlags.Union) { + } else if (type.flags & TypeFlags.Union) { return mapType(type, getInstantiatedType); - } - else if (type.flags & TypeFlags.Intersection) { - return getIntersectionType(sameMap((type as IntersectionType).types, getInstantiatedTypePart)); + } else if (type.flags & TypeFlags.Intersection) { + return getIntersectionType( + sameMap( + (type as IntersectionType).types, + getInstantiatedTypePart + ) + ); } return type; } } function getInstantiatedSignatures(signatures: readonly Signature[]) { - const applicableSignatures = filter(signatures, sig => !!sig.typeParameters && hasCorrectTypeArgumentArity(sig, typeArguments)); - return sameMap(applicableSignatures, sig => { - const typeArgumentTypes = checkTypeArguments(sig, typeArguments!, /*reportErrors*/ true); - return typeArgumentTypes ? getSignatureInstantiation(sig, typeArgumentTypes, isInJSFile(sig.declaration)) : sig; + const applicableSignatures = filter( + signatures, + (sig) => + !!sig.typeParameters && + hasCorrectTypeArgumentArity(sig, typeArguments) + ); + return sameMap(applicableSignatures, (sig) => { + const typeArgumentTypes = checkTypeArguments( + sig, + typeArguments!, + /*reportErrors*/ true + ); + return typeArgumentTypes + ? getSignatureInstantiation( + sig, + typeArgumentTypes, + isInJSFile(sig.declaration) + ) + : sig; }); } } @@ -38067,14 +67074,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return checkSatisfiesExpressionWorker(node.expression, node.type); } - function checkSatisfiesExpressionWorker(expression: Expression, target: TypeNode, checkMode?: CheckMode) { + function checkSatisfiesExpressionWorker( + expression: Expression, + target: TypeNode, + checkMode?: CheckMode + ) { const exprType = checkExpression(expression, checkMode); const targetType = getTypeFromTypeNode(target); if (isErrorType(targetType)) { return targetType; } - const errorNode = findAncestor(target.parent, n => n.kind === SyntaxKind.SatisfiesExpression || n.kind === SyntaxKind.JSDocSatisfiesTag); - checkTypeAssignableToAndOptionallyElaborate(exprType, targetType, errorNode, expression, Diagnostics.Type_0_does_not_satisfy_the_expected_type_1); + const errorNode = findAncestor( + target.parent, + (n) => + n.kind === SyntaxKind.SatisfiesExpression || + n.kind === SyntaxKind.JSDocSatisfiesTag + ); + checkTypeAssignableToAndOptionallyElaborate( + exprType, + targetType, + errorNode, + expression, + Diagnostics.Type_0_does_not_satisfy_the_expected_type_1 + ); return exprType; } @@ -38087,7 +67109,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (node.keywordToken === SyntaxKind.ImportKeyword) { if (node.name.escapedText === "defer") { - Debug.assert(!isCallExpression(node.parent) || node.parent.expression !== node, "Trying to get the type of `import.defer` in `import.defer(...)`"); + Debug.assert( + !isCallExpression(node.parent) || + node.parent.expression !== node, + "Trying to get the type of `import.defer` in `import.defer(...)`" + ); return errorType; } return checkImportMetaProperty(node); @@ -38102,7 +67128,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getGlobalImportMetaExpressionType(); case SyntaxKind.NewKeyword: const type = checkNewTargetMetaProperty(node); - return isErrorType(type) ? errorType : createNewTargetExpressionType(type); + return isErrorType(type) + ? errorType + : createNewTargetExpressionType(type); default: Debug.assertNever(node.keywordToken); } @@ -38111,31 +67139,52 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkNewTargetMetaProperty(node: MetaProperty) { const container = getNewTargetContainer(node); if (!container) { - error(node, Diagnostics.Meta_property_0_is_only_allowed_in_the_body_of_a_function_declaration_function_expression_or_constructor, "new.target"); + error( + node, + Diagnostics.Meta_property_0_is_only_allowed_in_the_body_of_a_function_declaration_function_expression_or_constructor, + "new.target" + ); return errorType; - } - else if (container.kind === SyntaxKind.Constructor) { + } else if (container.kind === SyntaxKind.Constructor) { const symbol = getSymbolOfDeclaration(container.parent); return getTypeOfSymbol(symbol); - } - else { + } else { const symbol = getSymbolOfDeclaration(container); return getTypeOfSymbol(symbol); } } function checkImportMetaProperty(node: MetaProperty) { - if (ModuleKind.Node16 <= moduleKind && moduleKind <= ModuleKind.NodeNext) { - if (getSourceFileOfNode(node).impliedNodeFormat !== ModuleKind.ESNext) { - error(node, Diagnostics.The_import_meta_meta_property_is_not_allowed_in_files_which_will_build_into_CommonJS_output); + if ( + ModuleKind.Node16 <= moduleKind && + moduleKind <= ModuleKind.NodeNext + ) { + if ( + getSourceFileOfNode(node).impliedNodeFormat !== + ModuleKind.ESNext + ) { + error( + node, + Diagnostics.The_import_meta_meta_property_is_not_allowed_in_files_which_will_build_into_CommonJS_output + ); } - } - else if (moduleKind < ModuleKind.ES2020 && moduleKind !== ModuleKind.System) { - error(node, Diagnostics.The_import_meta_meta_property_is_only_allowed_when_the_module_option_is_es2020_es2022_esnext_system_node16_node18_node20_or_nodenext); + } else if ( + moduleKind < ModuleKind.ES2020 && + moduleKind !== ModuleKind.System + ) { + error( + node, + Diagnostics.The_import_meta_meta_property_is_only_allowed_when_the_module_option_is_es2020_es2022_esnext_system_node16_node18_node20_or_nodenext + ); } const file = getSourceFileOfNode(node); - Debug.assert(!!(file.flags & NodeFlags.PossiblyContainsImportMeta), "Containing file is missing import meta node flag."); - return node.name.escapedText === "meta" ? getGlobalImportMetaType() : errorType; + Debug.assert( + !!(file.flags & NodeFlags.PossiblyContainsImportMeta), + "Containing file is missing import meta node flag." + ); + return node.name.escapedText === "meta" + ? getGlobalImportMetaType() + : errorType; } function getTypeOfParameter(symbol: Symbol) { @@ -38143,7 +67192,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return addOptionality( getTypeOfSymbol(symbol), /*isProperty*/ false, - /*isOptional*/ !!declaration && (hasInitializer(declaration) || isOptionalDeclaration(declaration)), + /*isOptional*/ !!declaration && + (hasInitializer(declaration) || + isOptionalDeclaration(declaration)) ); } @@ -38153,7 +67204,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param index The index into the tuple * @param elementFlags The {@see ElementFlags} of the tuple element */ - function getTupleElementLabelFromBindingElement(node: BindingElement | ParameterDeclaration, index: number, elementFlags: ElementFlags): __String { + function getTupleElementLabelFromBindingElement( + node: BindingElement | ParameterDeclaration, + index: number, + elementFlags: ElementFlags + ): __String { switch (node.name.kind) { case SyntaxKind.Identifier: { const name = node.name.escapedText; @@ -38169,9 +67224,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // this produces // (x: number, y: number, ...z: number[], z_1: number) => ... // which preserves rest elements of z but gives distinct numbers to fixed elements of 'z' - return elementFlags & ElementFlags.Variable ? name : `${name}_${index}` as __String; - } - else { + return elementFlags & ElementFlags.Variable + ? name + : (`${name}_${index}` as __String); + } else { // given // (...[x]: [number]) => ... // this produces @@ -38183,22 +67239,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // this produces // (x_0: number) => ... // which which numbers fixed elements of 'x' whose tuple element type is variable - return elementFlags & ElementFlags.Fixed ? name : `${name}_n` as __String; + return elementFlags & ElementFlags.Fixed + ? name + : (`${name}_n` as __String); } } case SyntaxKind.ArrayBindingPattern: { if (node.dotDotDotToken) { const elements = node.name.elements; - const lastElement = tryCast(lastOrUndefined(elements), isBindingElement); - const elementCount = elements.length - (lastElement?.dotDotDotToken ? 1 : 0); + const lastElement = tryCast( + lastOrUndefined(elements), + isBindingElement + ); + const elementCount = + elements.length - (lastElement?.dotDotDotToken ? 1 : 0); if (index < elementCount) { const element = elements[index]; if (isBindingElement(element)) { - return getTupleElementLabelFromBindingElement(element, index, elementFlags); + return getTupleElementLabelFromBindingElement( + element, + index, + elementFlags + ); } - } - else if (lastElement?.dotDotDotToken) { - return getTupleElementLabelFromBindingElement(lastElement, index - elementCount, elementFlags); + } else if (lastElement?.dotDotDotToken) { + return getTupleElementLabelFromBindingElement( + lastElement, + index - elementCount, + elementFlags + ); } } break; @@ -38207,20 +67276,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return `arg_${index}` as __String; } - function getTupleElementLabel(d: ParameterDeclaration | NamedTupleMember): __String; - function getTupleElementLabel(d: ParameterDeclaration | NamedTupleMember | undefined, index: number, elementFlags: ElementFlags, restSymbol?: Symbol): __String; - function getTupleElementLabel(d: ParameterDeclaration | NamedTupleMember | undefined, index = 0, elementFlags = ElementFlags.Fixed, restSymbol?: Symbol) { + function getTupleElementLabel( + d: ParameterDeclaration | NamedTupleMember + ): __String; + function getTupleElementLabel( + d: ParameterDeclaration | NamedTupleMember | undefined, + index: number, + elementFlags: ElementFlags, + restSymbol?: Symbol + ): __String; + function getTupleElementLabel( + d: ParameterDeclaration | NamedTupleMember | undefined, + index = 0, + elementFlags = ElementFlags.Fixed, + restSymbol?: Symbol + ) { if (!d) { - const restParameter = tryCast(restSymbol?.valueDeclaration, isParameter); - return restParameter ? getTupleElementLabelFromBindingElement(restParameter, index, elementFlags) : - `${restSymbol?.escapedName ?? "arg"}_${index}` as __String; + const restParameter = tryCast( + restSymbol?.valueDeclaration, + isParameter + ); + return restParameter + ? getTupleElementLabelFromBindingElement( + restParameter, + index, + elementFlags + ) + : (`${restSymbol?.escapedName ?? "arg"}_${index}` as __String); } Debug.assert(isIdentifier(d.name)); // Parameter declarations could be binding patterns, but we only allow identifier names return d.name.escapedText; } - function getParameterNameAtPosition(signature: Signature, pos: number, overrideRestType?: Type) { - const paramCount = signature.parameters.length - (signatureHasRestParameter(signature) ? 1 : 0); + function getParameterNameAtPosition( + signature: Signature, + pos: number, + overrideRestType?: Type + ) { + const paramCount = + signature.parameters.length - + (signatureHasRestParameter(signature) ? 1 : 0); if (pos < paramCount) { return signature.parameters[pos].escapedName; } @@ -38229,26 +67324,45 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isTupleType(restType)) { const tupleType = (restType as TypeReference).target as TupleType; const index = pos - paramCount; - const associatedName = tupleType.labeledElementDeclarations?.[index]; + const associatedName = + tupleType.labeledElementDeclarations?.[index]; const elementFlags = tupleType.elementFlags[index]; - return getTupleElementLabel(associatedName, index, elementFlags, restParameter); + return getTupleElementLabel( + associatedName, + index, + elementFlags, + restParameter + ); } return restParameter.escapedName; } - function getParameterIdentifierInfoAtPosition(signature: Signature, pos: number): { parameter: Identifier; parameterName: __String; isRestParameter: boolean; } | undefined { + function getParameterIdentifierInfoAtPosition( + signature: Signature, + pos: number + ): + | { + parameter: Identifier; + parameterName: __String; + isRestParameter: boolean; + } + | undefined { if (signature.declaration?.kind === SyntaxKind.JSDocFunctionType) { return undefined; } - const paramCount = signature.parameters.length - (signatureHasRestParameter(signature) ? 1 : 0); + const paramCount = + signature.parameters.length - + (signatureHasRestParameter(signature) ? 1 : 0); if (pos < paramCount) { const param = signature.parameters[pos]; const paramIdent = getParameterDeclarationIdentifier(param); - return paramIdent ? { - parameter: paramIdent, - parameterName: param.escapedName, - isRestParameter: false, - } : undefined; + return paramIdent + ? { + parameter: paramIdent, + parameterName: param.escapedName, + isRestParameter: false, + } + : undefined; } const restParameter = signature.parameters[paramCount] || unknownSymbol; @@ -38259,54 +67373,91 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const restType = getTypeOfSymbol(restParameter); if (isTupleType(restType)) { - const associatedNames = ((restType as TypeReference).target as TupleType).labeledElementDeclarations; + const associatedNames = ( + (restType as TypeReference).target as TupleType + ).labeledElementDeclarations; const index = pos - paramCount; const associatedName = associatedNames?.[index]; const isRestTupleElement = !!associatedName?.dotDotDotToken; if (associatedName) { Debug.assert(isIdentifier(associatedName.name)); - return { parameter: associatedName.name, parameterName: associatedName.name.escapedText, isRestParameter: isRestTupleElement }; + return { + parameter: associatedName.name, + parameterName: associatedName.name.escapedText, + isRestParameter: isRestTupleElement, + }; } return undefined; } if (pos === paramCount) { - return { parameter: restIdent, parameterName: restParameter.escapedName, isRestParameter: true }; + return { + parameter: restIdent, + parameterName: restParameter.escapedName, + isRestParameter: true, + }; } return undefined; } function getParameterDeclarationIdentifier(symbol: Symbol) { - return symbol.valueDeclaration && isParameter(symbol.valueDeclaration) && isIdentifier(symbol.valueDeclaration.name) && symbol.valueDeclaration.name; + return ( + symbol.valueDeclaration && + isParameter(symbol.valueDeclaration) && + isIdentifier(symbol.valueDeclaration.name) && + symbol.valueDeclaration.name + ); } - function isValidDeclarationForTupleLabel(d: Declaration): d is NamedTupleMember | (ParameterDeclaration & { name: Identifier; }) { - return d.kind === SyntaxKind.NamedTupleMember || (isParameter(d) && d.name && isIdentifier(d.name)); + function isValidDeclarationForTupleLabel( + d: Declaration + ): d is NamedTupleMember | (ParameterDeclaration & { name: Identifier }) { + return ( + d.kind === SyntaxKind.NamedTupleMember || + (isParameter(d) && d.name && isIdentifier(d.name)) + ); } - function getNameableDeclarationAtPosition(signature: Signature, pos: number) { - const paramCount = signature.parameters.length - (signatureHasRestParameter(signature) ? 1 : 0); + function getNameableDeclarationAtPosition( + signature: Signature, + pos: number + ) { + const paramCount = + signature.parameters.length - + (signatureHasRestParameter(signature) ? 1 : 0); if (pos < paramCount) { const decl = signature.parameters[pos].valueDeclaration; - return decl && isValidDeclarationForTupleLabel(decl) ? decl : undefined; + return decl && isValidDeclarationForTupleLabel(decl) + ? decl + : undefined; } const restParameter = signature.parameters[paramCount] || unknownSymbol; const restType = getTypeOfSymbol(restParameter); if (isTupleType(restType)) { - const associatedNames = ((restType as TypeReference).target as TupleType).labeledElementDeclarations; + const associatedNames = ( + (restType as TypeReference).target as TupleType + ).labeledElementDeclarations; const index = pos - paramCount; return associatedNames && associatedNames[index]; } - return restParameter.valueDeclaration && isValidDeclarationForTupleLabel(restParameter.valueDeclaration) ? restParameter.valueDeclaration : undefined; + return restParameter.valueDeclaration && + isValidDeclarationForTupleLabel(restParameter.valueDeclaration) + ? restParameter.valueDeclaration + : undefined; } function getTypeAtPosition(signature: Signature, pos: number): Type { return tryGetTypeAtPosition(signature, pos) || anyType; } - function tryGetTypeAtPosition(signature: Signature, pos: number): Type | undefined { - const paramCount = signature.parameters.length - (signatureHasRestParameter(signature) ? 1 : 0); + function tryGetTypeAtPosition( + signature: Signature, + pos: number + ): Type | undefined { + const paramCount = + signature.parameters.length - + (signatureHasRestParameter(signature) ? 1 : 0); if (pos < paramCount) { return getTypeOfParameter(signature.parameters[pos]); } @@ -38316,19 +67467,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // otherwise would return the type 'undefined'). const restType = getTypeOfSymbol(signature.parameters[paramCount]); const index = pos - paramCount; - if (!isTupleType(restType) || restType.target.combinedFlags & ElementFlags.Variable || index < restType.target.fixedLength) { - return getIndexedAccessType(restType, getNumberLiteralType(index)); + if ( + !isTupleType(restType) || + restType.target.combinedFlags & ElementFlags.Variable || + index < restType.target.fixedLength + ) { + return getIndexedAccessType( + restType, + getNumberLiteralType(index) + ); } } return undefined; } - function getRestTypeAtPosition(source: Signature, pos: number, readonly?: boolean): Type { + function getRestTypeAtPosition( + source: Signature, + pos: number, + readonly?: boolean + ): Type { const parameterCount = getParameterCount(source); const minArgumentCount = getMinArgumentCount(source); const restType = getEffectiveRestType(source); if (restType && pos >= parameterCount - 1) { - return pos === parameterCount - 1 ? restType : createArrayType(getIndexedAccessType(restType, numberType)); + return pos === parameterCount - 1 + ? restType + : createArrayType(getIndexedAccessType(restType, numberType)); } const types = []; const flags = []; @@ -38336,9 +67500,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (let i = pos; i < parameterCount; i++) { if (!restType || i < parameterCount - 1) { types.push(getTypeAtPosition(source, i)); - flags.push(i < minArgumentCount ? ElementFlags.Required : ElementFlags.Optional); - } - else { + flags.push( + i < minArgumentCount + ? ElementFlags.Required + : ElementFlags.Optional + ); + } else { types.push(restType); flags.push(ElementFlags.Variadic); } @@ -38365,29 +67532,55 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (signatureHasRestParameter(signature)) { const restType = getTypeOfSymbol(signature.parameters[length - 1]); if (isTupleType(restType)) { - return length + restType.target.fixedLength - (restType.target.combinedFlags & ElementFlags.Variable ? 0 : 1); + return ( + length + + restType.target.fixedLength - + (restType.target.combinedFlags & ElementFlags.Variable + ? 0 + : 1) + ); } } return length; } - function getMinArgumentCount(signature: Signature, flags?: MinArgumentCountFlags) { - const strongArityForUntypedJS = flags! & MinArgumentCountFlags.StrongArityForUntypedJS; - const voidIsNonOptional = flags! & MinArgumentCountFlags.VoidIsNonOptional; - if (voidIsNonOptional || signature.resolvedMinArgumentCount === undefined) { + function getMinArgumentCount( + signature: Signature, + flags?: MinArgumentCountFlags + ) { + const strongArityForUntypedJS = + flags! & MinArgumentCountFlags.StrongArityForUntypedJS; + const voidIsNonOptional = + flags! & MinArgumentCountFlags.VoidIsNonOptional; + if ( + voidIsNonOptional || + signature.resolvedMinArgumentCount === undefined + ) { let minArgumentCount: number | undefined; if (signatureHasRestParameter(signature)) { - const restType = getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]); + const restType = getTypeOfSymbol( + signature.parameters[signature.parameters.length - 1] + ); if (isTupleType(restType)) { - const firstOptionalIndex = findIndex(restType.target.elementFlags, f => !(f & ElementFlags.Required)); - const requiredCount = firstOptionalIndex < 0 ? restType.target.fixedLength : firstOptionalIndex; + const firstOptionalIndex = findIndex( + restType.target.elementFlags, + (f) => !(f & ElementFlags.Required) + ); + const requiredCount = + firstOptionalIndex < 0 + ? restType.target.fixedLength + : firstOptionalIndex; if (requiredCount > 0) { - minArgumentCount = signature.parameters.length - 1 + requiredCount; + minArgumentCount = + signature.parameters.length - 1 + requiredCount; } } } if (minArgumentCount === undefined) { - if (!strongArityForUntypedJS && signature.flags & SignatureFlags.IsUntypedSignatureInJSFile) { + if ( + !strongArityForUntypedJS && + signature.flags & SignatureFlags.IsUntypedSignatureInJSFile + ) { return 0; } minArgumentCount = signature.minArgumentCount; @@ -38409,15 +67602,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function hasEffectiveRestParameter(signature: Signature) { if (signatureHasRestParameter(signature)) { - const restType = getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]); - return !isTupleType(restType) || !!(restType.target.combinedFlags & ElementFlags.Variable); + const restType = getTypeOfSymbol( + signature.parameters[signature.parameters.length - 1] + ); + return ( + !isTupleType(restType) || + !!(restType.target.combinedFlags & ElementFlags.Variable) + ); } return false; } function getEffectiveRestType(signature: Signature) { if (signatureHasRestParameter(signature)) { - const restType = getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]); + const restType = getTypeOfSymbol( + signature.parameters[signature.parameters.length - 1] + ); if (!isTupleType(restType)) { return isTypeAny(restType) ? anyArrayType : restType; } @@ -38430,29 +67630,52 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getNonArrayRestType(signature: Signature) { const restType = getEffectiveRestType(signature); - return restType && !isArrayType(restType) && !isTypeAny(restType) ? restType : undefined; + return restType && !isArrayType(restType) && !isTypeAny(restType) + ? restType + : undefined; } function getTypeOfFirstParameterOfSignature(signature: Signature) { - return getTypeOfFirstParameterOfSignatureWithFallback(signature, neverType); + return getTypeOfFirstParameterOfSignatureWithFallback( + signature, + neverType + ); } - function getTypeOfFirstParameterOfSignatureWithFallback(signature: Signature, fallbackType: Type) { - return signature.parameters.length > 0 ? getTypeAtPosition(signature, 0) : fallbackType; + function getTypeOfFirstParameterOfSignatureWithFallback( + signature: Signature, + fallbackType: Type + ) { + return signature.parameters.length > 0 + ? getTypeAtPosition(signature, 0) + : fallbackType; } - function inferFromAnnotatedParametersAndReturn(signature: Signature, context: Signature, inferenceContext: InferenceContext) { - const len = signature.parameters.length - (signatureHasRestParameter(signature) ? 1 : 0); + function inferFromAnnotatedParametersAndReturn( + signature: Signature, + context: Signature, + inferenceContext: InferenceContext + ) { + const len = + signature.parameters.length - + (signatureHasRestParameter(signature) ? 1 : 0); for (let i = 0; i < len; i++) { - const declaration = signature.parameters[i].valueDeclaration as ParameterDeclaration; + const declaration = signature.parameters[i] + .valueDeclaration as ParameterDeclaration; const typeNode = getEffectiveTypeAnnotationNode(declaration); if (typeNode) { - const source = addOptionality(getTypeFromTypeNode(typeNode), /*isProperty*/ false, isOptionalDeclaration(declaration)); + const source = addOptionality( + getTypeFromTypeNode(typeNode), + /*isProperty*/ false, + isOptionalDeclaration(declaration) + ); const target = getTypeAtPosition(context, i); inferTypes(inferenceContext.inferences, source, target); } } - const typeNode = signature.declaration && getEffectiveReturnTypeNode(signature.declaration); + const typeNode = + signature.declaration && + getEffectiveReturnTypeNode(signature.declaration); if (typeNode) { const source = getTypeFromTypeNode(typeNode); const target = getReturnTypeOfSignature(context); @@ -38460,33 +67683,60 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function assignContextualParameterTypes(signature: Signature, context: Signature) { + function assignContextualParameterTypes( + signature: Signature, + context: Signature + ) { if (context.typeParameters) { if (!signature.typeParameters) { signature.typeParameters = context.typeParameters; - } - else { + } else { return; // This signature has already has a contextual inference performed and cached on it! } } if (context.thisParameter) { const parameter = signature.thisParameter; - if (!parameter || parameter.valueDeclaration && !(parameter.valueDeclaration as ParameterDeclaration).type) { + if ( + !parameter || + (parameter.valueDeclaration && + !(parameter.valueDeclaration as ParameterDeclaration).type) + ) { if (!parameter) { - signature.thisParameter = createSymbolWithType(context.thisParameter, /*type*/ undefined); + signature.thisParameter = createSymbolWithType( + context.thisParameter, + /*type*/ undefined + ); } - assignParameterType(signature.thisParameter!, getTypeOfSymbol(context.thisParameter)); + assignParameterType( + signature.thisParameter!, + getTypeOfSymbol(context.thisParameter) + ); } } - const len = signature.parameters.length - (signatureHasRestParameter(signature) ? 1 : 0); + const len = + signature.parameters.length - + (signatureHasRestParameter(signature) ? 1 : 0); for (let i = 0; i < len; i++) { const parameter = signature.parameters[i]; - const declaration = parameter.valueDeclaration as ParameterDeclaration; + const declaration = + parameter.valueDeclaration as ParameterDeclaration; if (!getEffectiveTypeAnnotationNode(declaration)) { let type = tryGetTypeAtPosition(context, i); if (type && declaration.initializer) { - let initializerType = checkDeclarationInitializer(declaration, CheckMode.Normal); - if (!isTypeAssignableTo(initializerType, type) && isTypeAssignableTo(type, initializerType = widenTypeInferredFromInitializer(declaration, initializerType))) { + let initializerType = checkDeclarationInitializer( + declaration, + CheckMode.Normal + ); + if ( + !isTypeAssignableTo(initializerType, type) && + isTypeAssignableTo( + type, + (initializerType = widenTypeInferredFromInitializer( + declaration, + initializerType + )) + ) + ) { type = initializerType; } } @@ -38498,12 +67748,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const parameter = last(signature.parameters); if ( parameter.valueDeclaration - ? !getEffectiveTypeAnnotationNode(parameter.valueDeclaration as ParameterDeclaration) - // a declarationless parameter may still have a `.type` already set by its construction logic - // (which may pull a type from a jsdoc) - only allow fixing on `DeferredType` parameters with a fallback type - : !!(getCheckFlags(parameter) & CheckFlags.DeferredType) + ? !getEffectiveTypeAnnotationNode( + parameter.valueDeclaration as ParameterDeclaration + ) + : // a declarationless parameter may still have a `.type` already set by its construction logic + // (which may pull a type from a jsdoc) - only allow fixing on `DeferredType` parameters with a fallback type + !!(getCheckFlags(parameter) & CheckFlags.DeferredType) ) { - const contextualParameterType = getRestTypeAtPosition(context, len); + const contextualParameterType = getRestTypeAtPosition( + context, + len + ); assignParameterType(parameter, contextualParameterType); } } @@ -38521,35 +67776,57 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function assignParameterType(parameter: Symbol, contextualType?: Type) { const links = getSymbolLinks(parameter); if (!links.type) { - const declaration = parameter.valueDeclaration as ParameterDeclaration | undefined; + const declaration = parameter.valueDeclaration as + | ParameterDeclaration + | undefined; links.type = addOptionality( - contextualType || (declaration ? getWidenedTypeForVariableLikeDeclaration(declaration, /*reportErrors*/ true) : getTypeOfSymbol(parameter)), + contextualType || + (declaration + ? getWidenedTypeForVariableLikeDeclaration( + declaration, + /*reportErrors*/ true + ) + : getTypeOfSymbol(parameter)), /*isProperty*/ false, - /*isOptional*/ !!declaration && !declaration.initializer && isOptionalDeclaration(declaration), + /*isOptional*/ !!declaration && + !declaration.initializer && + isOptionalDeclaration(declaration) ); - if (declaration && declaration.name.kind !== SyntaxKind.Identifier) { + if ( + declaration && + declaration.name.kind !== SyntaxKind.Identifier + ) { // if inference didn't come up with anything but unknown, fall back to the binding pattern if present. if (links.type === unknownType) { links.type = getTypeFromBindingPattern(declaration.name); } assignBindingElementTypes(declaration.name, links.type); } - } - else if (contextualType) { - Debug.assertEqual(links.type, contextualType, "Parameter symbol already has a cached type which differs from newly assigned type"); + } else if (contextualType) { + Debug.assertEqual( + links.type, + contextualType, + "Parameter symbol already has a cached type which differs from newly assigned type" + ); } } // When contextual typing assigns a type to a parameter that contains a binding pattern, we also need to push // the destructured type into the contained binding elements. - function assignBindingElementTypes(pattern: BindingPattern, parentType: Type) { + function assignBindingElementTypes( + pattern: BindingPattern, + parentType: Type + ) { for (const element of pattern.elements) { if (!isOmittedExpression(element)) { - const type = getBindingElementTypeFromParentType(element, parentType, /*noTupleBoundsCheck*/ false); + const type = getBindingElementTypeFromParentType( + element, + parentType, + /*noTupleBoundsCheck*/ false + ); if (element.name.kind === SyntaxKind.Identifier) { getSymbolLinks(getSymbolOfDeclaration(element)).type = type; - } - else { + } else { assignBindingElementTypes(element.name, type); } } @@ -38557,84 +67834,193 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function createClassDecoratorContextType(classType: Type) { - return tryCreateTypeReference(getGlobalClassDecoratorContextType(/*reportErrors*/ true), [classType]); + return tryCreateTypeReference( + getGlobalClassDecoratorContextType(/*reportErrors*/ true), + [classType] + ); } - function createClassMethodDecoratorContextType(thisType: Type, valueType: Type) { - return tryCreateTypeReference(getGlobalClassMethodDecoratorContextType(/*reportErrors*/ true), [thisType, valueType]); + function createClassMethodDecoratorContextType( + thisType: Type, + valueType: Type + ) { + return tryCreateTypeReference( + getGlobalClassMethodDecoratorContextType(/*reportErrors*/ true), + [thisType, valueType] + ); } - function createClassGetterDecoratorContextType(thisType: Type, valueType: Type) { - return tryCreateTypeReference(getGlobalClassGetterDecoratorContextType(/*reportErrors*/ true), [thisType, valueType]); + function createClassGetterDecoratorContextType( + thisType: Type, + valueType: Type + ) { + return tryCreateTypeReference( + getGlobalClassGetterDecoratorContextType(/*reportErrors*/ true), + [thisType, valueType] + ); } - function createClassSetterDecoratorContextType(thisType: Type, valueType: Type) { - return tryCreateTypeReference(getGlobalClassSetterDecoratorContextType(/*reportErrors*/ true), [thisType, valueType]); + function createClassSetterDecoratorContextType( + thisType: Type, + valueType: Type + ) { + return tryCreateTypeReference( + getGlobalClassSetterDecoratorContextType(/*reportErrors*/ true), + [thisType, valueType] + ); } - function createClassAccessorDecoratorContextType(thisType: Type, valueType: Type) { - return tryCreateTypeReference(getGlobalClassAccessorDecoratorContextType(/*reportErrors*/ true), [thisType, valueType]); + function createClassAccessorDecoratorContextType( + thisType: Type, + valueType: Type + ) { + return tryCreateTypeReference( + getGlobalClassAccessorDecoratorContextType(/*reportErrors*/ true), + [thisType, valueType] + ); } - function createClassFieldDecoratorContextType(thisType: Type, valueType: Type) { - return tryCreateTypeReference(getGlobalClassFieldDecoratorContextType(/*reportErrors*/ true), [thisType, valueType]); + function createClassFieldDecoratorContextType( + thisType: Type, + valueType: Type + ) { + return tryCreateTypeReference( + getGlobalClassFieldDecoratorContextType(/*reportErrors*/ true), + [thisType, valueType] + ); } /** * Gets a type like `{ name: "foo", private: false, static: true }` that is used to provided member-specific * details that will be intersected with a decorator context type. */ - function getClassMemberDecoratorContextOverrideType(nameType: Type, isPrivate: boolean, isStatic: boolean) { - const key = `${isPrivate ? "p" : "P"}${isStatic ? "s" : "S"}${nameType.id}` as const; + function getClassMemberDecoratorContextOverrideType( + nameType: Type, + isPrivate: boolean, + isStatic: boolean + ) { + const key = `${isPrivate ? "p" : "P"}${isStatic ? "s" : "S"}${ + nameType.id + }` as const; let overrideType = decoratorContextOverrideTypeCache.get(key); if (!overrideType) { const members = createSymbolTable(); - members.set("name" as __String, createProperty("name" as __String, nameType)); - members.set("private" as __String, createProperty("private" as __String, isPrivate ? trueType : falseType)); - members.set("static" as __String, createProperty("static" as __String, isStatic ? trueType : falseType)); - overrideType = createAnonymousType(/*symbol*/ undefined, members, emptyArray, emptyArray, emptyArray); + members.set( + "name" as __String, + createProperty("name" as __String, nameType) + ); + members.set( + "private" as __String, + createProperty( + "private" as __String, + isPrivate ? trueType : falseType + ) + ); + members.set( + "static" as __String, + createProperty( + "static" as __String, + isStatic ? trueType : falseType + ) + ); + overrideType = createAnonymousType( + /*symbol*/ undefined, + members, + emptyArray, + emptyArray, + emptyArray + ); decoratorContextOverrideTypeCache.set(key, overrideType); } return overrideType; } - function createClassMemberDecoratorContextTypeForNode(node: MethodDeclaration | AccessorDeclaration | PropertyDeclaration, thisType: Type, valueType: Type) { + function createClassMemberDecoratorContextTypeForNode( + node: MethodDeclaration | AccessorDeclaration | PropertyDeclaration, + thisType: Type, + valueType: Type + ) { const isStatic = hasStaticModifier(node); const isPrivate = isPrivateIdentifier(node.name); - const nameType = isPrivate ? getStringLiteralType(idText(node.name)) : getLiteralTypeFromPropertyName(node.name); - const contextType = isMethodDeclaration(node) ? createClassMethodDecoratorContextType(thisType, valueType) : - isGetAccessorDeclaration(node) ? createClassGetterDecoratorContextType(thisType, valueType) : - isSetAccessorDeclaration(node) ? createClassSetterDecoratorContextType(thisType, valueType) : - isAutoAccessorPropertyDeclaration(node) ? createClassAccessorDecoratorContextType(thisType, valueType) : - isPropertyDeclaration(node) ? createClassFieldDecoratorContextType(thisType, valueType) : - Debug.failBadSyntaxKind(node); - const overrideType = getClassMemberDecoratorContextOverrideType(nameType, isPrivate, isStatic); + const nameType = isPrivate + ? getStringLiteralType(idText(node.name)) + : getLiteralTypeFromPropertyName(node.name); + const contextType = isMethodDeclaration(node) + ? createClassMethodDecoratorContextType(thisType, valueType) + : isGetAccessorDeclaration(node) + ? createClassGetterDecoratorContextType(thisType, valueType) + : isSetAccessorDeclaration(node) + ? createClassSetterDecoratorContextType(thisType, valueType) + : isAutoAccessorPropertyDeclaration(node) + ? createClassAccessorDecoratorContextType(thisType, valueType) + : isPropertyDeclaration(node) + ? createClassFieldDecoratorContextType(thisType, valueType) + : Debug.failBadSyntaxKind(node); + const overrideType = getClassMemberDecoratorContextOverrideType( + nameType, + isPrivate, + isStatic + ); return getIntersectionType([contextType, overrideType]); } - function createClassAccessorDecoratorTargetType(thisType: Type, valueType: Type) { - return tryCreateTypeReference(getGlobalClassAccessorDecoratorTargetType(/*reportErrors*/ true), [thisType, valueType]); + function createClassAccessorDecoratorTargetType( + thisType: Type, + valueType: Type + ) { + return tryCreateTypeReference( + getGlobalClassAccessorDecoratorTargetType(/*reportErrors*/ true), + [thisType, valueType] + ); } - function createClassAccessorDecoratorResultType(thisType: Type, valueType: Type) { - return tryCreateTypeReference(getGlobalClassAccessorDecoratorResultType(/*reportErrors*/ true), [thisType, valueType]); + function createClassAccessorDecoratorResultType( + thisType: Type, + valueType: Type + ) { + return tryCreateTypeReference( + getGlobalClassAccessorDecoratorResultType(/*reportErrors*/ true), + [thisType, valueType] + ); } - function createClassFieldDecoratorInitializerMutatorType(thisType: Type, valueType: Type) { + function createClassFieldDecoratorInitializerMutatorType( + thisType: Type, + valueType: Type + ) { const thisParam = createParameter("this" as __String, thisType); const valueParam = createParameter("value" as __String, valueType); - return createFunctionType(/*typeParameters*/ undefined, thisParam, [valueParam], valueType, /*typePredicate*/ undefined, 1); + return createFunctionType( + /*typeParameters*/ undefined, + thisParam, + [valueParam], + valueType, + /*typePredicate*/ undefined, + 1 + ); } /** * Creates a call signature for an ES Decorator. This method is used by the semantics of * `getESDecoratorCallSignature`, which you should probably be using instead. */ - function createESDecoratorCallSignature(targetType: Type, contextType: Type, nonOptionalReturnType: Type) { + function createESDecoratorCallSignature( + targetType: Type, + contextType: Type, + nonOptionalReturnType: Type + ) { const targetParam = createParameter("target" as __String, targetType); - const contextParam = createParameter("context" as __String, contextType); + const contextParam = createParameter( + "context" as __String, + contextType + ); const returnType = getUnionType([nonOptionalReturnType, voidType]); - return createCallSignature(/*typeParameters*/ undefined, /*thisParameter*/ undefined, [targetParam, contextParam], returnType); + return createCallSignature( + /*typeParameters*/ undefined, + /*thisParameter*/ undefined, + [targetParam, contextParam], + returnType + ); } /** @@ -38736,16 +68122,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // argument will be the "final type" of the class after all decorators are applied. const node = parent as ClassDeclaration | ClassExpression; - const targetType = getTypeOfSymbol(getSymbolOfDeclaration(node)); - const contextType = createClassDecoratorContextType(targetType); - links.decoratorSignature = createESDecoratorCallSignature(targetType, contextType, targetType); + const targetType = getTypeOfSymbol( + getSymbolOfDeclaration(node) + ); + const contextType = + createClassDecoratorContextType(targetType); + links.decoratorSignature = createESDecoratorCallSignature( + targetType, + contextType, + targetType + ); break; } case SyntaxKind.MethodDeclaration: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: { - const node = parent as MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration; + const node = parent as + | MethodDeclaration + | GetAccessorDeclaration + | SetAccessorDeclaration; if (!isClassLike(node.parent)) break; // Method decorators have a `context` of `ClassMethodDecoratorContext`, where the @@ -38760,28 +68156,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // In all three cases, the `This` type argument is the "final type" of either the class or // instance, depending on whether the member was `static`. - const valueType = isMethodDeclaration(node) ? getOrCreateTypeFromSignature(getSignatureFromDeclaration(node)) : - getTypeOfNode(node); + const valueType = isMethodDeclaration(node) + ? getOrCreateTypeFromSignature( + getSignatureFromDeclaration(node) + ) + : getTypeOfNode(node); - const thisType = hasStaticModifier(node) ? - getTypeOfSymbol(getSymbolOfDeclaration(node.parent)) : - getDeclaredTypeOfClassOrInterface(getSymbolOfDeclaration(node.parent)); + const thisType = hasStaticModifier(node) + ? getTypeOfSymbol(getSymbolOfDeclaration(node.parent)) + : getDeclaredTypeOfClassOrInterface( + getSymbolOfDeclaration(node.parent) + ); // We wrap the "input type", if necessary, to match the decoration target. For getters this is // something like `() => inputType`, for setters it's `(value: inputType) => void` and for // methods it is just the input type. - const targetType = isGetAccessorDeclaration(node) ? createGetterFunctionType(valueType) : - isSetAccessorDeclaration(node) ? createSetterFunctionType(valueType) : - valueType; - - const contextType = createClassMemberDecoratorContextTypeForNode(node, thisType, valueType); + const targetType = isGetAccessorDeclaration(node) + ? createGetterFunctionType(valueType) + : isSetAccessorDeclaration(node) + ? createSetterFunctionType(valueType) + : valueType; + + const contextType = + createClassMemberDecoratorContextTypeForNode( + node, + thisType, + valueType + ); // We also wrap the "output type", as needed. - const returnType = isGetAccessorDeclaration(node) ? createGetterFunctionType(valueType) : - isSetAccessorDeclaration(node) ? createSetterFunctionType(valueType) : - valueType; + const returnType = isGetAccessorDeclaration(node) + ? createGetterFunctionType(valueType) + : isSetAccessorDeclaration(node) + ? createSetterFunctionType(valueType) + : valueType; - links.decoratorSignature = createESDecoratorCallSignature(targetType, contextType, returnType); + links.decoratorSignature = createESDecoratorCallSignature( + targetType, + contextType, + returnType + ); break; } @@ -38796,31 +68210,55 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // the "final type" of the value stored in the field. const valueType = getTypeOfNode(node); - const thisType = hasStaticModifier(node) ? - getTypeOfSymbol(getSymbolOfDeclaration(node.parent)) : - getDeclaredTypeOfClassOrInterface(getSymbolOfDeclaration(node.parent)); + const thisType = hasStaticModifier(node) + ? getTypeOfSymbol(getSymbolOfDeclaration(node.parent)) + : getDeclaredTypeOfClassOrInterface( + getSymbolOfDeclaration(node.parent) + ); // The `target` of an auto-accessor decorator is a `{ get, set }` object, representing the // runtime-generated getter and setter that are added to the class/prototype. The `target` of a // regular field decorator is always `undefined` as it isn't installed until it is initialized. - const targetType = hasAccessorModifier(node) ? createClassAccessorDecoratorTargetType(thisType, valueType) : - undefinedType; - - const contextType = createClassMemberDecoratorContextTypeForNode(node, thisType, valueType); + const targetType = hasAccessorModifier(node) + ? createClassAccessorDecoratorTargetType( + thisType, + valueType + ) + : undefinedType; + + const contextType = + createClassMemberDecoratorContextTypeForNode( + node, + thisType, + valueType + ); // We wrap the "output type" depending on the declaration. For auto-accessors, we wrap the // "output type" in a `ClassAccessorDecoratorResult` type, which allows for // mutation of the runtime-generated getter and setter, as well as the injection of an // initializer mutator. For regular fields, we wrap the "output type" in an initializer mutator. - const returnType = hasAccessorModifier(node) ? createClassAccessorDecoratorResultType(thisType, valueType) : - createClassFieldDecoratorInitializerMutatorType(thisType, valueType); - - links.decoratorSignature = createESDecoratorCallSignature(targetType, contextType, returnType); + const returnType = hasAccessorModifier(node) + ? createClassAccessorDecoratorResultType( + thisType, + valueType + ) + : createClassFieldDecoratorInitializerMutatorType( + thisType, + valueType + ); + + links.decoratorSignature = createESDecoratorCallSignature( + targetType, + contextType, + returnType + ); break; } } } - return links.decoratorSignature === anySignature ? undefined : links.decoratorSignature; + return links.decoratorSignature === anySignature + ? undefined + : links.decoratorSignature; } function getLegacyDecoratorCallSignature(decorator: Decorator) { @@ -38834,13 +68272,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const node = parent as ClassDeclaration | ClassExpression; // For a class decorator, the `target` is the type of the class (e.g. the // "static" or "constructor" side of the class). - const targetType = getTypeOfSymbol(getSymbolOfDeclaration(node)); - const targetParam = createParameter("target" as __String, targetType); + const targetType = getTypeOfSymbol( + getSymbolOfDeclaration(node) + ); + const targetParam = createParameter( + "target" as __String, + targetType + ); links.decoratorSignature = createCallSignature( /*typeParameters*/ undefined, /*thisParameter*/ undefined, [targetParam], - getUnionType([targetType, voidType]), + getUnionType([targetType, voidType]) ); break; } @@ -38848,7 +68291,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const node = parent as ParameterDeclaration; if ( !isConstructorDeclaration(node.parent) && - !(isMethodDeclaration(node.parent) || isSetAccessorDeclaration(node.parent) && isClassLike(node.parent.parent)) + !( + isMethodDeclaration(node.parent) || + (isSetAccessorDeclaration(node.parent) && + isClassLike(node.parent.parent)) + ) ) { break; } @@ -38857,30 +68304,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { break; } - const index = getThisParameter(node.parent) ? - node.parent.parameters.indexOf(node) - 1 : - node.parent.parameters.indexOf(node); + const index = getThisParameter(node.parent) + ? node.parent.parameters.indexOf(node) - 1 + : node.parent.parameters.indexOf(node); Debug.assert(index >= 0); // A parameter declaration decorator will have three arguments (see `ParameterDecorator` in // core.d.ts). - const targetType = isConstructorDeclaration(node.parent) ? getTypeOfSymbol(getSymbolOfDeclaration(node.parent.parent)) : - getParentTypeOfClassElement(node.parent); + const targetType = isConstructorDeclaration(node.parent) + ? getTypeOfSymbol( + getSymbolOfDeclaration(node.parent.parent) + ) + : getParentTypeOfClassElement(node.parent); - const keyType = isConstructorDeclaration(node.parent) ? undefinedType : - getClassElementPropertyKeyType(node.parent); + const keyType = isConstructorDeclaration(node.parent) + ? undefinedType + : getClassElementPropertyKeyType(node.parent); const indexType = getNumberLiteralType(index); - const targetParam = createParameter("target" as __String, targetType); - const keyParam = createParameter("propertyKey" as __String, keyType); - const indexParam = createParameter("parameterIndex" as __String, indexType); + const targetParam = createParameter( + "target" as __String, + targetType + ); + const keyParam = createParameter( + "propertyKey" as __String, + keyType + ); + const indexParam = createParameter( + "parameterIndex" as __String, + indexType + ); links.decoratorSignature = createCallSignature( /*typeParameters*/ undefined, /*thisParameter*/ undefined, [targetParam, keyParam, indexParam], - voidType, + voidType ); break; } @@ -38888,50 +68348,72 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: case SyntaxKind.PropertyDeclaration: { - const node = parent as MethodDeclaration | AccessorDeclaration | PropertyDeclaration; + const node = parent as + | MethodDeclaration + | AccessorDeclaration + | PropertyDeclaration; if (!isClassLike(node.parent)) break; // A method or accessor declaration decorator will have either two or three arguments (see // `PropertyDecorator` and `MethodDecorator` in core.d.ts). const targetType = getParentTypeOfClassElement(node); - const targetParam = createParameter("target" as __String, targetType); + const targetParam = createParameter( + "target" as __String, + targetType + ); const keyType = getClassElementPropertyKeyType(node); - const keyParam = createParameter("propertyKey" as __String, keyType); + const keyParam = createParameter( + "propertyKey" as __String, + keyType + ); - const returnType = isPropertyDeclaration(node) ? voidType : - createTypedPropertyDescriptorType(getTypeOfNode(node)); + const returnType = isPropertyDeclaration(node) + ? voidType + : createTypedPropertyDescriptorType( + getTypeOfNode(node) + ); - const hasPropDesc = !isPropertyDeclaration(parent) || hasAccessorModifier(parent); + const hasPropDesc = + !isPropertyDeclaration(parent) || + hasAccessorModifier(parent); if (hasPropDesc) { - const descriptorType = createTypedPropertyDescriptorType(getTypeOfNode(node)); - const descriptorParam = createParameter("descriptor" as __String, descriptorType); + const descriptorType = + createTypedPropertyDescriptorType( + getTypeOfNode(node) + ); + const descriptorParam = createParameter( + "descriptor" as __String, + descriptorType + ); links.decoratorSignature = createCallSignature( /*typeParameters*/ undefined, /*thisParameter*/ undefined, [targetParam, keyParam, descriptorParam], - getUnionType([returnType, voidType]), + getUnionType([returnType, voidType]) ); - } - else { + } else { links.decoratorSignature = createCallSignature( /*typeParameters*/ undefined, /*thisParameter*/ undefined, [targetParam, keyParam], - getUnionType([returnType, voidType]), + getUnionType([returnType, voidType]) ); } break; } } } - return links.decoratorSignature === anySignature ? undefined : links.decoratorSignature; + return links.decoratorSignature === anySignature + ? undefined + : links.decoratorSignature; } function getDecoratorCallSignature(decorator: Decorator) { - return legacyDecorators ? getLegacyDecoratorCallSignature(decorator) : - getESDecoratorCallSignature(decorator); + return legacyDecorators + ? getLegacyDecoratorCallSignature(decorator) + : getESDecoratorCallSignature(decorator); } function createPromiseType(promisedType: Type): Type { @@ -38940,7 +68422,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (globalPromiseType !== emptyGenericType) { // if the promised type is itself a promise, get the underlying type; otherwise, fallback to the promised type // Unwrap an `Awaited` to `T` to improve inference. - promisedType = getAwaitedTypeNoAlias(unwrapAwaitedType(promisedType)) || unknownType; + promisedType = + getAwaitedTypeNoAlias(unwrapAwaitedType(promisedType)) || + unknownType; return createTypeReference(globalPromiseType, [promisedType]); } @@ -38949,34 +68433,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function createPromiseLikeType(promisedType: Type): Type { // creates a `PromiseLike` type where `T` is the promisedType argument - const globalPromiseLikeType = getGlobalPromiseLikeType(/*reportErrors*/ true); + const globalPromiseLikeType = getGlobalPromiseLikeType( + /*reportErrors*/ true + ); if (globalPromiseLikeType !== emptyGenericType) { // if the promised type is itself a promise, get the underlying type; otherwise, fallback to the promised type // Unwrap an `Awaited` to `T` to improve inference. - promisedType = getAwaitedTypeNoAlias(unwrapAwaitedType(promisedType)) || unknownType; + promisedType = + getAwaitedTypeNoAlias(unwrapAwaitedType(promisedType)) || + unknownType; return createTypeReference(globalPromiseLikeType, [promisedType]); } return unknownType; } - function createPromiseReturnType(func: FunctionLikeDeclaration | ImportCall, promisedType: Type) { + function createPromiseReturnType( + func: FunctionLikeDeclaration | ImportCall, + promisedType: Type + ) { const promiseType = createPromiseType(promisedType); if (promiseType === unknownType) { error( func, - isImportCall(func) ? - Diagnostics.A_dynamic_import_call_returns_a_Promise_Make_sure_you_have_a_declaration_for_Promise_or_include_ES2015_in_your_lib_option : - 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, + isImportCall(func) + ? Diagnostics.A_dynamic_import_call_returns_a_Promise_Make_sure_you_have_a_declaration_for_Promise_or_include_ES2015_in_your_lib_option + : 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 ); return errorType; - } - else if (!getGlobalPromiseConstructorSymbol(/*reportErrors*/ true)) { + } else if (!getGlobalPromiseConstructorSymbol(/*reportErrors*/ true)) { error( func, - isImportCall(func) ? - Diagnostics.A_dynamic_import_call_in_ES5_requires_the_Promise_constructor_Make_sure_you_have_a_declaration_for_the_Promise_constructor_or_include_ES2015_in_your_lib_option : - Diagnostics.An_async_function_or_method_in_ES5_requires_the_Promise_constructor_Make_sure_you_have_a_declaration_for_the_Promise_constructor_or_include_ES2015_in_your_lib_option, + isImportCall(func) + ? Diagnostics.A_dynamic_import_call_in_ES5_requires_the_Promise_constructor_Make_sure_you_have_a_declaration_for_the_Promise_constructor_or_include_ES2015_in_your_lib_option + : Diagnostics.An_async_function_or_method_in_ES5_requires_the_Promise_constructor_Make_sure_you_have_a_declaration_for_the_Promise_constructor_or_include_ES2015_in_your_lib_option ); } @@ -38985,18 +68475,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function createNewTargetExpressionType(targetType: Type): Type { // Create a synthetic type `NewTargetExpression { target: TargetType; }` - const symbol = createSymbol(SymbolFlags.None, "NewTargetExpression" as __String); + const symbol = createSymbol( + SymbolFlags.None, + "NewTargetExpression" as __String + ); - const targetPropertySymbol = createSymbol(SymbolFlags.Property, "target" as __String, CheckFlags.Readonly); + const targetPropertySymbol = createSymbol( + SymbolFlags.Property, + "target" as __String, + CheckFlags.Readonly + ); targetPropertySymbol.parent = symbol; targetPropertySymbol.links.type = targetType; const members = createSymbolTable([targetPropertySymbol]); symbol.members = members; - return createAnonymousType(symbol, members, emptyArray, emptyArray, emptyArray); + return createAnonymousType( + symbol, + members, + emptyArray, + emptyArray, + emptyArray + ); } - function getReturnTypeFromBody(func: FunctionLikeDeclaration, checkMode?: CheckMode): Type { + function getReturnTypeFromBody( + func: FunctionLikeDeclaration, + checkMode?: CheckMode + ): Type { if (!func.body) { return errorType; } @@ -39009,30 +68515,51 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let yieldType: Type | undefined; let nextType: Type | undefined; let fallbackReturnType: Type = voidType; - if (func.body.kind !== SyntaxKind.Block) { // Async or normal arrow function - returnType = checkExpressionCached(func.body, checkMode && checkMode & ~CheckMode.SkipGenericFunctions); + if (func.body.kind !== SyntaxKind.Block) { + // Async or normal arrow function + returnType = checkExpressionCached( + func.body, + checkMode && checkMode & ~CheckMode.SkipGenericFunctions + ); if (isAsync) { // From within an async function you can return either a non-promise value or a promise. Any // Promise/A+ compatible implementation will always assimilate any foreign promise, so the // return type of the body should be unwrapped to its awaited type, which we will wrap in // the native Promise type later in this function. - 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)); + 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 + ) + ); } - } - else if (isGenerator) { // Generator or AsyncGenerator function - const returnTypes = checkAndAggregateReturnExpressionTypes(func, checkMode); + } else if (isGenerator) { + // Generator or AsyncGenerator function + const returnTypes = checkAndAggregateReturnExpressionTypes( + func, + checkMode + ); if (!returnTypes) { fallbackReturnType = neverType; - } - else if (returnTypes.length > 0) { + } else if (returnTypes.length > 0) { returnType = getUnionType(returnTypes, UnionReduction.Subtype); } - const { yieldTypes, nextTypes } = checkAndAggregateYieldOperandTypes(func, checkMode); - yieldType = some(yieldTypes) ? getUnionType(yieldTypes, UnionReduction.Subtype) : undefined; - nextType = some(nextTypes) ? getIntersectionType(nextTypes) : undefined; - } - else { // Async or normal function - const types = checkAndAggregateReturnExpressionTypes(func, checkMode); + const { yieldTypes, nextTypes } = + checkAndAggregateYieldOperandTypes(func, checkMode); + yieldType = some(yieldTypes) + ? getUnionType(yieldTypes, UnionReduction.Subtype) + : undefined; + nextType = some(nextTypes) + ? getIntersectionType(nextTypes) + : undefined; + } else { + // Async or normal function + const types = checkAndAggregateReturnExpressionTypes( + func, + checkMode + ); if (!types) { // For an async function, the return type will not be never, but rather a Promise for never. return functionFlags & FunctionFlags.Async @@ -39041,10 +68568,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (types.length === 0) { // For an async function, the return type will not be void/undefined, but rather a Promise for void/undefined. - const contextualReturnType = getContextualReturnType(func, /*contextFlags*/ undefined); - const returnType = contextualReturnType && (unwrapReturnType(contextualReturnType, functionFlags) || voidType).flags & TypeFlags.Undefined ? undefinedType : voidType; - return functionFlags & FunctionFlags.Async ? createPromiseReturnType(func, returnType) : // Async function - returnType; // Normal function + const contextualReturnType = getContextualReturnType( + func, + /*contextFlags*/ undefined + ); + const returnType = + contextualReturnType && + ( + unwrapReturnType(contextualReturnType, functionFlags) || + voidType + ).flags & TypeFlags.Undefined + ? undefinedType + : voidType; + return functionFlags & FunctionFlags.Async + ? createPromiseReturnType(func, returnType) // Async function + : returnType; // Normal function } // Return a union of the return expression types. @@ -39052,25 +68590,71 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (returnType || yieldType || nextType) { - if (yieldType) reportErrorsFromWidening(func, yieldType, WideningKind.GeneratorYield); - if (returnType) reportErrorsFromWidening(func, returnType, WideningKind.FunctionReturn); - if (nextType) reportErrorsFromWidening(func, nextType, WideningKind.GeneratorNext); - if ( - returnType && isUnitType(returnType) || - yieldType && isUnitType(yieldType) || - nextType && isUnitType(nextType) - ) { - const contextualSignature = getContextualSignatureForFunctionLikeDeclaration(func); - const contextualType = !contextualSignature ? undefined : - contextualSignature === getSignatureFromDeclaration(func) ? isGenerator ? undefined : returnType : - instantiateContextualType(getReturnTypeOfSignature(contextualSignature), func, /*contextFlags*/ undefined); + if (yieldType) + reportErrorsFromWidening( + func, + yieldType, + WideningKind.GeneratorYield + ); + if (returnType) + reportErrorsFromWidening( + func, + returnType, + WideningKind.FunctionReturn + ); + if (nextType) + reportErrorsFromWidening( + func, + nextType, + WideningKind.GeneratorNext + ); + if ( + (returnType && isUnitType(returnType)) || + (yieldType && isUnitType(yieldType)) || + (nextType && isUnitType(nextType)) + ) { + const contextualSignature = + getContextualSignatureForFunctionLikeDeclaration(func); + const contextualType = !contextualSignature + ? undefined + : contextualSignature === getSignatureFromDeclaration(func) + ? isGenerator + ? undefined + : returnType + : instantiateContextualType( + getReturnTypeOfSignature(contextualSignature), + func, + /*contextFlags*/ undefined + ); if (isGenerator) { - yieldType = getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded(yieldType, contextualType, IterationTypeKind.Yield, isAsync); - returnType = getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded(returnType, contextualType, IterationTypeKind.Return, isAsync); - nextType = getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded(nextType, contextualType, IterationTypeKind.Next, isAsync); - } - else { - returnType = getWidenedLiteralLikeTypeForContextualReturnTypeIfNeeded(returnType, contextualType, isAsync); + yieldType = + getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded( + yieldType, + contextualType, + IterationTypeKind.Yield, + isAsync + ); + returnType = + getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded( + returnType, + contextualType, + IterationTypeKind.Return, + isAsync + ); + nextType = + getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded( + nextType, + contextualType, + IterationTypeKind.Next, + isAsync + ); + } else { + returnType = + getWidenedLiteralLikeTypeForContextualReturnTypeIfNeeded( + returnType, + contextualType, + isAsync + ); } } @@ -39083,11 +68667,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return createGeneratorType( yieldType || neverType, returnType || fallbackReturnType, - nextType || getContextualIterationType(IterationTypeKind.Next, func) || unknownType, - isAsync, + nextType || + getContextualIterationType(IterationTypeKind.Next, func) || + unknownType, + isAsync ); - } - else { + } else { // From within an async function you can return either a non-promise value or a promise. Any // Promise/A+ compatible implementation will always assimilate any foreign promise, so the // return type of the body is awaited type of the body, wrapped in a native Promise type. @@ -39097,16 +68682,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function createGeneratorType(yieldType: Type, returnType: Type, nextType: Type, isAsyncGenerator: boolean) { - const resolver = isAsyncGenerator ? asyncIterationTypesResolver : syncIterationTypesResolver; - const globalGeneratorType = resolver.getGlobalGeneratorType(/*reportErrors*/ false); - yieldType = resolver.resolveIterationType(yieldType, /*errorNode*/ undefined) || unknownType; - returnType = resolver.resolveIterationType(returnType, /*errorNode*/ undefined) || unknownType; + function createGeneratorType( + yieldType: Type, + returnType: Type, + nextType: Type, + isAsyncGenerator: boolean + ) { + const resolver = isAsyncGenerator + ? asyncIterationTypesResolver + : syncIterationTypesResolver; + const globalGeneratorType = resolver.getGlobalGeneratorType( + /*reportErrors*/ false + ); + yieldType = + resolver.resolveIterationType(yieldType, /*errorNode*/ undefined) || + unknownType; + returnType = + resolver.resolveIterationType( + returnType, + /*errorNode*/ undefined + ) || unknownType; if (globalGeneratorType === emptyGenericType) { // Fall back to the global IterableIterator type. - const globalIterableIteratorType = resolver.getGlobalIterableIteratorType(/*reportErrors*/ false); + const globalIterableIteratorType = + resolver.getGlobalIterableIteratorType(/*reportErrors*/ false); if (globalIterableIteratorType !== emptyGenericType) { - return createTypeFromGenericGlobalType(globalIterableIteratorType, [yieldType, returnType, nextType]); + return createTypeFromGenericGlobalType( + globalIterableIteratorType, + [yieldType, returnType, nextType] + ); } // The global Generator type doesn't exist, so report an error @@ -39114,52 +68718,96 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return emptyObjectType; } - return createTypeFromGenericGlobalType(globalGeneratorType, [yieldType, returnType, nextType]); + return createTypeFromGenericGlobalType(globalGeneratorType, [ + yieldType, + returnType, + nextType, + ]); } - function checkAndAggregateYieldOperandTypes(func: FunctionLikeDeclaration, checkMode: CheckMode | undefined) { + function checkAndAggregateYieldOperandTypes( + func: FunctionLikeDeclaration, + checkMode: CheckMode | undefined + ) { const yieldTypes: Type[] = []; const nextTypes: Type[] = []; const isAsync = (getFunctionFlags(func) & FunctionFlags.Async) !== 0; - forEachYieldExpression(func.body as Block, yieldExpression => { - const yieldExpressionType = yieldExpression.expression ? checkExpression(yieldExpression.expression, checkMode) : undefinedWideningType; - pushIfUnique(yieldTypes, getYieldedTypeOfYieldExpression(yieldExpression, yieldExpressionType, anyType, isAsync)); + forEachYieldExpression(func.body as Block, (yieldExpression) => { + const yieldExpressionType = yieldExpression.expression + ? checkExpression(yieldExpression.expression, checkMode) + : undefinedWideningType; + pushIfUnique( + yieldTypes, + getYieldedTypeOfYieldExpression( + yieldExpression, + yieldExpressionType, + anyType, + isAsync + ) + ); let nextType: Type | undefined; if (yieldExpression.asteriskToken) { const iterationTypes = getIterationTypesOfIterable( yieldExpressionType, - isAsync ? IterationUse.AsyncYieldStar : IterationUse.YieldStar, - yieldExpression.expression, + isAsync + ? IterationUse.AsyncYieldStar + : IterationUse.YieldStar, + yieldExpression.expression ); nextType = iterationTypes && iterationTypes.nextType; - } - else { - nextType = getContextualType(yieldExpression, /*contextFlags*/ undefined); + } else { + nextType = getContextualType( + yieldExpression, + /*contextFlags*/ undefined + ); } if (nextType) pushIfUnique(nextTypes, nextType); }); return { yieldTypes, nextTypes }; } - function getYieldedTypeOfYieldExpression(node: YieldExpression, expressionType: Type, sentType: Type, isAsync: boolean): Type | undefined { + function getYieldedTypeOfYieldExpression( + node: YieldExpression, + expressionType: Type, + sentType: Type, + isAsync: boolean + ): Type | undefined { const errorNode = node.expression || node; // A `yield*` expression effectively yields everything that its operand yields - const yieldedType = node.asteriskToken ? checkIteratedTypeOrElementType(isAsync ? IterationUse.AsyncYieldStar : IterationUse.YieldStar, expressionType, sentType, errorNode) : expressionType; - return !isAsync ? yieldedType : getAwaitedType( - yieldedType, - errorNode, - node.asteriskToken - ? Diagnostics.Type_of_iterated_elements_of_a_yield_Asterisk_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member - : Diagnostics.Type_of_yield_operand_in_an_async_generator_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member, - ); + const yieldedType = node.asteriskToken + ? checkIteratedTypeOrElementType( + isAsync + ? IterationUse.AsyncYieldStar + : IterationUse.YieldStar, + expressionType, + sentType, + errorNode + ) + : expressionType; + return !isAsync + ? yieldedType + : getAwaitedType( + yieldedType, + errorNode, + node.asteriskToken + ? Diagnostics.Type_of_iterated_elements_of_a_yield_Asterisk_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member + : Diagnostics.Type_of_yield_operand_in_an_async_generator_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member + ); } // Return the combined not-equal type facts for all cases except those between the start and end indices. - function getNotEqualFactsFromTypeofSwitch(start: number, end: number, witnesses: (string | undefined)[]): TypeFacts { + function getNotEqualFactsFromTypeofSwitch( + start: number, + end: number, + witnesses: (string | undefined)[] + ): TypeFacts { let facts: TypeFacts = TypeFacts.None; for (let i = 0; i < witnesses.length; i++) { const witness = i < start || i >= end ? witnesses[i] : undefined; - facts |= witness !== undefined ? typeofNEFacts.get(witness) || TypeFacts.TypeofNEHostObject : 0; + facts |= + witness !== undefined + ? typeofNEFacts.get(witness) || TypeFacts.TypeofNEHostObject + : 0; } return facts; } @@ -39172,8 +68820,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (links.isExhaustive === 0) { links.isExhaustive = exhaustive; } - } - else if (links.isExhaustive === 0) { + } else if (links.isExhaustive === 0) { links.isExhaustive = false; // Resolve circularity to false } return links.isExhaustive; @@ -39185,25 +68832,47 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!witnesses) { return false; } - const operandConstraint = getBaseConstraintOrType(checkExpressionCached((node.expression as TypeOfExpression).expression)); + const operandConstraint = getBaseConstraintOrType( + checkExpressionCached( + (node.expression as TypeOfExpression).expression + ) + ); // Get the not-equal flags for all handled cases. - const notEqualFacts = getNotEqualFactsFromTypeofSwitch(0, 0, witnesses); + const notEqualFacts = getNotEqualFactsFromTypeofSwitch( + 0, + 0, + witnesses + ); if (operandConstraint.flags & TypeFlags.AnyOrUnknown) { // We special case the top types to be exhaustive when all cases are handled. - return (TypeFacts.AllTypeofNE & notEqualFacts) === TypeFacts.AllTypeofNE; + return ( + (TypeFacts.AllTypeofNE & notEqualFacts) === + TypeFacts.AllTypeofNE + ); } // A missing not-equal flag indicates that the type wasn't handled by some case. - return !someType(operandConstraint, t => getTypeFacts(t, notEqualFacts) === notEqualFacts); + return !someType( + operandConstraint, + (t) => getTypeFacts(t, notEqualFacts) === notEqualFacts + ); } - const type = getBaseConstraintOrType(checkExpressionCached(node.expression)); + const type = getBaseConstraintOrType( + checkExpressionCached(node.expression) + ); if (!isLiteralType(type)) { return false; } const switchTypes = getSwitchClauseTypes(node); - if (!switchTypes.length || some(switchTypes, isNeitherUnitTypeNorNever)) { + if ( + !switchTypes.length || + some(switchTypes, isNeitherUnitTypeNorNever) + ) { return false; } - return eachTypeContainedIn(mapType(type, getRegularTypeOfLiteralType), switchTypes); + return eachTypeContainedIn( + mapType(type, getRegularTypeOfLiteralType), + switchTypes + ); } function functionHasImplicitReturn(func: FunctionLikeDeclaration) { @@ -39211,53 +68880,90 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } /** NOTE: Return value of `[]` means a different thing than `undefined`. `[]` means func returns `void`, `undefined` means it returns `never`. */ - function checkAndAggregateReturnExpressionTypes(func: FunctionLikeDeclaration, checkMode: CheckMode | undefined): Type[] | undefined { + function checkAndAggregateReturnExpressionTypes( + func: FunctionLikeDeclaration, + checkMode: CheckMode | undefined + ): Type[] | undefined { const functionFlags = getFunctionFlags(func); const aggregatedTypes: Type[] = []; let hasReturnWithNoExpression = functionHasImplicitReturn(func); let hasReturnOfTypeNever = false; - forEachReturnStatement(func.body as Block, returnStatement => { + forEachReturnStatement(func.body as Block, (returnStatement) => { let expr = returnStatement.expression; if (expr) { - expr = skipParentheses(expr, /*excludeJSDocTypeAssertions*/ true); + expr = skipParentheses( + expr, + /*excludeJSDocTypeAssertions*/ true + ); // Bare calls to this same function don't contribute to inference // and `return await` is also safe to unwrap here - if (functionFlags & FunctionFlags.Async && expr.kind === SyntaxKind.AwaitExpression) { - expr = skipParentheses((expr as AwaitExpression).expression, /*excludeJSDocTypeAssertions*/ true); + if ( + functionFlags & FunctionFlags.Async && + expr.kind === SyntaxKind.AwaitExpression + ) { + expr = skipParentheses( + (expr as AwaitExpression).expression, + /*excludeJSDocTypeAssertions*/ true + ); } if ( expr.kind === SyntaxKind.CallExpression && - (expr as CallExpression).expression.kind === SyntaxKind.Identifier && - checkExpressionCached((expr as CallExpression).expression).symbol === getMergedSymbol(func.symbol) && - (!isFunctionExpressionOrArrowFunction(func.symbol.valueDeclaration!) || isConstantReference((expr as CallExpression).expression)) + (expr as CallExpression).expression.kind === + SyntaxKind.Identifier && + checkExpressionCached((expr as CallExpression).expression) + .symbol === getMergedSymbol(func.symbol) && + (!isFunctionExpressionOrArrowFunction( + func.symbol.valueDeclaration! + ) || + isConstantReference( + (expr as CallExpression).expression + )) ) { hasReturnOfTypeNever = true; return; } - let type = checkExpressionCached(expr, checkMode && checkMode & ~CheckMode.SkipGenericFunctions); + let type = checkExpressionCached( + expr, + checkMode && checkMode & ~CheckMode.SkipGenericFunctions + ); if (functionFlags & FunctionFlags.Async) { // From within an async function you can return either a non-promise value or a promise. Any // Promise/A+ compatible implementation will always assimilate any foreign promise, so the // return type of the body should be unwrapped to its awaited type, which should be wrapped in // the native Promise type by the caller. - 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)); + 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 + ) + ); } if (type.flags & TypeFlags.Never) { hasReturnOfTypeNever = true; } pushIfUnique(aggregatedTypes, type); - } - else { + } else { hasReturnWithNoExpression = true; } }); - if (aggregatedTypes.length === 0 && !hasReturnWithNoExpression && (hasReturnOfTypeNever || mayReturnNever(func))) { + if ( + aggregatedTypes.length === 0 && + !hasReturnWithNoExpression && + (hasReturnOfTypeNever || mayReturnNever(func)) + ) { return undefined; } if ( - strictNullChecks && aggregatedTypes.length && hasReturnWithNoExpression && - !(isJSConstructor(func) && aggregatedTypes.some(t => t.symbol === func.symbol)) + strictNullChecks && + aggregatedTypes.length && + hasReturnWithNoExpression && + !( + isJSConstructor(func) && + aggregatedTypes.some((t) => t.symbol === func.symbol) + ) ) { // Javascript "callable constructors", containing eg `if (!(this instanceof A)) return new A()` should not add undefined pushIfUnique(aggregatedTypes, undefinedType); @@ -39276,7 +68982,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getTypePredicateFromBody(func: FunctionLikeDeclaration): TypePredicate | undefined { + function getTypePredicateFromBody( + func: FunctionLikeDeclaration + ): TypePredicate | undefined { switch (func.kind) { case SyntaxKind.Constructor: case SyntaxKind.GetAccessor: @@ -39290,48 +68998,104 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let singleReturn: Expression | undefined; if (func.body && func.body.kind !== SyntaxKind.Block) { singleReturn = func.body; // arrow function - } - else { - const bailedEarly = forEachReturnStatement(func.body as Block, returnStatement => { - if (singleReturn || !returnStatement.expression) return true; - singleReturn = returnStatement.expression; - }); - if (bailedEarly || !singleReturn || functionHasImplicitReturn(func)) return undefined; + } else { + const bailedEarly = forEachReturnStatement( + func.body as Block, + (returnStatement) => { + if (singleReturn || !returnStatement.expression) + return true; + singleReturn = returnStatement.expression; + } + ); + if (bailedEarly || !singleReturn || functionHasImplicitReturn(func)) + return undefined; } return checkIfExpressionRefinesAnyParameter(func, singleReturn); } - function checkIfExpressionRefinesAnyParameter(func: FunctionLikeDeclaration, expr: Expression): TypePredicate | undefined { + function checkIfExpressionRefinesAnyParameter( + func: FunctionLikeDeclaration, + expr: Expression + ): TypePredicate | undefined { expr = skipParentheses(expr, /*excludeJSDocTypeAssertions*/ true); const returnType = checkExpressionCached(expr); if (!(returnType.flags & TypeFlags.Boolean)) return undefined; return forEach(func.parameters, (param, i) => { const initType = getTypeOfSymbol(param.symbol); - if (!initType || initType.flags & TypeFlags.Boolean || !isIdentifier(param.name) || isSymbolAssigned(param.symbol) || isRestParameter(param)) { + if ( + !initType || + initType.flags & TypeFlags.Boolean || + !isIdentifier(param.name) || + isSymbolAssigned(param.symbol) || + isRestParameter(param) + ) { // Refining "x: boolean" to "x is true" or "x is false" isn't useful. return; } - const trueType = checkIfExpressionRefinesParameter(func, expr, param, initType); + const trueType = checkIfExpressionRefinesParameter( + func, + expr, + param, + initType + ); if (trueType) { - return createTypePredicate(TypePredicateKind.Identifier, unescapeLeadingUnderscores(param.name.escapedText), i, trueType); + return createTypePredicate( + TypePredicateKind.Identifier, + unescapeLeadingUnderscores(param.name.escapedText), + i, + trueType + ); } }); } - function checkIfExpressionRefinesParameter(func: FunctionLikeDeclaration, expr: Expression, param: ParameterDeclaration, initType: Type): Type | undefined { - const antecedent = canHaveFlowNode(expr) && expr.flowNode || - expr.parent.kind === SyntaxKind.ReturnStatement && (expr.parent as ReturnStatement).flowNode || - createFlowNode(FlowFlags.Start, /*node*/ undefined, /*antecedent*/ undefined); - const trueCondition = createFlowNode(FlowFlags.TrueCondition, expr, antecedent); + function checkIfExpressionRefinesParameter( + func: FunctionLikeDeclaration, + expr: Expression, + param: ParameterDeclaration, + initType: Type + ): Type | undefined { + const antecedent = + (canHaveFlowNode(expr) && expr.flowNode) || + (expr.parent.kind === SyntaxKind.ReturnStatement && + (expr.parent as ReturnStatement).flowNode) || + createFlowNode( + FlowFlags.Start, + /*node*/ undefined, + /*antecedent*/ undefined + ); + const trueCondition = createFlowNode( + FlowFlags.TrueCondition, + expr, + antecedent + ); - const trueType = getFlowTypeOfReference(param.name, initType, initType, func, trueCondition); + const trueType = getFlowTypeOfReference( + param.name, + initType, + initType, + func, + trueCondition + ); if (trueType === initType) return undefined; // "x is T" means that x is T if and only if it returns true. If it returns false then x is not T. // This means that if the function is called with an argument of type trueType, there can't be anything left in the `else` branch. It must reduce to `never`. - const falseCondition = createFlowNode(FlowFlags.FalseCondition, expr, antecedent); - const falseSubtype = getReducedType(getFlowTypeOfReference(param.name, initType, trueType, func, falseCondition)); + const falseCondition = createFlowNode( + FlowFlags.FalseCondition, + expr, + antecedent + ); + const falseSubtype = getReducedType( + getFlowTypeOfReference( + param.name, + initType, + trueType, + func, + falseCondition + ) + ); return falseSubtype.flags & TypeFlags.Never ? trueType : undefined; } @@ -39344,23 +69108,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * * @param returnType - return type of the function, can be undefined if return type is not explicitly specified */ - function checkAllCodePathsInNonVoidFunctionReturnOrThrow(func: FunctionLikeDeclaration | MethodSignature, returnType: Type | undefined) { - addLazyDiagnostic(checkAllCodePathsInNonVoidFunctionReturnOrThrowDiagnostics); + function checkAllCodePathsInNonVoidFunctionReturnOrThrow( + func: FunctionLikeDeclaration | MethodSignature, + returnType: Type | undefined + ) { + addLazyDiagnostic( + checkAllCodePathsInNonVoidFunctionReturnOrThrowDiagnostics + ); return; function checkAllCodePathsInNonVoidFunctionReturnOrThrowDiagnostics(): void { const functionFlags = getFunctionFlags(func); - const type = returnType && unwrapReturnType(returnType, functionFlags); + const type = + returnType && unwrapReturnType(returnType, functionFlags); // Functions with an explicitly specified return type that includes `void` or is exactly `any` or `undefined` don't // need any return statements. - if (type && (maybeTypeOfKind(type, TypeFlags.Void) || type.flags & (TypeFlags.Any | TypeFlags.Undefined))) { + if ( + type && + (maybeTypeOfKind(type, TypeFlags.Void) || + type.flags & (TypeFlags.Any | TypeFlags.Undefined)) + ) { return; } // If all we have is a function signature, or an arrow function with an expression body, then there is nothing to check. // also if HasImplicitReturn flag is not set this means that all codepaths in function body end with return or throw - if (func.kind === SyntaxKind.MethodSignature || nodeIsMissing(func.body) || func.body!.kind !== SyntaxKind.Block || !functionHasImplicitReturn(func)) { + if ( + func.kind === SyntaxKind.MethodSignature || + nodeIsMissing(func.body) || + func.body!.kind !== SyntaxKind.Block || + !functionHasImplicitReturn(func) + ) { return; } @@ -39368,17 +69147,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const errorNode = getEffectiveReturnTypeNode(func) || func; if (type && type.flags & TypeFlags.Never) { - error(errorNode, Diagnostics.A_function_returning_never_cannot_have_a_reachable_end_point); - } - else if (type && !hasExplicitReturn) { + error( + errorNode, + Diagnostics.A_function_returning_never_cannot_have_a_reachable_end_point + ); + } else if (type && !hasExplicitReturn) { // minimal check: function has syntactic return type annotation and no explicit return statements in the body // this function does not conform to the specification. - error(errorNode, Diagnostics.A_function_whose_declared_type_is_neither_undefined_void_nor_any_must_return_a_value); - } - else if (type && strictNullChecks && !isTypeAssignableTo(undefinedType, type)) { - error(errorNode, Diagnostics.Function_lacks_ending_return_statement_and_return_type_does_not_include_undefined); - } - else if (compilerOptions.noImplicitReturns) { + error( + errorNode, + Diagnostics.A_function_whose_declared_type_is_neither_undefined_void_nor_any_must_return_a_value + ); + } else if ( + type && + strictNullChecks && + !isTypeAssignableTo(undefinedType, type) + ) { + error( + errorNode, + Diagnostics.Function_lacks_ending_return_statement_and_return_type_does_not_include_undefined + ); + } else if (compilerOptions.noImplicitReturns) { if (!type) { // If return type annotation is omitted check if function has any explicit return statements. // If it does not have any - its inferred return type is void - don't do any checks. @@ -39386,8 +69175,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!hasExplicitReturn) { return; } - const inferredReturnType = getReturnTypeOfSignature(getSignatureFromDeclaration(func)); - if (isUnwrappedReturnTypeUndefinedVoidOrAny(func, inferredReturnType)) { + const inferredReturnType = getReturnTypeOfSignature( + getSignatureFromDeclaration(func) + ); + if ( + isUnwrappedReturnTypeUndefinedVoidOrAny( + func, + inferredReturnType + ) + ) { return; } } @@ -39396,8 +69192,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function checkFunctionExpressionOrObjectLiteralMethod(node: FunctionExpression | ArrowFunction | MethodDeclaration, checkMode?: CheckMode): Type { - Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); + function checkFunctionExpressionOrObjectLiteralMethod( + node: FunctionExpression | ArrowFunction | MethodDeclaration, + checkMode?: CheckMode + ): Type { + Debug.assert( + node.kind !== SyntaxKind.MethodDeclaration || + isObjectLiteralMethod(node) + ); checkNodeDeferred(node); if (isFunctionExpression(node)) { @@ -39405,21 +69207,48 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // The identityMapper object is used to indicate that function expressions are wildcards - if (checkMode && checkMode & CheckMode.SkipContextSensitive && isContextSensitive(node)) { + if ( + checkMode && + checkMode & CheckMode.SkipContextSensitive && + isContextSensitive(node) + ) { // Skip parameters, return signature with return type that retains noncontextual parts so inferences can still be drawn in an early stage - if (!getEffectiveReturnTypeNode(node) && !hasContextSensitiveParameters(node)) { + if ( + !getEffectiveReturnTypeNode(node) && + !hasContextSensitiveParameters(node) + ) { // Return plain anyFunctionType if there is no possibility we'll make inferences from the return type const contextualSignature = getContextualSignature(node); - if (contextualSignature && couldContainTypeVariables(getReturnTypeOfSignature(contextualSignature))) { + if ( + contextualSignature && + couldContainTypeVariables( + getReturnTypeOfSignature(contextualSignature) + ) + ) { const links = getNodeLinks(node); if (links.contextFreeType) { return links.contextFreeType; } const returnType = getReturnTypeFromBody(node, checkMode); - const returnOnlySignature = createSignature(/*declaration*/ undefined, /*typeParameters*/ undefined, /*thisParameter*/ undefined, emptyArray, returnType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.IsNonInferrable); - const returnOnlyType = createAnonymousType(node.symbol, emptySymbols, [returnOnlySignature], emptyArray, emptyArray); + const returnOnlySignature = createSignature( + /*declaration*/ undefined, + /*typeParameters*/ undefined, + /*thisParameter*/ undefined, + emptyArray, + returnType, + /*resolvedTypePredicate*/ undefined, + 0, + SignatureFlags.IsNonInferrable + ); + const returnOnlyType = createAnonymousType( + node.symbol, + emptySymbols, + [returnOnlySignature], + emptyArray, + emptyArray + ); returnOnlyType.objectFlags |= ObjectFlags.NonInferrableType; - return links.contextFreeType = returnOnlyType; + return (links.contextFreeType = returnOnlyType); } } return anyFunctionType; @@ -39431,12 +69260,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkGrammarForGenerator(node); } - contextuallyCheckFunctionExpressionOrObjectLiteralMethod(node, checkMode); + contextuallyCheckFunctionExpressionOrObjectLiteralMethod( + node, + checkMode + ); return getTypeOfSymbol(getSymbolOfDeclaration(node)); } - function contextuallyCheckFunctionExpressionOrObjectLiteralMethod(node: FunctionExpression | ArrowFunction | MethodDeclaration, checkMode?: CheckMode) { + function contextuallyCheckFunctionExpressionOrObjectLiteralMethod( + node: FunctionExpression | ArrowFunction | MethodDeclaration, + checkMode?: CheckMode + ) { const links = getNodeLinks(node); // Check if function expression is contextually typed and assign parameter types if so. if (!(links.flags & NodeCheckFlags.ContextChecked)) { @@ -39446,37 +69281,74 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // already assigned contextual types. if (!(links.flags & NodeCheckFlags.ContextChecked)) { links.flags |= NodeCheckFlags.ContextChecked; - const signature = firstOrUndefined(getSignaturesOfType(getTypeOfSymbol(getSymbolOfDeclaration(node)), SignatureKind.Call)); + const signature = firstOrUndefined( + getSignaturesOfType( + getTypeOfSymbol(getSymbolOfDeclaration(node)), + SignatureKind.Call + ) + ); if (!signature) { return; } if (isContextSensitive(node)) { if (contextualSignature) { const inferenceContext = getInferenceContext(node); - let instantiatedContextualSignature: Signature | undefined; + let instantiatedContextualSignature: + | Signature + | undefined; if (checkMode && checkMode & CheckMode.Inferential) { - inferFromAnnotatedParametersAndReturn(signature, contextualSignature, inferenceContext!); - const restType = getEffectiveRestType(contextualSignature); - if (restType && restType.flags & TypeFlags.TypeParameter) { - instantiatedContextualSignature = instantiateSignature(contextualSignature, inferenceContext!.nonFixingMapper); + inferFromAnnotatedParametersAndReturn( + signature, + contextualSignature, + inferenceContext! + ); + const restType = + getEffectiveRestType(contextualSignature); + if ( + restType && + restType.flags & TypeFlags.TypeParameter + ) { + instantiatedContextualSignature = + instantiateSignature( + contextualSignature, + inferenceContext!.nonFixingMapper + ); } } - instantiatedContextualSignature ||= inferenceContext ? - instantiateSignature(contextualSignature, inferenceContext.mapper) : contextualSignature; - assignContextualParameterTypes(signature, instantiatedContextualSignature); - } - else { + instantiatedContextualSignature ||= inferenceContext + ? instantiateSignature( + contextualSignature, + inferenceContext.mapper + ) + : contextualSignature; + assignContextualParameterTypes( + signature, + instantiatedContextualSignature + ); + } else { // Force resolution of all parameter types such that the absence of a contextual type is consistently reflected. assignNonContextualParameterTypes(signature); } - } - else if (contextualSignature && !node.typeParameters && contextualSignature.parameters.length > node.parameters.length) { + } else if ( + contextualSignature && + !node.typeParameters && + contextualSignature.parameters.length > + node.parameters.length + ) { const inferenceContext = getInferenceContext(node); if (checkMode && checkMode & CheckMode.Inferential) { - inferFromAnnotatedParametersAndReturn(signature, contextualSignature, inferenceContext!); + inferFromAnnotatedParametersAndReturn( + signature, + contextualSignature, + inferenceContext! + ); } } - if (contextualSignature && !getReturnTypeFromAnnotation(node) && !signature.resolvedReturnType) { + if ( + contextualSignature && + !getReturnTypeFromAnnotation(node) && + !signature.resolvedReturnType + ) { const returnType = getReturnTypeFromBody(node, checkMode); if (!signature.resolvedReturnType) { signature.resolvedReturnType = returnType; @@ -39487,8 +69359,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function checkFunctionExpressionOrObjectLiteralMethodDeferred(node: ArrowFunction | FunctionExpression | MethodDeclaration) { - Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); + function checkFunctionExpressionOrObjectLiteralMethodDeferred( + node: ArrowFunction | FunctionExpression | MethodDeclaration + ) { + Debug.assert( + node.kind !== SyntaxKind.MethodDeclaration || + isObjectLiteralMethod(node) + ); const functionFlags = getFunctionFlags(node); const returnType = getReturnTypeFromAnnotation(node); @@ -39506,29 +69383,41 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (node.body.kind === SyntaxKind.Block) { checkSourceElement(node.body); - } - else { + } else { // From within an async function you can return either a non-promise value or a promise. Any // Promise/A+ compatible implementation will always assimilate any foreign promise, so we // should not be checking assignability of a promise to the return type. Instead, we need to // check assignability of the awaited type of the expression body against the promised type of // its return type annotation. const exprType = checkExpression(node.body); - const returnOrPromisedType = returnType && unwrapReturnType(returnType, functionFlags); + const returnOrPromisedType = + returnType && unwrapReturnType(returnType, functionFlags); if (returnOrPromisedType) { - checkReturnExpression(node, returnOrPromisedType, node.body, node.body, exprType); + checkReturnExpression( + node, + returnOrPromisedType, + node.body, + node.body, + exprType + ); } } } } - function checkArithmeticOperandType(operand: Node, type: Type, diagnostic: DiagnosticMessage, isAwaitValid = false): boolean { + function checkArithmeticOperandType( + operand: Node, + type: Type, + diagnostic: DiagnosticMessage, + isAwaitValid = false + ): boolean { if (!isTypeAssignableTo(type, numberOrBigIntType)) { const awaitedType = isAwaitValid && getAwaitedTypeOfPromise(type); errorAndMaybeSuggestAwait( operand, - !!awaitedType && isTypeAssignableTo(awaitedType, numberOrBigIntType), - diagnostic, + !!awaitedType && + isTypeAssignableTo(awaitedType, numberOrBigIntType), + diagnostic ); return false; } @@ -39543,20 +69432,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } const objectLitType = checkExpressionCached(d.arguments[2]); - const valueType = getTypeOfPropertyOfType(objectLitType, "value" as __String); + const valueType = getTypeOfPropertyOfType( + objectLitType, + "value" as __String + ); if (valueType) { - const writableProp = getPropertyOfType(objectLitType, "writable" as __String); + const writableProp = getPropertyOfType( + objectLitType, + "writable" as __String + ); const writableType = writableProp && getTypeOfSymbol(writableProp); - if (!writableType || writableType === falseType || writableType === regularFalseType) { + if ( + !writableType || + writableType === falseType || + writableType === regularFalseType + ) { return true; } // We include this definition whereupon we walk back and check the type at the declaration because // The usual definition of `Object.defineProperty` will _not_ cause literal types to be preserved in the // argument types, should the type be contextualized by the call itself. - if (writableProp && writableProp.valueDeclaration && isPropertyAssignment(writableProp.valueDeclaration)) { + if ( + writableProp && + writableProp.valueDeclaration && + isPropertyAssignment(writableProp.valueDeclaration) + ) { const initializer = writableProp.valueDeclaration.initializer; const rawOriginalType = checkExpression(initializer); - if (rawOriginalType === falseType || rawOriginalType === regularFalseType) { + if ( + rawOriginalType === falseType || + rawOriginalType === regularFalseType + ) { return true; } } @@ -39574,15 +69480,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Enum members // Object.defineProperty assignments with writable false or no setter // Unions and intersections of the above (unions and intersections eagerly set isReadonly on creation) - return !!(getCheckFlags(symbol) & CheckFlags.Readonly || - symbol.flags & SymbolFlags.Property && getDeclarationModifierFlagsFromSymbol(symbol) & ModifierFlags.Readonly || - symbol.flags & SymbolFlags.Variable && getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Constant || - symbol.flags & SymbolFlags.Accessor && !(symbol.flags & SymbolFlags.SetAccessor) || + return !!( + getCheckFlags(symbol) & CheckFlags.Readonly || + (symbol.flags & SymbolFlags.Property && + getDeclarationModifierFlagsFromSymbol(symbol) & + ModifierFlags.Readonly) || + (symbol.flags & SymbolFlags.Variable && + getDeclarationNodeFlagsFromSymbol(symbol) & + NodeFlags.Constant) || + (symbol.flags & SymbolFlags.Accessor && + !(symbol.flags & SymbolFlags.SetAccessor)) || symbol.flags & SymbolFlags.EnumMember || - some(symbol.declarations, isReadonlyAssignmentDeclaration)); + some(symbol.declarations, isReadonlyAssignmentDeclaration) + ); } - function isAssignmentToReadonlyEntity(expr: Expression, symbol: Symbol, assignmentKind: AssignmentKind) { + function isAssignmentToReadonlyEntity( + expr: Expression, + symbol: Symbol, + assignmentKind: AssignmentKind + ) { if (assignmentKind === AssignmentKind.None) { // no assigment means it doesn't matter whether the entity is readonly return false; @@ -39596,19 +69513,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { ) { // Look for if this is the constructor for the class that `symbol` is a property of. const ctor = getControlFlowContainer(expr); - if (!(ctor && (ctor.kind === SyntaxKind.Constructor || isJSConstructor(ctor)))) { + if ( + !( + ctor && + (ctor.kind === SyntaxKind.Constructor || + isJSConstructor(ctor)) + ) + ) { return true; } if (symbol.valueDeclaration) { - const isAssignmentDeclaration = isBinaryExpression(symbol.valueDeclaration); - const isLocalPropertyDeclaration = ctor.parent === symbol.valueDeclaration.parent; - const isLocalParameterProperty = ctor === symbol.valueDeclaration.parent; - const isLocalThisPropertyAssignment = isAssignmentDeclaration && symbol.parent?.valueDeclaration === ctor.parent; - const isLocalThisPropertyAssignmentConstructorFunction = isAssignmentDeclaration && symbol.parent?.valueDeclaration === ctor; - const isWriteableSymbol = isLocalPropertyDeclaration - || isLocalParameterProperty - || isLocalThisPropertyAssignment - || isLocalThisPropertyAssignmentConstructorFunction; + const isAssignmentDeclaration = isBinaryExpression( + symbol.valueDeclaration + ); + const isLocalPropertyDeclaration = + ctor.parent === symbol.valueDeclaration.parent; + const isLocalParameterProperty = + ctor === symbol.valueDeclaration.parent; + const isLocalThisPropertyAssignment = + isAssignmentDeclaration && + symbol.parent?.valueDeclaration === ctor.parent; + const isLocalThisPropertyAssignmentConstructorFunction = + isAssignmentDeclaration && + symbol.parent?.valueDeclaration === ctor; + const isWriteableSymbol = + isLocalPropertyDeclaration || + isLocalParameterProperty || + isLocalThisPropertyAssignment || + isLocalThisPropertyAssignmentConstructorFunction; return !isWriteableSymbol; } } @@ -39621,16 +69553,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const symbol = getNodeLinks(node).resolvedSymbol!; if (symbol.flags & SymbolFlags.Alias) { const declaration = getDeclarationOfAliasSymbol(symbol); - return !!declaration && declaration.kind === SyntaxKind.NamespaceImport; + return ( + !!declaration && + declaration.kind === SyntaxKind.NamespaceImport + ); } } } return false; } - function checkReferenceExpression(expr: Expression, invalidReferenceMessage: DiagnosticMessage, invalidOptionalChainMessage: DiagnosticMessage): boolean { + function checkReferenceExpression( + expr: Expression, + invalidReferenceMessage: DiagnosticMessage, + invalidOptionalChainMessage: DiagnosticMessage + ): boolean { // References are combinations of identifiers, parentheses, and property accesses. - const node = skipOuterExpressions(expr, OuterExpressionKinds.Assertions | OuterExpressionKinds.Parentheses); + const node = skipOuterExpressions( + expr, + OuterExpressionKinds.Assertions | OuterExpressionKinds.Parentheses + ); if (node.kind !== SyntaxKind.Identifier && !isAccessExpression(node)) { error(expr, invalidReferenceMessage); return false; @@ -39646,33 +69588,54 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkExpression(node.expression); const expr = skipParentheses(node.expression); if (!isAccessExpression(expr)) { - error(expr, Diagnostics.The_operand_of_a_delete_operator_must_be_a_property_reference); + error( + expr, + Diagnostics.The_operand_of_a_delete_operator_must_be_a_property_reference + ); return booleanType; } - if (isPropertyAccessExpression(expr) && isPrivateIdentifier(expr.name)) { - error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_private_identifier); + if ( + isPropertyAccessExpression(expr) && + isPrivateIdentifier(expr.name) + ) { + error( + expr, + Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_private_identifier + ); } const links = getNodeLinks(expr); - const symbol = getExportSymbolOfValueSymbolIfExported(links.resolvedSymbol); + const symbol = getExportSymbolOfValueSymbolIfExported( + links.resolvedSymbol + ); if (symbol) { if (isReadonlySymbol(symbol)) { - error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_read_only_property); - } - else { + error( + expr, + Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_read_only_property + ); + } else { checkDeleteExpressionMustBeOptional(expr, symbol); } } return booleanType; } - function checkDeleteExpressionMustBeOptional(expr: AccessExpression, symbol: Symbol) { + function checkDeleteExpressionMustBeOptional( + expr: AccessExpression, + symbol: Symbol + ) { const type = getTypeOfSymbol(symbol); if ( strictNullChecks && !(type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Never)) && - !(exactOptionalPropertyTypes ? symbol.flags & SymbolFlags.Optional : hasTypeFacts(type, TypeFacts.IsUndefined)) + !(exactOptionalPropertyTypes + ? symbol.flags & SymbolFlags.Optional + : hasTypeFacts(type, TypeFacts.IsUndefined)) ) { - error(expr, Diagnostics.The_operand_of_a_delete_operator_must_be_optional); + error( + expr, + Diagnostics.The_operand_of_a_delete_operator_must_be_optional + ); } } @@ -39686,27 +69649,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefinedWideningType; } - function checkAwaitGrammar(node: AwaitExpression | VariableDeclarationList): boolean { + function checkAwaitGrammar( + node: AwaitExpression | VariableDeclarationList + ): boolean { // Grammar checking let hasError = false; const container = getContainingFunctionOrClassStaticBlock(node); if (container && isClassStaticBlockDeclaration(container)) { // NOTE: We report this regardless as to whether there are parse diagnostics. - const message = isAwaitExpression(node) ? Diagnostics.await_expression_cannot_be_used_inside_a_class_static_block : - Diagnostics.await_using_statements_cannot_be_used_inside_a_class_static_block; + const message = isAwaitExpression(node) + ? Diagnostics.await_expression_cannot_be_used_inside_a_class_static_block + : Diagnostics.await_using_statements_cannot_be_used_inside_a_class_static_block; error(node, message); hasError = true; - } - else if (!(node.flags & NodeFlags.AwaitContext)) { + } else if (!(node.flags & NodeFlags.AwaitContext)) { if (isInTopLevelContext(node)) { const sourceFile = getSourceFileOfNode(node); if (!hasParseDiagnostics(sourceFile)) { let span: TextSpan | undefined; - if (!isEffectiveExternalModule(sourceFile, compilerOptions)) { + if ( + !isEffectiveExternalModule(sourceFile, compilerOptions) + ) { span ??= getSpanOfTokenAtPosition(sourceFile, node.pos); - const message = isAwaitExpression(node) ? 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 : - Diagnostics.await_using_statements_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; - const diagnostic = createFileDiagnostic(sourceFile, span.start, span.length, message); + const message = isAwaitExpression(node) + ? 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 + : Diagnostics.await_using_statements_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; + const diagnostic = createFileDiagnostic( + sourceFile, + span.start, + span.length, + message + ); diagnostics.add(diagnostic); hasError = true; } @@ -39715,15 +69688,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case ModuleKind.Node18: case ModuleKind.Node20: case ModuleKind.NodeNext: - if (sourceFile.impliedNodeFormat === ModuleKind.CommonJS) { - span ??= getSpanOfTokenAtPosition(sourceFile, node.pos); + if ( + sourceFile.impliedNodeFormat === + ModuleKind.CommonJS + ) { + span ??= getSpanOfTokenAtPosition( + sourceFile, + node.pos + ); diagnostics.add( - createFileDiagnostic(sourceFile, span.start, span.length, Diagnostics.The_current_file_is_a_CommonJS_module_and_cannot_use_await_at_the_top_level), + createFileDiagnostic( + sourceFile, + span.start, + span.length, + Diagnostics.The_current_file_is_a_CommonJS_module_and_cannot_use_await_at_the_top_level + ) ); hasError = true; break; } - // fallthrough + // fallthrough case ModuleKind.ES2022: case ModuleKind.ESNext: case ModuleKind.Preserve: @@ -39731,27 +69715,51 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (languageVersion >= ScriptTarget.ES2017) { break; } - // fallthrough + // fallthrough default: - span ??= getSpanOfTokenAtPosition(sourceFile, node.pos); - const message = isAwaitExpression(node) ? Diagnostics.Top_level_await_expressions_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_node18_node20_nodenext_or_preserve_and_the_target_option_is_set_to_es2017_or_higher : - Diagnostics.Top_level_await_using_statements_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_node18_node20_nodenext_or_preserve_and_the_target_option_is_set_to_es2017_or_higher; - diagnostics.add(createFileDiagnostic(sourceFile, span.start, span.length, message)); + span ??= getSpanOfTokenAtPosition( + sourceFile, + node.pos + ); + const message = isAwaitExpression(node) + ? Diagnostics.Top_level_await_expressions_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_node18_node20_nodenext_or_preserve_and_the_target_option_is_set_to_es2017_or_higher + : Diagnostics.Top_level_await_using_statements_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_node18_node20_nodenext_or_preserve_and_the_target_option_is_set_to_es2017_or_higher; + diagnostics.add( + createFileDiagnostic( + sourceFile, + span.start, + span.length, + message + ) + ); hasError = true; break; } } - } - else { + } else { // use of 'await' in non-async function const sourceFile = getSourceFileOfNode(node); if (!hasParseDiagnostics(sourceFile)) { const span = getSpanOfTokenAtPosition(sourceFile, node.pos); - const message = isAwaitExpression(node) ? Diagnostics.await_expressions_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules : - Diagnostics.await_using_statements_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules; - const diagnostic = createFileDiagnostic(sourceFile, span.start, span.length, message); - if (container && container.kind !== SyntaxKind.Constructor && (getFunctionFlags(container) & FunctionFlags.Async) === 0) { - const relatedInfo = createDiagnosticForNode(container, Diagnostics.Did_you_mean_to_mark_this_function_as_async); + const message = isAwaitExpression(node) + ? Diagnostics.await_expressions_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules + : Diagnostics.await_using_statements_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules; + const diagnostic = createFileDiagnostic( + sourceFile, + span.start, + span.length, + message + ); + if ( + container && + container.kind !== SyntaxKind.Constructor && + (getFunctionFlags(container) & FunctionFlags.Async) === + 0 + ) { + const relatedInfo = createDiagnosticForNode( + container, + Diagnostics.Did_you_mean_to_mark_this_function_as_async + ); addRelatedInfo(diagnostic, relatedInfo); } diagnostics.add(diagnostic); @@ -39760,9 +69768,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - if (isAwaitExpression(node) && isInParameterInitializerBeforeContainingFunction(node)) { + if ( + isAwaitExpression(node) && + isInParameterInitializerBeforeContainingFunction(node) + ) { // NOTE: We report this regardless as to whether there are parse diagnostics. - error(node, Diagnostics.await_expressions_cannot_be_used_in_a_parameter_initializer); + error( + node, + Diagnostics.await_expressions_cannot_be_used_in_a_parameter_initializer + ); hasError = true; } @@ -39773,9 +69787,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { addLazyDiagnostic(() => checkAwaitGrammar(node)); const operandType = checkExpression(node.expression); - 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); - if (awaitedType === operandType && !isErrorType(awaitedType) && !(operandType.flags & TypeFlags.AnyOrUnknown)) { - addErrorOrSuggestion(/*isError*/ false, createDiagnosticForNode(node, Diagnostics.await_has_no_effect_on_the_type_of_this_expression)); + 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 + ); + if ( + awaitedType === operandType && + !isErrorType(awaitedType) && + !(operandType.flags & TypeFlags.AnyOrUnknown) + ) { + addErrorOrSuggestion( + /*isError*/ false, + createDiagnosticForNode( + node, + Diagnostics.await_has_no_effect_on_the_type_of_this_expression + ) + ); } return awaitedType; } @@ -39789,17 +69818,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.NumericLiteral: switch (node.operator) { case SyntaxKind.MinusToken: - return getFreshTypeOfLiteralType(getNumberLiteralType(-(node.operand as NumericLiteral).text)); + return getFreshTypeOfLiteralType( + getNumberLiteralType( + -(node.operand as NumericLiteral).text + ) + ); case SyntaxKind.PlusToken: - return getFreshTypeOfLiteralType(getNumberLiteralType(+(node.operand as NumericLiteral).text)); + return getFreshTypeOfLiteralType( + getNumberLiteralType( + +(node.operand as NumericLiteral).text + ) + ); } break; case SyntaxKind.BigIntLiteral: if (node.operator === SyntaxKind.MinusToken) { - return getFreshTypeOfLiteralType(getBigIntLiteralType({ - negative: true, - base10Value: parsePseudoBigInt((node.operand as BigIntLiteral).text), - })); + return getFreshTypeOfLiteralType( + getBigIntLiteralType({ + negative: true, + base10Value: parsePseudoBigInt( + (node.operand as BigIntLiteral).text + ), + }) + ); } } switch (node.operator) { @@ -39807,31 +69848,59 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.MinusToken: case SyntaxKind.TildeToken: checkNonNullType(operandType, node.operand); - if (maybeTypeOfKindConsideringBaseConstraint(operandType, TypeFlags.ESSymbolLike)) { - error(node.operand, Diagnostics.The_0_operator_cannot_be_applied_to_type_symbol, tokenToString(node.operator)); + if ( + maybeTypeOfKindConsideringBaseConstraint( + operandType, + TypeFlags.ESSymbolLike + ) + ) { + error( + node.operand, + Diagnostics.The_0_operator_cannot_be_applied_to_type_symbol, + tokenToString(node.operator) + ); } if (node.operator === SyntaxKind.PlusToken) { - if (maybeTypeOfKindConsideringBaseConstraint(operandType, TypeFlags.BigIntLike)) { - error(node.operand, Diagnostics.Operator_0_cannot_be_applied_to_type_1, tokenToString(node.operator), typeToString(getBaseTypeOfLiteralType(operandType))); + if ( + maybeTypeOfKindConsideringBaseConstraint( + operandType, + TypeFlags.BigIntLike + ) + ) { + error( + node.operand, + Diagnostics.Operator_0_cannot_be_applied_to_type_1, + tokenToString(node.operator), + typeToString(getBaseTypeOfLiteralType(operandType)) + ); } return numberType; } return getUnaryResultType(operandType); case SyntaxKind.ExclamationToken: checkTruthinessOfType(operandType, node.operand); - const facts = getTypeFacts(operandType, TypeFacts.Truthy | TypeFacts.Falsy); - return facts === TypeFacts.Truthy ? falseType : - facts === TypeFacts.Falsy ? trueType : - booleanType; + const facts = getTypeFacts( + operandType, + TypeFacts.Truthy | TypeFacts.Falsy + ); + return facts === TypeFacts.Truthy + ? falseType + : facts === TypeFacts.Falsy + ? trueType + : booleanType; case SyntaxKind.PlusPlusToken: case SyntaxKind.MinusMinusToken: - const ok = checkArithmeticOperandType(node.operand, checkNonNullType(operandType, node.operand), Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_bigint_or_an_enum_type); + const ok = checkArithmeticOperandType( + node.operand, + checkNonNullType(operandType, node.operand), + Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_bigint_or_an_enum_type + ); if (ok) { // run check only if former checks succeeded to avoid reporting cascading errors checkReferenceExpression( node.operand, Diagnostics.The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access, - Diagnostics.The_operand_of_an_increment_or_decrement_operator_may_not_be_an_optional_property_access, + Diagnostics.The_operand_of_an_increment_or_decrement_operator_may_not_be_an_optional_property_access ); } return getUnaryResultType(operandType); @@ -39847,14 +69916,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const ok = checkArithmeticOperandType( node.operand, checkNonNullType(operandType, node.operand), - Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_bigint_or_an_enum_type, + Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_bigint_or_an_enum_type ); if (ok) { // run check only if former checks succeeded to avoid reporting cascading errors checkReferenceExpression( node.operand, Diagnostics.The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access, - Diagnostics.The_operand_of_an_increment_or_decrement_operator_may_not_be_an_optional_property_access, + Diagnostics.The_operand_of_an_increment_or_decrement_operator_may_not_be_an_optional_property_access ); } return getUnaryResultType(operandType); @@ -39862,7 +69931,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getUnaryResultType(operandType: Type): Type { if (maybeTypeOfKind(operandType, TypeFlags.BigIntLike)) { - return isTypeAssignableToKind(operandType, TypeFlags.AnyOrUnknown) || maybeTypeOfKind(operandType, TypeFlags.NumberLike) + return isTypeAssignableToKind( + operandType, + TypeFlags.AnyOrUnknown + ) || maybeTypeOfKind(operandType, TypeFlags.NumberLike) ? numberOrBigIntType : bigintType; } @@ -39870,7 +69942,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return numberType; } - function maybeTypeOfKindConsideringBaseConstraint(type: Type, kind: TypeFlags): boolean { + function maybeTypeOfKindConsideringBaseConstraint( + type: Type, + kind: TypeFlags + ): boolean { if (maybeTypeOfKind(type, kind)) { return true; } @@ -39896,33 +69971,66 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function isTypeAssignableToKind(source: Type, kind: TypeFlags, strict?: boolean): boolean { + function isTypeAssignableToKind( + source: Type, + kind: TypeFlags, + strict?: boolean + ): boolean { if (source.flags & kind) { return true; } - if (strict && source.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Void | TypeFlags.Undefined | TypeFlags.Null)) { + if ( + strict && + source.flags & + (TypeFlags.AnyOrUnknown | + TypeFlags.Void | + TypeFlags.Undefined | + TypeFlags.Null) + ) { return false; } - return !!(kind & TypeFlags.NumberLike) && isTypeAssignableTo(source, numberType) || - !!(kind & TypeFlags.BigIntLike) && isTypeAssignableTo(source, bigintType) || - !!(kind & TypeFlags.StringLike) && isTypeAssignableTo(source, stringType) || - !!(kind & TypeFlags.BooleanLike) && isTypeAssignableTo(source, booleanType) || - !!(kind & TypeFlags.Void) && isTypeAssignableTo(source, voidType) || - !!(kind & TypeFlags.Never) && isTypeAssignableTo(source, neverType) || - !!(kind & TypeFlags.Null) && isTypeAssignableTo(source, nullType) || - !!(kind & TypeFlags.Undefined) && isTypeAssignableTo(source, undefinedType) || - !!(kind & TypeFlags.ESSymbol) && isTypeAssignableTo(source, esSymbolType) || - !!(kind & TypeFlags.NonPrimitive) && isTypeAssignableTo(source, nonPrimitiveType); + return ( + (!!(kind & TypeFlags.NumberLike) && + isTypeAssignableTo(source, numberType)) || + (!!(kind & TypeFlags.BigIntLike) && + isTypeAssignableTo(source, bigintType)) || + (!!(kind & TypeFlags.StringLike) && + isTypeAssignableTo(source, stringType)) || + (!!(kind & TypeFlags.BooleanLike) && + isTypeAssignableTo(source, booleanType)) || + (!!(kind & TypeFlags.Void) && + isTypeAssignableTo(source, voidType)) || + (!!(kind & TypeFlags.Never) && + isTypeAssignableTo(source, neverType)) || + (!!(kind & TypeFlags.Null) && + isTypeAssignableTo(source, nullType)) || + (!!(kind & TypeFlags.Undefined) && + isTypeAssignableTo(source, undefinedType)) || + (!!(kind & TypeFlags.ESSymbol) && + isTypeAssignableTo(source, esSymbolType)) || + (!!(kind & TypeFlags.NonPrimitive) && + isTypeAssignableTo(source, nonPrimitiveType)) + ); } - function allTypesAssignableToKind(source: Type, kind: TypeFlags, strict?: boolean): boolean { - return source.flags & TypeFlags.Union ? - every((source as UnionType).types, subType => allTypesAssignableToKind(subType, kind, strict)) : - isTypeAssignableToKind(source, kind, strict); + function allTypesAssignableToKind( + source: Type, + kind: TypeFlags, + strict?: boolean + ): boolean { + return source.flags & TypeFlags.Union + ? every((source as UnionType).types, (subType) => + allTypesAssignableToKind(subType, kind, strict) + ) + : isTypeAssignableToKind(source, kind, strict); } function isConstEnumObjectType(type: Type): boolean { - return !!(getObjectFlags(type) & ObjectFlags.Anonymous) && !!type.symbol && isConstEnumSymbol(type.symbol); + return ( + !!(getObjectFlags(type) & ObjectFlags.Anonymous) && + !!type.symbol && + isConstEnumSymbol(type.symbol) + ); } function isConstEnumSymbol(symbol: Symbol): boolean { @@ -39933,19 +70041,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Get the type of the `[Symbol.hasInstance]` method of an object type. */ function getSymbolHasInstanceMethodOfObjectType(type: Type) { - const hasInstancePropertyName = getPropertyNameForKnownSymbolName("hasInstance"); + const hasInstancePropertyName = + getPropertyNameForKnownSymbolName("hasInstance"); if (allTypesAssignableToKind(type, TypeFlags.NonPrimitive)) { - const hasInstanceProperty = getPropertyOfType(type, hasInstancePropertyName); + const hasInstanceProperty = getPropertyOfType( + type, + hasInstancePropertyName + ); if (hasInstanceProperty) { - const hasInstancePropertyType = getTypeOfSymbol(hasInstanceProperty); - if (hasInstancePropertyType && getSignaturesOfType(hasInstancePropertyType, SignatureKind.Call).length !== 0) { + const hasInstancePropertyType = + getTypeOfSymbol(hasInstanceProperty); + if ( + hasInstancePropertyType && + getSignaturesOfType( + hasInstancePropertyType, + SignatureKind.Call + ).length !== 0 + ) { return hasInstancePropertyType; } } } } - function checkInstanceOfExpression(left: Expression, right: Expression, leftType: Type, rightType: Type, checkMode?: CheckMode): Type { + function checkInstanceOfExpression( + left: Expression, + right: Expression, + leftType: Type, + rightType: Type, + checkMode?: CheckMode + ): Type { if (leftType === silentNeverType || rightType === silentNeverType) { return silentNeverType; } @@ -39959,11 +70084,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { !isTypeAny(leftType) && allTypesAssignableToKind(leftType, TypeFlags.Primitive) ) { - error(left, Diagnostics.The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter); + error( + left, + Diagnostics.The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter + ); } Debug.assert(isInstanceOfExpression(left.parent)); - const signature = getResolvedSignature(left.parent, /*candidatesOutArray*/ undefined, checkMode); + const signature = getResolvedSignature( + left.parent, + /*candidatesOutArray*/ undefined, + checkMode + ); if (signature === resolvingSignature) { // CheckMode.SkipGenericFunctions is enabled and this is a call to a generic function that // returns a function type. We defer checking and return silentNeverType. @@ -39979,68 +70111,128 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We also verify that the return type of the `[Symbol.hasInstance]` method is assignable to // `boolean`. According to the spec, the runtime will actually perform `ToBoolean` on the result, // but this is more type-safe. - checkTypeAssignableTo(returnType, booleanType, right, Diagnostics.An_object_s_Symbol_hasInstance_method_must_return_a_boolean_value_for_it_to_be_used_on_the_right_hand_side_of_an_instanceof_expression); + checkTypeAssignableTo( + returnType, + booleanType, + right, + Diagnostics.An_object_s_Symbol_hasInstance_method_must_return_a_boolean_value_for_it_to_be_used_on_the_right_hand_side_of_an_instanceof_expression + ); return booleanType; } function hasEmptyObjectIntersection(type: Type): boolean { - return someType(type, t => t === unknownEmptyObjectType || !!(t.flags & TypeFlags.Intersection) && isEmptyAnonymousObjectType(getBaseConstraintOrType(t))); + return someType( + type, + (t) => + t === unknownEmptyObjectType || + (!!(t.flags & TypeFlags.Intersection) && + isEmptyAnonymousObjectType(getBaseConstraintOrType(t))) + ); } - function checkInExpression(left: Expression, right: Expression, leftType: Type, rightType: Type): Type { + function checkInExpression( + left: Expression, + right: Expression, + leftType: Type, + rightType: Type + ): Type { if (leftType === silentNeverType || rightType === silentNeverType) { return silentNeverType; } if (isPrivateIdentifier(left)) { if ( - languageVersion < LanguageFeatureMinimumTarget.PrivateNamesAndClassStaticBlocks || - languageVersion < LanguageFeatureMinimumTarget.ClassAndClassElementDecorators || + languageVersion < + LanguageFeatureMinimumTarget.PrivateNamesAndClassStaticBlocks || + languageVersion < + LanguageFeatureMinimumTarget.ClassAndClassElementDecorators || !useDefineForClassFields ) { - checkExternalEmitHelpers(left, ExternalEmitHelpers.ClassPrivateFieldIn); + checkExternalEmitHelpers( + left, + ExternalEmitHelpers.ClassPrivateFieldIn + ); } // Unlike in 'checkPrivateIdentifierExpression' we now have access to the RHS type // which provides us with the opportunity to emit more detailed errors - if (!getNodeLinks(left).resolvedSymbol && getContainingClass(left)) { - const isUncheckedJS = isUncheckedJSSuggestion(left, rightType.symbol, /*excludeClasses*/ true); + if ( + !getNodeLinks(left).resolvedSymbol && + getContainingClass(left) + ) { + const isUncheckedJS = isUncheckedJSSuggestion( + left, + rightType.symbol, + /*excludeClasses*/ true + ); reportNonexistentProperty(left, rightType, isUncheckedJS); } - } - else { + } else { // The type of the lef operand must be assignable to string, number, or symbol. - checkTypeAssignableTo(checkNonNullType(leftType, left), stringNumberSymbolType, left); + checkTypeAssignableTo( + checkNonNullType(leftType, left), + stringNumberSymbolType, + left + ); } // The type of the right operand must be assignable to 'object'. - if (checkTypeAssignableTo(checkNonNullType(rightType, right), nonPrimitiveType, right)) { + if ( + checkTypeAssignableTo( + checkNonNullType(rightType, right), + nonPrimitiveType, + right + ) + ) { // The {} type is assignable to the object type, yet {} might represent a primitive type. Here we // detect and error on {} that results from narrowing the unknown type, as well as intersections // that include {} (we know that the other types in such intersections are assignable to object // since we already checked for that). if (hasEmptyObjectIntersection(rightType)) { - error(right, Diagnostics.Type_0_may_represent_a_primitive_value_which_is_not_permitted_as_the_right_operand_of_the_in_operator, typeToString(rightType)); + error( + right, + Diagnostics.Type_0_may_represent_a_primitive_value_which_is_not_permitted_as_the_right_operand_of_the_in_operator, + typeToString(rightType) + ); } } // The result is always of the Boolean primitive type. return booleanType; } - function checkObjectLiteralAssignment(node: ObjectLiteralExpression, sourceType: Type, rightIsThis?: boolean): Type { + function checkObjectLiteralAssignment( + node: ObjectLiteralExpression, + sourceType: Type, + rightIsThis?: boolean + ): Type { const properties = node.properties; if (strictNullChecks && properties.length === 0) { return checkNonNullType(sourceType, node); } for (let i = 0; i < properties.length; i++) { - checkObjectLiteralDestructuringPropertyAssignment(node, sourceType, i, properties, rightIsThis); + checkObjectLiteralDestructuringPropertyAssignment( + node, + sourceType, + i, + properties, + rightIsThis + ); } return sourceType; } /** Note: If property cannot be a SpreadAssignment, then allProperties does not need to be provided */ - function checkObjectLiteralDestructuringPropertyAssignment(node: ObjectLiteralExpression, objectLiteralType: Type, propertyIndex: number, allProperties?: NodeArray, rightIsThis = false) { + function checkObjectLiteralDestructuringPropertyAssignment( + node: ObjectLiteralExpression, + objectLiteralType: Type, + propertyIndex: number, + allProperties?: NodeArray, + rightIsThis = false + ) { const properties = node.properties; const property = properties[propertyIndex]; - if (property.kind === SyntaxKind.PropertyAssignment || property.kind === SyntaxKind.ShorthandPropertyAssignment) { + if ( + property.kind === SyntaxKind.PropertyAssignment || + property.kind === SyntaxKind.ShorthandPropertyAssignment + ) { const name = property.name; const exprType = getLiteralTypeFromPropertyName(name); if (isTypeUsableAsPropertyName(exprType)) { @@ -40048,20 +70240,44 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const prop = getPropertyOfType(objectLiteralType, text); if (prop) { markPropertyAsReferenced(prop, property, rightIsThis); - checkPropertyAccessibility(property, /*isSuper*/ false, /*writing*/ true, objectLiteralType, prop); + checkPropertyAccessibility( + property, + /*isSuper*/ false, + /*writing*/ true, + objectLiteralType, + prop + ); } } - const elementType = getIndexedAccessType(objectLiteralType, exprType, AccessFlags.ExpressionPosition | (hasDefaultValue(property) ? AccessFlags.AllowMissing : 0), name); + const elementType = getIndexedAccessType( + objectLiteralType, + exprType, + AccessFlags.ExpressionPosition | + (hasDefaultValue(property) ? AccessFlags.AllowMissing : 0), + name + ); const type = getFlowTypeOfDestructuring(property, elementType); - return checkDestructuringAssignment(property.kind === SyntaxKind.ShorthandPropertyAssignment ? property : property.initializer, type); - } - else if (property.kind === SyntaxKind.SpreadAssignment) { + return checkDestructuringAssignment( + property.kind === SyntaxKind.ShorthandPropertyAssignment + ? property + : property.initializer, + type + ); + } else if (property.kind === SyntaxKind.SpreadAssignment) { if (propertyIndex < properties.length - 1) { - error(property, Diagnostics.A_rest_element_must_be_last_in_a_destructuring_pattern); - } - else { - if (languageVersion < LanguageFeatureMinimumTarget.ObjectSpreadRest) { - checkExternalEmitHelpers(property, ExternalEmitHelpers.Rest); + error( + property, + Diagnostics.A_rest_element_must_be_last_in_a_destructuring_pattern + ); + } else { + if ( + languageVersion < + LanguageFeatureMinimumTarget.ObjectSpreadRest + ) { + checkExternalEmitHelpers( + property, + ExternalEmitHelpers.Rest + ); } const nonRestNames: PropertyName[] = []; if (allProperties) { @@ -40071,37 +70287,80 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } } - const type = getRestType(objectLiteralType, nonRestNames, objectLiteralType.symbol); - checkGrammarForDisallowedTrailingComma(allProperties, Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma); + const type = getRestType( + objectLiteralType, + nonRestNames, + objectLiteralType.symbol + ); + checkGrammarForDisallowedTrailingComma( + allProperties, + Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma + ); return checkDestructuringAssignment(property.expression, type); } - } - else { + } else { error(property, Diagnostics.Property_assignment_expected); } } - function checkArrayLiteralAssignment(node: ArrayLiteralExpression, sourceType: Type, checkMode?: CheckMode): Type { + function checkArrayLiteralAssignment( + node: ArrayLiteralExpression, + sourceType: Type, + checkMode?: CheckMode + ): Type { const elements = node.elements; - if (languageVersion < LanguageFeatureMinimumTarget.DestructuringAssignment && compilerOptions.downlevelIteration) { + if ( + languageVersion < + LanguageFeatureMinimumTarget.DestructuringAssignment && + compilerOptions.downlevelIteration + ) { checkExternalEmitHelpers(node, ExternalEmitHelpers.Read); } // This elementType will be used if the specific property corresponding to this index is not // present (aka the tuple element property). This call also checks that the parentType is in // fact an iterable or array (depending on target language). - const possiblyOutOfBoundsType = checkIteratedTypeOrElementType(IterationUse.Destructuring | IterationUse.PossiblyOutOfBounds, sourceType, undefinedType, node) || errorType; - let inBoundsType: Type | undefined = compilerOptions.noUncheckedIndexedAccess ? undefined : possiblyOutOfBoundsType; + const possiblyOutOfBoundsType = + checkIteratedTypeOrElementType( + IterationUse.Destructuring | IterationUse.PossiblyOutOfBounds, + sourceType, + undefinedType, + node + ) || errorType; + let inBoundsType: Type | undefined = + compilerOptions.noUncheckedIndexedAccess + ? undefined + : possiblyOutOfBoundsType; for (let i = 0; i < elements.length; i++) { let type = possiblyOutOfBoundsType; if (node.elements[i].kind === SyntaxKind.SpreadElement) { - type = inBoundsType = inBoundsType ?? (checkIteratedTypeOrElementType(IterationUse.Destructuring, sourceType, undefinedType, node) || errorType); - } - checkArrayLiteralDestructuringElementAssignment(node, sourceType, i, type, checkMode); + type = inBoundsType = + inBoundsType ?? + (checkIteratedTypeOrElementType( + IterationUse.Destructuring, + sourceType, + undefinedType, + node + ) || + errorType); + } + checkArrayLiteralDestructuringElementAssignment( + node, + sourceType, + i, + type, + checkMode + ); } return sourceType; } - function checkArrayLiteralDestructuringElementAssignment(node: ArrayLiteralExpression, sourceType: Type, elementIndex: number, elementType: Type, checkMode?: CheckMode) { + function checkArrayLiteralDestructuringElementAssignment( + node: ArrayLiteralExpression, + sourceType: Type, + elementIndex: number, + elementType: Type, + checkMode?: CheckMode + ) { const elements = node.elements; const element = elements[elementIndex]; if (element.kind !== SyntaxKind.OmittedExpression) { @@ -40110,35 +70369,83 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isArrayLikeType(sourceType)) { // We create a synthetic expression so that getIndexedAccessType doesn't get confused // when the element is a SyntaxKind.ElementAccessExpression. - const accessFlags = AccessFlags.ExpressionPosition | (hasDefaultValue(element) ? AccessFlags.AllowMissing : 0); - const elementType = getIndexedAccessTypeOrUndefined(sourceType, indexType, accessFlags, createSyntheticExpression(element, indexType)) || errorType; - const assignedType = hasDefaultValue(element) ? getTypeWithFacts(elementType, TypeFacts.NEUndefined) : elementType; - const type = getFlowTypeOfDestructuring(element, assignedType); - return checkDestructuringAssignment(element, type, checkMode); + const accessFlags = + AccessFlags.ExpressionPosition | + (hasDefaultValue(element) + ? AccessFlags.AllowMissing + : 0); + const elementType = + getIndexedAccessTypeOrUndefined( + sourceType, + indexType, + accessFlags, + createSyntheticExpression(element, indexType) + ) || errorType; + const assignedType = hasDefaultValue(element) + ? getTypeWithFacts(elementType, TypeFacts.NEUndefined) + : elementType; + const type = getFlowTypeOfDestructuring( + element, + assignedType + ); + return checkDestructuringAssignment( + element, + type, + checkMode + ); } - return checkDestructuringAssignment(element, elementType, checkMode); + return checkDestructuringAssignment( + element, + elementType, + checkMode + ); } if (elementIndex < elements.length - 1) { - error(element, Diagnostics.A_rest_element_must_be_last_in_a_destructuring_pattern); - } - else { + error( + element, + Diagnostics.A_rest_element_must_be_last_in_a_destructuring_pattern + ); + } else { const restExpression = (element as SpreadElement).expression; - if (restExpression.kind === SyntaxKind.BinaryExpression && (restExpression as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken) { - error((restExpression as BinaryExpression).operatorToken, Diagnostics.A_rest_element_cannot_have_an_initializer); - } - else { - checkGrammarForDisallowedTrailingComma(node.elements, Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma); - const type = everyType(sourceType, isTupleType) ? - mapType(sourceType, t => sliceTupleType(t as TupleTypeReference, elementIndex)) : - createArrayType(elementType); - return checkDestructuringAssignment(restExpression, type, checkMode); + if ( + restExpression.kind === SyntaxKind.BinaryExpression && + (restExpression as BinaryExpression).operatorToken.kind === + SyntaxKind.EqualsToken + ) { + error( + (restExpression as BinaryExpression).operatorToken, + Diagnostics.A_rest_element_cannot_have_an_initializer + ); + } else { + checkGrammarForDisallowedTrailingComma( + node.elements, + Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma + ); + const type = everyType(sourceType, isTupleType) + ? mapType(sourceType, (t) => + sliceTupleType( + t as TupleTypeReference, + elementIndex + ) + ) + : createArrayType(elementType); + return checkDestructuringAssignment( + restExpression, + type, + checkMode + ); } } } return undefined; } - function checkDestructuringAssignment(exprOrAssignment: Expression | ShorthandPropertyAssignment, sourceType: Type, checkMode?: CheckMode, rightIsThis?: boolean): Type { + function checkDestructuringAssignment( + exprOrAssignment: Expression | ShorthandPropertyAssignment, + sourceType: Type, + checkMode?: CheckMode, + rightIsThis?: boolean + ): Type { let target: Expression; if (exprOrAssignment.kind === SyntaxKind.ShorthandPropertyAssignment) { const prop = exprOrAssignment as ShorthandPropertyAssignment; @@ -40147,49 +70454,88 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // undefined from the final type. if ( strictNullChecks && - !(hasTypeFacts(checkExpression(prop.objectAssignmentInitializer), TypeFacts.IsUndefined)) + !hasTypeFacts( + checkExpression(prop.objectAssignmentInitializer), + TypeFacts.IsUndefined + ) ) { - sourceType = getTypeWithFacts(sourceType, TypeFacts.NEUndefined); + sourceType = getTypeWithFacts( + sourceType, + TypeFacts.NEUndefined + ); } - checkBinaryLikeExpression(prop.name, prop.equalsToken!, prop.objectAssignmentInitializer, checkMode); + checkBinaryLikeExpression( + prop.name, + prop.equalsToken!, + prop.objectAssignmentInitializer, + checkMode + ); } target = (exprOrAssignment as ShorthandPropertyAssignment).name; - } - else { + } else { target = exprOrAssignment; } - if (target.kind === SyntaxKind.BinaryExpression && (target as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken) { + if ( + target.kind === SyntaxKind.BinaryExpression && + (target as BinaryExpression).operatorToken.kind === + SyntaxKind.EqualsToken + ) { checkBinaryExpression(target as BinaryExpression, checkMode); target = (target as BinaryExpression).left; // A default value is specified, so remove undefined from the final type. if (strictNullChecks) { - sourceType = getTypeWithFacts(sourceType, TypeFacts.NEUndefined); + sourceType = getTypeWithFacts( + sourceType, + TypeFacts.NEUndefined + ); } } if (target.kind === SyntaxKind.ObjectLiteralExpression) { - return checkObjectLiteralAssignment(target as ObjectLiteralExpression, sourceType, rightIsThis); + return checkObjectLiteralAssignment( + target as ObjectLiteralExpression, + sourceType, + rightIsThis + ); } if (target.kind === SyntaxKind.ArrayLiteralExpression) { - return checkArrayLiteralAssignment(target as ArrayLiteralExpression, sourceType, checkMode); + return checkArrayLiteralAssignment( + target as ArrayLiteralExpression, + sourceType, + checkMode + ); } return checkReferenceAssignment(target, sourceType, checkMode); } - function checkReferenceAssignment(target: Expression, sourceType: Type, checkMode?: CheckMode): Type { + function checkReferenceAssignment( + target: Expression, + sourceType: Type, + checkMode?: CheckMode + ): Type { const targetType = checkExpression(target, checkMode); - const error = target.parent.kind === SyntaxKind.SpreadAssignment ? - Diagnostics.The_target_of_an_object_rest_assignment_must_be_a_variable_or_a_property_access : - Diagnostics.The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access; - const optionalError = target.parent.kind === SyntaxKind.SpreadAssignment ? - Diagnostics.The_target_of_an_object_rest_assignment_may_not_be_an_optional_property_access : - Diagnostics.The_left_hand_side_of_an_assignment_expression_may_not_be_an_optional_property_access; + const error = + target.parent.kind === SyntaxKind.SpreadAssignment + ? Diagnostics.The_target_of_an_object_rest_assignment_must_be_a_variable_or_a_property_access + : Diagnostics.The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access; + const optionalError = + target.parent.kind === SyntaxKind.SpreadAssignment + ? Diagnostics.The_target_of_an_object_rest_assignment_may_not_be_an_optional_property_access + : Diagnostics.The_left_hand_side_of_an_assignment_expression_may_not_be_an_optional_property_access; if (checkReferenceExpression(target, error, optionalError)) { - checkTypeAssignableToAndOptionallyElaborate(sourceType, targetType, target, target); + checkTypeAssignableToAndOptionallyElaborate( + sourceType, + targetType, + target, + target + ); } if (isPrivateIdentifierPropertyAccessExpression(target)) { // NOTE: we do not limit this to LanguageFeatureTargets.PrivateNames as some other feature downleveling still requires this. - checkExternalEmitHelpers(target.parent, ExternalEmitHelpers.ClassPrivateFieldSet); + checkExternalEmitHelpers( + target.parent, + ExternalEmitHelpers.ClassPrivateFieldSet + ); } return sourceType; } @@ -40229,15 +70575,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; case SyntaxKind.ConditionalExpression: - return isSideEffectFree((node as ConditionalExpression).whenTrue) && - isSideEffectFree((node as ConditionalExpression).whenFalse); + return ( + isSideEffectFree( + (node as ConditionalExpression).whenTrue + ) && + isSideEffectFree((node as ConditionalExpression).whenFalse) + ); case SyntaxKind.BinaryExpression: - if (isAssignmentOperator((node as BinaryExpression).operatorToken.kind)) { + if ( + isAssignmentOperator( + (node as BinaryExpression).operatorToken.kind + ) + ) { return false; } - return isSideEffectFree((node as BinaryExpression).left) && - isSideEffectFree((node as BinaryExpression).right); + return ( + isSideEffectFree((node as BinaryExpression).left) && + isSideEffectFree((node as BinaryExpression).right) + ); case SyntaxKind.PrefixUnaryExpression: case SyntaxKind.PostfixUnaryExpression: @@ -40262,7 +70618,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isTypeEqualityComparableTo(source: Type, target: Type) { - return (target.flags & TypeFlags.Nullable) !== 0 || isTypeComparableTo(source, target); + return ( + (target.flags & TypeFlags.Nullable) !== 0 || + isTypeComparableTo(source, target) + ); } function createCheckBinaryExpression() { @@ -40278,7 +70637,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { typeStack: (Type | undefined)[]; } - const trampoline = createBinaryExpressionTrampoline(onEnter, onLeft, onOperator, onRight, onExit, foldState); + const trampoline = createBinaryExpressionTrampoline( + onEnter, + onLeft, + onOperator, + onRight, + onExit, + foldState + ); return (node: BinaryExpression, checkMode: CheckMode | undefined) => { const result = trampoline(node, checkMode); @@ -40286,14 +70652,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; }; - function onEnter(node: BinaryExpression, state: WorkArea | undefined, checkMode: CheckMode | undefined) { + function onEnter( + node: BinaryExpression, + state: WorkArea | undefined, + checkMode: CheckMode | undefined + ) { if (state) { state.stackIndex++; state.skip = false; setLeftType(state, /*type*/ undefined); setLastResult(state, /*type*/ undefined); - } - else { + } else { state = { checkMode, skip: false, @@ -40311,22 +70680,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkNullishCoalesceOperands(node); const operator = node.operatorToken.kind; - if (operator === SyntaxKind.EqualsToken && (node.left.kind === SyntaxKind.ObjectLiteralExpression || node.left.kind === SyntaxKind.ArrayLiteralExpression)) { + if ( + operator === SyntaxKind.EqualsToken && + (node.left.kind === SyntaxKind.ObjectLiteralExpression || + node.left.kind === SyntaxKind.ArrayLiteralExpression) + ) { state.skip = true; - setLastResult(state, checkDestructuringAssignment(node.left, checkExpression(node.right, checkMode), checkMode, node.right.kind === SyntaxKind.ThisKeyword)); + setLastResult( + state, + checkDestructuringAssignment( + node.left, + checkExpression(node.right, checkMode), + checkMode, + node.right.kind === SyntaxKind.ThisKeyword + ) + ); return state; } return state; } - function onLeft(left: Expression, state: WorkArea, _node: BinaryExpression) { + function onLeft( + left: Expression, + state: WorkArea, + _node: BinaryExpression + ) { if (!state.skip) { return maybeCheckExpression(state, left); } } - function onOperator(operatorToken: BinaryOperatorToken, state: WorkArea, node: BinaryExpression) { + function onOperator( + operatorToken: BinaryOperatorToken, + state: WorkArea, + node: BinaryExpression + ) { if (!state.skip) { const leftType = getLastResult(state); Debug.assertIsDefined(leftType); @@ -40335,11 +70724,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const operator = operatorToken.kind; if (isLogicalOrCoalescingBinaryOperator(operator)) { let parent = node.parent; - while (parent.kind === SyntaxKind.ParenthesizedExpression || isLogicalOrCoalescingBinaryExpression(parent)) { + while ( + parent.kind === SyntaxKind.ParenthesizedExpression || + isLogicalOrCoalescingBinaryExpression(parent) + ) { parent = parent.parent; } - if (operator === SyntaxKind.AmpersandAmpersandToken || isIfStatement(parent)) { - checkTestingKnownTruthyCallableOrAwaitableOrEnumMemberType(node.left, leftType, isIfStatement(parent) ? parent.thenStatement : undefined); + if ( + operator === SyntaxKind.AmpersandAmpersandToken || + isIfStatement(parent) + ) { + checkTestingKnownTruthyCallableOrAwaitableOrEnumMemberType( + node.left, + leftType, + isIfStatement(parent) + ? parent.thenStatement + : undefined + ); } if (isBinaryLogicalOperator(operator)) { checkTruthinessOfType(leftType, node.left); @@ -40348,25 +70749,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function onRight(right: Expression, state: WorkArea, _node: BinaryExpression) { + function onRight( + right: Expression, + state: WorkArea, + _node: BinaryExpression + ) { if (!state.skip) { return maybeCheckExpression(state, right); } } - function onExit(node: BinaryExpression, state: WorkArea): Type | undefined { + function onExit( + node: BinaryExpression, + state: WorkArea + ): Type | undefined { let result: Type | undefined; if (state.skip) { result = getLastResult(state); - } - else { + } else { const leftType = getLeftType(state); Debug.assertIsDefined(leftType); const rightType = getLastResult(state); Debug.assertIsDefined(rightType); - result = checkBinaryLikeExpressionWorker(node.left, node.operatorToken, node.right, leftType, rightType, state.checkMode, node); + result = checkBinaryLikeExpressionWorker( + node.left, + node.operatorToken, + node.right, + leftType, + rightType, + state.checkMode, + node + ); } state.skip = false; @@ -40376,12 +70791,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function foldState(state: WorkArea, result: Type | undefined, _side: "left" | "right") { + function foldState( + state: WorkArea, + result: Type | undefined, + _side: "left" | "right" + ) { setLastResult(state, result); return state; } - function maybeCheckExpression(state: WorkArea, node: Expression): BinaryExpression | undefined { + function maybeCheckExpression( + state: WorkArea, + node: Expression + ): BinaryExpression | undefined { if (isBinaryExpression(node)) { return node; } @@ -40412,11 +70834,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkNullishCoalesceOperands(node: BinaryExpression) { const { left, operatorToken, right } = node; if (operatorToken.kind === SyntaxKind.QuestionQuestionToken) { - if (isBinaryExpression(left) && (left.operatorToken.kind === SyntaxKind.BarBarToken || left.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken)) { - grammarErrorOnNode(left, Diagnostics._0_and_1_operations_cannot_be_mixed_without_parentheses, tokenToString(left.operatorToken.kind), tokenToString(operatorToken.kind)); + if ( + isBinaryExpression(left) && + (left.operatorToken.kind === SyntaxKind.BarBarToken || + left.operatorToken.kind === + SyntaxKind.AmpersandAmpersandToken) + ) { + grammarErrorOnNode( + left, + Diagnostics._0_and_1_operations_cannot_be_mixed_without_parentheses, + tokenToString(left.operatorToken.kind), + tokenToString(operatorToken.kind) + ); } - if (isBinaryExpression(right) && (right.operatorToken.kind === SyntaxKind.BarBarToken || right.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken)) { - grammarErrorOnNode(right, Diagnostics._0_and_1_operations_cannot_be_mixed_without_parentheses, tokenToString(right.operatorToken.kind), tokenToString(operatorToken.kind)); + if ( + isBinaryExpression(right) && + (right.operatorToken.kind === SyntaxKind.BarBarToken || + right.operatorToken.kind === + SyntaxKind.AmpersandAmpersandToken) + ) { + grammarErrorOnNode( + right, + Diagnostics._0_and_1_operations_cannot_be_mixed_without_parentheses, + tokenToString(right.operatorToken.kind), + tokenToString(operatorToken.kind) + ); } checkNullishCoalesceOperandLeft(node); @@ -40425,21 +70867,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkNullishCoalesceOperandLeft(node: BinaryExpression) { - const leftTarget = skipOuterExpressions(node.left, OuterExpressionKinds.All); + const leftTarget = skipOuterExpressions( + node.left, + OuterExpressionKinds.All + ); const nullishSemantics = getSyntacticNullishnessSemantics(leftTarget); if (nullishSemantics !== PredicateSemantics.Sometimes) { if (nullishSemantics === PredicateSemantics.Always) { - error(leftTarget, Diagnostics.This_expression_is_always_nullish); - } - else { - error(leftTarget, Diagnostics.Right_operand_of_is_unreachable_because_the_left_operand_is_never_nullish); + error( + leftTarget, + Diagnostics.This_expression_is_always_nullish + ); + } else { + error( + leftTarget, + Diagnostics.Right_operand_of_is_unreachable_because_the_left_operand_is_never_nullish + ); } } } function checkNullishCoalesceOperandRight(node: BinaryExpression) { - const rightTarget = skipOuterExpressions(node.right, OuterExpressionKinds.All); + const rightTarget = skipOuterExpressions( + node.right, + OuterExpressionKinds.All + ); const nullishSemantics = getSyntacticNullishnessSemantics(rightTarget); if (isNotWithinNullishCoalesceExpression(node)) { return; @@ -40447,14 +70900,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (nullishSemantics === PredicateSemantics.Always) { error(rightTarget, Diagnostics.This_expression_is_always_nullish); - } - else if (nullishSemantics === PredicateSemantics.Never) { + } else if (nullishSemantics === PredicateSemantics.Never) { error(rightTarget, Diagnostics.This_expression_is_never_nullish); } } function isNotWithinNullishCoalesceExpression(node: BinaryExpression) { - return !isBinaryExpression(node.parent) || node.parent.operatorToken.kind !== SyntaxKind.QuestionQuestionToken; + return ( + !isBinaryExpression(node.parent) || + node.parent.operatorToken.kind !== SyntaxKind.QuestionQuestionToken + ); } function getSyntacticNullishnessSemantics(node: Node): PredicateSemantics { @@ -40483,11 +70938,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.AmpersandAmpersandEqualsToken: return PredicateSemantics.Sometimes; case SyntaxKind.CommaToken: - return getSyntacticNullishnessSemantics((node as BinaryExpression).right); + return getSyntacticNullishnessSemantics( + (node as BinaryExpression).right + ); } return PredicateSemantics.Never; case SyntaxKind.ConditionalExpression: - return getSyntacticNullishnessSemantics((node as ConditionalExpression).whenTrue) | getSyntacticNullishnessSemantics((node as ConditionalExpression).whenFalse); + return ( + getSyntacticNullishnessSemantics( + (node as ConditionalExpression).whenTrue + ) | + getSyntacticNullishnessSemantics( + (node as ConditionalExpression).whenFalse + ) + ); case SyntaxKind.NullKeyword: return PredicateSemantics.Always; case SyntaxKind.Identifier: @@ -40501,21 +70965,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Note that this and `checkBinaryExpression` above should behave mostly the same, except this elides some // expression-wide checks and does not use a work stack to fold nested binary expressions into the same callstack frame - function checkBinaryLikeExpression(left: Expression, operatorToken: BinaryOperatorToken, right: Expression, checkMode?: CheckMode, errorNode?: Node): Type { + function checkBinaryLikeExpression( + left: Expression, + operatorToken: BinaryOperatorToken, + right: Expression, + checkMode?: CheckMode, + errorNode?: Node + ): Type { const operator = operatorToken.kind; - if (operator === SyntaxKind.EqualsToken && (left.kind === SyntaxKind.ObjectLiteralExpression || left.kind === SyntaxKind.ArrayLiteralExpression)) { - return checkDestructuringAssignment(left, checkExpression(right, checkMode), checkMode, right.kind === SyntaxKind.ThisKeyword); + if ( + operator === SyntaxKind.EqualsToken && + (left.kind === SyntaxKind.ObjectLiteralExpression || + left.kind === SyntaxKind.ArrayLiteralExpression) + ) { + return checkDestructuringAssignment( + left, + checkExpression(right, checkMode), + checkMode, + right.kind === SyntaxKind.ThisKeyword + ); } let leftType: Type; if (isBinaryLogicalOperator(operator)) { leftType = checkTruthinessExpression(left, checkMode); - } - else { + } else { leftType = checkExpression(left, checkMode); } const rightType = checkExpression(right, checkMode); - return checkBinaryLikeExpressionWorker(left, operatorToken, right, leftType, rightType, checkMode, errorNode); + return checkBinaryLikeExpressionWorker( + left, + operatorToken, + right, + leftType, + rightType, + checkMode, + errorNode + ); } function checkBinaryLikeExpressionWorker( @@ -40525,7 +71011,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { leftType: Type, rightType: Type, checkMode?: CheckMode, - errorNode?: Node, + errorNode?: Node ): Type { const operator = operatorToken.kind; switch (operator) { @@ -40551,7 +71037,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.CaretEqualsToken: case SyntaxKind.AmpersandToken: case SyntaxKind.AmpersandEqualsToken: - if (leftType === silentNeverType || rightType === silentNeverType) { + if ( + leftType === silentNeverType || + rightType === silentNeverType + ) { return silentNeverType; } @@ -40562,23 +71051,49 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // if a user tries to apply a bitwise operator to 2 boolean operands // try and return them a helpful suggestion if ( - (leftType.flags & TypeFlags.BooleanLike) && - (rightType.flags & TypeFlags.BooleanLike) && - (suggestedOperator = getSuggestedBooleanOperator(operatorToken.kind)) !== undefined + leftType.flags & TypeFlags.BooleanLike && + rightType.flags & TypeFlags.BooleanLike && + (suggestedOperator = getSuggestedBooleanOperator( + operatorToken.kind + )) !== undefined ) { - error(errorNode || operatorToken, Diagnostics.The_0_operator_is_not_allowed_for_boolean_types_Consider_using_1_instead, tokenToString(operatorToken.kind), tokenToString(suggestedOperator)); + error( + errorNode || operatorToken, + Diagnostics.The_0_operator_is_not_allowed_for_boolean_types_Consider_using_1_instead, + tokenToString(operatorToken.kind), + tokenToString(suggestedOperator) + ); return numberType; - } - else { + } else { // otherwise just check each operand separately and report errors as normal - 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); - 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); + 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 + ); + 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 + ); let resultType: Type; // If both are any or unknown, allow operation; assume it will resolve to number if ( - (isTypeAssignableToKind(leftType, TypeFlags.AnyOrUnknown) && isTypeAssignableToKind(rightType, TypeFlags.AnyOrUnknown)) || + (isTypeAssignableToKind( + leftType, + TypeFlags.AnyOrUnknown + ) && + isTypeAssignableToKind( + rightType, + TypeFlags.AnyOrUnknown + )) || // Or, if neither could be bigint, implicit coercion results in a number result - !(maybeTypeOfKind(leftType, TypeFlags.BigIntLike) || maybeTypeOfKind(rightType, TypeFlags.BigIntLike)) + !( + maybeTypeOfKind(leftType, TypeFlags.BigIntLike) || + maybeTypeOfKind(rightType, TypeFlags.BigIntLike) + ) ) { resultType = numberType; } @@ -40592,7 +71107,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.AsteriskAsteriskToken: case SyntaxKind.AsteriskAsteriskEqualsToken: if (languageVersion < ScriptTarget.ES2016) { - error(errorNode, Diagnostics.Exponentiation_cannot_be_performed_on_bigint_values_unless_the_target_option_is_set_to_es2016_or_later); + error( + errorNode, + Diagnostics.Exponentiation_cannot_be_performed_on_bigint_values_unless_the_target_option_is_set_to_es2016_or_later + ); } } resultType = bigintType; @@ -40612,14 +71130,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: const rhsEval = evaluate(right); - if (typeof rhsEval.value === "number" && Math.abs(rhsEval.value) >= 32) { + if ( + typeof rhsEval.value === "number" && + Math.abs(rhsEval.value) >= 32 + ) { errorOrSuggestion( - isEnumMember(walkUpParenthesizedExpressions(right.parent.parent)), // elevate from suggestion to error within an enum member + isEnumMember( + walkUpParenthesizedExpressions( + right.parent.parent + ) + ), // elevate from suggestion to error within an enum member errorNode || operatorToken, Diagnostics.This_operation_can_be_simplified_This_shift_is_identical_to_0_1_2, getTextOfNode(left), tokenToString(operator), - rhsEval.value % 32, + rhsEval.value % 32 ); } break; @@ -40631,37 +71156,79 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } case SyntaxKind.PlusToken: case SyntaxKind.PlusEqualsToken: - if (leftType === silentNeverType || rightType === silentNeverType) { + if ( + leftType === silentNeverType || + rightType === silentNeverType + ) { return silentNeverType; } - if (!isTypeAssignableToKind(leftType, TypeFlags.StringLike) && !isTypeAssignableToKind(rightType, TypeFlags.StringLike)) { + if ( + !isTypeAssignableToKind(leftType, TypeFlags.StringLike) && + !isTypeAssignableToKind(rightType, TypeFlags.StringLike) + ) { leftType = checkNonNullType(leftType, left); rightType = checkNonNullType(rightType, right); } let resultType: Type | undefined; - if (isTypeAssignableToKind(leftType, TypeFlags.NumberLike, /*strict*/ true) && isTypeAssignableToKind(rightType, TypeFlags.NumberLike, /*strict*/ true)) { + if ( + isTypeAssignableToKind( + leftType, + TypeFlags.NumberLike, + /*strict*/ true + ) && + isTypeAssignableToKind( + rightType, + TypeFlags.NumberLike, + /*strict*/ true + ) + ) { // Operands of an enum type are treated as having the primitive type Number. // If both operands are of the Number primitive type, the result is of the Number primitive type. resultType = numberType; - } - else if (isTypeAssignableToKind(leftType, TypeFlags.BigIntLike, /*strict*/ true) && isTypeAssignableToKind(rightType, TypeFlags.BigIntLike, /*strict*/ true)) { + } else if ( + isTypeAssignableToKind( + leftType, + TypeFlags.BigIntLike, + /*strict*/ true + ) && + isTypeAssignableToKind( + rightType, + TypeFlags.BigIntLike, + /*strict*/ true + ) + ) { // If both operands are of the BigInt primitive type, the result is of the BigInt primitive type. resultType = bigintType; - } - else if (isTypeAssignableToKind(leftType, TypeFlags.StringLike, /*strict*/ true) || isTypeAssignableToKind(rightType, TypeFlags.StringLike, /*strict*/ true)) { + } else if ( + isTypeAssignableToKind( + leftType, + TypeFlags.StringLike, + /*strict*/ true + ) || + isTypeAssignableToKind( + rightType, + TypeFlags.StringLike, + /*strict*/ true + ) + ) { // If one or both operands are of the String primitive type, the result is of the String primitive type. resultType = stringType; - } - else if (isTypeAny(leftType) || isTypeAny(rightType)) { + } else if (isTypeAny(leftType) || isTypeAny(rightType)) { // Otherwise, the result is of type Any. // NOTE: unknown type here denotes error type. Old compiler treated this case as any type so do we. - resultType = isErrorType(leftType) || isErrorType(rightType) ? errorType : anyType; + resultType = + isErrorType(leftType) || isErrorType(rightType) + ? errorType + : anyType; } // Symbols are not allowed at all in arithmetic expressions - if (resultType && !checkForDisallowedESSymbolOperand(operator)) { + if ( + resultType && + !checkForDisallowedESSymbolOperand(operator) + ) { return resultType; } @@ -40670,10 +71237,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If both types have an awaited type of one of these, we'll assume the user // might be missing an await without doing an exhaustive check that inserting // await(s) will actually be a completely valid binary expression. - const closeEnoughKind = TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.AnyOrUnknown; - reportOperatorError((left, right) => - isTypeAssignableToKind(left, closeEnoughKind) && - isTypeAssignableToKind(right, closeEnoughKind) + const closeEnoughKind = + TypeFlags.NumberLike | + TypeFlags.BigIntLike | + TypeFlags.StringLike | + TypeFlags.AnyOrUnknown; + reportOperatorError( + (left, right) => + isTypeAssignableToKind(left, closeEnoughKind) && + isTypeAssignableToKind(right, closeEnoughKind) ); return anyType; } @@ -40687,16 +71259,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.LessThanEqualsToken: case SyntaxKind.GreaterThanEqualsToken: if (checkForDisallowedESSymbolOperand(operator)) { - leftType = getBaseTypeOfLiteralTypeForComparison(checkNonNullType(leftType, left)); - rightType = getBaseTypeOfLiteralTypeForComparison(checkNonNullType(rightType, right)); + leftType = getBaseTypeOfLiteralTypeForComparison( + checkNonNullType(leftType, left) + ); + rightType = getBaseTypeOfLiteralTypeForComparison( + checkNonNullType(rightType, right) + ); reportOperatorErrorUnless((left, right) => { if (isTypeAny(left) || isTypeAny(right)) { return true; } - const leftAssignableToNumber = isTypeAssignableTo(left, numberOrBigIntType); - const rightAssignableToNumber = isTypeAssignableTo(right, numberOrBigIntType); - return leftAssignableToNumber && rightAssignableToNumber || - !leftAssignableToNumber && !rightAssignableToNumber && areTypesComparable(left, right); + const leftAssignableToNumber = isTypeAssignableTo( + left, + numberOrBigIntType + ); + const rightAssignableToNumber = isTypeAssignableTo( + right, + numberOrBigIntType + ); + return ( + (leftAssignableToNumber && + rightAssignableToNumber) || + (!leftAssignableToNumber && + !rightAssignableToNumber && + areTypesComparable(left, right)) + ); }); } return booleanType; @@ -40709,26 +71296,53 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // types may cause the operands to not be comparable. We don't want such errors reported (see #46475). if (!(checkMode && checkMode & CheckMode.TypeOnly)) { if ( - (isLiteralExpressionOfObject(left) || isLiteralExpressionOfObject(right)) && + (isLiteralExpressionOfObject(left) || + isLiteralExpressionOfObject(right)) && // only report for === and !== in JS, not == or != - (!isInJSFile(left) || (operator === SyntaxKind.EqualsEqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken)) + (!isInJSFile(left) || + operator === SyntaxKind.EqualsEqualsEqualsToken || + operator === + SyntaxKind.ExclamationEqualsEqualsToken) ) { - const eqType = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.EqualsEqualsEqualsToken; - error(errorNode, Diagnostics.This_condition_will_always_return_0_since_JavaScript_compares_objects_by_reference_not_value, eqType ? "false" : "true"); + const eqType = + operator === SyntaxKind.EqualsEqualsToken || + operator === SyntaxKind.EqualsEqualsEqualsToken; + error( + errorNode, + Diagnostics.This_condition_will_always_return_0_since_JavaScript_compares_objects_by_reference_not_value, + eqType ? "false" : "true" + ); } checkNaNEquality(errorNode, operator, left, right); - reportOperatorErrorUnless((left, right) => isTypeEqualityComparableTo(left, right) || isTypeEqualityComparableTo(right, left)); + reportOperatorErrorUnless( + (left, right) => + isTypeEqualityComparableTo(left, right) || + isTypeEqualityComparableTo(right, left) + ); } return booleanType; case SyntaxKind.InstanceOfKeyword: - return checkInstanceOfExpression(left, right, leftType, rightType, checkMode); + return checkInstanceOfExpression( + left, + right, + leftType, + rightType, + checkMode + ); case SyntaxKind.InKeyword: return checkInExpression(left, right, leftType, rightType); case SyntaxKind.AmpersandAmpersandToken: case SyntaxKind.AmpersandAmpersandEqualsToken: { - const resultType = hasTypeFacts(leftType, TypeFacts.Truthy) ? - getUnionType([extractDefinitelyFalsyTypes(strictNullChecks ? leftType : getBaseTypeOfLiteralType(rightType)), rightType]) : - leftType; + const resultType = hasTypeFacts(leftType, TypeFacts.Truthy) + ? getUnionType([ + extractDefinitelyFalsyTypes( + strictNullChecks + ? leftType + : getBaseTypeOfLiteralType(rightType) + ), + rightType, + ]) + : leftType; if (operator === SyntaxKind.AmpersandAmpersandEqualsToken) { checkAssignmentOperator(rightType); } @@ -40736,9 +71350,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } case SyntaxKind.BarBarToken: case SyntaxKind.BarBarEqualsToken: { - const resultType = hasTypeFacts(leftType, TypeFacts.Falsy) ? - getUnionType([getNonNullableType(removeDefinitelyFalsyTypes(leftType)), rightType], UnionReduction.Subtype) : - leftType; + const resultType = hasTypeFacts(leftType, TypeFacts.Falsy) + ? getUnionType( + [ + getNonNullableType( + removeDefinitelyFalsyTypes(leftType) + ), + rightType, + ], + UnionReduction.Subtype + ) + : leftType; if (operator === SyntaxKind.BarBarEqualsToken) { checkAssignmentOperator(rightType); } @@ -40746,45 +71368,66 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } case SyntaxKind.QuestionQuestionToken: case SyntaxKind.QuestionQuestionEqualsToken: { - const resultType = hasTypeFacts(leftType, TypeFacts.EQUndefinedOrNull) ? - getUnionType([getNonNullableType(leftType), rightType], UnionReduction.Subtype) : - leftType; + const resultType = hasTypeFacts( + leftType, + TypeFacts.EQUndefinedOrNull + ) + ? getUnionType( + [getNonNullableType(leftType), rightType], + UnionReduction.Subtype + ) + : leftType; if (operator === SyntaxKind.QuestionQuestionEqualsToken) { checkAssignmentOperator(rightType); } return resultType; } case SyntaxKind.EqualsToken: - const declKind = isBinaryExpression(left.parent) ? getAssignmentDeclarationKind(left.parent) : AssignmentDeclarationKind.None; + const declKind = isBinaryExpression(left.parent) + ? getAssignmentDeclarationKind(left.parent) + : AssignmentDeclarationKind.None; checkAssignmentDeclaration(declKind, rightType); if (isAssignmentDeclaration(declKind)) { if ( !(rightType.flags & TypeFlags.Object) || - declKind !== AssignmentDeclarationKind.ModuleExports && + (declKind !== AssignmentDeclarationKind.ModuleExports && declKind !== AssignmentDeclarationKind.Prototype && !isEmptyObjectType(rightType) && !isFunctionObjectType(rightType as ObjectType) && - !(getObjectFlags(rightType) & ObjectFlags.Class) + !(getObjectFlags(rightType) & ObjectFlags.Class)) ) { // don't check assignability of module.exports=, C.prototype=, or expando types because they will necessarily be incomplete checkAssignmentOperator(rightType); } return leftType; - } - else { + } else { checkAssignmentOperator(rightType); return rightType; } case SyntaxKind.CommaToken: - if (!compilerOptions.allowUnreachableCode && isSideEffectFree(left) && !isIndirectCall(left.parent as BinaryExpression)) { + if ( + !compilerOptions.allowUnreachableCode && + isSideEffectFree(left) && + !isIndirectCall(left.parent as BinaryExpression) + ) { const sf = getSourceFileOfNode(left); const sourceText = sf.text; const start = skipTrivia(sourceText, left.pos); - const isInDiag2657 = sf.parseDiagnostics.some(diag => { - if (diag.code !== Diagnostics.JSX_expressions_must_have_one_parent_element.code) return false; + const isInDiag2657 = sf.parseDiagnostics.some((diag) => { + if ( + diag.code !== + Diagnostics + .JSX_expressions_must_have_one_parent_element + .code + ) + return false; return textSpanContainsPosition(diag, start); }); - if (!isInDiag2657) error(left, Diagnostics.Left_side_of_comma_operator_is_unused_and_has_no_side_effects); + if (!isInDiag2657) + error( + left, + Diagnostics.Left_side_of_comma_operator_is_unused_and_has_no_side_effects + ); } return rightType; @@ -40793,19 +71436,47 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function bothAreBigIntLike(left: Type, right: Type): boolean { - return isTypeAssignableToKind(left, TypeFlags.BigIntLike) && isTypeAssignableToKind(right, TypeFlags.BigIntLike); + return ( + isTypeAssignableToKind(left, TypeFlags.BigIntLike) && + isTypeAssignableToKind(right, TypeFlags.BigIntLike) + ); } - function checkAssignmentDeclaration(kind: AssignmentDeclarationKind, rightType: Type) { + function checkAssignmentDeclaration( + kind: AssignmentDeclarationKind, + rightType: Type + ) { if (kind === AssignmentDeclarationKind.ModuleExports) { for (const prop of getPropertiesOfObjectType(rightType)) { const propType = getTypeOfSymbol(prop); - if (propType.symbol && propType.symbol.flags & SymbolFlags.Class) { + if ( + propType.symbol && + propType.symbol.flags & SymbolFlags.Class + ) { const name = prop.escapedName; - const symbol = resolveName(prop.valueDeclaration, name, SymbolFlags.Type, /*nameNotFoundMessage*/ undefined, /*isUse*/ false); - if (symbol?.declarations && symbol.declarations.some(isJSDocTypedefTag)) { - addDuplicateDeclarationErrorsForSymbols(symbol, Diagnostics.Duplicate_identifier_0, unescapeLeadingUnderscores(name), prop); - addDuplicateDeclarationErrorsForSymbols(prop, Diagnostics.Duplicate_identifier_0, unescapeLeadingUnderscores(name), symbol); + const symbol = resolveName( + prop.valueDeclaration, + name, + SymbolFlags.Type, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ false + ); + if ( + symbol?.declarations && + symbol.declarations.some(isJSDocTypedefTag) + ) { + addDuplicateDeclarationErrorsForSymbols( + symbol, + Diagnostics.Duplicate_identifier_0, + unescapeLeadingUnderscores(name), + prop + ); + addDuplicateDeclarationErrorsForSymbols( + prop, + Diagnostics.Duplicate_identifier_0, + unescapeLeadingUnderscores(name), + symbol + ); } } } @@ -40814,29 +71485,53 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Return true for "indirect calls", (i.e. `(0, x.f)(...)` or `(0, eval)(...)`), which prevents passing `this`. function isIndirectCall(node: BinaryExpression): boolean { - return node.parent.kind === SyntaxKind.ParenthesizedExpression && + return ( + node.parent.kind === SyntaxKind.ParenthesizedExpression && isNumericLiteral(node.left) && node.left.text === "0" && - (isCallExpression(node.parent.parent) && node.parent.parent.expression === node.parent || node.parent.parent.kind === SyntaxKind.TaggedTemplateExpression) && + ((isCallExpression(node.parent.parent) && + node.parent.parent.expression === node.parent) || + node.parent.parent.kind === + SyntaxKind.TaggedTemplateExpression) && // special-case for "eval" because it's the only non-access case where an indirect call actually affects behavior. - (isAccessExpression(node.right) || isIdentifier(node.right) && node.right.escapedText === "eval"); + (isAccessExpression(node.right) || + (isIdentifier(node.right) && + node.right.escapedText === "eval")) + ); } // Return true if there was no error, false if there was an error. - function checkForDisallowedESSymbolOperand(operator: PunctuationSyntaxKind): boolean { - const offendingSymbolOperand = maybeTypeOfKindConsideringBaseConstraint(leftType, TypeFlags.ESSymbolLike) ? left : - maybeTypeOfKindConsideringBaseConstraint(rightType, TypeFlags.ESSymbolLike) ? right : - undefined; + function checkForDisallowedESSymbolOperand( + operator: PunctuationSyntaxKind + ): boolean { + const offendingSymbolOperand = + maybeTypeOfKindConsideringBaseConstraint( + leftType, + TypeFlags.ESSymbolLike + ) + ? left + : maybeTypeOfKindConsideringBaseConstraint( + rightType, + TypeFlags.ESSymbolLike + ) + ? right + : undefined; if (offendingSymbolOperand) { - error(offendingSymbolOperand, Diagnostics.The_0_operator_cannot_be_applied_to_type_symbol, tokenToString(operator)); + error( + offendingSymbolOperand, + Diagnostics.The_0_operator_cannot_be_applied_to_type_symbol, + tokenToString(operator) + ); return false; } return true; } - function getSuggestedBooleanOperator(operator: SyntaxKind): PunctuationSyntaxKind | undefined { + function getSuggestedBooleanOperator( + operator: SyntaxKind + ): PunctuationSyntaxKind | undefined { switch (operator) { case SyntaxKind.BarToken: case SyntaxKind.BarEqualsToken: @@ -40861,8 +71556,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let assigneeType = leftType; // getters can be a subtype of setters, so to check for assignability we use the setter's type instead - if (isCompoundAssignment(operatorToken.kind) && left.kind === SyntaxKind.PropertyAccessExpression) { - assigneeType = checkPropertyAccessExpression(left as PropertyAccessExpression, /*checkMode*/ undefined, /*writeOnly*/ true); + if ( + isCompoundAssignment(operatorToken.kind) && + left.kind === SyntaxKind.PropertyAccessExpression + ) { + assigneeType = checkPropertyAccessExpression( + left as PropertyAccessExpression, + /*checkMode*/ undefined, + /*writeOnly*/ true + ); } // TypeScript 1.0 spec (April 2014): 4.17 @@ -40872,16 +71574,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // A compound assignment furthermore requires VarExpr to be classified as a reference (section 4.1) // and the type of the non-compound operation to be assignable to the type of VarExpr. - if (checkReferenceExpression(left, Diagnostics.The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access, Diagnostics.The_left_hand_side_of_an_assignment_expression_may_not_be_an_optional_property_access)) { + if ( + checkReferenceExpression( + left, + Diagnostics.The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access, + Diagnostics.The_left_hand_side_of_an_assignment_expression_may_not_be_an_optional_property_access + ) + ) { let headMessage: DiagnosticMessage | undefined; - if (exactOptionalPropertyTypes && isPropertyAccessExpression(left) && maybeTypeOfKind(valueType, TypeFlags.Undefined)) { - const target = getTypeOfPropertyOfType(getTypeOfExpression(left.expression), left.name.escapedText); - if (isExactOptionalPropertyMismatch(valueType, target)) { - headMessage = Diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_type_of_the_target; + if ( + exactOptionalPropertyTypes && + isPropertyAccessExpression(left) && + maybeTypeOfKind(valueType, TypeFlags.Undefined) + ) { + const target = getTypeOfPropertyOfType( + getTypeOfExpression(left.expression), + left.name.escapedText + ); + if ( + isExactOptionalPropertyMismatch(valueType, target) + ) { + headMessage = + Diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_type_of_the_target; } } // to avoid cascading errors check assignability only if 'isReference' check succeeded and no errors were reported - checkTypeAssignableToAndOptionallyElaborate(valueType, assigneeType, left, right, headMessage); + checkTypeAssignableToAndOptionallyElaborate( + valueType, + assigneeType, + left, + right, + headMessage + ); } } } @@ -40897,8 +71621,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case AssignmentDeclarationKind.ThisProperty: const symbol = getSymbolOfNode(left); const init = getAssignedExpandoInitializer(right); - return !!init && isObjectLiteralExpression(init) && - !!symbol?.exports?.size; + return ( + !!init && + isObjectLiteralExpression(init) && + !!symbol?.exports?.size + ); default: return false; } @@ -40907,7 +71634,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** * Returns true if an error is reported */ - function reportOperatorErrorUnless(typesAreCompatible: (left: Type, right: Type) => boolean): boolean { + function reportOperatorErrorUnless( + typesAreCompatible: (left: Type, right: Type) => boolean + ): boolean { if (!typesAreCompatible(leftType, rightType)) { reportOperatorError(typesAreCompatible); return true; @@ -40915,36 +71644,61 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function reportOperatorError(isRelated?: (left: Type, right: Type) => boolean) { + function reportOperatorError( + isRelated?: (left: Type, right: Type) => boolean + ) { let wouldWorkWithAwait = false; const errNode = errorNode || operatorToken; if (isRelated) { const awaitedLeftType = getAwaitedTypeNoAlias(leftType); const awaitedRightType = getAwaitedTypeNoAlias(rightType); - wouldWorkWithAwait = !(awaitedLeftType === leftType && awaitedRightType === rightType) - && !!(awaitedLeftType && awaitedRightType) - && isRelated(awaitedLeftType, awaitedRightType); + wouldWorkWithAwait = + !( + awaitedLeftType === leftType && + awaitedRightType === rightType + ) && + !!(awaitedLeftType && awaitedRightType) && + isRelated(awaitedLeftType, awaitedRightType); } let effectiveLeft = leftType; let effectiveRight = rightType; if (!wouldWorkWithAwait && isRelated) { - [effectiveLeft, effectiveRight] = getBaseTypesIfUnrelated(leftType, rightType, isRelated); + [effectiveLeft, effectiveRight] = getBaseTypesIfUnrelated( + leftType, + rightType, + isRelated + ); } - const [leftStr, rightStr] = getTypeNamesForErrorDisplay(effectiveLeft, effectiveRight); - if (!tryGiveBetterPrimaryError(errNode, wouldWorkWithAwait, leftStr, rightStr)) { + const [leftStr, rightStr] = getTypeNamesForErrorDisplay( + effectiveLeft, + effectiveRight + ); + if ( + !tryGiveBetterPrimaryError( + errNode, + wouldWorkWithAwait, + leftStr, + rightStr + ) + ) { errorAndMaybeSuggestAwait( errNode, wouldWorkWithAwait, Diagnostics.Operator_0_cannot_be_applied_to_types_1_and_2, tokenToString(operatorToken.kind), leftStr, - rightStr, + rightStr ); } } - function tryGiveBetterPrimaryError(errNode: Node, maybeMissingAwait: boolean, leftStr: string, rightStr: string) { + function tryGiveBetterPrimaryError( + errNode: Node, + maybeMissingAwait: boolean, + leftStr: string, + rightStr: string + ) { switch (operatorToken.kind) { case SyntaxKind.EqualsEqualsEqualsToken: case SyntaxKind.EqualsEqualsToken: @@ -40955,36 +71709,72 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { maybeMissingAwait, Diagnostics.This_comparison_appears_to_be_unintentional_because_the_types_0_and_1_have_no_overlap, leftStr, - rightStr, + rightStr ); default: return undefined; } } - function checkNaNEquality(errorNode: Node | undefined, operator: SyntaxKind, left: Expression, right: Expression) { + function checkNaNEquality( + errorNode: Node | undefined, + operator: SyntaxKind, + left: Expression, + right: Expression + ) { const isLeftNaN = isGlobalNaN(skipParentheses(left)); const isRightNaN = isGlobalNaN(skipParentheses(right)); if (isLeftNaN || isRightNaN) { - const err = error(errorNode, Diagnostics.This_condition_will_always_return_0, tokenToString(operator === SyntaxKind.EqualsEqualsEqualsToken || operator === SyntaxKind.EqualsEqualsToken ? SyntaxKind.FalseKeyword : SyntaxKind.TrueKeyword)); + const err = error( + errorNode, + Diagnostics.This_condition_will_always_return_0, + tokenToString( + operator === SyntaxKind.EqualsEqualsEqualsToken || + operator === SyntaxKind.EqualsEqualsToken + ? SyntaxKind.FalseKeyword + : SyntaxKind.TrueKeyword + ) + ); if (isLeftNaN && isRightNaN) return; - const operatorString = operator === SyntaxKind.ExclamationEqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken ? tokenToString(SyntaxKind.ExclamationToken) : ""; + const operatorString = + operator === SyntaxKind.ExclamationEqualsEqualsToken || + operator === SyntaxKind.ExclamationEqualsToken + ? tokenToString(SyntaxKind.ExclamationToken) + : ""; const location = isLeftNaN ? right : left; const expression = skipParentheses(location); - addRelatedInfo(err, createDiagnosticForNode(location, Diagnostics.Did_you_mean_0, `${operatorString}Number.isNaN(${isEntityNameExpression(expression) ? entityNameToString(expression) : "..."})`)); + addRelatedInfo( + err, + createDiagnosticForNode( + location, + Diagnostics.Did_you_mean_0, + `${operatorString}Number.isNaN(${ + isEntityNameExpression(expression) + ? entityNameToString(expression) + : "..." + })` + ) + ); } } function isGlobalNaN(expr: Expression): boolean { if (isIdentifier(expr) && expr.escapedText === "NaN") { const globalNaNSymbol = getGlobalNaNSymbol(); - return !!globalNaNSymbol && globalNaNSymbol === getResolvedSymbol(expr); + return ( + !!globalNaNSymbol && + globalNaNSymbol === getResolvedSymbol(expr) + ); } return false; } } - function getBaseTypesIfUnrelated(leftType: Type, rightType: Type, isRelated: (left: Type, right: Type) => boolean): [Type, Type] { + function getBaseTypesIfUnrelated( + leftType: Type, + rightType: Type, + isRelated: (left: Type, right: Type) => boolean + ): [Type, Type] { let effectiveLeft = leftType; let effectiveRight = rightType; const leftBase = getBaseTypeOfLiteralType(leftType); @@ -41012,12 +71802,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (node.asteriskToken) { // Async generator functions prior to ES2018 require the __await, __asyncDelegator, // and __asyncValues helpers - if (isAsync && languageVersion < LanguageFeatureMinimumTarget.AsyncGenerators) { - checkExternalEmitHelpers(node, ExternalEmitHelpers.AsyncDelegatorIncludes); + if ( + isAsync && + languageVersion < LanguageFeatureMinimumTarget.AsyncGenerators + ) { + checkExternalEmitHelpers( + node, + ExternalEmitHelpers.AsyncDelegatorIncludes + ); } // Generator functions prior to ES2015 require the __values helper - if (!isAsync && languageVersion < LanguageFeatureMinimumTarget.Generators && compilerOptions.downlevelIteration) { + if ( + !isAsync && + languageVersion < LanguageFeatureMinimumTarget.Generators && + compilerOptions.downlevelIteration + ) { checkExternalEmitHelpers(node, ExternalEmitHelpers.Values); } } @@ -41027,34 +71827,74 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // from the yield expressions. let returnType = getReturnTypeFromAnnotation(func); if (returnType && returnType.flags & TypeFlags.Union) { - returnType = filterType(returnType, t => checkGeneratorInstantiationAssignabilityToReturnType(t, functionFlags, /*errorNode*/ undefined)); + returnType = filterType(returnType, (t) => + checkGeneratorInstantiationAssignabilityToReturnType( + t, + functionFlags, + /*errorNode*/ undefined + ) + ); } - const iterationTypes = returnType && getIterationTypesOfGeneratorFunctionReturnType(returnType, isAsync); - const signatureYieldType = iterationTypes && iterationTypes.yieldType || anyType; - const signatureNextType = iterationTypes && iterationTypes.nextType || anyType; - const yieldExpressionType = node.expression ? checkExpression(node.expression) : undefinedWideningType; - const yieldedType = getYieldedTypeOfYieldExpression(node, yieldExpressionType, signatureNextType, isAsync); + const iterationTypes = + returnType && + getIterationTypesOfGeneratorFunctionReturnType(returnType, isAsync); + const signatureYieldType = + (iterationTypes && iterationTypes.yieldType) || anyType; + const signatureNextType = + (iterationTypes && iterationTypes.nextType) || anyType; + const yieldExpressionType = node.expression + ? checkExpression(node.expression) + : undefinedWideningType; + const yieldedType = getYieldedTypeOfYieldExpression( + node, + yieldExpressionType, + signatureNextType, + isAsync + ); if (returnType && yieldedType) { - checkTypeAssignableToAndOptionallyElaborate(yieldedType, signatureYieldType, node.expression || node, node.expression); + checkTypeAssignableToAndOptionallyElaborate( + yieldedType, + signatureYieldType, + node.expression || node, + node.expression + ); } if (node.asteriskToken) { - const use = isAsync ? IterationUse.AsyncYieldStar : IterationUse.YieldStar; - return getIterationTypeOfIterable(use, IterationTypeKind.Return, yieldExpressionType, node.expression) - || anyType; - } - else if (returnType) { - return getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Next, returnType, isAsync) - || anyType; + const use = isAsync + ? IterationUse.AsyncYieldStar + : IterationUse.YieldStar; + return ( + getIterationTypeOfIterable( + use, + IterationTypeKind.Return, + yieldExpressionType, + node.expression + ) || anyType + ); + } else if (returnType) { + return ( + getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Next, + returnType, + isAsync + ) || anyType + ); } let type = getContextualIterationType(IterationTypeKind.Next, func); if (!type) { type = anyType; addLazyDiagnostic(() => { if (noImplicitAny && !expressionResultIsUnused(node)) { - const contextualType = getContextualType(node, /*contextFlags*/ undefined); + const contextualType = getContextualType( + node, + /*contextFlags*/ undefined + ); if (!contextualType || isTypeAny(contextualType)) { - error(node, Diagnostics.yield_expression_implicitly_results_in_an_any_type_because_its_containing_generator_lacks_a_return_type_annotation); + error( + node, + Diagnostics.yield_expression_implicitly_results_in_an_any_type_because_its_containing_generator_lacks_a_return_type_annotation + ); } } }); @@ -41063,18 +71903,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkYieldExpressionGrammar() { if (!(node.flags & NodeFlags.YieldContext)) { - grammarErrorOnFirstToken(node, Diagnostics.A_yield_expression_is_only_allowed_in_a_generator_body); + grammarErrorOnFirstToken( + node, + Diagnostics.A_yield_expression_is_only_allowed_in_a_generator_body + ); } if (isInParameterInitializerBeforeContainingFunction(node)) { - error(node, Diagnostics.yield_expressions_cannot_be_used_in_a_parameter_initializer); + error( + node, + Diagnostics.yield_expressions_cannot_be_used_in_a_parameter_initializer + ); } } } - function checkConditionalExpression(node: ConditionalExpression, checkMode?: CheckMode): Type { + function checkConditionalExpression( + node: ConditionalExpression, + checkMode?: CheckMode + ): Type { const type = checkTruthinessExpression(node.condition, checkMode); - checkTestingKnownTruthyCallableOrAwaitableOrEnumMemberType(node.condition, type, node.whenTrue); + checkTestingKnownTruthyCallableOrAwaitableOrEnumMemberType( + node.condition, + type, + node.whenTrue + ); const type1 = checkExpression(node.whenTrue, checkMode); const type2 = checkExpression(node.whenFalse, checkMode); return getUnionType([type1, type2], UnionReduction.Subtype); @@ -41082,8 +71935,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isTemplateLiteralContext(node: Node): boolean { const parent = node.parent; - return isParenthesizedExpression(parent) && isTemplateLiteralContext(parent) || - isElementAccessExpression(parent) && parent.argumentExpression === node; + return ( + (isParenthesizedExpression(parent) && + isTemplateLiteralContext(parent)) || + (isElementAccessExpression(parent) && + parent.argumentExpression === node) + ); } function checkTemplateExpression(node: TemplateExpression): Type { @@ -41091,25 +71948,54 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const types = []; for (const span of node.templateSpans) { const type = checkExpression(span.expression); - if (maybeTypeOfKindConsideringBaseConstraint(type, TypeFlags.ESSymbolLike)) { - error(span.expression, Diagnostics.Implicit_conversion_of_a_symbol_to_a_string_will_fail_at_runtime_Consider_wrapping_this_expression_in_String); + if ( + maybeTypeOfKindConsideringBaseConstraint( + type, + TypeFlags.ESSymbolLike + ) + ) { + error( + span.expression, + Diagnostics.Implicit_conversion_of_a_symbol_to_a_string_will_fail_at_runtime_Consider_wrapping_this_expression_in_String + ); } texts.push(span.literal.text); - types.push(isTypeAssignableTo(type, templateConstraintType) ? type : stringType); + types.push( + isTypeAssignableTo(type, templateConstraintType) + ? type + : stringType + ); } - const evaluated = node.parent.kind !== SyntaxKind.TaggedTemplateExpression && evaluate(node).value; + const evaluated = + node.parent.kind !== SyntaxKind.TaggedTemplateExpression && + evaluate(node).value; if (evaluated) { return getFreshTypeOfLiteralType(getStringLiteralType(evaluated)); } - if (isConstContext(node) || isTemplateLiteralContext(node) || someType(getContextualType(node, /*contextFlags*/ undefined) || unknownType, isTemplateLiteralContextualType)) { + if ( + isConstContext(node) || + isTemplateLiteralContext(node) || + someType( + getContextualType(node, /*contextFlags*/ undefined) || + unknownType, + isTemplateLiteralContextualType + ) + ) { return getTemplateLiteralType(texts, types); } return stringType; } function isTemplateLiteralContextualType(type: Type): boolean { - return !!(type.flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral) || - type.flags & TypeFlags.InstantiableNonPrimitive && maybeTypeOfKind(getBaseConstraintOfType(type) || unknownType, TypeFlags.StringLike)); + return !!( + type.flags & + (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral) || + (type.flags & TypeFlags.InstantiableNonPrimitive && + maybeTypeOfKind( + getBaseConstraintOfType(type) || unknownType, + TypeFlags.StringLike + )) + ); } function getContextNode(node: Expression): Expression { @@ -41119,27 +72005,53 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return node; } - function checkExpressionWithContextualType(node: Expression, contextualType: Type, inferenceContext: InferenceContext | undefined, checkMode: CheckMode): Type { + function checkExpressionWithContextualType( + node: Expression, + contextualType: Type, + inferenceContext: InferenceContext | undefined, + checkMode: CheckMode + ): Type { const contextNode = getContextNode(node); pushContextualType(contextNode, contextualType, /*isCache*/ false); pushInferenceContext(contextNode, inferenceContext); - const type = checkExpression(node, checkMode | CheckMode.Contextual | (inferenceContext ? CheckMode.Inferential : 0)); + const type = checkExpression( + node, + checkMode | + CheckMode.Contextual | + (inferenceContext ? CheckMode.Inferential : 0) + ); // In CheckMode.Inferential we collect intra-expression inference sites to process before fixing any type // parameters. This information is no longer needed after the call to checkExpression. - if (inferenceContext && inferenceContext.intraExpressionInferenceSites) { + if ( + inferenceContext && + inferenceContext.intraExpressionInferenceSites + ) { inferenceContext.intraExpressionInferenceSites = undefined; } // We strip literal freshness when an appropriate contextual type is present such that contextually typed // literals always preserve their literal types (otherwise they might widen during type inference). An alternative // here would be to not mark contextually typed literals as fresh in the first place. - const result = maybeTypeOfKind(type, TypeFlags.Literal) && isLiteralOfContextualType(type, instantiateContextualType(contextualType, node, /*contextFlags*/ undefined)) ? - getRegularTypeOfLiteralType(type) : type; + const result = + maybeTypeOfKind(type, TypeFlags.Literal) && + isLiteralOfContextualType( + type, + instantiateContextualType( + contextualType, + node, + /*contextFlags*/ undefined + ) + ) + ? getRegularTypeOfLiteralType(type) + : type; popInferenceContext(); popContextualType(); return result; } - function checkExpressionCached(node: Expression | QualifiedName, checkMode?: CheckMode): Type { + function checkExpressionCached( + node: Expression | QualifiedName, + checkMode?: CheckMode + ): Type { if (checkMode) { return checkExpression(node, checkMode); } @@ -41161,38 +72073,69 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isTypeAssertion(node: Expression) { node = skipParentheses(node, /*excludeJSDocTypeAssertions*/ true); - return node.kind === SyntaxKind.TypeAssertionExpression || + return ( + node.kind === SyntaxKind.TypeAssertionExpression || node.kind === SyntaxKind.AsExpression || - isJSDocTypeAssertion(node); + isJSDocTypeAssertion(node) + ); } function checkDeclarationInitializer( declaration: HasExpressionInitializer, checkMode: CheckMode, - contextualType?: Type | undefined, + contextualType?: Type | undefined ) { const initializer = getEffectiveInitializer(declaration)!; if (isInJSFile(declaration)) { const typeNode = tryGetJSDocSatisfiesTypeNode(declaration); if (typeNode) { - return checkSatisfiesExpressionWorker(initializer, typeNode, checkMode); + return checkSatisfiesExpressionWorker( + initializer, + typeNode, + checkMode + ); } } - const type = getQuickTypeOfExpression(initializer) || (contextualType ? - checkExpressionWithContextualType(initializer, contextualType, /*inferenceContext*/ undefined, checkMode || CheckMode.Normal) : - checkExpressionCached(initializer, checkMode)); - if (isParameter(isBindingElement(declaration) ? walkUpBindingElementsAndPatterns(declaration) : declaration)) { - if (declaration.name.kind === SyntaxKind.ObjectBindingPattern && isObjectLiteralType(type)) { - return padObjectLiteralType(type as ObjectType, declaration.name); + const type = + getQuickTypeOfExpression(initializer) || + (contextualType + ? checkExpressionWithContextualType( + initializer, + contextualType, + /*inferenceContext*/ undefined, + checkMode || CheckMode.Normal + ) + : checkExpressionCached(initializer, checkMode)); + if ( + isParameter( + isBindingElement(declaration) + ? walkUpBindingElementsAndPatterns(declaration) + : declaration + ) + ) { + if ( + declaration.name.kind === SyntaxKind.ObjectBindingPattern && + isObjectLiteralType(type) + ) { + return padObjectLiteralType( + type as ObjectType, + declaration.name + ); } - if (declaration.name.kind === SyntaxKind.ArrayBindingPattern && isTupleType(type)) { + if ( + declaration.name.kind === SyntaxKind.ArrayBindingPattern && + isTupleType(type) + ) { return padTupleType(type, declaration.name); } } return type; } - function padObjectLiteralType(type: ObjectType, pattern: ObjectBindingPattern): Type { + function padObjectLiteralType( + type: ObjectType, + pattern: ObjectBindingPattern + ): Type { let missingElements: BindingElement[] | undefined; for (const e of pattern.elements) { if (e.initializer) { @@ -41210,48 +72153,92 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { members.set(prop.escapedName, prop); } for (const e of missingElements) { - const symbol = createSymbol(SymbolFlags.Property | SymbolFlags.Optional, getPropertyNameFromBindingElement(e)!); - symbol.links.type = getTypeFromBindingElement(e, /*includePatternInType*/ false, /*reportErrors*/ false); + const symbol = createSymbol( + SymbolFlags.Property | SymbolFlags.Optional, + getPropertyNameFromBindingElement(e)! + ); + symbol.links.type = getTypeFromBindingElement( + e, + /*includePatternInType*/ false, + /*reportErrors*/ false + ); members.set(symbol.escapedName, symbol); } - const result = createAnonymousType(type.symbol, members, emptyArray, emptyArray, getIndexInfosOfType(type)); + const result = createAnonymousType( + type.symbol, + members, + emptyArray, + emptyArray, + getIndexInfosOfType(type) + ); result.objectFlags = type.objectFlags; return result; } function getPropertyNameFromBindingElement(e: BindingElement) { - const exprType = getLiteralTypeFromPropertyName(e.propertyName || e.name as Identifier); - return isTypeUsableAsPropertyName(exprType) ? getPropertyNameFromType(exprType) : undefined; + const exprType = getLiteralTypeFromPropertyName( + e.propertyName || (e.name as Identifier) + ); + return isTypeUsableAsPropertyName(exprType) + ? getPropertyNameFromType(exprType) + : undefined; } - function padTupleType(type: TupleTypeReference, pattern: ArrayBindingPattern) { - if (type.target.combinedFlags & ElementFlags.Variable || getTypeReferenceArity(type) >= pattern.elements.length) { + function padTupleType( + type: TupleTypeReference, + pattern: ArrayBindingPattern + ) { + if ( + type.target.combinedFlags & ElementFlags.Variable || + getTypeReferenceArity(type) >= pattern.elements.length + ) { return type; } const patternElements = pattern.elements; const elementTypes = getElementTypes(type).slice(); const elementFlags = type.target.elementFlags.slice(); - for (let i = getTypeReferenceArity(type); i < patternElements.length; i++) { + for ( + let i = getTypeReferenceArity(type); + i < patternElements.length; + i++ + ) { const e = patternElements[i]; - if (i < patternElements.length - 1 || !(e.kind === SyntaxKind.BindingElement && e.dotDotDotToken)) { - elementTypes.push(!isOmittedExpression(e) && hasDefaultValue(e) ? getTypeFromBindingElement(e, /*includePatternInType*/ false, /*reportErrors*/ false) : anyType); + if ( + i < patternElements.length - 1 || + !(e.kind === SyntaxKind.BindingElement && e.dotDotDotToken) + ) { + elementTypes.push( + !isOmittedExpression(e) && hasDefaultValue(e) + ? getTypeFromBindingElement( + e, + /*includePatternInType*/ false, + /*reportErrors*/ false + ) + : anyType + ); elementFlags.push(ElementFlags.Optional); if (!isOmittedExpression(e) && !hasDefaultValue(e)) { reportImplicitAny(e, anyType); } } } - return createTupleType(elementTypes, elementFlags, type.target.readonly); + return createTupleType( + elementTypes, + elementFlags, + type.target.readonly + ); } - function widenTypeInferredFromInitializer(declaration: HasExpressionInitializer, type: Type) { + function widenTypeInferredFromInitializer( + declaration: HasExpressionInitializer, + type: Type + ) { const widened = getWidenedLiteralTypeForInitializer(declaration, type); if (isInJSFile(declaration)) { if (isEmptyLiteralType(widened)) { reportImplicitAny(declaration, anyType); return anyType; - } - else if (isEmptyArrayLiteralType(widened)) { + } else if (isEmptyArrayLiteralType(widened)) { reportImplicitAny(declaration, anyArrayType); return anyArrayType; } @@ -41259,55 +72246,125 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return widened; } - function getWidenedLiteralTypeForInitializer(declaration: HasExpressionInitializer, type: Type) { - return getCombinedNodeFlagsCached(declaration) & NodeFlags.Constant || isDeclarationReadonly(declaration) ? type : getWidenedLiteralType(type); + function getWidenedLiteralTypeForInitializer( + declaration: HasExpressionInitializer, + type: Type + ) { + return getCombinedNodeFlagsCached(declaration) & NodeFlags.Constant || + isDeclarationReadonly(declaration) + ? type + : getWidenedLiteralType(type); } - function isLiteralOfContextualType(candidateType: Type, contextualType: Type | undefined): boolean { + function isLiteralOfContextualType( + candidateType: Type, + contextualType: Type | undefined + ): boolean { if (contextualType) { if (contextualType.flags & TypeFlags.UnionOrIntersection) { const types = (contextualType as UnionType).types; - return some(types, t => isLiteralOfContextualType(candidateType, t)); + return some(types, (t) => + isLiteralOfContextualType(candidateType, t) + ); } if (contextualType.flags & TypeFlags.InstantiableNonPrimitive) { // If the contextual type is a type variable constrained to a primitive type, consider // this a literal context for literals of that primitive type. For example, given a // type parameter 'T extends string', infer string literal types for T. - const constraint = getBaseConstraintOfType(contextualType) || unknownType; - return maybeTypeOfKind(constraint, TypeFlags.String) && maybeTypeOfKind(candidateType, TypeFlags.StringLiteral) || - maybeTypeOfKind(constraint, TypeFlags.Number) && maybeTypeOfKind(candidateType, TypeFlags.NumberLiteral) || - maybeTypeOfKind(constraint, TypeFlags.BigInt) && maybeTypeOfKind(candidateType, TypeFlags.BigIntLiteral) || - maybeTypeOfKind(constraint, TypeFlags.ESSymbol) && maybeTypeOfKind(candidateType, TypeFlags.UniqueESSymbol) || - isLiteralOfContextualType(candidateType, constraint); + const constraint = + getBaseConstraintOfType(contextualType) || unknownType; + return ( + (maybeTypeOfKind(constraint, TypeFlags.String) && + maybeTypeOfKind( + candidateType, + TypeFlags.StringLiteral + )) || + (maybeTypeOfKind(constraint, TypeFlags.Number) && + maybeTypeOfKind( + candidateType, + TypeFlags.NumberLiteral + )) || + (maybeTypeOfKind(constraint, TypeFlags.BigInt) && + maybeTypeOfKind( + candidateType, + TypeFlags.BigIntLiteral + )) || + (maybeTypeOfKind(constraint, TypeFlags.ESSymbol) && + maybeTypeOfKind( + candidateType, + TypeFlags.UniqueESSymbol + )) || + isLiteralOfContextualType(candidateType, constraint) + ); } // If the contextual type is a literal of a particular primitive type, we consider this a // literal context for all literals of that primitive type. - return !!(contextualType.flags & (TypeFlags.StringLiteral | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) && maybeTypeOfKind(candidateType, TypeFlags.StringLiteral) || - contextualType.flags & TypeFlags.NumberLiteral && maybeTypeOfKind(candidateType, TypeFlags.NumberLiteral) || - contextualType.flags & TypeFlags.BigIntLiteral && maybeTypeOfKind(candidateType, TypeFlags.BigIntLiteral) || - contextualType.flags & TypeFlags.BooleanLiteral && maybeTypeOfKind(candidateType, TypeFlags.BooleanLiteral) || - contextualType.flags & TypeFlags.UniqueESSymbol && maybeTypeOfKind(candidateType, TypeFlags.UniqueESSymbol)); + return !!( + (contextualType.flags & + (TypeFlags.StringLiteral | + TypeFlags.Index | + TypeFlags.TemplateLiteral | + TypeFlags.StringMapping) && + maybeTypeOfKind(candidateType, TypeFlags.StringLiteral)) || + (contextualType.flags & TypeFlags.NumberLiteral && + maybeTypeOfKind(candidateType, TypeFlags.NumberLiteral)) || + (contextualType.flags & TypeFlags.BigIntLiteral && + maybeTypeOfKind(candidateType, TypeFlags.BigIntLiteral)) || + (contextualType.flags & TypeFlags.BooleanLiteral && + maybeTypeOfKind(candidateType, TypeFlags.BooleanLiteral)) || + (contextualType.flags & TypeFlags.UniqueESSymbol && + maybeTypeOfKind(candidateType, TypeFlags.UniqueESSymbol)) + ); } return false; } function isConstContext(node: Expression): boolean { const parent = node.parent; - return isAssertionExpression(parent) && isConstTypeReference(parent.type) || - isJSDocTypeAssertion(parent) && isConstTypeReference(getJSDocTypeAssertionType(parent)) || - isValidConstAssertionArgument(node) && isConstTypeVariable(getContextualType(node, ContextFlags.None)) || - (isParenthesizedExpression(parent) || isArrayLiteralExpression(parent) || isSpreadElement(parent)) && isConstContext(parent) || - (isPropertyAssignment(parent) || isShorthandPropertyAssignment(parent) || isTemplateSpan(parent)) && isConstContext(parent.parent); + return ( + (isAssertionExpression(parent) && + isConstTypeReference(parent.type)) || + (isJSDocTypeAssertion(parent) && + isConstTypeReference(getJSDocTypeAssertionType(parent))) || + (isValidConstAssertionArgument(node) && + isConstTypeVariable( + getContextualType(node, ContextFlags.None) + )) || + ((isParenthesizedExpression(parent) || + isArrayLiteralExpression(parent) || + isSpreadElement(parent)) && + isConstContext(parent)) || + ((isPropertyAssignment(parent) || + isShorthandPropertyAssignment(parent) || + isTemplateSpan(parent)) && + isConstContext(parent.parent)) + ); } - function checkExpressionForMutableLocation(node: Expression, checkMode: CheckMode | undefined, forceTuple?: boolean): Type { + function checkExpressionForMutableLocation( + node: Expression, + checkMode: CheckMode | undefined, + forceTuple?: boolean + ): Type { const type = checkExpression(node, checkMode, forceTuple); - return isConstContext(node) || isCommonJsExportedExpression(node) ? getRegularTypeOfLiteralType(type) : - isTypeAssertion(node) ? type : - getWidenedLiteralLikeTypeForContextualType(type, instantiateContextualType(getContextualType(node, /*contextFlags*/ undefined), node, /*contextFlags*/ undefined)); - } - - function checkPropertyAssignment(node: PropertyAssignment, checkMode?: CheckMode): Type { + return isConstContext(node) || isCommonJsExportedExpression(node) + ? getRegularTypeOfLiteralType(type) + : isTypeAssertion(node) + ? type + : getWidenedLiteralLikeTypeForContextualType( + type, + instantiateContextualType( + getContextualType(node, /*contextFlags*/ undefined), + node, + /*contextFlags*/ undefined + ) + ); + } + + function checkPropertyAssignment( + node: PropertyAssignment, + checkMode?: CheckMode + ): Type { // Do not use hasDynamicName here, because that returns false for well known symbols. // We want to perform checkComputedPropertyName for all computed properties, including // well known symbols. @@ -41318,7 +72375,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return checkExpressionForMutableLocation(node.initializer, checkMode); } - function checkObjectLiteralMethod(node: MethodDeclaration, checkMode?: CheckMode): Type { + function checkObjectLiteralMethod( + node: MethodDeclaration, + checkMode?: CheckMode + ): Type { // Grammar checking checkGrammarMethod(node); @@ -41329,20 +72389,54 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkComputedPropertyName(node.name); } - const uninstantiatedType = checkFunctionExpressionOrObjectLiteralMethod(node, checkMode); - return instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, checkMode); + const uninstantiatedType = checkFunctionExpressionOrObjectLiteralMethod( + node, + checkMode + ); + return instantiateTypeWithSingleGenericCallSignature( + node, + uninstantiatedType, + checkMode + ); } - function instantiateTypeWithSingleGenericCallSignature(node: Expression | MethodDeclaration | QualifiedName, type: Type, checkMode?: CheckMode) { - if (checkMode && checkMode & (CheckMode.Inferential | CheckMode.SkipGenericFunctions)) { - const callSignature = getSingleSignature(type, SignatureKind.Call, /*allowMembers*/ true); - const constructSignature = getSingleSignature(type, SignatureKind.Construct, /*allowMembers*/ true); + function instantiateTypeWithSingleGenericCallSignature( + node: Expression | MethodDeclaration | QualifiedName, + type: Type, + checkMode?: CheckMode + ) { + if ( + checkMode && + checkMode & (CheckMode.Inferential | CheckMode.SkipGenericFunctions) + ) { + const callSignature = getSingleSignature( + type, + SignatureKind.Call, + /*allowMembers*/ true + ); + const constructSignature = getSingleSignature( + type, + SignatureKind.Construct, + /*allowMembers*/ true + ); const signature = callSignature || constructSignature; if (signature && signature.typeParameters) { - const contextualType = getApparentTypeOfContextualType(node as Expression, ContextFlags.NoConstraints); + const contextualType = getApparentTypeOfContextualType( + node as Expression, + ContextFlags.NoConstraints + ); if (contextualType) { - const contextualSignature = getSingleSignature(getNonNullableType(contextualType), callSignature ? SignatureKind.Call : SignatureKind.Construct, /*allowMembers*/ false); - if (contextualSignature && !contextualSignature.typeParameters) { + const contextualSignature = getSingleSignature( + getNonNullableType(contextualType), + callSignature + ? SignatureKind.Call + : SignatureKind.Construct, + /*allowMembers*/ false + ); + if ( + contextualSignature && + !contextualSignature.typeParameters + ) { if (checkMode & CheckMode.SkipGenericFunctions) { skippedGenericFunction(node, checkMode); return anyFunctionType; @@ -41354,36 +72448,88 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // if the outer function returns a function type with a single non-generic call signature and // if some of the outer function type parameters have no inferences so far. If so, we can // potentially add inferred type parameters to the outer function return type. - const returnType = context.signature && getReturnTypeOfSignature(context.signature); - const returnSignature = returnType && getSingleCallOrConstructSignature(returnType); - if (returnSignature && !returnSignature.typeParameters && !every(context.inferences, hasInferenceCandidates)) { + const returnType = + context.signature && + getReturnTypeOfSignature(context.signature); + const returnSignature = + returnType && + getSingleCallOrConstructSignature(returnType); + if ( + returnSignature && + !returnSignature.typeParameters && + !every(context.inferences, hasInferenceCandidates) + ) { // Instantiate the signature with its own type parameters as type arguments, possibly // renaming the type parameters to ensure they have unique names. - const uniqueTypeParameters = getUniqueTypeParameters(context, signature.typeParameters); - const instantiatedSignature = getSignatureInstantiationWithoutFillingInTypeArguments(signature, uniqueTypeParameters); + const uniqueTypeParameters = + getUniqueTypeParameters( + context, + signature.typeParameters + ); + const instantiatedSignature = + getSignatureInstantiationWithoutFillingInTypeArguments( + signature, + uniqueTypeParameters + ); // Infer from the parameters of the instantiated signature to the parameters of the // contextual signature starting with an empty set of inference candidates. - const inferences = map(context.inferences, info => createInferenceInfo(info.typeParameter)); - applyToParameterTypes(instantiatedSignature, contextualSignature, (source, target) => { - inferTypes(inferences, source, target, /*priority*/ 0, /*contravariant*/ true); - }); + const inferences = map(context.inferences, (info) => + createInferenceInfo(info.typeParameter) + ); + applyToParameterTypes( + instantiatedSignature, + contextualSignature, + (source, target) => { + inferTypes( + inferences, + source, + target, + /*priority*/ 0, + /*contravariant*/ true + ); + } + ); if (some(inferences, hasInferenceCandidates)) { // We have inference candidates, indicating that one or more type parameters are referenced // in the parameter types of the contextual signature. Now also infer from the return type. - applyToReturnTypes(instantiatedSignature, contextualSignature, (source, target) => { - inferTypes(inferences, source, target); - }); + applyToReturnTypes( + instantiatedSignature, + contextualSignature, + (source, target) => { + inferTypes(inferences, source, target); + } + ); // If the type parameters for which we produced candidates do not have any inferences yet, // we adopt the new inference candidates and add the type parameters of the expression type // to the set of inferred type parameters for the outer function return type. - if (!hasOverlappingInferences(context.inferences, inferences)) { - mergeInferences(context.inferences, inferences); - context.inferredTypeParameters = concatenate(context.inferredTypeParameters, uniqueTypeParameters); - return getOrCreateTypeFromSignature(instantiatedSignature); + if ( + !hasOverlappingInferences( + context.inferences, + inferences + ) + ) { + mergeInferences( + context.inferences, + inferences + ); + context.inferredTypeParameters = + concatenate( + context.inferredTypeParameters, + uniqueTypeParameters + ); + return getOrCreateTypeFromSignature( + instantiatedSignature + ); } } } - return getOrCreateTypeFromSignature(instantiateSignatureInContextOf(signature, contextualSignature, context)); + return getOrCreateTypeFromSignature( + instantiateSignatureInContextOf( + signature, + contextualSignature, + context + ) + ); } } } @@ -41405,7 +72551,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function hasInferenceCandidatesOrDefault(info: InferenceInfo) { - return !!(info.candidates || info.contraCandidates || hasTypeParameterDefault(info.typeParameter)); + return !!( + info.candidates || + info.contraCandidates || + hasTypeParameterDefault(info.typeParameter) + ); } function hasOverlappingInferences(a: InferenceInfo[], b: InferenceInfo[]) { @@ -41419,33 +72569,47 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function mergeInferences(target: InferenceInfo[], source: InferenceInfo[]) { for (let i = 0; i < target.length; i++) { - if (!hasInferenceCandidates(target[i]) && hasInferenceCandidates(source[i])) { + if ( + !hasInferenceCandidates(target[i]) && + hasInferenceCandidates(source[i]) + ) { target[i] = source[i]; } } } - function getUniqueTypeParameters(context: InferenceContext, typeParameters: readonly TypeParameter[]): readonly TypeParameter[] { + function getUniqueTypeParameters( + context: InferenceContext, + typeParameters: readonly TypeParameter[] + ): readonly TypeParameter[] { const result: TypeParameter[] = []; let oldTypeParameters: TypeParameter[] | undefined; let newTypeParameters: TypeParameter[] | undefined; for (const tp of typeParameters) { const name = tp.symbol.escapedName; - if (hasTypeParameterByName(context.inferredTypeParameters, name) || hasTypeParameterByName(result, name)) { - const newName = getUniqueTypeParameterName(concatenate(context.inferredTypeParameters, result), name); + if ( + hasTypeParameterByName(context.inferredTypeParameters, name) || + hasTypeParameterByName(result, name) + ) { + const newName = getUniqueTypeParameterName( + concatenate(context.inferredTypeParameters, result), + name + ); const symbol = createSymbol(SymbolFlags.TypeParameter, newName); const newTypeParameter = createTypeParameter(symbol); newTypeParameter.target = tp; oldTypeParameters = append(oldTypeParameters, tp); newTypeParameters = append(newTypeParameters, newTypeParameter); result.push(newTypeParameter); - } - else { + } else { result.push(tp); } } if (newTypeParameters) { - const mapper = createTypeMapper(oldTypeParameters!, newTypeParameters); + const mapper = createTypeMapper( + oldTypeParameters!, + newTypeParameters + ); for (const tp of newTypeParameters) { tp.mapper = mapper; } @@ -41453,16 +72617,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function hasTypeParameterByName(typeParameters: readonly TypeParameter[] | undefined, name: __String) { - return some(typeParameters, tp => tp.symbol.escapedName === name); + function hasTypeParameterByName( + typeParameters: readonly TypeParameter[] | undefined, + name: __String + ) { + return some(typeParameters, (tp) => tp.symbol.escapedName === name); } - function getUniqueTypeParameterName(typeParameters: readonly TypeParameter[], baseName: __String) { + function getUniqueTypeParameterName( + typeParameters: readonly TypeParameter[], + baseName: __String + ) { let len = (baseName as string).length; - while (len > 1 && (baseName as string).charCodeAt(len - 1) >= CharacterCodes._0 && (baseName as string).charCodeAt(len - 1) <= CharacterCodes._9) len--; + while ( + len > 1 && + (baseName as string).charCodeAt(len - 1) >= CharacterCodes._0 && + (baseName as string).charCodeAt(len - 1) <= CharacterCodes._9 + ) + len--; const s = (baseName as string).slice(0, len); for (let index = 1; true; index++) { - const augmentedName = s + index as __String; + const augmentedName = (s + index) as __String; if (!hasTypeParameterByName(typeParameters, augmentedName)) { return augmentedName; } @@ -41476,11 +72651,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr: CallChain) { + function getReturnTypeOfSingleNonGenericSignatureOfCallChain( + expr: CallChain + ) { const funcType = checkExpression(expr.expression); - const nonOptionalType = getOptionalExpressionType(funcType, expr.expression); - const returnType = getReturnTypeOfSingleNonGenericCallSignature(funcType); - return returnType && propagateOptionalTypeMarker(returnType, expr, nonOptionalType !== funcType); + const nonOptionalType = getOptionalExpressionType( + funcType, + expr.expression + ); + const returnType = + getReturnTypeOfSingleNonGenericCallSignature(funcType); + return ( + returnType && + propagateOptionalTypeMarker( + returnType, + expr, + nonOptionalType !== funcType + ) + ); } /** @@ -41526,14 +72714,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Optimize for the common case of a call to a function with a single non-generic call // signature where we can just fetch the return type without checking the arguments. - if (isCallExpression(expr) && expr.expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(expr, /*requireStringLiteralLikeArgument*/ true) && !isSymbolOrSymbolForCall(expr) && !isImportCall(expr)) { - return isCallChain(expr) ? getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr) : - getReturnTypeOfSingleNonGenericCallSignature(checkNonNullExpression(expr.expression)); - } - else if (isAssertionExpression(expr) && !isConstTypeReference(expr.type)) { + if ( + isCallExpression(expr) && + expr.expression.kind !== SyntaxKind.SuperKeyword && + !isRequireCall(expr, /*requireStringLiteralLikeArgument*/ true) && + !isSymbolOrSymbolForCall(expr) && + !isImportCall(expr) + ) { + return isCallChain(expr) + ? getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr) + : getReturnTypeOfSingleNonGenericCallSignature( + checkNonNullExpression(expr.expression) + ); + } else if ( + isAssertionExpression(expr) && + !isConstTypeReference(expr.type) + ) { return getTypeFromTypeNode((expr as TypeAssertion).type); - } - else if (isLiteralExpression(node) || isBooleanLiteral(node)) { + } else if (isLiteralExpression(node) || isBooleanLiteral(node)) { return checkExpression(node); } return undefined; @@ -41552,18 +72750,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return links.contextFreeType; } pushContextualType(node, anyType, /*isCache*/ false); - const type = links.contextFreeType = checkExpression(node, CheckMode.SkipContextSensitive); + const type = (links.contextFreeType = checkExpression( + node, + CheckMode.SkipContextSensitive + )); popContextualType(); return type; } - function checkExpression(node: Expression | QualifiedName, checkMode?: CheckMode, forceTuple?: boolean): Type { - tracing?.push(tracing.Phase.Check, "checkExpression", { kind: node.kind, pos: node.pos, end: node.end, path: (node as TracingNode).tracingPath }); + function checkExpression( + node: Expression | QualifiedName, + checkMode?: CheckMode, + forceTuple?: boolean + ): Type { + tracing?.push(tracing.Phase.Check, "checkExpression", { + kind: node.kind, + pos: node.pos, + end: node.end, + path: (node as TracingNode).tracingPath, + }); const saveCurrentNode = currentNode; currentNode = node; instantiationCount = 0; - const uninstantiatedType = checkExpressionWorker(node, checkMode, forceTuple); - const type = instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, checkMode); + const uninstantiatedType = checkExpressionWorker( + node, + checkMode, + forceTuple + ); + const type = instantiateTypeWithSingleGenericCallSignature( + node, + uninstantiatedType, + checkMode + ); if (isConstEnumObjectType(type)) { checkConstEnumAccess(node, type); } @@ -41572,50 +72790,84 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return type; } - function checkConstEnumAccess(node: Expression | QualifiedName, type: Type) { + function checkConstEnumAccess( + node: Expression | QualifiedName, + type: Type + ) { // enum object type for const enums are only permitted in: // - 'left' in property access // - 'object' in indexed access // - target in rhs of import statement - const ok = (node.parent.kind === SyntaxKind.PropertyAccessExpression && (node.parent as PropertyAccessExpression).expression === node) || - (node.parent.kind === SyntaxKind.ElementAccessExpression && (node.parent as ElementAccessExpression).expression === node) || - ((node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName) && isInRightSideOfImportOrExportAssignment(node as Identifier) || - (node.parent.kind === SyntaxKind.TypeQuery && (node.parent as TypeQueryNode).exprName === node)) || - (node.parent.kind === SyntaxKind.ExportSpecifier); // We allow reexporting const enums + const ok = + (node.parent.kind === SyntaxKind.PropertyAccessExpression && + (node.parent as PropertyAccessExpression).expression === + node) || + (node.parent.kind === SyntaxKind.ElementAccessExpression && + (node.parent as ElementAccessExpression).expression === node) || + ((node.kind === SyntaxKind.Identifier || + node.kind === SyntaxKind.QualifiedName) && + isInRightSideOfImportOrExportAssignment(node as Identifier)) || + (node.parent.kind === SyntaxKind.TypeQuery && + (node.parent as TypeQueryNode).exprName === node) || + node.parent.kind === SyntaxKind.ExportSpecifier; // We allow reexporting const enums if (!ok) { - 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); + 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 + ); } // --verbatimModuleSyntax only gets checked here when the enum usage does not // resolve to an import, because imports of ambient const enums get checked // separately in `checkAliasSymbol`. if ( - compilerOptions.isolatedModules - || compilerOptions.verbatimModuleSyntax - && ok - && !resolveName( + compilerOptions.isolatedModules || + (compilerOptions.verbatimModuleSyntax && + ok && + !resolveName( node, - getFirstIdentifier(node as EntityNameOrEntityNameExpression), + getFirstIdentifier( + node as EntityNameOrEntityNameExpression + ), SymbolFlags.Alias, /*nameNotFoundMessage*/ undefined, /*isUse*/ false, - /*excludeGlobals*/ true, - ) + /*excludeGlobals*/ true + )) ) { Debug.assert(!!(type.symbol.flags & SymbolFlags.ConstEnum)); - const constEnumDeclaration = type.symbol.valueDeclaration as EnumDeclaration; - const redirect = host.getRedirectFromOutput(getSourceFileOfNode(constEnumDeclaration).resolvedPath)?.resolvedRef; - if (constEnumDeclaration.flags & NodeFlags.Ambient && !isValidTypeOnlyAliasUseSite(node) && (!redirect || !shouldPreserveConstEnums(redirect.commandLine.options))) { - error(node, Diagnostics.Cannot_access_ambient_const_enums_when_0_is_enabled, isolatedModulesLikeFlagName); + const constEnumDeclaration = type.symbol + .valueDeclaration as EnumDeclaration; + const redirect = host.getRedirectFromOutput( + getSourceFileOfNode(constEnumDeclaration).resolvedPath + )?.resolvedRef; + if ( + constEnumDeclaration.flags & NodeFlags.Ambient && + !isValidTypeOnlyAliasUseSite(node) && + (!redirect || + !shouldPreserveConstEnums(redirect.commandLine.options)) + ) { + error( + node, + Diagnostics.Cannot_access_ambient_const_enums_when_0_is_enabled, + isolatedModulesLikeFlagName + ); } } } - function checkParenthesizedExpression(node: ParenthesizedExpression, checkMode?: CheckMode): Type { + function checkParenthesizedExpression( + node: ParenthesizedExpression, + checkMode?: CheckMode + ): Type { if (hasJSDocNodes(node)) { if (isJSDocSatisfiesExpression(node)) { - return checkSatisfiesExpressionWorker(node.expression, getJSDocSatisfiesExpressionType(node), checkMode); + return checkSatisfiesExpressionWorker( + node.expression, + getJSDocSatisfiesExpressionType(node), + checkMode + ); } if (isJSDocTypeAssertion(node)) { return checkAssertionWorker(node, checkMode); @@ -41624,7 +72876,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return checkExpression(node.expression, checkMode); } - function checkExpressionWorker(node: Expression | QualifiedName, checkMode: CheckMode | undefined, forceTuple?: boolean): Type { + function checkExpressionWorker( + node: Expression | QualifiedName, + checkMode: CheckMode | undefined, + forceTuple?: boolean + ): Type { const kind = node.kind; if (cancellationToken) { // Only bother checking on a few construct kinds. We don't want to be excessively @@ -41640,7 +72896,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.Identifier: return checkIdentifier(node as Identifier, checkMode); case SyntaxKind.PrivateIdentifier: - return checkPrivateIdentifierExpression(node as PrivateIdentifier); + return checkPrivateIdentifierExpression( + node as PrivateIdentifier + ); case SyntaxKind.ThisKeyword: return checkThisExpression(node); case SyntaxKind.SuperKeyword: @@ -41649,18 +72907,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return nullWideningType; case SyntaxKind.NoSubstitutionTemplateLiteral: case SyntaxKind.StringLiteral: - return hasSkipDirectInferenceFlag(node) ? - blockedStringType : - getFreshTypeOfLiteralType(getStringLiteralType((node as StringLiteralLike).text)); + return hasSkipDirectInferenceFlag(node) + ? blockedStringType + : getFreshTypeOfLiteralType( + getStringLiteralType((node as StringLiteralLike).text) + ); case SyntaxKind.NumericLiteral: checkGrammarNumericLiteral(node as NumericLiteral); - return getFreshTypeOfLiteralType(getNumberLiteralType(+(node as NumericLiteral).text)); + return getFreshTypeOfLiteralType( + getNumberLiteralType(+(node as NumericLiteral).text) + ); case SyntaxKind.BigIntLiteral: checkGrammarBigIntLiteral(node as BigIntLiteral); - return getFreshTypeOfLiteralType(getBigIntLiteralType({ - negative: false, - base10Value: parsePseudoBigInt((node as BigIntLiteral).text), - })); + return getFreshTypeOfLiteralType( + getBigIntLiteralType({ + negative: false, + base10Value: parsePseudoBigInt( + (node as BigIntLiteral).text + ), + }) + ); case SyntaxKind.TrueKeyword: return trueType; case SyntaxKind.FalseKeyword: @@ -41668,33 +72934,56 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.TemplateExpression: return checkTemplateExpression(node as TemplateExpression); case SyntaxKind.RegularExpressionLiteral: - return checkRegularExpressionLiteral(node as RegularExpressionLiteral); + return checkRegularExpressionLiteral( + node as RegularExpressionLiteral + ); case SyntaxKind.ArrayLiteralExpression: - return checkArrayLiteral(node as ArrayLiteralExpression, checkMode, forceTuple); + return checkArrayLiteral( + node as ArrayLiteralExpression, + checkMode, + forceTuple + ); case SyntaxKind.ObjectLiteralExpression: - return checkObjectLiteral(node as ObjectLiteralExpression, checkMode); + return checkObjectLiteral( + node as ObjectLiteralExpression, + checkMode + ); case SyntaxKind.PropertyAccessExpression: - return checkPropertyAccessExpression(node as PropertyAccessExpression, checkMode); + return checkPropertyAccessExpression( + node as PropertyAccessExpression, + checkMode + ); case SyntaxKind.QualifiedName: return checkQualifiedName(node as QualifiedName, checkMode); case SyntaxKind.ElementAccessExpression: - return checkIndexedAccess(node as ElementAccessExpression, checkMode); + return checkIndexedAccess( + node as ElementAccessExpression, + checkMode + ); case SyntaxKind.CallExpression: if (isImportCall(node)) { return checkImportCallExpression(node); } - // falls through + // falls through case SyntaxKind.NewExpression: return checkCallExpression(node as CallExpression, checkMode); case SyntaxKind.TaggedTemplateExpression: - return checkTaggedTemplateExpression(node as TaggedTemplateExpression); + return checkTaggedTemplateExpression( + node as TaggedTemplateExpression + ); case SyntaxKind.ParenthesizedExpression: - return checkParenthesizedExpression(node as ParenthesizedExpression, checkMode); + return checkParenthesizedExpression( + node as ParenthesizedExpression, + checkMode + ); case SyntaxKind.ClassExpression: return checkClassExpression(node as ClassExpression); case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: - return checkFunctionExpressionOrObjectLiteralMethod(node as FunctionExpression | ArrowFunction, checkMode); + return checkFunctionExpressionOrObjectLiteralMethod( + node as FunctionExpression | ArrowFunction, + checkMode + ); case SyntaxKind.TypeOfExpression: return checkTypeOfExpression(node as TypeOfExpression); case SyntaxKind.TypeAssertionExpression: @@ -41703,7 +72992,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.NonNullExpression: return checkNonNullAssertion(node as NonNullExpression); case SyntaxKind.ExpressionWithTypeArguments: - return checkExpressionWithTypeArguments(node as ExpressionWithTypeArguments); + return checkExpressionWithTypeArguments( + node as ExpressionWithTypeArguments + ); case SyntaxKind.SatisfiesExpression: return checkSatisfiesExpression(node as SatisfiesExpression); case SyntaxKind.MetaProperty: @@ -41715,13 +73006,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.AwaitExpression: return checkAwaitExpression(node as AwaitExpression); case SyntaxKind.PrefixUnaryExpression: - return checkPrefixUnaryExpression(node as PrefixUnaryExpression); + return checkPrefixUnaryExpression( + node as PrefixUnaryExpression + ); case SyntaxKind.PostfixUnaryExpression: - return checkPostfixUnaryExpression(node as PostfixUnaryExpression); + return checkPostfixUnaryExpression( + node as PostfixUnaryExpression + ); case SyntaxKind.BinaryExpression: - return checkBinaryExpression(node as BinaryExpression, checkMode); + return checkBinaryExpression( + node as BinaryExpression, + checkMode + ); case SyntaxKind.ConditionalExpression: - return checkConditionalExpression(node as ConditionalExpression, checkMode); + return checkConditionalExpression( + node as ConditionalExpression, + checkMode + ); case SyntaxKind.SpreadElement: return checkSpreadExpression(node as SpreadElement, checkMode); case SyntaxKind.OmittedExpression: @@ -41735,7 +73036,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.JsxElement: return checkJsxElement(node as JsxElement, checkMode); case SyntaxKind.JsxSelfClosingElement: - return checkJsxSelfClosingElement(node as JsxSelfClosingElement, checkMode); + return checkJsxSelfClosingElement( + node as JsxSelfClosingElement, + checkMode + ); case SyntaxKind.JsxFragment: return checkJsxFragment(node as JsxFragment); case SyntaxKind.JsxAttributes: @@ -41752,42 +73056,110 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Grammar Checking checkGrammarModifiers(node); if (node.expression) { - grammarErrorOnFirstToken(node.expression, Diagnostics.Type_expected); + grammarErrorOnFirstToken( + node.expression, + Diagnostics.Type_expected + ); } checkSourceElement(node.constraint); checkSourceElement(node.default); - const typeParameter = getDeclaredTypeOfTypeParameter(getSymbolOfDeclaration(node)); + const typeParameter = getDeclaredTypeOfTypeParameter( + getSymbolOfDeclaration(node) + ); // Resolve base constraint to reveal circularity errors getBaseConstraintOfType(typeParameter); if (!hasNonCircularTypeParameterDefault(typeParameter)) { - error(node.default, Diagnostics.Type_parameter_0_has_a_circular_default, typeToString(typeParameter)); + error( + node.default, + Diagnostics.Type_parameter_0_has_a_circular_default, + typeToString(typeParameter) + ); } const constraintType = getConstraintOfTypeParameter(typeParameter); const defaultType = getDefaultFromTypeParameter(typeParameter); if (constraintType && defaultType) { - checkTypeAssignableTo(defaultType, getTypeWithThisArgument(instantiateType(constraintType, makeUnaryTypeMapper(typeParameter, defaultType)), defaultType), node.default, Diagnostics.Type_0_does_not_satisfy_the_constraint_1); + checkTypeAssignableTo( + defaultType, + getTypeWithThisArgument( + instantiateType( + constraintType, + makeUnaryTypeMapper(typeParameter, defaultType) + ), + defaultType + ), + node.default, + Diagnostics.Type_0_does_not_satisfy_the_constraint_1 + ); } checkNodeDeferred(node); - addLazyDiagnostic(() => checkTypeNameIsReserved(node.name, Diagnostics.Type_parameter_name_cannot_be_0)); + addLazyDiagnostic(() => + checkTypeNameIsReserved( + node.name, + Diagnostics.Type_parameter_name_cannot_be_0 + ) + ); } function checkTypeParameterDeferred(node: TypeParameterDeclaration) { - if (isInterfaceDeclaration(node.parent) || isClassLike(node.parent) || isTypeAliasDeclaration(node.parent)) { - const typeParameter = getDeclaredTypeOfTypeParameter(getSymbolOfDeclaration(node)); - const modifiers = getTypeParameterModifiers(typeParameter) & (ModifierFlags.In | ModifierFlags.Out); + if ( + isInterfaceDeclaration(node.parent) || + isClassLike(node.parent) || + isTypeAliasDeclaration(node.parent) + ) { + const typeParameter = getDeclaredTypeOfTypeParameter( + getSymbolOfDeclaration(node) + ); + const modifiers = + getTypeParameterModifiers(typeParameter) & + (ModifierFlags.In | ModifierFlags.Out); if (modifiers) { const symbol = getSymbolOfDeclaration(node.parent); - if (isTypeAliasDeclaration(node.parent) && !(getObjectFlags(getDeclaredTypeOfSymbol(symbol)) & (ObjectFlags.Anonymous | ObjectFlags.Mapped))) { - error(node, Diagnostics.Variance_annotations_are_only_supported_in_type_aliases_for_object_function_constructor_and_mapped_types); - } - else if (modifiers === ModifierFlags.In || modifiers === ModifierFlags.Out) { - tracing?.push(tracing.Phase.CheckTypes, "checkTypeParameterDeferred", { parent: getTypeId(getDeclaredTypeOfSymbol(symbol)), id: getTypeId(typeParameter) }); - const source = createMarkerType(symbol, typeParameter, modifiers === ModifierFlags.Out ? markerSubTypeForCheck : markerSuperTypeForCheck); - const target = createMarkerType(symbol, typeParameter, modifiers === ModifierFlags.Out ? markerSuperTypeForCheck : markerSubTypeForCheck); + if ( + isTypeAliasDeclaration(node.parent) && + !( + getObjectFlags(getDeclaredTypeOfSymbol(symbol)) & + (ObjectFlags.Anonymous | ObjectFlags.Mapped) + ) + ) { + error( + node, + Diagnostics.Variance_annotations_are_only_supported_in_type_aliases_for_object_function_constructor_and_mapped_types + ); + } else if ( + modifiers === ModifierFlags.In || + modifiers === ModifierFlags.Out + ) { + tracing?.push( + tracing.Phase.CheckTypes, + "checkTypeParameterDeferred", + { + parent: getTypeId(getDeclaredTypeOfSymbol(symbol)), + id: getTypeId(typeParameter), + } + ); + const source = createMarkerType( + symbol, + typeParameter, + modifiers === ModifierFlags.Out + ? markerSubTypeForCheck + : markerSuperTypeForCheck + ); + const target = createMarkerType( + symbol, + typeParameter, + modifiers === ModifierFlags.Out + ? markerSuperTypeForCheck + : markerSubTypeForCheck + ); const saveVarianceTypeParameter = typeParameter; varianceTypeParameter = typeParameter; - checkTypeAssignableTo(source, target, node, Diagnostics.Type_0_is_not_assignable_to_type_1_as_implied_by_variance_annotation); + checkTypeAssignableTo( + source, + target, + node, + Diagnostics.Type_0_is_not_assignable_to_type_1_as_implied_by_variance_annotation + ); varianceTypeParameter = saveVarianceTypeParameter; tracing?.pop(); } @@ -41804,38 +73176,98 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkVariableLikeDeclaration(node); const func = getContainingFunction(node)!; - if (hasSyntacticModifier(node, ModifierFlags.ParameterPropertyModifier)) { + if ( + hasSyntacticModifier(node, ModifierFlags.ParameterPropertyModifier) + ) { if (compilerOptions.erasableSyntaxOnly) { - error(node, Diagnostics.This_syntax_is_not_allowed_when_erasableSyntaxOnly_is_enabled); + error( + node, + Diagnostics.This_syntax_is_not_allowed_when_erasableSyntaxOnly_is_enabled + ); } - if (!(func.kind === SyntaxKind.Constructor && nodeIsPresent(func.body))) { - error(node, Diagnostics.A_parameter_property_is_only_allowed_in_a_constructor_implementation); + if ( + !( + func.kind === SyntaxKind.Constructor && + nodeIsPresent(func.body) + ) + ) { + error( + node, + Diagnostics.A_parameter_property_is_only_allowed_in_a_constructor_implementation + ); } - if (func.kind === SyntaxKind.Constructor && isIdentifier(node.name) && node.name.escapedText === "constructor") { - error(node.name, Diagnostics.constructor_cannot_be_used_as_a_parameter_property_name); + if ( + func.kind === SyntaxKind.Constructor && + isIdentifier(node.name) && + node.name.escapedText === "constructor" + ) { + error( + node.name, + Diagnostics.constructor_cannot_be_used_as_a_parameter_property_name + ); } } - if (!node.initializer && isOptionalDeclaration(node) && isBindingPattern(node.name) && (func as FunctionLikeDeclaration).body) { - error(node, Diagnostics.A_binding_pattern_parameter_cannot_be_optional_in_an_implementation_signature); + if ( + !node.initializer && + isOptionalDeclaration(node) && + isBindingPattern(node.name) && + (func as FunctionLikeDeclaration).body + ) { + error( + node, + Diagnostics.A_binding_pattern_parameter_cannot_be_optional_in_an_implementation_signature + ); } - if (node.name && isIdentifier(node.name) && (node.name.escapedText === "this" || node.name.escapedText === "new")) { + if ( + node.name && + isIdentifier(node.name) && + (node.name.escapedText === "this" || + node.name.escapedText === "new") + ) { if (func.parameters.indexOf(node) !== 0) { - error(node, Diagnostics.A_0_parameter_must_be_the_first_parameter, node.name.escapedText as string); + error( + node, + Diagnostics.A_0_parameter_must_be_the_first_parameter, + node.name.escapedText as string + ); } - if (func.kind === SyntaxKind.Constructor || func.kind === SyntaxKind.ConstructSignature || func.kind === SyntaxKind.ConstructorType) { - error(node, Diagnostics.A_constructor_cannot_have_a_this_parameter); + if ( + func.kind === SyntaxKind.Constructor || + func.kind === SyntaxKind.ConstructSignature || + func.kind === SyntaxKind.ConstructorType + ) { + error( + node, + Diagnostics.A_constructor_cannot_have_a_this_parameter + ); } if (func.kind === SyntaxKind.ArrowFunction) { - error(node, Diagnostics.An_arrow_function_cannot_have_a_this_parameter); + error( + node, + Diagnostics.An_arrow_function_cannot_have_a_this_parameter + ); } - if (func.kind === SyntaxKind.GetAccessor || func.kind === SyntaxKind.SetAccessor) { - error(node, Diagnostics.get_and_set_accessors_cannot_declare_this_parameters); + if ( + func.kind === SyntaxKind.GetAccessor || + func.kind === SyntaxKind.SetAccessor + ) { + error( + node, + Diagnostics.get_and_set_accessors_cannot_declare_this_parameters + ); } } // Only check rest parameter type if it's not a binding pattern. Since binding patterns are // not allowed in a rest parameter, we already have an error from checkGrammarParameterList. - if (node.dotDotDotToken && !isBindingPattern(node.name) && !isTypeAssignableTo(getReducedType(getTypeOfSymbol(node.symbol)), anyReadonlyArrayType)) { + if ( + node.dotDotDotToken && + !isBindingPattern(node.name) && + !isTypeAssignableTo( + getReducedType(getTypeOfSymbol(node.symbol)), + anyReadonlyArrayType + ) + ) { error(node, Diagnostics.A_rest_parameter_must_be_of_an_array_type); } } @@ -41844,7 +73276,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const parent = getTypePredicateParent(node); if (!parent) { // The parent must not be valid. - error(node, Diagnostics.A_type_predicate_is_only_allowed_in_return_type_position_for_functions_and_methods); + error( + node, + Diagnostics.A_type_predicate_is_only_allowed_in_return_type_position_for_functions_and_methods + ); return; } @@ -41857,37 +73292,69 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkSourceElement(node.type); const { parameterName } = node; - if (typePredicate.kind !== TypePredicateKind.This && typePredicate.kind !== TypePredicateKind.AssertsThis) { + if ( + typePredicate.kind !== TypePredicateKind.This && + typePredicate.kind !== TypePredicateKind.AssertsThis + ) { if (typePredicate.parameterIndex >= 0) { - if (signatureHasRestParameter(signature) && typePredicate.parameterIndex === signature.parameters.length - 1) { - error(parameterName, Diagnostics.A_type_predicate_cannot_reference_a_rest_parameter); - } - else { + if ( + signatureHasRestParameter(signature) && + typePredicate.parameterIndex === + signature.parameters.length - 1 + ) { + error( + parameterName, + Diagnostics.A_type_predicate_cannot_reference_a_rest_parameter + ); + } else { if (typePredicate.type) { - const leadingError = () => chainDiagnosticMessages(/*details*/ undefined, Diagnostics.A_type_predicate_s_type_must_be_assignable_to_its_parameter_s_type); - checkTypeAssignableTo(typePredicate.type, getTypeOfSymbol(signature.parameters[typePredicate.parameterIndex]), node.type, /*headMessage*/ undefined, leadingError); + const leadingError = () => + chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.A_type_predicate_s_type_must_be_assignable_to_its_parameter_s_type + ); + checkTypeAssignableTo( + typePredicate.type, + getTypeOfSymbol( + signature.parameters[ + typePredicate.parameterIndex + ] + ), + node.type, + /*headMessage*/ undefined, + leadingError + ); } } - } - else if (parameterName) { + } else if (parameterName) { let hasReportedError = false; for (const { name } of parent.parameters) { if ( isBindingPattern(name) && - checkIfTypePredicateVariableIsDeclaredInBindingPattern(name, parameterName, typePredicate.parameterName) + checkIfTypePredicateVariableIsDeclaredInBindingPattern( + name, + parameterName, + typePredicate.parameterName + ) ) { hasReportedError = true; break; } } if (!hasReportedError) { - error(node.parameterName, Diagnostics.Cannot_find_parameter_0, typePredicate.parameterName); + error( + node.parameterName, + Diagnostics.Cannot_find_parameter_0, + typePredicate.parameterName + ); } } } } - function getTypePredicateParent(node: Node): SignatureDeclaration | undefined { + function getTypePredicateParent( + node: Node + ): SignatureDeclaration | undefined { switch (node.parent.kind) { case SyntaxKind.ArrowFunction: case SyntaxKind.CallSignature: @@ -41906,7 +73373,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkIfTypePredicateVariableIsDeclaredInBindingPattern( pattern: BindingPattern, predicateVariableNode: Node, - predicateVariableName: string, + predicateVariableName: string ) { for (const element of pattern.elements) { if (isOmittedExpression(element)) { @@ -41914,16 +73381,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const name = element.name; - if (name.kind === SyntaxKind.Identifier && name.escapedText === predicateVariableName) { - error(predicateVariableNode, Diagnostics.A_type_predicate_cannot_reference_element_0_in_a_binding_pattern, predicateVariableName); + if ( + name.kind === SyntaxKind.Identifier && + name.escapedText === predicateVariableName + ) { + error( + predicateVariableNode, + Diagnostics.A_type_predicate_cannot_reference_element_0_in_a_binding_pattern, + predicateVariableName + ); return true; - } - else if (name.kind === SyntaxKind.ArrayBindingPattern || name.kind === SyntaxKind.ObjectBindingPattern) { + } else if ( + name.kind === SyntaxKind.ArrayBindingPattern || + name.kind === SyntaxKind.ObjectBindingPattern + ) { if ( checkIfTypePredicateVariableIsDeclaredInBindingPattern( name, predicateVariableNode, - predicateVariableName, + predicateVariableName ) ) { return true; @@ -41939,28 +73415,48 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // TODO (yuisu): Remove this check in else-if when SyntaxKind.Construct is moved and ambient context is handled else if ( - node.kind === SyntaxKind.FunctionType || node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.ConstructorType || - node.kind === SyntaxKind.CallSignature || node.kind === SyntaxKind.Constructor || + node.kind === SyntaxKind.FunctionType || + node.kind === SyntaxKind.FunctionDeclaration || + node.kind === SyntaxKind.ConstructorType || + node.kind === SyntaxKind.CallSignature || + node.kind === SyntaxKind.Constructor || node.kind === SyntaxKind.ConstructSignature ) { - checkGrammarFunctionLikeDeclaration(node as FunctionLikeDeclaration); + checkGrammarFunctionLikeDeclaration( + node as FunctionLikeDeclaration + ); } const functionFlags = getFunctionFlags(node as FunctionLikeDeclaration); if (!(functionFlags & FunctionFlags.Invalid)) { // Async generators prior to ES2018 require the __await and __asyncGenerator helpers - if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.AsyncGenerator && languageVersion < LanguageFeatureMinimumTarget.AsyncGenerators) { - checkExternalEmitHelpers(node, ExternalEmitHelpers.AsyncGeneratorIncludes); + if ( + (functionFlags & FunctionFlags.AsyncGenerator) === + FunctionFlags.AsyncGenerator && + languageVersion < LanguageFeatureMinimumTarget.AsyncGenerators + ) { + checkExternalEmitHelpers( + node, + ExternalEmitHelpers.AsyncGeneratorIncludes + ); } // Async functions prior to ES2017 require the __awaiter helper - if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async && languageVersion < LanguageFeatureMinimumTarget.AsyncFunctions) { + if ( + (functionFlags & FunctionFlags.AsyncGenerator) === + FunctionFlags.Async && + languageVersion < LanguageFeatureMinimumTarget.AsyncFunctions + ) { checkExternalEmitHelpers(node, ExternalEmitHelpers.Awaiter); } // Generator functions, Async functions, and Async Generator functions prior to // ES2015 require the __generator helper - if ((functionFlags & FunctionFlags.AsyncGenerator) !== FunctionFlags.Normal && languageVersion < LanguageFeatureMinimumTarget.Generators) { + if ( + (functionFlags & FunctionFlags.AsyncGenerator) !== + FunctionFlags.Normal && + languageVersion < LanguageFeatureMinimumTarget.Generators + ) { checkExternalEmitHelpers(node, ExternalEmitHelpers.Generator); } } @@ -41985,10 +73481,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isInJSFile(node)) { const typeTag = getJSDocTypeTag(node); - if (typeTag && typeTag.typeExpression && isTypeReferenceNode(typeTag.typeExpression.type)) { - const signature = getSingleCallSignature(getTypeFromTypeNode(typeTag.typeExpression)); + if ( + typeTag && + typeTag.typeExpression && + isTypeReferenceNode(typeTag.typeExpression.type) + ) { + const signature = getSingleCallSignature( + getTypeFromTypeNode(typeTag.typeExpression) + ); if (signature && signature.declaration) { - returnTypeNode = getEffectiveReturnTypeNode(signature.declaration); + returnTypeNode = getEffectiveReturnTypeNode( + signature.declaration + ); returnTypeErrorLocation = typeTag.typeExpression.type; } } @@ -41997,48 +73501,103 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (noImplicitAny && !returnTypeNode) { switch (node.kind) { case SyntaxKind.ConstructSignature: - error(node, Diagnostics.Construct_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type); + error( + node, + Diagnostics.Construct_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type + ); break; case SyntaxKind.CallSignature: - error(node, Diagnostics.Call_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type); + error( + node, + Diagnostics.Call_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type + ); break; } } if (returnTypeNode && returnTypeErrorLocation) { - const functionFlags = getFunctionFlags(node as FunctionDeclaration); - if ((functionFlags & (FunctionFlags.Invalid | FunctionFlags.Generator)) === FunctionFlags.Generator) { + const functionFlags = getFunctionFlags( + node as FunctionDeclaration + ); + if ( + (functionFlags & + (FunctionFlags.Invalid | FunctionFlags.Generator)) === + FunctionFlags.Generator + ) { const returnType = getTypeFromTypeNode(returnTypeNode); if (returnType === voidType) { - error(returnTypeErrorLocation, Diagnostics.A_generator_cannot_have_a_void_type_annotation); - } - else { - checkGeneratorInstantiationAssignabilityToReturnType(returnType, functionFlags, returnTypeErrorLocation); + error( + returnTypeErrorLocation, + Diagnostics.A_generator_cannot_have_a_void_type_annotation + ); + } else { + checkGeneratorInstantiationAssignabilityToReturnType( + returnType, + functionFlags, + returnTypeErrorLocation + ); } - } - else if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async) { - checkAsyncFunctionReturnType(node as FunctionLikeDeclaration, returnTypeNode, returnTypeErrorLocation); + } else if ( + (functionFlags & FunctionFlags.AsyncGenerator) === + FunctionFlags.Async + ) { + checkAsyncFunctionReturnType( + node as FunctionLikeDeclaration, + returnTypeNode, + returnTypeErrorLocation + ); } } - if (node.kind !== SyntaxKind.IndexSignature && node.kind !== SyntaxKind.JSDocFunctionType) { + if ( + node.kind !== SyntaxKind.IndexSignature && + node.kind !== SyntaxKind.JSDocFunctionType + ) { registerForUnusedIdentifiersCheck(node); } } } - function checkGeneratorInstantiationAssignabilityToReturnType(returnType: Type, functionFlags: FunctionFlags, errorNode?: TypeNode) { + function checkGeneratorInstantiationAssignabilityToReturnType( + returnType: Type, + functionFlags: FunctionFlags, + errorNode?: TypeNode + ) { // Naively, one could check that Generator is assignable to the return type annotation. // However, that would not catch the error in the following case. // // interface BadGenerator extends Iterable, Iterator { } // function* g(): BadGenerator { } // Iterable and Iterator have different types! // - const generatorYieldType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Yield, returnType, (functionFlags & FunctionFlags.Async) !== 0) || anyType; - const generatorReturnType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, returnType, (functionFlags & FunctionFlags.Async) !== 0) || generatorYieldType; - const generatorNextType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Next, returnType, (functionFlags & FunctionFlags.Async) !== 0) || unknownType; - const generatorInstantiation = createGeneratorType(generatorYieldType, generatorReturnType, generatorNextType, !!(functionFlags & FunctionFlags.Async)); + const generatorYieldType = + getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Yield, + returnType, + (functionFlags & FunctionFlags.Async) !== 0 + ) || anyType; + const generatorReturnType = + getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Return, + returnType, + (functionFlags & FunctionFlags.Async) !== 0 + ) || generatorYieldType; + const generatorNextType = + getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Next, + returnType, + (functionFlags & FunctionFlags.Async) !== 0 + ) || unknownType; + const generatorInstantiation = createGeneratorType( + generatorYieldType, + generatorReturnType, + generatorNextType, + !!(functionFlags & FunctionFlags.Async) + ); - return checkTypeAssignableTo(generatorInstantiation, returnType, errorNode); + return checkTypeAssignableTo( + generatorInstantiation, + returnType, + errorNode + ); } function checkClassForDuplicateDeclarations(node: ClassLikeDeclaration) { @@ -42048,72 +73607,129 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const privateIdentifiers = new Map<__String, DeclarationMeaning>(); for (const member of node.members) { if (member.kind === SyntaxKind.Constructor) { - for (const param of (member as ConstructorDeclaration).parameters) { - if (isParameterPropertyDeclaration(param, member) && !isBindingPattern(param.name)) { - addName(instanceNames, param.name, param.name.escapedText, DeclarationMeaning.GetOrSetAccessor); + for (const param of (member as ConstructorDeclaration) + .parameters) { + if ( + isParameterPropertyDeclaration(param, member) && + !isBindingPattern(param.name) + ) { + addName( + instanceNames, + param.name, + param.name.escapedText, + DeclarationMeaning.GetOrSetAccessor + ); } } - } - else { + } else { const isStaticMember = isStatic(member); const name = member.name; if (!name) { continue; } const isPrivate = isPrivateIdentifier(name); - const privateStaticFlags = isPrivate && isStaticMember ? DeclarationMeaning.PrivateStatic : 0; - const names = isPrivate ? privateIdentifiers : - isStaticMember ? staticNames : - instanceNames; - - const memberName = name && getEffectivePropertyNameForPropertyNameNode(name); + const privateStaticFlags = + isPrivate && isStaticMember + ? DeclarationMeaning.PrivateStatic + : 0; + const names = isPrivate + ? privateIdentifiers + : isStaticMember + ? staticNames + : instanceNames; + + const memberName = + name && getEffectivePropertyNameForPropertyNameNode(name); if (memberName) { switch (member.kind) { case SyntaxKind.GetAccessor: - addName(names, name, memberName, DeclarationMeaning.GetAccessor | privateStaticFlags); + addName( + names, + name, + memberName, + DeclarationMeaning.GetAccessor | + privateStaticFlags + ); break; case SyntaxKind.SetAccessor: - addName(names, name, memberName, DeclarationMeaning.SetAccessor | privateStaticFlags); + addName( + names, + name, + memberName, + DeclarationMeaning.SetAccessor | + privateStaticFlags + ); break; case SyntaxKind.PropertyDeclaration: - addName(names, name, memberName, DeclarationMeaning.GetOrSetAccessor | privateStaticFlags); + addName( + names, + name, + memberName, + DeclarationMeaning.GetOrSetAccessor | + privateStaticFlags + ); break; case SyntaxKind.MethodDeclaration: - addName(names, name, memberName, DeclarationMeaning.Method | privateStaticFlags); + addName( + names, + name, + memberName, + DeclarationMeaning.Method | privateStaticFlags + ); break; } } } } - function addName(names: Map<__String, DeclarationMeaning>, location: Node, name: __String, meaning: DeclarationMeaning) { + function addName( + names: Map<__String, DeclarationMeaning>, + location: Node, + name: __String, + meaning: DeclarationMeaning + ) { const prev = names.get(name); if (prev) { // For private identifiers, do not allow mixing of static and instance members with the same name - if ((prev & DeclarationMeaning.PrivateStatic) !== (meaning & DeclarationMeaning.PrivateStatic)) { - error(location, Diagnostics.Duplicate_identifier_0_Static_and_instance_elements_cannot_share_the_same_private_name, getTextOfNode(location)); - } - else { + if ( + (prev & DeclarationMeaning.PrivateStatic) !== + (meaning & DeclarationMeaning.PrivateStatic) + ) { + error( + location, + Diagnostics.Duplicate_identifier_0_Static_and_instance_elements_cannot_share_the_same_private_name, + getTextOfNode(location) + ); + } else { const prevIsMethod = !!(prev & DeclarationMeaning.Method); const isMethod = !!(meaning & DeclarationMeaning.Method); if (prevIsMethod || isMethod) { if (prevIsMethod !== isMethod) { - error(location, Diagnostics.Duplicate_identifier_0, getTextOfNode(location)); + error( + location, + Diagnostics.Duplicate_identifier_0, + getTextOfNode(location) + ); } // If this is a method/method duplication is might be an overload, so this will be handled when overloads are considered - } - else if (prev & meaning & ~DeclarationMeaning.PrivateStatic) { - error(location, Diagnostics.Duplicate_identifier_0, getTextOfNode(location)); - } - else { + } else if ( + prev & + meaning & + ~DeclarationMeaning.PrivateStatic + ) { + error( + location, + Diagnostics.Duplicate_identifier_0, + getTextOfNode(location) + ); + } else { names.set(name, prev | meaning); } } - } - else { + } else { names.set(name, meaning); } } @@ -42130,12 +73746,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @see http://www.ecma-international.org/ecma-262/6.0/#sec-properties-of-the-function-constructor * @see http://www.ecma-international.org/ecma-262/6.0/#sec-function-instances */ - function checkClassForStaticPropertyNameConflicts(node: ClassLikeDeclaration) { + function checkClassForStaticPropertyNameConflicts( + node: ClassLikeDeclaration + ) { for (const member of node.members) { const memberNameNode = member.name; const isStaticMember = isStatic(member); if (isStaticMember && memberNameNode) { - const memberName = getEffectivePropertyNameForPropertyNameNode(memberNameNode); + const memberName = + getEffectivePropertyNameForPropertyNameNode(memberNameNode); switch (memberName) { case "name": case "length": @@ -42144,10 +73763,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (useDefineForClassFields) { break; } - // fall through + // fall through case "prototype": - const message = Diagnostics.Static_property_0_conflicts_with_built_in_property_Function_0_of_constructor_function_1; - const className = getNameOfSymbolAsWritten(getSymbolOfDeclaration(node)); + const message = + Diagnostics.Static_property_0_conflicts_with_built_in_property_Function_0_of_constructor_function_1; + const className = getNameOfSymbolAsWritten( + getSymbolOfDeclaration(node) + ); error(memberNameNode, message, memberName, className); break; } @@ -42155,7 +73777,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function checkObjectTypeForDuplicateDeclarations(node: TypeLiteralNode | InterfaceDeclaration) { + function checkObjectTypeForDuplicateDeclarations( + node: TypeLiteralNode | InterfaceDeclaration + ) { const names = new Map(); for (const member of node.members) { if (member.kind === SyntaxKind.PropertySignature) { @@ -42174,22 +73798,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (names.get(memberName)) { - error(getNameOfDeclaration(member.symbol.valueDeclaration), Diagnostics.Duplicate_identifier_0, memberName); - error(member.name, Diagnostics.Duplicate_identifier_0, memberName); - } - else { + error( + getNameOfDeclaration(member.symbol.valueDeclaration), + Diagnostics.Duplicate_identifier_0, + memberName + ); + error( + member.name, + Diagnostics.Duplicate_identifier_0, + memberName + ); + } else { names.set(memberName, true); } } } } - function checkTypeForDuplicateIndexSignatures(node: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode) { + function checkTypeForDuplicateIndexSignatures( + node: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode + ) { if (node.kind === SyntaxKind.InterfaceDeclaration) { const nodeSymbol = getSymbolOfDeclaration(node); // in case of merging interface declaration it is possible that we'll enter this check procedure several times for every declaration // to prevent this run check only for the first declaration of a given kind - if (nodeSymbol.declarations && nodeSymbol.declarations.length > 0 && nodeSymbol.declarations[0] !== node) { + if ( + nodeSymbol.declarations && + nodeSymbol.declarations.length > 0 && + nodeSymbol.declarations[0] !== node + ) { return; } } @@ -42199,103 +73836,173 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // 8.5: A class declaration can have at most one string index member declaration and one numeric index member declaration const indexSymbol = getIndexSymbol(getSymbolOfDeclaration(node)); if (indexSymbol?.declarations) { - const indexSignatureMap = new Map(); + const indexSignatureMap = new Map< + TypeId, + { type: Type; declarations: IndexSignatureDeclaration[] } + >(); for (const declaration of indexSymbol.declarations) { if (isIndexSignatureDeclaration(declaration)) { - if (declaration.parameters.length === 1 && declaration.parameters[0].type) { - forEachType(getTypeFromTypeNode(declaration.parameters[0].type), type => { - const entry = indexSignatureMap.get(getTypeId(type)); - if (entry) { - entry.declarations.push(declaration); - } - else { - indexSignatureMap.set(getTypeId(type), { type, declarations: [declaration] }); + if ( + declaration.parameters.length === 1 && + declaration.parameters[0].type + ) { + forEachType( + getTypeFromTypeNode(declaration.parameters[0].type), + (type) => { + const entry = indexSignatureMap.get( + getTypeId(type) + ); + if (entry) { + entry.declarations.push(declaration); + } else { + indexSignatureMap.set(getTypeId(type), { + type, + declarations: [declaration], + }); + } } - }); + ); } } // Do nothing for late-bound index signatures: allow these to duplicate one another and explicit indexes } - indexSignatureMap.forEach(entry => { + indexSignatureMap.forEach((entry) => { if (entry.declarations.length > 1) { for (const declaration of entry.declarations) { - error(declaration, Diagnostics.Duplicate_index_signature_for_type_0, typeToString(entry.type)); + error( + declaration, + Diagnostics.Duplicate_index_signature_for_type_0, + typeToString(entry.type) + ); } } }); } } - function checkPropertyDeclaration(node: PropertyDeclaration | PropertySignature) { + function checkPropertyDeclaration( + node: PropertyDeclaration | PropertySignature + ) { // Grammar checking - if (!checkGrammarModifiers(node) && !checkGrammarProperty(node)) checkGrammarComputedPropertyName(node.name); + if (!checkGrammarModifiers(node) && !checkGrammarProperty(node)) + checkGrammarComputedPropertyName(node.name); checkVariableLikeDeclaration(node); setNodeLinksForPrivateIdentifierScope(node); // property signatures already report "initializer not allowed in ambient context" elsewhere - if (hasSyntacticModifier(node, ModifierFlags.Abstract) && node.kind === SyntaxKind.PropertyDeclaration && node.initializer) { - error(node, Diagnostics.Property_0_cannot_have_an_initializer_because_it_is_marked_abstract, declarationNameToString(node.name)); + if ( + hasSyntacticModifier(node, ModifierFlags.Abstract) && + node.kind === SyntaxKind.PropertyDeclaration && + node.initializer + ) { + error( + node, + Diagnostics.Property_0_cannot_have_an_initializer_because_it_is_marked_abstract, + declarationNameToString(node.name) + ); } } function checkPropertySignature(node: PropertySignature) { if (isPrivateIdentifier(node.name)) { - error(node, Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies); + error( + node, + Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies + ); } return checkPropertyDeclaration(node); } function checkMethodDeclaration(node: MethodDeclaration | MethodSignature) { // Grammar checking - if (!checkGrammarMethod(node)) checkGrammarComputedPropertyName(node.name); + if (!checkGrammarMethod(node)) + checkGrammarComputedPropertyName(node.name); - if (isMethodDeclaration(node) && node.asteriskToken && isIdentifier(node.name) && idText(node.name) === "constructor") { - error(node.name, Diagnostics.Class_constructor_may_not_be_a_generator); + if ( + isMethodDeclaration(node) && + node.asteriskToken && + isIdentifier(node.name) && + idText(node.name) === "constructor" + ) { + error( + node.name, + Diagnostics.Class_constructor_may_not_be_a_generator + ); } // Grammar checking for modifiers is done inside the function checkGrammarFunctionLikeDeclaration checkFunctionOrMethodDeclaration(node); // method signatures already report "implementation not allowed in ambient context" elsewhere - if (hasSyntacticModifier(node, ModifierFlags.Abstract) && node.kind === SyntaxKind.MethodDeclaration && node.body) { - error(node, Diagnostics.Method_0_cannot_have_an_implementation_because_it_is_marked_abstract, declarationNameToString(node.name)); + if ( + hasSyntacticModifier(node, ModifierFlags.Abstract) && + node.kind === SyntaxKind.MethodDeclaration && + node.body + ) { + error( + node, + Diagnostics.Method_0_cannot_have_an_implementation_because_it_is_marked_abstract, + declarationNameToString(node.name) + ); } // Private named methods are only allowed in class declarations if (isPrivateIdentifier(node.name) && !getContainingClass(node)) { - error(node, Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies); + error( + node, + Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies + ); } setNodeLinksForPrivateIdentifierScope(node); } - function setNodeLinksForPrivateIdentifierScope(node: PropertyDeclaration | PropertySignature | MethodDeclaration | MethodSignature | AccessorDeclaration) { + function setNodeLinksForPrivateIdentifierScope( + node: + | PropertyDeclaration + | PropertySignature + | MethodDeclaration + | MethodSignature + | AccessorDeclaration + ) { if (isPrivateIdentifier(node.name)) { if ( - languageVersion < LanguageFeatureMinimumTarget.PrivateNamesAndClassStaticBlocks || - languageVersion < LanguageFeatureMinimumTarget.ClassAndClassElementDecorators || + languageVersion < + LanguageFeatureMinimumTarget.PrivateNamesAndClassStaticBlocks || + languageVersion < + LanguageFeatureMinimumTarget.ClassAndClassElementDecorators || !useDefineForClassFields ) { - for (let lexicalScope = getEnclosingBlockScopeContainer(node); !!lexicalScope; lexicalScope = getEnclosingBlockScopeContainer(lexicalScope)) { - getNodeLinks(lexicalScope).flags |= NodeCheckFlags.ContainsClassWithPrivateIdentifiers; + for ( + let lexicalScope = getEnclosingBlockScopeContainer(node); + !!lexicalScope; + lexicalScope = getEnclosingBlockScopeContainer(lexicalScope) + ) { + getNodeLinks(lexicalScope).flags |= + NodeCheckFlags.ContainsClassWithPrivateIdentifiers; } // If this is a private element in a class expression inside the body of a loop, // then we must use a block-scoped binding to store the additional variables required // to transform private elements. if (isClassExpression(node.parent)) { - const enclosingIterationStatement = getEnclosingIterationStatement(node.parent); + const enclosingIterationStatement = + getEnclosingIterationStatement(node.parent); if (enclosingIterationStatement) { - getNodeLinks(node.name).flags |= NodeCheckFlags.BlockScopedBindingInLoop; - getNodeLinks(enclosingIterationStatement).flags |= NodeCheckFlags.LoopWithCapturedBlockScopedBinding; + getNodeLinks(node.name).flags |= + NodeCheckFlags.BlockScopedBindingInLoop; + getNodeLinks(enclosingIterationStatement).flags |= + NodeCheckFlags.LoopWithCapturedBlockScopedBinding; } } } } } - function checkClassStaticBlockDeclaration(node: ClassStaticBlockDeclaration) { + function checkClassStaticBlockDeclaration( + node: ClassStaticBlockDeclaration + ) { checkGrammarModifiers(node); forEachChild(node, checkSourceElement); @@ -42305,7 +74012,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Grammar check on signature of constructor and modifier of the constructor is done in checkSignatureDeclaration function. checkSignatureDeclaration(node); // Grammar check for checking only related to constructorDeclaration - if (!checkGrammarConstructorTypeParameters(node)) checkGrammarConstructorTypeAnnotation(node); + if (!checkGrammarConstructorTypeParameters(node)) + checkGrammarConstructorTypeAnnotation(node); checkSourceElement(node.body); @@ -42326,13 +74034,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return; - function isInstancePropertyWithInitializerOrPrivateIdentifierProperty(n: Node): boolean { + function isInstancePropertyWithInitializerOrPrivateIdentifierProperty( + n: Node + ): boolean { if (isPrivateIdentifierClassElementDeclaration(n)) { return true; } - return n.kind === SyntaxKind.PropertyDeclaration && + return ( + n.kind === SyntaxKind.PropertyDeclaration && !isStatic(n) && - !!(n as PropertyDeclaration).initializer; + !!(n as PropertyDeclaration).initializer + ); } function checkConstructorDeclarationDiagnostics() { @@ -42342,11 +74054,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const containingClassDecl = node.parent; if (getClassExtendsHeritageElement(containingClassDecl)) { captureLexicalThis(node.parent, containingClassDecl); - const classExtendsNull = classDeclarationExtendsNull(containingClassDecl); + const classExtendsNull = + classDeclarationExtendsNull(containingClassDecl); const superCall = findFirstSuperCall(node.body!); if (superCall) { if (classExtendsNull) { - error(superCall, Diagnostics.A_constructor_cannot_contain_a_super_call_when_its_class_extends_null); + error( + superCall, + Diagnostics.A_constructor_cannot_contain_a_super_call_when_its_class_extends_null + ); } // A super call must be root-level in a constructor if both of the following are true: @@ -42354,26 +74070,56 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // - The constructor declares parameter properties // or the containing class declares instance member variables with initializers. - const superCallShouldBeRootLevel = !emitStandardClassFields && - (some(node.parent.members, isInstancePropertyWithInitializerOrPrivateIdentifierProperty) || - some(node.parameters, p => hasSyntacticModifier(p, ModifierFlags.ParameterPropertyModifier))); + const superCallShouldBeRootLevel = + !emitStandardClassFields && + (some( + node.parent.members, + isInstancePropertyWithInitializerOrPrivateIdentifierProperty + ) || + some(node.parameters, (p) => + hasSyntacticModifier( + p, + ModifierFlags.ParameterPropertyModifier + ) + )); if (superCallShouldBeRootLevel) { // Until we have better flow analysis, it is an error to place the super call within any kind of block or conditional // See GH #8277 - if (!superCallIsRootLevelInConstructor(superCall, node.body!)) { - 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); + if ( + !superCallIsRootLevelInConstructor( + superCall, + node.body! + ) + ) { + 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 + ); } // Skip past any prologue directives to check statements for referring to 'super' or 'this' before a super call else { - let superCallStatement: ExpressionStatement | undefined; + let superCallStatement: + | ExpressionStatement + | undefined; for (const statement of node.body!.statements) { - if (isExpressionStatement(statement) && isSuperCall(skipOuterExpressions(statement.expression))) { + if ( + isExpressionStatement(statement) && + isSuperCall( + skipOuterExpressions( + statement.expression + ) + ) + ) { superCallStatement = statement; break; } - if (nodeImmediatelyReferencesSuperOrThis(statement)) { + if ( + nodeImmediatelyReferencesSuperOrThis( + statement + ) + ) { break; } } @@ -42381,25 +74127,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Until we have better flow analysis, it is an error to place the super call within any kind of block or conditional // See GH #8277 if (superCallStatement === undefined) { - 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); + 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 + ); } } } - } - else if (!classExtendsNull) { - error(node, Diagnostics.Constructors_for_derived_classes_must_contain_a_super_call); + } else if (!classExtendsNull) { + error( + node, + Diagnostics.Constructors_for_derived_classes_must_contain_a_super_call + ); } } } } function superCallIsRootLevelInConstructor(superCall: Node, body: Block) { - const superCallParent = walkUpParenthesizedExpressions(superCall.parent); - return isExpressionStatement(superCallParent) && superCallParent.parent === body; + const superCallParent = walkUpParenthesizedExpressions( + superCall.parent + ); + return ( + isExpressionStatement(superCallParent) && + superCallParent.parent === body + ); } function nodeImmediatelyReferencesSuperOrThis(node: Node): boolean { - if (node.kind === SyntaxKind.SuperKeyword || node.kind === SyntaxKind.ThisKeyword) { + if ( + node.kind === SyntaxKind.SuperKeyword || + node.kind === SyntaxKind.ThisKeyword + ) { return true; } @@ -42411,8 +74170,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkAccessorDeclaration(node: AccessorDeclaration) { - if (isIdentifier(node.name) && idText(node.name) === "constructor" && isClassLike(node.parent)) { - error(node.name, Diagnostics.Class_constructor_may_not_be_an_accessor); + if ( + isIdentifier(node.name) && + idText(node.name) === "constructor" && + isClassLike(node.parent) + ) { + error( + node.name, + Diagnostics.Class_constructor_may_not_be_an_accessor + ); } addLazyDiagnostic(checkAccessorDeclarationDiagnostics); checkSourceElement(node.body); @@ -42420,14 +74186,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkAccessorDeclarationDiagnostics() { // Grammar checking accessors - if (!checkGrammarFunctionLikeDeclaration(node) && !checkGrammarAccessor(node)) checkGrammarComputedPropertyName(node.name); + if ( + !checkGrammarFunctionLikeDeclaration(node) && + !checkGrammarAccessor(node) + ) + checkGrammarComputedPropertyName(node.name); checkDecorators(node); checkSignatureDeclaration(node); if (node.kind === SyntaxKind.GetAccessor) { - if (!(node.flags & NodeFlags.Ambient) && nodeIsPresent(node.body) && (node.flags & NodeFlags.HasImplicitReturn)) { + if ( + !(node.flags & NodeFlags.Ambient) && + nodeIsPresent(node.body) && + node.flags & NodeFlags.HasImplicitReturn + ) { if (!(node.flags & NodeFlags.HasExplicitReturn)) { - error(node.name, Diagnostics.A_get_accessor_must_return_a_value); + error( + node.name, + Diagnostics.A_get_accessor_must_return_a_value + ); } } } @@ -42442,28 +74219,62 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // TypeScript 1.0 spec (April 2014): 8.4.3 // Accessors for the same member name must specify the same accessibility. const symbol = getSymbolOfDeclaration(node); - const getter = getDeclarationOfKind(symbol, SyntaxKind.GetAccessor); - const setter = getDeclarationOfKind(symbol, SyntaxKind.SetAccessor); - if (getter && setter && !(getNodeCheckFlags(getter) & NodeCheckFlags.TypeChecked)) { + const getter = getDeclarationOfKind( + symbol, + SyntaxKind.GetAccessor + ); + const setter = getDeclarationOfKind( + symbol, + SyntaxKind.SetAccessor + ); + if ( + getter && + setter && + !(getNodeCheckFlags(getter) & NodeCheckFlags.TypeChecked) + ) { getNodeLinks(getter).flags |= NodeCheckFlags.TypeChecked; const getterFlags = getEffectiveModifierFlags(getter); const setterFlags = getEffectiveModifierFlags(setter); - if ((getterFlags & ModifierFlags.Abstract) !== (setterFlags & ModifierFlags.Abstract)) { - error(getter.name, Diagnostics.Accessors_must_both_be_abstract_or_non_abstract); - error(setter.name, Diagnostics.Accessors_must_both_be_abstract_or_non_abstract); + if ( + (getterFlags & ModifierFlags.Abstract) !== + (setterFlags & ModifierFlags.Abstract) + ) { + error( + getter.name, + Diagnostics.Accessors_must_both_be_abstract_or_non_abstract + ); + error( + setter.name, + Diagnostics.Accessors_must_both_be_abstract_or_non_abstract + ); } if ( - ((getterFlags & ModifierFlags.Protected) && !(setterFlags & (ModifierFlags.Protected | ModifierFlags.Private))) || - ((getterFlags & ModifierFlags.Private) && !(setterFlags & ModifierFlags.Private)) + (getterFlags & ModifierFlags.Protected && + !( + setterFlags & + (ModifierFlags.Protected | + ModifierFlags.Private) + )) || + (getterFlags & ModifierFlags.Private && + !(setterFlags & ModifierFlags.Private)) ) { - error(getter.name, Diagnostics.A_get_accessor_must_be_at_least_as_accessible_as_the_setter); - error(setter.name, Diagnostics.A_get_accessor_must_be_at_least_as_accessible_as_the_setter); + error( + getter.name, + Diagnostics.A_get_accessor_must_be_at_least_as_accessible_as_the_setter + ); + error( + setter.name, + Diagnostics.A_get_accessor_must_be_at_least_as_accessible_as_the_setter + ); } } } const returnType = getTypeOfAccessors(getSymbolOfDeclaration(node)); if (node.kind === SyntaxKind.GetAccessor) { - checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, returnType); + checkAllCodePathsInNonVoidFunctionReturnOrThrow( + node, + returnType + ); } } } @@ -42472,18 +74283,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkDecorators(node); } - function getEffectiveTypeArgumentAtIndex(node: TypeReferenceNode | ExpressionWithTypeArguments, typeParameters: readonly TypeParameter[], index: number): Type { + function getEffectiveTypeArgumentAtIndex( + node: TypeReferenceNode | ExpressionWithTypeArguments, + typeParameters: readonly TypeParameter[], + index: number + ): Type { if (node.typeArguments && index < node.typeArguments.length) { return getTypeFromTypeNode(node.typeArguments[index]); } return getEffectiveTypeArguments(node, typeParameters)[index]; } - function getEffectiveTypeArguments(node: TypeReferenceNode | ExpressionWithTypeArguments | NodeWithTypeArguments, typeParameters: readonly TypeParameter[]): Type[] { - return fillMissingTypeArguments(map(node.typeArguments!, getTypeFromTypeNode), typeParameters, getMinTypeArgumentCount(typeParameters), isInJSFile(node)); + function getEffectiveTypeArguments( + node: + | TypeReferenceNode + | ExpressionWithTypeArguments + | NodeWithTypeArguments, + typeParameters: readonly TypeParameter[] + ): Type[] { + return fillMissingTypeArguments( + map(node.typeArguments!, getTypeFromTypeNode), + typeParameters, + getMinTypeArgumentCount(typeParameters), + isInJSFile(node) + ); } - function checkTypeArgumentConstraints(node: TypeReferenceNode | ExpressionWithTypeArguments | NodeWithTypeArguments, typeParameters: readonly TypeParameter[]): boolean { + function checkTypeArgumentConstraints( + node: + | TypeReferenceNode + | ExpressionWithTypeArguments + | NodeWithTypeArguments, + typeParameters: readonly TypeParameter[] + ): boolean { let typeArguments: Type[] | undefined; let mapper: TypeMapper | undefined; let result = true; @@ -42491,15 +74323,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const constraint = getConstraintOfTypeParameter(typeParameters[i]); if (constraint) { if (!typeArguments) { - typeArguments = getEffectiveTypeArguments(node, typeParameters); + typeArguments = getEffectiveTypeArguments( + node, + typeParameters + ); mapper = createTypeMapper(typeParameters, typeArguments); } - result = result && checkTypeAssignableTo( - typeArguments[i], - instantiateType(constraint, mapper), - node.typeArguments![i], - Diagnostics.Type_0_does_not_satisfy_the_constraint_1, - ); + result = + result && + checkTypeAssignableTo( + typeArguments[i], + instantiateType(constraint, mapper), + node.typeArguments![i], + Diagnostics.Type_0_does_not_satisfy_the_constraint_1 + ); } } return result; @@ -42507,13 +74344,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getTypeParametersForTypeAndSymbol(type: Type, symbol: Symbol) { if (!isErrorType(type)) { - return symbol.flags & SymbolFlags.TypeAlias && getSymbolLinks(symbol).typeParameters || - (getObjectFlags(type) & ObjectFlags.Reference ? (type as TypeReference).target.localTypeParameters : undefined); + return ( + (symbol.flags & SymbolFlags.TypeAlias && + getSymbolLinks(symbol).typeParameters) || + (getObjectFlags(type) & ObjectFlags.Reference + ? (type as TypeReference).target.localTypeParameters + : undefined) + ); } return undefined; } - function getTypeParametersForTypeReferenceOrImport(node: TypeReferenceNode | ExpressionWithTypeArguments | ImportTypeNode) { + function getTypeParametersForTypeReferenceOrImport( + node: TypeReferenceNode | ExpressionWithTypeArguments | ImportTypeNode + ) { const type = getTypeFromTypeNode(node); if (!isErrorType(type)) { const symbol = getNodeLinks(node).resolvedSymbol; @@ -42524,25 +74368,44 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - function checkTypeReferenceNode(node: TypeReferenceNode | ExpressionWithTypeArguments) { + function checkTypeReferenceNode( + node: TypeReferenceNode | ExpressionWithTypeArguments + ) { checkGrammarTypeArguments(node, node.typeArguments); - if (node.kind === SyntaxKind.TypeReference && !isInJSFile(node) && !isInJSDoc(node) && node.typeArguments && node.typeName.end !== node.typeArguments.pos) { + if ( + node.kind === SyntaxKind.TypeReference && + !isInJSFile(node) && + !isInJSDoc(node) && + node.typeArguments && + node.typeName.end !== node.typeArguments.pos + ) { // If there was a token between the type name and the type arguments, check if it was a DotToken const sourceFile = getSourceFileOfNode(node); - if (scanTokenAtPosition(sourceFile, node.typeName.end) === SyntaxKind.DotToken) { - grammarErrorAtPos(node, skipTrivia(sourceFile.text, node.typeName.end), 1, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments); + if ( + scanTokenAtPosition(sourceFile, node.typeName.end) === + SyntaxKind.DotToken + ) { + grammarErrorAtPos( + node, + skipTrivia(sourceFile.text, node.typeName.end), + 1, + Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments + ); } } forEach(node.typeArguments, checkSourceElement); checkTypeReferenceOrImport(node); } - function checkTypeReferenceOrImport(node: TypeReferenceNode | ExpressionWithTypeArguments | ImportTypeNode) { + function checkTypeReferenceOrImport( + node: TypeReferenceNode | ExpressionWithTypeArguments | ImportTypeNode + ) { const type = getTypeFromTypeNode(node); if (!isErrorType(type)) { if (node.typeArguments) { addLazyDiagnostic(() => { - const typeParameters = getTypeParametersForTypeReferenceOrImport(node); + const typeParameters = + getTypeParametersForTypeReferenceOrImport(node); if (typeParameters) { checkTypeArgumentConstraints(node, typeParameters); } @@ -42550,11 +74413,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const symbol = getNodeLinks(node).resolvedSymbol; if (symbol) { - if (some(symbol.declarations, d => isTypeDeclaration(d) && !!(d.flags & NodeFlags.Deprecated))) { + if ( + some( + symbol.declarations, + (d) => + isTypeDeclaration(d) && + !!(d.flags & NodeFlags.Deprecated) + ) + ) { addDeprecatedSuggestion( getDeprecatedSuggestionNode(node), symbol.declarations!, - symbol.escapedName as string, + symbol.escapedName as string ); } } @@ -42564,10 +74434,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getTypeArgumentConstraint(node: TypeNode): Type | undefined { const typeReferenceNode = tryCast(node.parent, isTypeReferenceType); if (!typeReferenceNode) return undefined; - const typeParameters = getTypeParametersForTypeReferenceOrImport(typeReferenceNode); + const typeParameters = + getTypeParametersForTypeReferenceOrImport(typeReferenceNode); if (!typeParameters) return undefined; - const constraint = getConstraintOfTypeParameter(typeParameters[typeReferenceNode.typeArguments!.indexOf(node)]); - return constraint && instantiateType(constraint, createTypeMapper(typeParameters, getEffectiveTypeArguments(typeReferenceNode, typeParameters))); + const constraint = getConstraintOfTypeParameter( + typeParameters[typeReferenceNode.typeArguments!.indexOf(node)] + ); + return ( + constraint && + instantiateType( + constraint, + createTypeMapper( + typeParameters, + getEffectiveTypeArguments(typeReferenceNode, typeParameters) + ) + ) + ); } function checkTypeQuery(node: TypeQueryNode) { @@ -42579,7 +74461,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { addLazyDiagnostic(checkTypeLiteralDiagnostics); function checkTypeLiteralDiagnostics() { - const type = getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node); + const type = + getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node); checkIndexConstraints(type, type.symbol); checkTypeForDuplicateIndexSignatures(node); checkObjectTypeForDuplicateDeclarations(node); @@ -42596,31 +74479,47 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (const e of node.elements) { let flags = getTupleElementFlags(e); if (flags & ElementFlags.Variadic) { - const type = getTypeFromTypeNode((e as RestTypeNode | NamedTupleMember).type); + const type = getTypeFromTypeNode( + (e as RestTypeNode | NamedTupleMember).type + ); if (!isArrayLikeType(type)) { - error(e, Diagnostics.A_rest_element_type_must_be_an_array_type); + error( + e, + Diagnostics.A_rest_element_type_must_be_an_array_type + ); break; } - if (isArrayType(type) || isTupleType(type) && type.target.combinedFlags & ElementFlags.Rest) { + if ( + isArrayType(type) || + (isTupleType(type) && + type.target.combinedFlags & ElementFlags.Rest) + ) { flags |= ElementFlags.Rest; } } if (flags & ElementFlags.Rest) { if (seenRestElement) { - grammarErrorOnNode(e, Diagnostics.A_rest_element_cannot_follow_another_rest_element); + grammarErrorOnNode( + e, + Diagnostics.A_rest_element_cannot_follow_another_rest_element + ); break; } seenRestElement = true; - } - else if (flags & ElementFlags.Optional) { + } else if (flags & ElementFlags.Optional) { if (seenRestElement) { - grammarErrorOnNode(e, Diagnostics.An_optional_element_cannot_follow_a_rest_element); + grammarErrorOnNode( + e, + Diagnostics.An_optional_element_cannot_follow_a_rest_element + ); break; } seenOptionalElement = true; - } - else if (flags & ElementFlags.Required && seenOptionalElement) { - grammarErrorOnNode(e, Diagnostics.A_required_element_cannot_follow_an_optional_element); + } else if (flags & ElementFlags.Required && seenOptionalElement) { + grammarErrorOnNode( + e, + Diagnostics.A_required_element_cannot_follow_an_optional_element + ); break; } } @@ -42633,7 +74532,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { getTypeFromTypeNode(node); } - function checkIndexedAccessIndexType(type: Type, accessNode: IndexedAccessTypeNode | ElementAccessExpression) { + function checkIndexedAccessIndexType( + type: Type, + accessNode: IndexedAccessTypeNode | ElementAccessExpression + ) { if (!(type.flags & TypeFlags.IndexedAccess)) { return type; } @@ -42641,37 +74543,76 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const objectType = (type as IndexedAccessType).objectType; const indexType = (type as IndexedAccessType).indexType; // skip index type deferral on remapping mapped types - const objectIndexType = isGenericMappedType(objectType) && getMappedTypeNameTypeKind(objectType) === MappedTypeNameTypeKind.Remapping - ? getIndexTypeForMappedType(objectType, IndexFlags.None) - : getIndexType(objectType, IndexFlags.None); + const objectIndexType = + isGenericMappedType(objectType) && + getMappedTypeNameTypeKind(objectType) === + MappedTypeNameTypeKind.Remapping + ? getIndexTypeForMappedType(objectType, IndexFlags.None) + : getIndexType(objectType, IndexFlags.None); const hasNumberIndexInfo = !!getIndexInfoOfType(objectType, numberType); - if (everyType(indexType, t => isTypeAssignableTo(t, objectIndexType) || hasNumberIndexInfo && isApplicableIndexType(t, numberType))) { + if ( + everyType( + indexType, + (t) => + isTypeAssignableTo(t, objectIndexType) || + (hasNumberIndexInfo && isApplicableIndexType(t, numberType)) + ) + ) { if ( - accessNode.kind === SyntaxKind.ElementAccessExpression && isAssignmentTarget(accessNode) && - getObjectFlags(objectType) & ObjectFlags.Mapped && getMappedTypeModifiers(objectType as MappedType) & MappedTypeModifiers.IncludeReadonly + accessNode.kind === SyntaxKind.ElementAccessExpression && + isAssignmentTarget(accessNode) && + getObjectFlags(objectType) & ObjectFlags.Mapped && + getMappedTypeModifiers(objectType as MappedType) & + MappedTypeModifiers.IncludeReadonly ) { - error(accessNode, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(objectType)); + error( + accessNode, + Diagnostics.Index_signature_in_type_0_only_permits_reading, + typeToString(objectType) + ); } return type; } if (isGenericObjectType(objectType)) { - const propertyName = getPropertyNameFromIndex(indexType, accessNode); + const propertyName = getPropertyNameFromIndex( + indexType, + accessNode + ); if (propertyName) { - const propertySymbol = forEachType(getApparentType(objectType), t => getPropertyOfType(t, propertyName)); - if (propertySymbol && getDeclarationModifierFlagsFromSymbol(propertySymbol) & ModifierFlags.NonPublicAccessibilityModifier) { - error(accessNode, Diagnostics.Private_or_protected_member_0_cannot_be_accessed_on_a_type_parameter, unescapeLeadingUnderscores(propertyName)); + const propertySymbol = forEachType( + getApparentType(objectType), + (t) => getPropertyOfType(t, propertyName) + ); + if ( + propertySymbol && + getDeclarationModifierFlagsFromSymbol(propertySymbol) & + ModifierFlags.NonPublicAccessibilityModifier + ) { + error( + accessNode, + Diagnostics.Private_or_protected_member_0_cannot_be_accessed_on_a_type_parameter, + unescapeLeadingUnderscores(propertyName) + ); return errorType; } } } - error(accessNode, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(objectType)); + error( + accessNode, + Diagnostics.Type_0_cannot_be_used_to_index_type_1, + typeToString(indexType), + typeToString(objectType) + ); return errorType; } function checkIndexedAccessType(node: IndexedAccessTypeNode) { checkSourceElement(node.objectType); checkSourceElement(node.indexType); - checkIndexedAccessIndexType(getTypeFromIndexedAccessTypeNode(node), node); + checkIndexedAccessIndexType( + getTypeFromIndexedAccessTypeNode(node), + node + ); } function checkMappedType(node: MappedTypeNode) { @@ -42687,17 +74628,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const type = getTypeFromMappedTypeNode(node) as MappedType; const nameType = getNameTypeFromMappedType(type); if (nameType) { - checkTypeAssignableTo(nameType, stringNumberSymbolType, node.nameType); - } - else { + checkTypeAssignableTo( + nameType, + stringNumberSymbolType, + node.nameType + ); + } else { const constraintType = getConstraintTypeFromMappedType(type); - checkTypeAssignableTo(constraintType, stringNumberSymbolType, getEffectiveConstraintOfTypeParameter(node.typeParameter)); + checkTypeAssignableTo( + constraintType, + stringNumberSymbolType, + getEffectiveConstraintOfTypeParameter(node.typeParameter) + ); } } function checkGrammarMappedType(node: MappedTypeNode) { if (node.members?.length) { - return grammarErrorOnNode(node.members[0], Diagnostics.A_mapped_type_may_not_declare_properties_or_methods); + return grammarErrorOnNode( + node.members[0], + Diagnostics.A_mapped_type_may_not_declare_properties_or_methods + ); } } @@ -42715,8 +74666,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkInferType(node: InferTypeNode) { - if (!findAncestor(node, n => n.parent && n.parent.kind === SyntaxKind.ConditionalType && (n.parent as ConditionalTypeNode).extendsType === n)) { - grammarErrorOnNode(node, Diagnostics.infer_declarations_are_only_permitted_in_the_extends_clause_of_a_conditional_type); + if ( + !findAncestor( + node, + (n) => + n.parent && + n.parent.kind === SyntaxKind.ConditionalType && + (n.parent as ConditionalTypeNode).extendsType === n + ) + ) { + grammarErrorOnNode( + node, + Diagnostics.infer_declarations_are_only_permitted_in_the_extends_clause_of_a_conditional_type + ); } checkSourceElement(node.typeParameter); const symbol = getSymbolOfDeclaration(node.typeParameter); @@ -42725,12 +74687,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!links.typeParametersChecked) { links.typeParametersChecked = true; const typeParameter = getDeclaredTypeOfTypeParameter(symbol); - const declarations: TypeParameterDeclaration[] = getDeclarationsOfKind(symbol, SyntaxKind.TypeParameter); - if (!areTypeParametersIdentical(declarations, [typeParameter], decl => [decl])) { + const declarations: TypeParameterDeclaration[] = + getDeclarationsOfKind(symbol, SyntaxKind.TypeParameter); + if ( + !areTypeParametersIdentical( + declarations, + [typeParameter], + (decl) => [decl] + ) + ) { // Report an error on every conflicting declaration. const name = symbolToString(symbol); for (const declaration of declarations) { - error(declaration.name, Diagnostics.All_declarations_of_0_must_have_identical_constraints, name); + error( + declaration.name, + Diagnostics.All_declarations_of_0_must_have_identical_constraints, + name + ); } } } @@ -42758,23 +74731,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkNamedTupleMember(node: NamedTupleMember) { if (node.dotDotDotToken && node.questionToken) { - grammarErrorOnNode(node, Diagnostics.A_tuple_member_cannot_be_both_optional_and_rest); + grammarErrorOnNode( + node, + Diagnostics.A_tuple_member_cannot_be_both_optional_and_rest + ); } if (node.type.kind === SyntaxKind.OptionalType) { - 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); + 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 + ); } if (node.type.kind === SyntaxKind.RestType) { - grammarErrorOnNode(node.type, Diagnostics.A_labeled_tuple_element_is_declared_as_rest_with_a_before_the_name_rather_than_before_the_type); + grammarErrorOnNode( + node.type, + Diagnostics.A_labeled_tuple_element_is_declared_as_rest_with_a_before_the_name_rather_than_before_the_type + ); } checkSourceElement(node.type); getTypeFromTypeNode(node); } function isPrivateWithinAmbient(node: Node): boolean { - return (hasEffectiveModifier(node, ModifierFlags.Private) || isPrivateIdentifierClassElementDeclaration(node)) && !!(node.flags & NodeFlags.Ambient); + return ( + (hasEffectiveModifier(node, ModifierFlags.Private) || + isPrivateIdentifierClassElementDeclaration(node)) && + !!(node.flags & NodeFlags.Ambient) + ); } - function getEffectiveDeclarationFlags(n: Declaration, flagsToCheck: ModifierFlags): ModifierFlags { + function getEffectiveDeclarationFlags( + n: Declaration, + flagsToCheck: ModifierFlags + ): ModifierFlags { let flags = getCombinedModifierFlagsCached(n); // children of classes (even ambient classes) should not be marked as ambient or export @@ -42786,7 +74775,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { n.flags & NodeFlags.Ambient ) { const container = getEnclosingContainer(n); - if ((container && container.flags & NodeFlags.ExportContext) && !(flags & ModifierFlags.Ambient) && !(isModuleBlock(n.parent) && isModuleDeclaration(n.parent.parent) && isGlobalScopeAugmentation(n.parent.parent))) { + if ( + container && + container.flags & NodeFlags.ExportContext && + !(flags & ModifierFlags.Ambient) && + !( + isModuleBlock(n.parent) && + isModuleDeclaration(n.parent.parent) && + isGlobalScopeAugmentation(n.parent.parent) + ) + ) { // It is nested in an ambient export context, which means it is automatically exported flags |= ModifierFlags.Export; } @@ -42801,27 +74799,54 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkFunctionOrConstructorSymbolWorker(symbol: Symbol): void { - function getCanonicalOverload(overloads: readonly Declaration[], implementation: FunctionLikeDeclaration | undefined): Declaration { + function getCanonicalOverload( + overloads: readonly Declaration[], + implementation: FunctionLikeDeclaration | undefined + ): Declaration { // Consider the canonical set of flags to be the flags of the bodyDeclaration or the first declaration // Error on all deviations from this canonical set of flags // The caveat is that if some overloads are defined in lib.d.ts, we don't want to // report the errors on those. To achieve this, we will say that the implementation is // the canonical signature only if it is in the same container as the first overload - const implementationSharesContainerWithFirstOverload = implementation !== undefined && implementation.parent === overloads[0].parent; - return implementationSharesContainerWithFirstOverload ? implementation : overloads[0]; - } - - function checkFlagAgreementBetweenOverloads(overloads: Declaration[], implementation: FunctionLikeDeclaration | undefined, flagsToCheck: ModifierFlags, someOverloadFlags: ModifierFlags, allOverloadFlags: ModifierFlags): void { + const implementationSharesContainerWithFirstOverload = + implementation !== undefined && + implementation.parent === overloads[0].parent; + return implementationSharesContainerWithFirstOverload + ? implementation + : overloads[0]; + } + + function checkFlagAgreementBetweenOverloads( + overloads: Declaration[], + implementation: FunctionLikeDeclaration | undefined, + flagsToCheck: ModifierFlags, + someOverloadFlags: ModifierFlags, + allOverloadFlags: ModifierFlags + ): void { // Error if some overloads have a flag that is not shared by all overloads. To find the // deviations, we XOR someOverloadFlags with allOverloadFlags - const someButNotAllOverloadFlags = someOverloadFlags ^ allOverloadFlags; + const someButNotAllOverloadFlags = + someOverloadFlags ^ allOverloadFlags; if (someButNotAllOverloadFlags !== 0) { - const canonicalFlags = getEffectiveDeclarationFlags(getCanonicalOverload(overloads, implementation), flagsToCheck); - group(overloads, o => getSourceFileOfNode(o).fileName).forEach(overloadsInFile => { - const canonicalFlagsForFile = getEffectiveDeclarationFlags(getCanonicalOverload(overloadsInFile, implementation), flagsToCheck); + const canonicalFlags = getEffectiveDeclarationFlags( + getCanonicalOverload(overloads, implementation), + flagsToCheck + ); + group( + overloads, + (o) => getSourceFileOfNode(o).fileName + ).forEach((overloadsInFile) => { + const canonicalFlagsForFile = getEffectiveDeclarationFlags( + getCanonicalOverload(overloadsInFile, implementation), + flagsToCheck + ); for (const o of overloadsInFile) { - const deviation = getEffectiveDeclarationFlags(o, flagsToCheck) ^ canonicalFlags; - const deviationInFile = getEffectiveDeclarationFlags(o, flagsToCheck) ^ canonicalFlagsForFile; + const deviation = + getEffectiveDeclarationFlags(o, flagsToCheck) ^ + canonicalFlags; + const deviationInFile = + getEffectiveDeclarationFlags(o, flagsToCheck) ^ + canonicalFlagsForFile; if (deviationInFile & ModifierFlags.Export) { // Overloads in different files need not all have export modifiers. This is ok: // // lib.d.ts @@ -42833,37 +74858,65 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // declare module "lib" { // export function foo(s: boolean): boolean; // } - error(getNameOfDeclaration(o), Diagnostics.Overload_signatures_must_all_be_exported_or_non_exported); - } - else if (deviationInFile & ModifierFlags.Ambient) { + error( + getNameOfDeclaration(o), + Diagnostics.Overload_signatures_must_all_be_exported_or_non_exported + ); + } else if (deviationInFile & ModifierFlags.Ambient) { // Though rare, a module augmentation (necessarily ambient) is allowed to add overloads // to a non-ambient function in an implementation file. - error(getNameOfDeclaration(o), Diagnostics.Overload_signatures_must_all_be_ambient_or_non_ambient); - } - else if (deviation & (ModifierFlags.Private | ModifierFlags.Protected)) { - error(getNameOfDeclaration(o) || o, Diagnostics.Overload_signatures_must_all_be_public_private_or_protected); - } - else if (deviation & ModifierFlags.Abstract) { - error(getNameOfDeclaration(o), Diagnostics.Overload_signatures_must_all_be_abstract_or_non_abstract); + error( + getNameOfDeclaration(o), + Diagnostics.Overload_signatures_must_all_be_ambient_or_non_ambient + ); + } else if ( + deviation & + (ModifierFlags.Private | ModifierFlags.Protected) + ) { + error( + getNameOfDeclaration(o) || o, + Diagnostics.Overload_signatures_must_all_be_public_private_or_protected + ); + } else if (deviation & ModifierFlags.Abstract) { + error( + getNameOfDeclaration(o), + Diagnostics.Overload_signatures_must_all_be_abstract_or_non_abstract + ); } } }); } } - function checkQuestionTokenAgreementBetweenOverloads(overloads: Declaration[], implementation: FunctionLikeDeclaration | undefined, someHaveQuestionToken: boolean, allHaveQuestionToken: boolean): void { + function checkQuestionTokenAgreementBetweenOverloads( + overloads: Declaration[], + implementation: FunctionLikeDeclaration | undefined, + someHaveQuestionToken: boolean, + allHaveQuestionToken: boolean + ): void { if (someHaveQuestionToken !== allHaveQuestionToken) { - const canonicalHasQuestionToken = hasQuestionToken(getCanonicalOverload(overloads, implementation)); - forEach(overloads, o => { - const deviation = hasQuestionToken(o) !== canonicalHasQuestionToken; + const canonicalHasQuestionToken = hasQuestionToken( + getCanonicalOverload(overloads, implementation) + ); + forEach(overloads, (o) => { + const deviation = + hasQuestionToken(o) !== canonicalHasQuestionToken; if (deviation) { - error(getNameOfDeclaration(o), Diagnostics.Overload_signatures_must_all_be_optional_or_required); + error( + getNameOfDeclaration(o), + Diagnostics.Overload_signatures_must_all_be_optional_or_required + ); } }); } } - const flagsToCheck: ModifierFlags = ModifierFlags.Export | ModifierFlags.Ambient | ModifierFlags.Private | ModifierFlags.Protected | ModifierFlags.Abstract; + const flagsToCheck: ModifierFlags = + ModifierFlags.Export | + ModifierFlags.Ambient | + ModifierFlags.Private | + ModifierFlags.Protected | + ModifierFlags.Abstract; let someNodeFlags: ModifierFlags = ModifierFlags.None; let allNodeFlags = flagsToCheck; let someHaveQuestionToken = false; @@ -42876,17 +74929,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const declarations = symbol.declarations; const isConstructor = (symbol.flags & SymbolFlags.Constructor) !== 0; - function reportImplementationExpectedError(node: SignatureDeclaration): void { + function reportImplementationExpectedError( + node: SignatureDeclaration + ): void { if (node.name && nodeIsMissing(node.name)) { return; } let seen = false; - const subsequentNode = forEachChild(node.parent, c => { + const subsequentNode = forEachChild(node.parent, (c) => { if (seen) { return c; - } - else { + } else { seen = c === node; } }); @@ -42894,49 +74948,86 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // In this case the subsequent node is not really consecutive (.pos !== node.end), and we must ignore it here. if (subsequentNode && subsequentNode.pos === node.end) { if (subsequentNode.kind === node.kind) { - const errorNode: Node = (subsequentNode as FunctionLikeDeclaration).name || subsequentNode; - const subsequentName = (subsequentNode as FunctionLikeDeclaration).name; + const errorNode: Node = + (subsequentNode as FunctionLikeDeclaration).name || + subsequentNode; + const subsequentName = ( + subsequentNode as FunctionLikeDeclaration + ).name; if ( - node.name && subsequentName && ( - // both are private identifiers - isPrivateIdentifier(node.name) && isPrivateIdentifier(subsequentName) && node.name.escapedText === subsequentName.escapedText || + node.name && + subsequentName && + // both are private identifiers + ((isPrivateIdentifier(node.name) && + isPrivateIdentifier(subsequentName) && + node.name.escapedText === + subsequentName.escapedText) || // Both are computed property names - isComputedPropertyName(node.name) && isComputedPropertyName(subsequentName) && isTypeIdenticalTo(checkComputedPropertyName(node.name), checkComputedPropertyName(subsequentName)) || + (isComputedPropertyName(node.name) && + isComputedPropertyName(subsequentName) && + isTypeIdenticalTo( + checkComputedPropertyName(node.name), + checkComputedPropertyName(subsequentName) + )) || // Both are literal property names that are the same. - isPropertyNameLiteral(node.name) && isPropertyNameLiteral(subsequentName) && - getEscapedTextOfIdentifierOrLiteral(node.name) === getEscapedTextOfIdentifierOrLiteral(subsequentName) - ) + (isPropertyNameLiteral(node.name) && + isPropertyNameLiteral(subsequentName) && + getEscapedTextOfIdentifierOrLiteral( + node.name + ) === + getEscapedTextOfIdentifierOrLiteral( + subsequentName + ))) ) { - const reportError = (node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature) && + const reportError = + (node.kind === SyntaxKind.MethodDeclaration || + node.kind === SyntaxKind.MethodSignature) && isStatic(node) !== isStatic(subsequentNode); // we can get here in two cases // 1. mixed static and instance class members // 2. something with the same name was defined before the set of overloads that prevents them from merging // here we'll report error only for the first case since for second we should already report error in binder if (reportError) { - const diagnostic = isStatic(node) ? Diagnostics.Function_overload_must_be_static : Diagnostics.Function_overload_must_not_be_static; + const diagnostic = isStatic(node) + ? Diagnostics.Function_overload_must_be_static + : Diagnostics.Function_overload_must_not_be_static; error(errorNode, diagnostic); } return; } - if (nodeIsPresent((subsequentNode as FunctionLikeDeclaration).body)) { - error(errorNode, Diagnostics.Function_implementation_name_must_be_0, declarationNameToString(node.name)); + if ( + nodeIsPresent( + (subsequentNode as FunctionLikeDeclaration).body + ) + ) { + error( + errorNode, + Diagnostics.Function_implementation_name_must_be_0, + declarationNameToString(node.name) + ); return; } } } const errorNode: Node = node.name || node; if (isConstructor) { - error(errorNode, Diagnostics.Constructor_implementation_is_missing); - } - else { + error( + errorNode, + Diagnostics.Constructor_implementation_is_missing + ); + } else { // Report different errors regarding non-consecutive blocks of declarations depending on whether // the node in question is abstract. if (hasSyntacticModifier(node, ModifierFlags.Abstract)) { - error(errorNode, Diagnostics.All_declarations_of_an_abstract_method_must_be_consecutive); - } - else { - error(errorNode, Diagnostics.Function_implementation_is_missing_or_not_immediately_following_the_declaration); + error( + errorNode, + Diagnostics.All_declarations_of_an_abstract_method_must_be_consecutive + ); + } else { + error( + errorNode, + Diagnostics.Function_implementation_is_missing_or_not_immediately_following_the_declaration + ); } } } @@ -42947,9 +75038,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const functionDeclarations = [] as Declaration[]; if (declarations) { for (const current of declarations) { - const node = current as SignatureDeclaration | ClassDeclaration | ClassExpression; + const node = current as + | SignatureDeclaration + | ClassDeclaration + | ClassExpression; const inAmbientContext = node.flags & NodeFlags.Ambient; - const inAmbientContextOrInterface = node.parent && (node.parent.kind === SyntaxKind.InterfaceDeclaration || node.parent.kind === SyntaxKind.TypeLiteral) || inAmbientContext; + const inAmbientContextOrInterface = + (node.parent && + (node.parent.kind === SyntaxKind.InterfaceDeclaration || + node.parent.kind === SyntaxKind.TypeLiteral)) || + inAmbientContext; if (inAmbientContextOrInterface) { // check if declarations are consecutive only if they are non-ambient // 1. ambient declarations can be interleaved @@ -42961,28 +75059,45 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { previousDeclaration = undefined; } - if ((node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression) && !inAmbientContext) { + if ( + (node.kind === SyntaxKind.ClassDeclaration || + node.kind === SyntaxKind.ClassExpression) && + !inAmbientContext + ) { hasNonAmbientClass = true; } - if (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature || node.kind === SyntaxKind.Constructor) { + if ( + node.kind === SyntaxKind.FunctionDeclaration || + node.kind === SyntaxKind.MethodDeclaration || + node.kind === SyntaxKind.MethodSignature || + node.kind === SyntaxKind.Constructor + ) { functionDeclarations.push(node); - const currentNodeFlags = getEffectiveDeclarationFlags(node, flagsToCheck); + const currentNodeFlags = getEffectiveDeclarationFlags( + node, + flagsToCheck + ); someNodeFlags |= currentNodeFlags; allNodeFlags &= currentNodeFlags; - someHaveQuestionToken = someHaveQuestionToken || hasQuestionToken(node); - allHaveQuestionToken = allHaveQuestionToken && hasQuestionToken(node); - const bodyIsPresent = nodeIsPresent((node as FunctionLikeDeclaration).body); + someHaveQuestionToken = + someHaveQuestionToken || hasQuestionToken(node); + allHaveQuestionToken = + allHaveQuestionToken && hasQuestionToken(node); + const bodyIsPresent = nodeIsPresent( + (node as FunctionLikeDeclaration).body + ); if (bodyIsPresent && bodyDeclaration) { if (isConstructor) { multipleConstructorImplementation = true; - } - else { + } else { duplicateFunctionDeclaration = true; } - } - else if (previousDeclaration?.parent === node.parent && previousDeclaration.end !== node.pos) { + } else if ( + previousDeclaration?.parent === node.parent && + previousDeclaration.end !== node.pos + ) { reportImplementationExpectedError(previousDeclaration); } @@ -42990,49 +75105,76 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!bodyDeclaration) { bodyDeclaration = node as FunctionLikeDeclaration; } - } - else { + } else { hasOverloads = true; } previousDeclaration = node; if (!inAmbientContextOrInterface) { - lastSeenNonAmbientDeclaration = node as FunctionLikeDeclaration; + lastSeenNonAmbientDeclaration = + node as FunctionLikeDeclaration; } } - if (isInJSFile(current) && isFunctionLike(current) && current.jsDoc) { + if ( + isInJSFile(current) && + isFunctionLike(current) && + current.jsDoc + ) { hasOverloads = length(getJSDocOverloadTags(current)) > 0; } } } if (multipleConstructorImplementation) { - forEach(functionDeclarations, declaration => { - error(declaration, Diagnostics.Multiple_constructor_implementations_are_not_allowed); + forEach(functionDeclarations, (declaration) => { + error( + declaration, + Diagnostics.Multiple_constructor_implementations_are_not_allowed + ); }); } if (duplicateFunctionDeclaration) { - forEach(functionDeclarations, declaration => { - error(getNameOfDeclaration(declaration) || declaration, Diagnostics.Duplicate_function_implementation); + forEach(functionDeclarations, (declaration) => { + error( + getNameOfDeclaration(declaration) || declaration, + Diagnostics.Duplicate_function_implementation + ); }); } - if (hasNonAmbientClass && !isConstructor && symbol.flags & SymbolFlags.Function && declarations) { - const relatedDiagnostics = filter(declarations, d => d.kind === SyntaxKind.ClassDeclaration) - .map(d => createDiagnosticForNode(d, Diagnostics.Consider_adding_a_declare_modifier_to_this_class)); + if ( + hasNonAmbientClass && + !isConstructor && + symbol.flags & SymbolFlags.Function && + declarations + ) { + const relatedDiagnostics = filter( + declarations, + (d) => d.kind === SyntaxKind.ClassDeclaration + ).map((d) => + createDiagnosticForNode( + d, + Diagnostics.Consider_adding_a_declare_modifier_to_this_class + ) + ); - forEach(declarations, declaration => { - const diagnostic = declaration.kind === SyntaxKind.ClassDeclaration - ? Diagnostics.Class_declaration_cannot_implement_overload_list_for_0 - : declaration.kind === SyntaxKind.FunctionDeclaration - ? Diagnostics.Function_with_bodies_can_only_merge_with_classes_that_are_ambient - : undefined; + forEach(declarations, (declaration) => { + const diagnostic = + declaration.kind === SyntaxKind.ClassDeclaration + ? Diagnostics.Class_declaration_cannot_implement_overload_list_for_0 + : declaration.kind === SyntaxKind.FunctionDeclaration + ? Diagnostics.Function_with_bodies_can_only_merge_with_classes_that_are_ambient + : undefined; if (diagnostic) { addRelatedInfo( - error(getNameOfDeclaration(declaration) || declaration, diagnostic, symbolName(symbol)), - ...relatedDiagnostics, + error( + getNameOfDeclaration(declaration) || declaration, + diagnostic, + symbolName(symbol) + ), + ...relatedDiagnostics ); } }); @@ -43040,29 +75182,63 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Abstract methods can't have an implementation -- in particular, they don't need one. if ( - lastSeenNonAmbientDeclaration && !lastSeenNonAmbientDeclaration.body && - !hasSyntacticModifier(lastSeenNonAmbientDeclaration, ModifierFlags.Abstract) && !lastSeenNonAmbientDeclaration.questionToken + lastSeenNonAmbientDeclaration && + !lastSeenNonAmbientDeclaration.body && + !hasSyntacticModifier( + lastSeenNonAmbientDeclaration, + ModifierFlags.Abstract + ) && + !lastSeenNonAmbientDeclaration.questionToken ) { reportImplementationExpectedError(lastSeenNonAmbientDeclaration); } if (hasOverloads) { if (declarations) { - checkFlagAgreementBetweenOverloads(declarations, bodyDeclaration, flagsToCheck, someNodeFlags, allNodeFlags); - checkQuestionTokenAgreementBetweenOverloads(declarations, bodyDeclaration, someHaveQuestionToken, allHaveQuestionToken); + checkFlagAgreementBetweenOverloads( + declarations, + bodyDeclaration, + flagsToCheck, + someNodeFlags, + allNodeFlags + ); + checkQuestionTokenAgreementBetweenOverloads( + declarations, + bodyDeclaration, + someHaveQuestionToken, + allHaveQuestionToken + ); } if (bodyDeclaration) { const signatures = getSignaturesOfSymbol(symbol); - const bodySignature = getSignatureFromDeclaration(bodyDeclaration); + const bodySignature = + getSignatureFromDeclaration(bodyDeclaration); for (const signature of signatures) { - if (!isImplementationCompatibleWithOverload(bodySignature, signature)) { - const errorNode = signature.declaration && isJSDocSignature(signature.declaration) - ? (signature.declaration.parent as JSDocOverloadTag | JSDocCallbackTag).tagName - : signature.declaration; + if ( + !isImplementationCompatibleWithOverload( + bodySignature, + signature + ) + ) { + const errorNode = + signature.declaration && + isJSDocSignature(signature.declaration) + ? ( + signature.declaration.parent as + | JSDocOverloadTag + | JSDocCallbackTag + ).tagName + : signature.declaration; addRelatedInfo( - error(errorNode, Diagnostics.This_overload_signature_is_not_compatible_with_its_implementation_signature), - createDiagnosticForNode(bodyDeclaration, Diagnostics.The_implementation_signature_is_declared_here), + error( + errorNode, + Diagnostics.This_overload_signature_is_not_compatible_with_its_implementation_signature + ), + createDiagnosticForNode( + bodyDeclaration, + Diagnostics.The_implementation_signature_is_declared_here + ) ); break; } @@ -43098,39 +75274,60 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let defaultExportedDeclarationSpaces = DeclarationSpaces.None; for (const d of symbol.declarations!) { const declarationSpaces = getDeclarationSpaces(d); - const effectiveDeclarationFlags = getEffectiveDeclarationFlags(d, ModifierFlags.Export | ModifierFlags.Default); + const effectiveDeclarationFlags = getEffectiveDeclarationFlags( + d, + ModifierFlags.Export | ModifierFlags.Default + ); if (effectiveDeclarationFlags & ModifierFlags.Export) { if (effectiveDeclarationFlags & ModifierFlags.Default) { defaultExportedDeclarationSpaces |= declarationSpaces; - } - else { + } else { exportedDeclarationSpaces |= declarationSpaces; } - } - else { + } else { nonExportedDeclarationSpaces |= declarationSpaces; } } // Spaces for anything not declared a 'default export'. - const nonDefaultExportedDeclarationSpaces = exportedDeclarationSpaces | nonExportedDeclarationSpaces; + const nonDefaultExportedDeclarationSpaces = + exportedDeclarationSpaces | nonExportedDeclarationSpaces; - const commonDeclarationSpacesForExportsAndLocals = exportedDeclarationSpaces & nonExportedDeclarationSpaces; - const commonDeclarationSpacesForDefaultAndNonDefault = defaultExportedDeclarationSpaces & nonDefaultExportedDeclarationSpaces; + const commonDeclarationSpacesForExportsAndLocals = + exportedDeclarationSpaces & nonExportedDeclarationSpaces; + const commonDeclarationSpacesForDefaultAndNonDefault = + defaultExportedDeclarationSpaces & + nonDefaultExportedDeclarationSpaces; - if (commonDeclarationSpacesForExportsAndLocals || commonDeclarationSpacesForDefaultAndNonDefault) { + if ( + commonDeclarationSpacesForExportsAndLocals || + commonDeclarationSpacesForDefaultAndNonDefault + ) { // declaration spaces for exported and non-exported declarations intersect for (const d of symbol.declarations!) { const declarationSpaces = getDeclarationSpaces(d); const name = getNameOfDeclaration(d); // Only error on the declarations that contributed to the intersecting spaces. - if (declarationSpaces & commonDeclarationSpacesForDefaultAndNonDefault) { - error(name, Diagnostics.Merged_declaration_0_cannot_include_a_default_export_declaration_Consider_adding_a_separate_export_default_0_declaration_instead, declarationNameToString(name)); - } - else if (declarationSpaces & commonDeclarationSpacesForExportsAndLocals) { - error(name, Diagnostics.Individual_declarations_in_merged_declaration_0_must_be_all_exported_or_all_local, declarationNameToString(name)); + if ( + declarationSpaces & + commonDeclarationSpacesForDefaultAndNonDefault + ) { + error( + name, + Diagnostics.Merged_declaration_0_cannot_include_a_default_export_declaration_Consider_adding_a_separate_export_default_0_declaration_instead, + declarationNameToString(name) + ); + } else if ( + declarationSpaces & + commonDeclarationSpacesForExportsAndLocals + ) { + error( + name, + Diagnostics.Individual_declarations_in_merged_declaration_0_must_be_all_exported_or_all_local, + declarationNameToString(name) + ); } } } @@ -43148,19 +75345,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.JSDocEnumTag: return DeclarationSpaces.ExportType; case SyntaxKind.ModuleDeclaration: - return isAmbientModule(d as ModuleDeclaration) || getModuleInstanceState(d as ModuleDeclaration) !== ModuleInstanceState.NonInstantiated - ? DeclarationSpaces.ExportNamespace | DeclarationSpaces.ExportValue + return isAmbientModule(d as ModuleDeclaration) || + getModuleInstanceState(d as ModuleDeclaration) !== + ModuleInstanceState.NonInstantiated + ? DeclarationSpaces.ExportNamespace | + DeclarationSpaces.ExportValue : DeclarationSpaces.ExportNamespace; case SyntaxKind.ClassDeclaration: case SyntaxKind.EnumDeclaration: case SyntaxKind.EnumMember: - return DeclarationSpaces.ExportType | DeclarationSpaces.ExportValue; + return ( + DeclarationSpaces.ExportType | + DeclarationSpaces.ExportValue + ); case SyntaxKind.SourceFile: - return DeclarationSpaces.ExportType | DeclarationSpaces.ExportValue | DeclarationSpaces.ExportNamespace; + return ( + DeclarationSpaces.ExportType | + DeclarationSpaces.ExportValue | + DeclarationSpaces.ExportNamespace + ); case SyntaxKind.ExportAssignment: case SyntaxKind.BinaryExpression: const node = d as ExportAssignment | BinaryExpression; - const expression = isExportAssignment(node) ? node.expression : node.right; + const expression = isExportAssignment(node) + ? node.expression + : node.right; // Export assigned entity name expressions act as aliases and should fall through, otherwise they export values if (!isEntityNameExpression(expression)) { return DeclarationSpaces.ExportValue; @@ -43173,8 +75382,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.NamespaceImport: case SyntaxKind.ImportClause: let result = DeclarationSpaces.None; - const target = resolveAlias(getSymbolOfDeclaration(d as ImportEqualsDeclaration | NamespaceImport | ImportClause | ExportAssignment | BinaryExpression)); - forEach(target.declarations, d => { + const target = resolveAlias( + getSymbolOfDeclaration( + d as + | ImportEqualsDeclaration + | NamespaceImport + | ImportClause + | ExportAssignment + | BinaryExpression + ) + ); + forEach(target.declarations, (d) => { result |= getDeclarationSpaces(d); }); return result; @@ -43199,9 +75417,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getAwaitedTypeOfPromise(type: Type, errorNode?: Node, diagnosticMessage?: DiagnosticMessage, ...args: DiagnosticArguments): Type | undefined { + function getAwaitedTypeOfPromise( + type: Type, + errorNode?: Node, + diagnosticMessage?: DiagnosticMessage, + ...args: DiagnosticArguments + ): Type | undefined { const promisedType = getPromisedTypeOfPromise(type, errorNode); - return promisedType && getAwaitedType(promisedType, errorNode, diagnosticMessage, ...args); + return ( + promisedType && + getAwaitedType(promisedType, errorNode, diagnosticMessage, ...args) + ); } /** @@ -43209,7 +75435,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param type The type of the promise. * @remarks The "promised type" of a type is the type of the "value" parameter of the "onfulfilled" callback. */ - function getPromisedTypeOfPromise(type: Type, errorNode?: Node, thisTypeForErrorOut?: { value?: Type; }): Type | undefined { + function getPromisedTypeOfPromise( + type: Type, + errorNode?: Node, + thisTypeForErrorOut?: { value?: Type } + ): Type | undefined { // // { // type // then( // thenFunction @@ -43229,12 +75459,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return typeAsPromise.promisedTypeOfPromise; } - if (isReferenceToType(type, getGlobalPromiseType(/*reportErrors*/ false))) { - return typeAsPromise.promisedTypeOfPromise = getTypeArguments(type as GenericType)[0]; + if ( + isReferenceToType( + type, + getGlobalPromiseType(/*reportErrors*/ false) + ) + ) { + return (typeAsPromise.promisedTypeOfPromise = getTypeArguments( + type as GenericType + )[0]); } // primitives with a `{ then() }` won't be unwrapped/adopted. - if (allTypesAssignableToKind(getBaseConstraintOrType(type), TypeFlags.Primitive | TypeFlags.Never)) { + if ( + allTypesAssignableToKind( + getBaseConstraintOrType(type), + TypeFlags.Primitive | TypeFlags.Never + ) + ) { return undefined; } @@ -43243,7 +75485,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - const thenSignatures = thenFunction ? getSignaturesOfType(thenFunction, SignatureKind.Call) : emptyArray; + const thenSignatures = thenFunction + ? getSignaturesOfType(thenFunction, SignatureKind.Call) + : emptyArray; if (thenSignatures.length === 0) { if (errorNode) { error(errorNode, Diagnostics.A_promise_must_have_a_then_method); @@ -43255,10 +75499,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let candidates: Signature[] | undefined; for (const thenSignature of thenSignatures) { const thisType = getThisTypeOfSignature(thenSignature); - if (thisType && thisType !== voidType && !isTypeRelatedTo(type, thisType, subtypeRelation)) { + if ( + thisType && + thisType !== voidType && + !isTypeRelatedTo(type, thisType, subtypeRelation) + ) { thisTypeForError = thisType; - } - else { + } else { candidates = append(candidates, thenSignature); } } @@ -43269,25 +75516,45 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { thisTypeForErrorOut.value = thisTypeForError; } if (errorNode) { - error(errorNode, Diagnostics.The_this_context_of_type_0_is_not_assignable_to_method_s_this_of_type_1, typeToString(type), typeToString(thisTypeForError)); + error( + errorNode, + Diagnostics.The_this_context_of_type_0_is_not_assignable_to_method_s_this_of_type_1, + typeToString(type), + typeToString(thisTypeForError) + ); } return undefined; } - const onfulfilledParameterType = getTypeWithFacts(getUnionType(map(candidates, getTypeOfFirstParameterOfSignature)), TypeFacts.NEUndefinedOrNull); + const onfulfilledParameterType = getTypeWithFacts( + getUnionType(map(candidates, getTypeOfFirstParameterOfSignature)), + TypeFacts.NEUndefinedOrNull + ); if (isTypeAny(onfulfilledParameterType)) { return undefined; } - const onfulfilledParameterSignatures = getSignaturesOfType(onfulfilledParameterType, SignatureKind.Call); + const onfulfilledParameterSignatures = getSignaturesOfType( + onfulfilledParameterType, + SignatureKind.Call + ); if (onfulfilledParameterSignatures.length === 0) { if (errorNode) { - error(errorNode, Diagnostics.The_first_parameter_of_the_then_method_of_a_promise_must_be_a_callback); + error( + errorNode, + Diagnostics.The_first_parameter_of_the_then_method_of_a_promise_must_be_a_callback + ); } return undefined; } - return typeAsPromise.promisedTypeOfPromise = getUnionType(map(onfulfilledParameterSignatures, getTypeOfFirstParameterOfSignature), UnionReduction.Subtype); + return (typeAsPromise.promisedTypeOfPromise = getUnionType( + map( + onfulfilledParameterSignatures, + getTypeOfFirstParameterOfSignature + ), + UnionReduction.Subtype + )); } /** @@ -43298,10 +75565,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Promise-like type; otherwise, it is the type of the expression. This is used to reflect * The runtime behavior of the `await` keyword. */ - function checkAwaitedType(type: Type, withAlias: boolean, errorNode: Node, diagnosticMessage: DiagnosticMessage, ...args: DiagnosticArguments): Type { - const awaitedType = withAlias ? - getAwaitedType(type, errorNode, diagnosticMessage, ...args) : - getAwaitedTypeNoAlias(type, errorNode, diagnosticMessage, ...args); + function checkAwaitedType( + type: Type, + withAlias: boolean, + errorNode: Node, + diagnosticMessage: DiagnosticMessage, + ...args: DiagnosticArguments + ): Type { + const awaitedType = withAlias + ? getAwaitedType(type, errorNode, diagnosticMessage, ...args) + : getAwaitedTypeNoAlias( + type, + errorNode, + diagnosticMessage, + ...args + ); return awaitedType || errorType; } @@ -43309,13 +75587,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Determines whether a type is an object with a callable `then` member. */ function isThenableType(type: Type): boolean { - if (allTypesAssignableToKind(getBaseConstraintOrType(type), TypeFlags.Primitive | TypeFlags.Never)) { + if ( + allTypesAssignableToKind( + getBaseConstraintOrType(type), + TypeFlags.Primitive | TypeFlags.Never + ) + ) { // primitive types cannot be considered "thenable" since they are not objects. return false; } const thenFunction = getTypeOfPropertyOfType(type, "then" as __String); - return !!thenFunction && getSignaturesOfType(getTypeWithFacts(thenFunction, TypeFacts.NEUndefinedOrNull), SignatureKind.Call).length > 0; + return ( + !!thenFunction && + getSignaturesOfType( + getTypeWithFacts(thenFunction, TypeFacts.NEUndefinedOrNull), + SignatureKind.Call + ).length > 0 + ); } interface AwaitedTypeInstantiation extends Type { @@ -43324,10 +75613,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { aliasTypeArguments: readonly Type[]; } - function isAwaitedTypeInstantiation(type: Type): type is AwaitedTypeInstantiation { + function isAwaitedTypeInstantiation( + type: Type + ): type is AwaitedTypeInstantiation { if (type.flags & TypeFlags.Conditional) { - const awaitedSymbol = getGlobalAwaitedSymbol(/*reportErrors*/ false); - return !!awaitedSymbol && type.aliasSymbol === awaitedSymbol && type.aliasTypeArguments?.length === 1; + const awaitedSymbol = getGlobalAwaitedSymbol( + /*reportErrors*/ false + ); + return ( + !!awaitedSymbol && + type.aliasSymbol === awaitedSymbol && + type.aliasTypeArguments?.length === 1 + ); } return false; } @@ -43336,9 +75633,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * For a generic `Awaited`, gets `T`. */ function unwrapAwaitedType(type: Type) { - return type.flags & TypeFlags.Union ? mapType(type, unwrapAwaitedType) : - isAwaitedTypeInstantiation(type) ? type.aliasTypeArguments[0] : - type; + return type.flags & TypeFlags.Union + ? mapType(type, unwrapAwaitedType) + : isAwaitedTypeInstantiation(type) + ? type.aliasTypeArguments[0] + : type; } function isAwaitedTypeNeeded(type: Type) { @@ -43353,9 +75652,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We only need `Awaited` if `T` is a type variable that has no base constraint, or the base constraint of `T` is `any`, `unknown`, `{}`, `object`, // or is promise-like. if ( - baseConstraint ? - baseConstraint.flags & TypeFlags.AnyOrUnknown || isEmptyObjectType(baseConstraint) || someType(baseConstraint, isThenableType) : - maybeTypeOfKind(type, TypeFlags.TypeVariable) + baseConstraint + ? baseConstraint.flags & TypeFlags.AnyOrUnknown || + isEmptyObjectType(baseConstraint) || + someType(baseConstraint, isThenableType) + : maybeTypeOfKind(type, TypeFlags.TypeVariable) ) { return true; } @@ -43370,7 +75671,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (awaitedSymbol) { // Unwrap unions that may contain `Awaited`, otherwise its possible to manufacture an `Awaited | U>` where // an `Awaited` would suffice. - return getTypeAliasInstantiation(awaitedSymbol, [unwrapAwaitedType(type)]); + return getTypeAliasInstantiation(awaitedSymbol, [ + unwrapAwaitedType(type), + ]); } return undefined; @@ -43389,7 +75692,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return tryCreateAwaitedType(type) ?? type; } - Debug.assert(isAwaitedTypeInstantiation(type) || getPromisedTypeOfPromise(type) === undefined, "type provided should not be a non-generic 'promise'-like."); + Debug.assert( + isAwaitedTypeInstantiation(type) || + getPromisedTypeOfPromise(type) === undefined, + "type provided should not be a non-generic 'promise'-like." + ); return type; } @@ -43403,8 +75710,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * * This is used to reflect the runtime behavior of the `await` keyword. */ - function getAwaitedType(type: Type, errorNode?: Node, diagnosticMessage?: DiagnosticMessage, ...args: DiagnosticArguments): Type | undefined { - const awaitedType = getAwaitedTypeNoAlias(type, errorNode, diagnosticMessage, ...args); + function getAwaitedType( + type: Type, + errorNode?: Node, + diagnosticMessage?: DiagnosticMessage, + ...args: DiagnosticArguments + ): Type | undefined { + const awaitedType = getAwaitedTypeNoAlias( + type, + errorNode, + diagnosticMessage, + ...args + ); return awaitedType && createAwaitedTypeIfNeeded(awaitedType); } @@ -43413,7 +75730,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * * @see {@link getAwaitedType} */ - function getAwaitedTypeNoAlias(type: Type, errorNode?: Node, diagnosticMessage?: DiagnosticMessage, ...args: DiagnosticArguments): Type | undefined { + function getAwaitedTypeNoAlias( + type: Type, + errorNode?: Node, + diagnosticMessage?: DiagnosticMessage, + ...args: DiagnosticArguments + ): Type | undefined { if (isTypeAny(type)) { return type; } @@ -43433,29 +75755,49 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (type.flags & TypeFlags.Union) { if (awaitedTypeStack.lastIndexOf(type.id) >= 0) { if (errorNode) { - error(errorNode, Diagnostics.Type_is_referenced_directly_or_indirectly_in_the_fulfillment_callback_of_its_own_then_method); + error( + errorNode, + Diagnostics.Type_is_referenced_directly_or_indirectly_in_the_fulfillment_callback_of_its_own_then_method + ); } return undefined; } - const mapper = errorNode ? (constituentType: Type) => getAwaitedTypeNoAlias(constituentType, errorNode, diagnosticMessage, ...args) : getAwaitedTypeNoAlias; + const mapper = errorNode + ? (constituentType: Type) => + getAwaitedTypeNoAlias( + constituentType, + errorNode, + diagnosticMessage, + ...args + ) + : getAwaitedTypeNoAlias; awaitedTypeStack.push(type.id); const mapped = mapType(type, mapper); awaitedTypeStack.pop(); - return typeAsAwaitable.awaitedTypeOfType = mapped; + return (typeAsAwaitable.awaitedTypeOfType = mapped); } // If `type` is generic and should be wrapped in `Awaited`, return it. if (isAwaitedTypeNeeded(type)) { - return typeAsAwaitable.awaitedTypeOfType = type; + return (typeAsAwaitable.awaitedTypeOfType = type); } - const thisTypeForErrorOut: { value: Type | undefined; } = { value: undefined }; - const promisedType = getPromisedTypeOfPromise(type, /*errorNode*/ undefined, thisTypeForErrorOut); + const thisTypeForErrorOut: { value: Type | undefined } = { + value: undefined, + }; + const promisedType = getPromisedTypeOfPromise( + type, + /*errorNode*/ undefined, + thisTypeForErrorOut + ); if (promisedType) { - if (type.id === promisedType.id || awaitedTypeStack.lastIndexOf(promisedType.id) >= 0) { + if ( + type.id === promisedType.id || + awaitedTypeStack.lastIndexOf(promisedType.id) >= 0 + ) { // Verify that we don't have a bad actor in the form of a promise whose // promised type is the same as the promise type, or a mutually recursive // promise. If so, we return undefined as we cannot guess the shape. If this @@ -43490,7 +75832,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // } // if (errorNode) { - error(errorNode, Diagnostics.Type_is_referenced_directly_or_indirectly_in_the_fulfillment_callback_of_its_own_then_method); + error( + errorNode, + Diagnostics.Type_is_referenced_directly_or_indirectly_in_the_fulfillment_callback_of_its_own_then_method + ); } return undefined; } @@ -43498,14 +75843,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Keep track of the type we're about to unwrap to avoid bad recursive promise types. // See the comments above for more information. awaitedTypeStack.push(type.id); - const awaitedType = getAwaitedTypeNoAlias(promisedType, errorNode, diagnosticMessage, ...args); + const awaitedType = getAwaitedTypeNoAlias( + promisedType, + errorNode, + diagnosticMessage, + ...args + ); awaitedTypeStack.pop(); if (!awaitedType) { return undefined; } - return typeAsAwaitable.awaitedTypeOfType = awaitedType; + return (typeAsAwaitable.awaitedTypeOfType = awaitedType); } // The type was not a promise, so it could not be unwrapped any further. @@ -43528,15 +75878,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { Debug.assertIsDefined(diagnosticMessage); let chain: DiagnosticMessageChain | undefined; if (thisTypeForErrorOut.value) { - 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)); + 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) + ); } - chain = chainDiagnosticMessages(chain, diagnosticMessage, ...args); - diagnostics.add(createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(errorNode), errorNode, chain)); + chain = chainDiagnosticMessages( + chain, + diagnosticMessage, + ...args + ); + diagnostics.add( + createDiagnosticForNodeFromMessageChain( + getSourceFileOfNode(errorNode), + errorNode, + chain + ) + ); } return undefined; } - return typeAsAwaitable.awaitedTypeOfType = type; + return (typeAsAwaitable.awaitedTypeOfType = type); } /** @@ -43551,7 +75916,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * * @param node The signature to check */ - function checkAsyncFunctionReturnType(node: FunctionLikeDeclaration | MethodSignature, returnTypeNode: TypeNode, returnTypeErrorLocation: TypeNode) { + function checkAsyncFunctionReturnType( + node: FunctionLikeDeclaration | MethodSignature, + returnTypeNode: TypeNode, + returnTypeErrorLocation: TypeNode + ) { // As part of our emit for an async function, we will need to emit the entity name of // the return type annotation as an expression. To meet the necessary runtime semantics // for __awaiter, we must also check that the type of the declaration (e.g. the static @@ -43581,71 +75950,151 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isErrorType(returnType)) { return; } - const globalPromiseType = getGlobalPromiseType(/*reportErrors*/ true); - if (globalPromiseType !== emptyGenericType && !isReferenceToType(returnType, globalPromiseType)) { + const globalPromiseType = getGlobalPromiseType( + /*reportErrors*/ true + ); + if ( + globalPromiseType !== emptyGenericType && + !isReferenceToType(returnType, globalPromiseType) + ) { // The promise type was not a valid type reference to the global promise type, so we // report an error and return the unknown type. - reportErrorForInvalidReturnType(Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type_Did_you_mean_to_write_Promise_0, returnTypeNode, returnTypeErrorLocation, typeToString(getAwaitedTypeNoAlias(returnType) || voidType)); + reportErrorForInvalidReturnType( + Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type_Did_you_mean_to_write_Promise_0, + returnTypeNode, + returnTypeErrorLocation, + typeToString(getAwaitedTypeNoAlias(returnType) || voidType) + ); return; } - } - else { + } else { // Always mark the type node as referenced if it points to a value markLinkedReferences(node, ReferenceHint.AsyncFunction); if (isErrorType(returnType)) { return; } - const promiseConstructorName = getEntityNameFromTypeNode(returnTypeNode); + const promiseConstructorName = + getEntityNameFromTypeNode(returnTypeNode); if (promiseConstructorName === undefined) { - reportErrorForInvalidReturnType(Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, returnTypeNode, returnTypeErrorLocation, typeToString(returnType)); + reportErrorForInvalidReturnType( + Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, + returnTypeNode, + returnTypeErrorLocation, + typeToString(returnType) + ); return; } - const promiseConstructorSymbol = resolveEntityName(promiseConstructorName, SymbolFlags.Value, /*ignoreErrors*/ true); - const promiseConstructorType = promiseConstructorSymbol ? getTypeOfSymbol(promiseConstructorSymbol) : errorType; + const promiseConstructorSymbol = resolveEntityName( + promiseConstructorName, + SymbolFlags.Value, + /*ignoreErrors*/ true + ); + const promiseConstructorType = promiseConstructorSymbol + ? getTypeOfSymbol(promiseConstructorSymbol) + : errorType; if (isErrorType(promiseConstructorType)) { - if (promiseConstructorName.kind === SyntaxKind.Identifier && promiseConstructorName.escapedText === "Promise" && getTargetType(returnType) === getGlobalPromiseType(/*reportErrors*/ false)) { - error(returnTypeErrorLocation, Diagnostics.An_async_function_or_method_in_ES5_requires_the_Promise_constructor_Make_sure_you_have_a_declaration_for_the_Promise_constructor_or_include_ES2015_in_your_lib_option); - } - else { - reportErrorForInvalidReturnType(Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, returnTypeNode, returnTypeErrorLocation, entityNameToString(promiseConstructorName)); + if ( + promiseConstructorName.kind === SyntaxKind.Identifier && + promiseConstructorName.escapedText === "Promise" && + getTargetType(returnType) === + getGlobalPromiseType(/*reportErrors*/ false) + ) { + error( + returnTypeErrorLocation, + Diagnostics.An_async_function_or_method_in_ES5_requires_the_Promise_constructor_Make_sure_you_have_a_declaration_for_the_Promise_constructor_or_include_ES2015_in_your_lib_option + ); + } else { + reportErrorForInvalidReturnType( + Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, + returnTypeNode, + returnTypeErrorLocation, + entityNameToString(promiseConstructorName) + ); } return; } - const globalPromiseConstructorLikeType = getGlobalPromiseConstructorLikeType(/*reportErrors*/ true); + const globalPromiseConstructorLikeType = + getGlobalPromiseConstructorLikeType(/*reportErrors*/ true); if (globalPromiseConstructorLikeType === emptyObjectType) { // If we couldn't resolve the global PromiseConstructorLike type we cannot verify // compatibility with __awaiter. - reportErrorForInvalidReturnType(Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, returnTypeNode, returnTypeErrorLocation, entityNameToString(promiseConstructorName)); + reportErrorForInvalidReturnType( + Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, + returnTypeNode, + returnTypeErrorLocation, + entityNameToString(promiseConstructorName) + ); return; } - const headMessage = Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_because_it_does_not_refer_to_a_Promise_compatible_constructor_value; - const errorInfo = () => returnTypeNode === returnTypeErrorLocation ? undefined : chainDiagnosticMessages(/*details*/ undefined, Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type); - if (!checkTypeAssignableTo(promiseConstructorType, globalPromiseConstructorLikeType, returnTypeErrorLocation, headMessage, errorInfo)) { + const headMessage = + Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_because_it_does_not_refer_to_a_Promise_compatible_constructor_value; + const errorInfo = () => + returnTypeNode === returnTypeErrorLocation + ? undefined + : chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type + ); + if ( + !checkTypeAssignableTo( + promiseConstructorType, + globalPromiseConstructorLikeType, + returnTypeErrorLocation, + headMessage, + errorInfo + ) + ) { return; } // Verify there is no local declaration that could collide with the promise constructor. - const rootName = promiseConstructorName && getFirstIdentifier(promiseConstructorName); - const collidingSymbol = getSymbol(node.locals!, rootName.escapedText, SymbolFlags.Value); + const rootName = + promiseConstructorName && + getFirstIdentifier(promiseConstructorName); + const collidingSymbol = getSymbol( + node.locals!, + rootName.escapedText, + SymbolFlags.Value + ); if (collidingSymbol) { - error(collidingSymbol.valueDeclaration, Diagnostics.Duplicate_identifier_0_Compiler_uses_declaration_1_to_support_async_functions, idText(rootName), entityNameToString(promiseConstructorName)); + error( + collidingSymbol.valueDeclaration, + Diagnostics.Duplicate_identifier_0_Compiler_uses_declaration_1_to_support_async_functions, + idText(rootName), + entityNameToString(promiseConstructorName) + ); return; } } - 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); + 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 + ); - function reportErrorForInvalidReturnType(message: DiagnosticMessage, returnTypeNode: TypeNode, returnTypeErrorLocation: TypeNode, typeName: string) { + function reportErrorForInvalidReturnType( + message: DiagnosticMessage, + returnTypeNode: TypeNode, + returnTypeErrorLocation: TypeNode, + typeName: string + ) { if (returnTypeNode === returnTypeErrorLocation) { error(returnTypeErrorLocation, message, typeName); - } - else { - const diag = error(returnTypeErrorLocation, Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type); - addRelatedInfo(diag, createDiagnosticForNode(returnTypeNode, message, typeName)); + } else { + const diag = error( + returnTypeErrorLocation, + Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type + ); + addRelatedInfo( + diag, + createDiagnosticForNode(returnTypeNode, message, typeName) + ); } } } @@ -43666,7 +76115,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let errorNode: Node | undefined; while (true) { // Allow TS syntax such as non-null assertions and instantiation expressions - if (isExpressionWithTypeArguments(node) || isNonNullExpression(node)) { + if ( + isExpressionWithTypeArguments(node) || + isNonNullExpression(node) + ) { node = node.expression; continue; } @@ -43712,8 +76164,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (errorNode) { addRelatedInfo( - error(decorator.expression, Diagnostics.Expression_must_be_enclosed_in_parentheses_to_be_used_as_a_decorator), - createDiagnosticForNode(errorNode, Diagnostics.Invalid_syntax_in_decorator), + error( + decorator.expression, + Diagnostics.Expression_must_be_enclosed_in_parentheses_to_be_used_as_a_decorator + ), + createDiagnosticForNode( + errorNode, + Diagnostics.Invalid_syntax_in_decorator + ) ); return true; } @@ -43742,31 +76200,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { switch (node.parent.kind) { case SyntaxKind.ClassDeclaration: case SyntaxKind.ClassExpression: - headMessage = Diagnostics.Decorator_function_return_type_0_is_not_assignable_to_type_1; + headMessage = + Diagnostics.Decorator_function_return_type_0_is_not_assignable_to_type_1; break; case SyntaxKind.PropertyDeclaration: if (!legacyDecorators) { - headMessage = Diagnostics.Decorator_function_return_type_0_is_not_assignable_to_type_1; + headMessage = + Diagnostics.Decorator_function_return_type_0_is_not_assignable_to_type_1; break; } - // falls through + // falls through case SyntaxKind.Parameter: - headMessage = Diagnostics.Decorator_function_return_type_is_0_but_is_expected_to_be_void_or_any; + headMessage = + Diagnostics.Decorator_function_return_type_is_0_but_is_expected_to_be_void_or_any; break; case SyntaxKind.MethodDeclaration: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: - headMessage = Diagnostics.Decorator_function_return_type_0_is_not_assignable_to_type_1; + headMessage = + Diagnostics.Decorator_function_return_type_0_is_not_assignable_to_type_1; break; default: return Debug.failBadSyntaxKind(node.parent); } - checkTypeAssignableTo(returnType, expectedReturnType, node.expression, headMessage); + checkTypeAssignableTo( + returnType, + expectedReturnType, + node.expression, + headMessage + ); } /** @@ -43779,10 +76246,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { returnType: Type, typePredicate?: TypePredicate, minArgumentCount: number = parameters.length, - flags: SignatureFlags = SignatureFlags.None, + flags: SignatureFlags = SignatureFlags.None ) { - const decl = factory.createFunctionTypeNode(/*typeParameters*/ undefined, emptyArray, factory.createKeywordTypeNode(SyntaxKind.AnyKeyword)); - return createSignature(decl, typeParameters, thisParameter, parameters, returnType, typePredicate, minArgumentCount, flags); + const decl = factory.createFunctionTypeNode( + /*typeParameters*/ undefined, + emptyArray, + factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) + ); + return createSignature( + decl, + typeParameters, + thisParameter, + parameters, + returnType, + typePredicate, + minArgumentCount, + flags + ); } /** @@ -43795,34 +76275,61 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { returnType: Type, typePredicate?: TypePredicate, minArgumentCount?: number, - flags?: SignatureFlags, + flags?: SignatureFlags ) { - const signature = createCallSignature(typeParameters, thisParameter, parameters, returnType, typePredicate, minArgumentCount, flags); + const signature = createCallSignature( + typeParameters, + thisParameter, + parameters, + returnType, + typePredicate, + minArgumentCount, + flags + ); return getOrCreateTypeFromSignature(signature); } function createGetterFunctionType(type: Type) { - return createFunctionType(/*typeParameters*/ undefined, /*thisParameter*/ undefined, emptyArray, type); + return createFunctionType( + /*typeParameters*/ undefined, + /*thisParameter*/ undefined, + emptyArray, + type + ); } function createSetterFunctionType(type: Type) { const valueParam = createParameter("value" as __String, type); - return createFunctionType(/*typeParameters*/ undefined, /*thisParameter*/ undefined, [valueParam], voidType); + return createFunctionType( + /*typeParameters*/ undefined, + /*thisParameter*/ undefined, + [valueParam], + voidType + ); } - function getEntityNameForDecoratorMetadata(node: TypeNode | undefined): EntityName | undefined { + function getEntityNameForDecoratorMetadata( + node: TypeNode | undefined + ): EntityName | undefined { if (node) { switch (node.kind) { case SyntaxKind.IntersectionType: case SyntaxKind.UnionType: - return getEntityNameForDecoratorMetadataFromTypeList((node as UnionOrIntersectionTypeNode).types); + return getEntityNameForDecoratorMetadataFromTypeList( + (node as UnionOrIntersectionTypeNode).types + ); case SyntaxKind.ConditionalType: - return getEntityNameForDecoratorMetadataFromTypeList([(node as ConditionalTypeNode).trueType, (node as ConditionalTypeNode).falseType]); + return getEntityNameForDecoratorMetadataFromTypeList([ + (node as ConditionalTypeNode).trueType, + (node as ConditionalTypeNode).falseType, + ]); case SyntaxKind.ParenthesizedType: case SyntaxKind.NamedTupleMember: - return getEntityNameForDecoratorMetadata((node as ParenthesizedTypeNode).type); + return getEntityNameForDecoratorMetadata( + (node as ParenthesizedTypeNode).type + ); case SyntaxKind.TypeReference: return (node as TypeReferenceNode).typeName; @@ -43830,19 +76337,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getEntityNameForDecoratorMetadataFromTypeList(types: readonly TypeNode[]): EntityName | undefined { + function getEntityNameForDecoratorMetadataFromTypeList( + types: readonly TypeNode[] + ): EntityName | undefined { let commonEntityName: EntityName | undefined; for (let typeNode of types) { - while (typeNode.kind === SyntaxKind.ParenthesizedType || typeNode.kind === SyntaxKind.NamedTupleMember) { - typeNode = (typeNode as ParenthesizedTypeNode | NamedTupleMember).type; // Skip parens if need be + while ( + typeNode.kind === SyntaxKind.ParenthesizedType || + typeNode.kind === SyntaxKind.NamedTupleMember + ) { + typeNode = ( + typeNode as ParenthesizedTypeNode | NamedTupleMember + ).type; // Skip parens if need be } if (typeNode.kind === SyntaxKind.NeverKeyword) { continue; // Always elide `never` from the union/intersection if possible } - if (!strictNullChecks && (typeNode.kind === SyntaxKind.LiteralType && (typeNode as LiteralTypeNode).literal.kind === SyntaxKind.NullKeyword || typeNode.kind === SyntaxKind.UndefinedKeyword)) { + if ( + !strictNullChecks && + ((typeNode.kind === SyntaxKind.LiteralType && + (typeNode as LiteralTypeNode).literal.kind === + SyntaxKind.NullKeyword) || + typeNode.kind === SyntaxKind.UndefinedKeyword) + ) { continue; // Elide null and undefined from unions for metadata, just like what we did prior to the implementation of strict null checks } - const individualEntityName = getEntityNameForDecoratorMetadata(typeNode); + const individualEntityName = + getEntityNameForDecoratorMetadata(typeNode); if (!individualEntityName) { // Individual is something like string number // So it would be serialized to either that type or object @@ -43858,28 +76379,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if ( !isIdentifier(commonEntityName) || !isIdentifier(individualEntityName) || - commonEntityName.escapedText !== individualEntityName.escapedText + commonEntityName.escapedText !== + individualEntityName.escapedText ) { return undefined; } - } - else { + } else { commonEntityName = individualEntityName; } } return commonEntityName; } - function getParameterTypeNodeForDecoratorCheck(node: ParameterDeclaration): TypeNode | undefined { + function getParameterTypeNodeForDecoratorCheck( + node: ParameterDeclaration + ): TypeNode | undefined { const typeNode = getEffectiveTypeAnnotationNode(node); - return isRestParameter(node) ? getRestParameterElementType(typeNode) : typeNode; + return isRestParameter(node) + ? getRestParameterElementType(typeNode) + : typeNode; } /** Check the decorators of a node */ function checkDecorators(node: Node): void { // skip this check for nodes that cannot have decorators. These should have already had an error reported by // checkGrammarModifiers. - if (!canHaveDecorators(node) || !hasDecorators(node) || !node.modifiers || !nodeCanBeDecorated(legacyDecorators, node, node.parent, node.parent.parent)) { + if ( + !canHaveDecorators(node) || + !hasDecorators(node) || + !node.modifiers || + !nodeCanBeDecorated( + legacyDecorators, + node, + node.parent, + node.parent.parent + ) + ) { return; } @@ -43889,30 +76424,57 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (legacyDecorators) { - checkExternalEmitHelpers(firstDecorator, ExternalEmitHelpers.Decorate); + checkExternalEmitHelpers( + firstDecorator, + ExternalEmitHelpers.Decorate + ); if (node.kind === SyntaxKind.Parameter) { - checkExternalEmitHelpers(firstDecorator, ExternalEmitHelpers.Param); + checkExternalEmitHelpers( + firstDecorator, + ExternalEmitHelpers.Param + ); } - } - else if (languageVersion < LanguageFeatureMinimumTarget.ClassAndClassElementDecorators) { - checkExternalEmitHelpers(firstDecorator, ExternalEmitHelpers.ESDecorateAndRunInitializers); + } else if ( + languageVersion < + LanguageFeatureMinimumTarget.ClassAndClassElementDecorators + ) { + checkExternalEmitHelpers( + firstDecorator, + ExternalEmitHelpers.ESDecorateAndRunInitializers + ); if (isClassDeclaration(node)) { if (!node.name) { - checkExternalEmitHelpers(firstDecorator, ExternalEmitHelpers.SetFunctionName); - } - else { - const member = getFirstTransformableStaticClassElement(node); + checkExternalEmitHelpers( + firstDecorator, + ExternalEmitHelpers.SetFunctionName + ); + } else { + const member = + getFirstTransformableStaticClassElement(node); if (member) { - checkExternalEmitHelpers(firstDecorator, ExternalEmitHelpers.SetFunctionName); + checkExternalEmitHelpers( + firstDecorator, + ExternalEmitHelpers.SetFunctionName + ); } } - } - else if (!isClassExpression(node)) { - if (isPrivateIdentifier(node.name) && (isMethodDeclaration(node) || isAccessor(node) || isAutoAccessorPropertyDeclaration(node))) { - checkExternalEmitHelpers(firstDecorator, ExternalEmitHelpers.SetFunctionName); + } else if (!isClassExpression(node)) { + if ( + isPrivateIdentifier(node.name) && + (isMethodDeclaration(node) || + isAccessor(node) || + isAutoAccessorPropertyDeclaration(node)) + ) { + checkExternalEmitHelpers( + firstDecorator, + ExternalEmitHelpers.SetFunctionName + ); } if (isComputedPropertyName(node.name)) { - checkExternalEmitHelpers(firstDecorator, ExternalEmitHelpers.PropKey); + checkExternalEmitHelpers( + firstDecorator, + ExternalEmitHelpers.PropKey + ); } } } @@ -43939,11 +76501,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkJSDocTypeAliasTag(node: JSDocTypedefTag | JSDocCallbackTag) { if (!node.typeExpression) { // If the node had `@property` tags, `typeExpression` would have been set to the first property tag. - error(node.name, Diagnostics.JSDoc_typedef_tag_should_either_have_a_type_annotation_or_be_followed_by_property_or_member_tags); + error( + node.name, + Diagnostics.JSDoc_typedef_tag_should_either_have_a_type_annotation_or_be_followed_by_property_or_member_tags + ); } if (node.name) { - checkTypeNameIsReserved(node.name, Diagnostics.Type_alias_name_cannot_be_0); + checkTypeNameIsReserved( + node.name, + Diagnostics.Type_alias_name_cannot_be_0 + ); } checkSourceElement(node.typeExpression); checkTypeParameters(getEffectiveTypeParameterDeclarations(node)); @@ -43968,13 +76536,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (length(tags) > 1) { for (let i = 1; i < length(tags); i++) { const tagName = tags[i].tagName; - error(tagName, Diagnostics._0_tag_already_specified, idText(tagName)); + error( + tagName, + Diagnostics._0_tag_already_specified, + idText(tagName) + ); } } } } - function checkJSDocLinkLikeTag(node: JSDocLink | JSDocLinkCode | JSDocLinkPlain) { + function checkJSDocLinkLikeTag( + node: JSDocLink | JSDocLinkCode | JSDocLinkPlain + ) { if (node.name) { resolveJSDocMemberName(node.name, /*ignoreErrors*/ true); } @@ -44002,7 +76576,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkJSDocThisTag(node: JSDocThisTag) { const host = getEffectiveJSDocHost(node); if (host && isArrowFunction(host)) { - error(node.tagName, Diagnostics.An_arrow_function_cannot_have_a_this_parameter); + error( + node.tagName, + Diagnostics.An_arrow_function_cannot_have_a_this_parameter + ); } } @@ -44012,44 +76589,82 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkJSDocImplementsTag(node: JSDocImplementsTag): void { const classLike = getEffectiveJSDocHost(node); - if (!classLike || !isClassDeclaration(classLike) && !isClassExpression(classLike)) { - error(classLike, Diagnostics.JSDoc_0_is_not_attached_to_a_class, idText(node.tagName)); + if ( + !classLike || + (!isClassDeclaration(classLike) && !isClassExpression(classLike)) + ) { + error( + classLike, + Diagnostics.JSDoc_0_is_not_attached_to_a_class, + idText(node.tagName) + ); } } function checkJSDocAugmentsTag(node: JSDocAugmentsTag): void { const classLike = getEffectiveJSDocHost(node); - if (!classLike || !isClassDeclaration(classLike) && !isClassExpression(classLike)) { - error(classLike, Diagnostics.JSDoc_0_is_not_attached_to_a_class, idText(node.tagName)); + if ( + !classLike || + (!isClassDeclaration(classLike) && !isClassExpression(classLike)) + ) { + error( + classLike, + Diagnostics.JSDoc_0_is_not_attached_to_a_class, + idText(node.tagName) + ); return; } const augmentsTags = getJSDocTags(classLike).filter(isJSDocAugmentsTag); Debug.assert(augmentsTags.length > 0); if (augmentsTags.length > 1) { - error(augmentsTags[1], Diagnostics.Class_declarations_cannot_have_more_than_one_augments_or_extends_tag); + error( + augmentsTags[1], + Diagnostics.Class_declarations_cannot_have_more_than_one_augments_or_extends_tag + ); } - const name = getIdentifierFromEntityNameExpression(node.class.expression); + const name = getIdentifierFromEntityNameExpression( + node.class.expression + ); const extend = getClassExtendsHeritageElement(classLike); if (extend) { - const className = getIdentifierFromEntityNameExpression(extend.expression); + const className = getIdentifierFromEntityNameExpression( + extend.expression + ); if (className && name.escapedText !== className.escapedText) { - error(name, Diagnostics.JSDoc_0_1_does_not_match_the_extends_2_clause, idText(node.tagName), idText(name), idText(className)); + error( + name, + Diagnostics.JSDoc_0_1_does_not_match_the_extends_2_clause, + idText(node.tagName), + idText(name), + idText(className) + ); } } } - function checkJSDocAccessibilityModifiers(node: JSDocPublicTag | JSDocProtectedTag | JSDocPrivateTag): void { + function checkJSDocAccessibilityModifiers( + node: JSDocPublicTag | JSDocProtectedTag | JSDocPrivateTag + ): void { const host = getJSDocHost(node); if (host && isPrivateIdentifierClassElementDeclaration(host)) { - error(node, Diagnostics.An_accessibility_modifier_cannot_be_used_with_a_private_identifier); + error( + node, + Diagnostics.An_accessibility_modifier_cannot_be_used_with_a_private_identifier + ); } } - function getIdentifierFromEntityNameExpression(node: Identifier | PropertyAccessExpression): Identifier | PrivateIdentifier; - function getIdentifierFromEntityNameExpression(node: Expression): Identifier | PrivateIdentifier | undefined; - function getIdentifierFromEntityNameExpression(node: Expression): Identifier | PrivateIdentifier | undefined { + function getIdentifierFromEntityNameExpression( + node: Identifier | PropertyAccessExpression + ): Identifier | PrivateIdentifier; + function getIdentifierFromEntityNameExpression( + node: Expression + ): Identifier | PrivateIdentifier | undefined; + function getIdentifierFromEntityNameExpression( + node: Expression + ): Identifier | PrivateIdentifier | undefined { switch (node.kind) { case SyntaxKind.Identifier: return node as Identifier; @@ -44060,7 +76675,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function checkFunctionOrMethodDeclaration(node: FunctionDeclaration | MethodDeclaration | MethodSignature): void { + function checkFunctionOrMethodDeclaration( + node: FunctionDeclaration | MethodDeclaration | MethodSignature + ): void { checkDecorators(node); checkSignatureDeclaration(node); const functionFlags = getFunctionFlags(node); @@ -44086,7 +76703,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // checkFunctionOrConstructorSymbol wouldn't be called if we didnt ignore javascript function. const firstDeclaration = localSymbol.declarations?.find( // Get first non javascript function declaration - declaration => declaration.kind === node.kind && !(declaration.flags & NodeFlags.JavaScriptFile), + (declaration) => + declaration.kind === node.kind && + !(declaration.flags & NodeFlags.JavaScriptFile) ); // Only type check the symbol once @@ -44100,17 +76719,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - const body = node.kind === SyntaxKind.MethodSignature ? undefined : node.body; + const body = + node.kind === SyntaxKind.MethodSignature ? undefined : node.body; checkSourceElement(body); - checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, getReturnTypeFromAnnotation(node)); + checkAllCodePathsInNonVoidFunctionReturnOrThrow( + node, + getReturnTypeFromAnnotation(node) + ); addLazyDiagnostic(checkFunctionOrMethodDeclarationDiagnostics); // A js function declaration can have a @type tag instead of a return type node, but that type must have a call signature if (isInJSFile(node)) { const typeTag = getJSDocTypeTag(node); - if (typeTag && typeTag.typeExpression && !getContextualCallSignature(getTypeFromTypeNode(typeTag.typeExpression), node)) { - error(typeTag.typeExpression.type, Diagnostics.The_type_of_a_function_declaration_must_match_the_function_s_signature); + if ( + typeTag && + typeTag.typeExpression && + !getContextualCallSignature( + getTypeFromTypeNode(typeTag.typeExpression), + node + ) + ) { + error( + typeTag.typeExpression.type, + Diagnostics.The_type_of_a_function_declaration_must_match_the_function_s_signature + ); } } @@ -44122,7 +76755,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { reportImplicitAny(node, anyType); } - if (functionFlags & FunctionFlags.Generator && nodeIsPresent(body)) { + if ( + functionFlags & FunctionFlags.Generator && + nodeIsPresent(body) + ) { // A generator with a body and no type annotation can still cause errors. It can error if the // yielded values have no common supertype, or it can give an implicit any error if it has no // yielded values. The only way to trigger these errors is to try checking its return type. @@ -44132,16 +76768,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function registerForUnusedIdentifiersCheck(node: PotentiallyUnusedIdentifier): void { + function registerForUnusedIdentifiersCheck( + node: PotentiallyUnusedIdentifier + ): void { addLazyDiagnostic(registerForUnusedIdentifiersCheckDiagnostics); function registerForUnusedIdentifiersCheckDiagnostics() { // May be in a call such as getTypeOfNode that happened to call this. But potentiallyUnusedIdentifiers is only defined in the scope of `checkSourceFile`. const sourceFile = getSourceFileOfNode(node); - let potentiallyUnusedIdentifiers = allPotentiallyUnusedIdentifiers.get(sourceFile.path); + let potentiallyUnusedIdentifiers = + allPotentiallyUnusedIdentifiers.get(sourceFile.path); if (!potentiallyUnusedIdentifiers) { potentiallyUnusedIdentifiers = []; - allPotentiallyUnusedIdentifiers.set(sourceFile.path, potentiallyUnusedIdentifiers); + allPotentiallyUnusedIdentifiers.set( + sourceFile.path, + potentiallyUnusedIdentifiers + ); } // TODO: GH#22580 // Debug.assert(addToSeen(seenPotentiallyUnusedIdentifiers, getNodeId(node)), "Adding potentially-unused identifier twice"); @@ -44149,9 +76791,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - type PotentiallyUnusedIdentifier = SourceFile | ModuleDeclaration | ClassLikeDeclaration | InterfaceDeclaration | Block | CaseBlock | ForStatement | ForInStatement | ForOfStatement | Exclude | TypeAliasDeclaration | InferTypeNode; - - function checkUnusedIdentifiers(potentiallyUnusedIdentifiers: readonly PotentiallyUnusedIdentifier[], addDiagnostic: AddUnusedDiagnostic) { + type PotentiallyUnusedIdentifier = + | SourceFile + | ModuleDeclaration + | ClassLikeDeclaration + | InterfaceDeclaration + | Block + | CaseBlock + | ForStatement + | ForInStatement + | ForOfStatement + | Exclude< + SignatureDeclaration, + IndexSignatureDeclaration | JSDocFunctionType + > + | TypeAliasDeclaration + | InferTypeNode; + + function checkUnusedIdentifiers( + potentiallyUnusedIdentifiers: readonly PotentiallyUnusedIdentifier[], + addDiagnostic: AddUnusedDiagnostic + ) { for (const node of potentiallyUnusedIdentifiers) { switch (node.kind) { case SyntaxKind.ClassDeclaration: @@ -44194,45 +76854,92 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkUnusedInferTypeParameter(node, addDiagnostic); break; default: - Debug.assertNever(node, "Node should not have been registered for unused identifiers check"); + Debug.assertNever( + node, + "Node should not have been registered for unused identifiers check" + ); } } } - function errorUnusedLocal(declaration: Declaration, name: string, addDiagnostic: AddUnusedDiagnostic) { + function errorUnusedLocal( + declaration: Declaration, + name: string, + addDiagnostic: AddUnusedDiagnostic + ) { const node = getNameOfDeclaration(declaration) || declaration; - const message = isTypeDeclaration(declaration) ? Diagnostics._0_is_declared_but_never_used : Diagnostics._0_is_declared_but_its_value_is_never_read; - addDiagnostic(declaration, UnusedKind.Local, createDiagnosticForNode(node, message, name)); + const message = isTypeDeclaration(declaration) + ? Diagnostics._0_is_declared_but_never_used + : Diagnostics._0_is_declared_but_its_value_is_never_read; + addDiagnostic( + declaration, + UnusedKind.Local, + createDiagnosticForNode(node, message, name) + ); } function isIdentifierThatStartsWithUnderscore(node: Node) { - return isIdentifier(node) && idText(node).charCodeAt(0) === CharacterCodes._; + return ( + isIdentifier(node) && + idText(node).charCodeAt(0) === CharacterCodes._ + ); } - function checkUnusedClassMembers(node: ClassDeclaration | ClassExpression, addDiagnostic: AddUnusedDiagnostic): void { + function checkUnusedClassMembers( + node: ClassDeclaration | ClassExpression, + addDiagnostic: AddUnusedDiagnostic + ): void { for (const member of node.members) { switch (member.kind) { case SyntaxKind.MethodDeclaration: case SyntaxKind.PropertyDeclaration: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: - if (member.kind === SyntaxKind.SetAccessor && member.symbol.flags & SymbolFlags.GetAccessor) { + if ( + member.kind === SyntaxKind.SetAccessor && + member.symbol.flags & SymbolFlags.GetAccessor + ) { // Already would have reported an error on the getter. break; } const symbol = getSymbolOfDeclaration(member); if ( - !symbol.isReferenced - && (hasEffectiveModifier(member, ModifierFlags.Private) || isNamedDeclaration(member) && isPrivateIdentifier(member.name)) - && !(member.flags & NodeFlags.Ambient) + !symbol.isReferenced && + (hasEffectiveModifier(member, ModifierFlags.Private) || + (isNamedDeclaration(member) && + isPrivateIdentifier(member.name))) && + !(member.flags & NodeFlags.Ambient) ) { - addDiagnostic(member, UnusedKind.Local, createDiagnosticForNode(member.name!, Diagnostics._0_is_declared_but_its_value_is_never_read, symbolToString(symbol))); + addDiagnostic( + member, + UnusedKind.Local, + createDiagnosticForNode( + member.name!, + Diagnostics._0_is_declared_but_its_value_is_never_read, + symbolToString(symbol) + ) + ); } break; case SyntaxKind.Constructor: - for (const parameter of (member as ConstructorDeclaration).parameters) { - if (!parameter.symbol.isReferenced && hasSyntacticModifier(parameter, ModifierFlags.Private)) { - addDiagnostic(parameter, UnusedKind.Local, createDiagnosticForNode(parameter.name, Diagnostics.Property_0_is_declared_but_its_value_is_never_read, symbolName(parameter.symbol))); + for (const parameter of (member as ConstructorDeclaration) + .parameters) { + if ( + !parameter.symbol.isReferenced && + hasSyntacticModifier( + parameter, + ModifierFlags.Private + ) + ) { + addDiagnostic( + parameter, + UnusedKind.Local, + createDiagnosticForNode( + parameter.name, + Diagnostics.Property_0_is_declared_but_its_value_is_never_read, + symbolName(parameter.symbol) + ) + ); } } break; @@ -44247,65 +76954,122 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function checkUnusedInferTypeParameter(node: InferTypeNode, addDiagnostic: AddUnusedDiagnostic): void { + function checkUnusedInferTypeParameter( + node: InferTypeNode, + addDiagnostic: AddUnusedDiagnostic + ): void { const { typeParameter } = node; if (isTypeParameterUnused(typeParameter)) { - addDiagnostic(node, UnusedKind.Parameter, createDiagnosticForNode(node, Diagnostics._0_is_declared_but_its_value_is_never_read, idText(typeParameter.name))); + addDiagnostic( + node, + UnusedKind.Parameter, + createDiagnosticForNode( + node, + Diagnostics._0_is_declared_but_its_value_is_never_read, + idText(typeParameter.name) + ) + ); } } - function checkUnusedTypeParameters(node: ClassLikeDeclaration | SignatureDeclaration | InterfaceDeclaration | TypeAliasDeclaration, addDiagnostic: AddUnusedDiagnostic): void { + function checkUnusedTypeParameters( + node: + | ClassLikeDeclaration + | SignatureDeclaration + | InterfaceDeclaration + | TypeAliasDeclaration, + addDiagnostic: AddUnusedDiagnostic + ): void { // Only report errors on the last declaration for the type parameter container; // this ensures that all uses have been accounted for. const declarations = getSymbolOfDeclaration(node).declarations; if (!declarations || last(declarations) !== node) return; const typeParameters = getEffectiveTypeParameterDeclarations(node); - const seenParentsWithEveryUnused = new Set(); + const seenParentsWithEveryUnused = + new Set(); for (const typeParameter of typeParameters) { if (!isTypeParameterUnused(typeParameter)) continue; const name = idText(typeParameter.name); const { parent } = typeParameter; - if (parent.kind !== SyntaxKind.InferType && parent.typeParameters!.every(isTypeParameterUnused)) { + if ( + parent.kind !== SyntaxKind.InferType && + parent.typeParameters!.every(isTypeParameterUnused) + ) { if (tryAddToSet(seenParentsWithEveryUnused, parent)) { const sourceFile = getSourceFileOfNode(parent); const range = isJSDocTemplateTag(parent) - // Whole @template tag - ? rangeOfNode(parent) - // Include the `<>` in the error message - : rangeOfTypeParameters(sourceFile, parent.typeParameters!); + ? // Whole @template tag + rangeOfNode(parent) + : // Include the `<>` in the error message + rangeOfTypeParameters( + sourceFile, + parent.typeParameters! + ); const only = parent.typeParameters!.length === 1; // TODO: following line is possible reason for bug #41974, unusedTypeParameters_TemplateTag const messageAndArg: DiagnosticAndArguments = only - ? [Diagnostics._0_is_declared_but_its_value_is_never_read, name] + ? [ + Diagnostics._0_is_declared_but_its_value_is_never_read, + name, + ] : [Diagnostics.All_type_parameters_are_unused]; - addDiagnostic(typeParameter, UnusedKind.Parameter, createFileDiagnostic(sourceFile, range.pos, range.end - range.pos, ...messageAndArg)); + addDiagnostic( + typeParameter, + UnusedKind.Parameter, + createFileDiagnostic( + sourceFile, + range.pos, + range.end - range.pos, + ...messageAndArg + ) + ); } - } - else { + } else { // TODO: following line is possible reason for bug #41974, unusedTypeParameters_TemplateTag - addDiagnostic(typeParameter, UnusedKind.Parameter, createDiagnosticForNode(typeParameter, Diagnostics._0_is_declared_but_its_value_is_never_read, name)); + addDiagnostic( + typeParameter, + UnusedKind.Parameter, + createDiagnosticForNode( + typeParameter, + Diagnostics._0_is_declared_but_its_value_is_never_read, + name + ) + ); } } } - function isTypeParameterUnused(typeParameter: TypeParameterDeclaration): boolean { - return !(getMergedSymbol(typeParameter.symbol).isReferenced! & SymbolFlags.TypeParameter) && !isIdentifierThatStartsWithUnderscore(typeParameter.name); + function isTypeParameterUnused( + typeParameter: TypeParameterDeclaration + ): boolean { + return ( + !( + getMergedSymbol(typeParameter.symbol).isReferenced! & + SymbolFlags.TypeParameter + ) && !isIdentifierThatStartsWithUnderscore(typeParameter.name) + ); } - function addToGroup(map: Map, key: K, value: V, getKey: (key: K) => number | string): void { + function addToGroup( + map: Map, + key: K, + value: V, + getKey: (key: K) => number | string + ): void { const keyString = String(getKey(key)); const group = map.get(keyString); if (group) { group[1].push(value); - } - else { + } else { map.set(keyString, [key, [value]]); } } - function tryGetRootParameterDeclaration(node: Node): ParameterDeclaration | undefined { + function tryGetRootParameterDeclaration( + node: Node + ): ParameterDeclaration | undefined { return tryCast(getRootDeclaration(node), isParameter); } @@ -44316,23 +77080,50 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * ignore starts with underscore names _ * const { a: _a } = { a: 1 } */ - return !!(declaration.propertyName && isIdentifierThatStartsWithUnderscore(declaration.name)); + return !!( + declaration.propertyName && + isIdentifierThatStartsWithUnderscore(declaration.name) + ); } return isIdentifierThatStartsWithUnderscore(declaration.name); } - return isAmbientModule(declaration) || - (isVariableDeclaration(declaration) && isForInOrOfStatement(declaration.parent.parent) || isImportedDeclaration(declaration)) && isIdentifierThatStartsWithUnderscore(declaration.name!); + return ( + isAmbientModule(declaration) || + (((isVariableDeclaration(declaration) && + isForInOrOfStatement(declaration.parent.parent)) || + isImportedDeclaration(declaration)) && + isIdentifierThatStartsWithUnderscore(declaration.name!)) + ); } - function checkUnusedLocalsAndParameters(nodeWithLocals: HasLocals, addDiagnostic: AddUnusedDiagnostic): void { + function checkUnusedLocalsAndParameters( + nodeWithLocals: HasLocals, + addDiagnostic: AddUnusedDiagnostic + ): void { // 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. - const unusedImports = new Map(); - const unusedDestructures = new Map(); - const unusedVariables = new Map(); - nodeWithLocals.locals!.forEach(local => { + const unusedImports = new Map< + string, + [ImportClause, ImportedDeclaration[]] + >(); + const unusedDestructures = new Map< + string, + [BindingPattern, BindingElement[]] + >(); + const unusedVariables = new Map< + string, + [VariableDeclarationList, VariableDeclaration[]] + >(); + nodeWithLocals.locals!.forEach((local) => { // If it's purely a type parameter, ignore, will be checked in `checkUnusedTypeParameters`. // If it's a type parameter merged with a parameter, check if the parameter-side is used. - if (local.flags & SymbolFlags.TypeParameter ? !(local.flags & SymbolFlags.Variable && !(local.isReferenced! & SymbolFlags.Variable)) : local.isReferenced || local.exportSymbol) { + if ( + local.flags & SymbolFlags.TypeParameter + ? !( + local.flags & SymbolFlags.Variable && + !(local.isReferenced! & SymbolFlags.Variable) + ) + : local.isReferenced || local.exportSymbol + ) { return; } @@ -44343,37 +77134,93 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (isImportedDeclaration(declaration)) { - addToGroup(unusedImports, importClauseFromImported(declaration), declaration, getNodeId); - } - else if (isBindingElement(declaration) && isObjectBindingPattern(declaration.parent)) { + addToGroup( + unusedImports, + importClauseFromImported(declaration), + declaration, + getNodeId + ); + } else if ( + isBindingElement(declaration) && + isObjectBindingPattern(declaration.parent) + ) { // In `{ a, ...b }, `a` is considered used since it removes a property from `b`. `b` may still be unused though. const lastElement = last(declaration.parent.elements); - if (declaration === lastElement || !last(declaration.parent.elements).dotDotDotToken) { - addToGroup(unusedDestructures, declaration.parent, declaration, getNodeId); + if ( + declaration === lastElement || + !last(declaration.parent.elements).dotDotDotToken + ) { + addToGroup( + unusedDestructures, + declaration.parent, + declaration, + getNodeId + ); } - } - else if (isVariableDeclaration(declaration)) { - const blockScopeKind = getCombinedNodeFlagsCached(declaration) & NodeFlags.BlockScoped; + } else if (isVariableDeclaration(declaration)) { + const blockScopeKind = + getCombinedNodeFlagsCached(declaration) & + NodeFlags.BlockScoped; const name = getNameOfDeclaration(declaration); - if (blockScopeKind !== NodeFlags.Using && blockScopeKind !== NodeFlags.AwaitUsing || !name || !isIdentifierThatStartsWithUnderscore(name)) { - addToGroup(unusedVariables, declaration.parent, declaration, getNodeId); + if ( + (blockScopeKind !== NodeFlags.Using && + blockScopeKind !== NodeFlags.AwaitUsing) || + !name || + !isIdentifierThatStartsWithUnderscore(name) + ) { + addToGroup( + unusedVariables, + declaration.parent, + declaration, + getNodeId + ); } - } - else { - const parameter = local.valueDeclaration && tryGetRootParameterDeclaration(local.valueDeclaration); - const name = local.valueDeclaration && getNameOfDeclaration(local.valueDeclaration); + } else { + const parameter = + local.valueDeclaration && + tryGetRootParameterDeclaration( + local.valueDeclaration + ); + const name = + local.valueDeclaration && + getNameOfDeclaration(local.valueDeclaration); if (parameter && name) { - if (!isParameterPropertyDeclaration(parameter, parameter.parent) && !parameterIsThisKeyword(parameter) && !isIdentifierThatStartsWithUnderscore(name)) { - if (isBindingElement(declaration) && isArrayBindingPattern(declaration.parent)) { - addToGroup(unusedDestructures, declaration.parent, declaration, getNodeId); - } - else { - addDiagnostic(parameter, UnusedKind.Parameter, createDiagnosticForNode(name, Diagnostics._0_is_declared_but_its_value_is_never_read, symbolName(local))); + if ( + !isParameterPropertyDeclaration( + parameter, + parameter.parent + ) && + !parameterIsThisKeyword(parameter) && + !isIdentifierThatStartsWithUnderscore(name) + ) { + if ( + isBindingElement(declaration) && + isArrayBindingPattern(declaration.parent) + ) { + addToGroup( + unusedDestructures, + declaration.parent, + declaration, + getNodeId + ); + } else { + addDiagnostic( + parameter, + UnusedKind.Parameter, + createDiagnosticForNode( + name, + Diagnostics._0_is_declared_but_its_value_is_never_read, + symbolName(local) + ) + ); } } - } - else { - errorUnusedLocal(declaration, symbolName(local), addDiagnostic); + } else { + errorUnusedLocal( + declaration, + symbolName(local), + addDiagnostic + ); } } } @@ -44381,42 +77228,83 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { }); unusedImports.forEach(([importClause, unuseds]) => { const importDecl = importClause.parent; - const nDeclarations = (importClause.name ? 1 : 0) + - (importClause.namedBindings ? - (importClause.namedBindings.kind === SyntaxKind.NamespaceImport ? 1 : importClause.namedBindings.elements.length) + const nDeclarations = + (importClause.name ? 1 : 0) + + (importClause.namedBindings + ? importClause.namedBindings.kind === + SyntaxKind.NamespaceImport + ? 1 + : importClause.namedBindings.elements.length : 0); if (nDeclarations === unuseds.length) { addDiagnostic( importDecl, UnusedKind.Local, unuseds.length === 1 - ? createDiagnosticForNode(importDecl, Diagnostics._0_is_declared_but_its_value_is_never_read, idText(first(unuseds).name!)) - : createDiagnosticForNode(importDecl, Diagnostics.All_imports_in_import_declaration_are_unused), + ? createDiagnosticForNode( + importDecl, + Diagnostics._0_is_declared_but_its_value_is_never_read, + idText(first(unuseds).name!) + ) + : createDiagnosticForNode( + importDecl, + Diagnostics.All_imports_in_import_declaration_are_unused + ) ); - } - else { - for (const unused of unuseds) errorUnusedLocal(unused, idText(unused.name!), addDiagnostic); + } else { + for (const unused of unuseds) + errorUnusedLocal( + unused, + idText(unused.name!), + addDiagnostic + ); } }); unusedDestructures.forEach(([bindingPattern, bindingElements]) => { - const kind = tryGetRootParameterDeclaration(bindingPattern.parent) ? UnusedKind.Parameter : UnusedKind.Local; + const kind = tryGetRootParameterDeclaration(bindingPattern.parent) + ? UnusedKind.Parameter + : UnusedKind.Local; if (bindingPattern.elements.length === bindingElements.length) { - if (bindingElements.length === 1 && bindingPattern.parent.kind === SyntaxKind.VariableDeclaration && bindingPattern.parent.parent.kind === SyntaxKind.VariableDeclarationList) { - addToGroup(unusedVariables, bindingPattern.parent.parent, bindingPattern.parent, getNodeId); - } - else { + if ( + bindingElements.length === 1 && + bindingPattern.parent.kind === + SyntaxKind.VariableDeclaration && + bindingPattern.parent.parent.kind === + SyntaxKind.VariableDeclarationList + ) { + addToGroup( + unusedVariables, + bindingPattern.parent.parent, + bindingPattern.parent, + getNodeId + ); + } else { addDiagnostic( bindingPattern, kind, bindingElements.length === 1 - ? createDiagnosticForNode(bindingPattern, Diagnostics._0_is_declared_but_its_value_is_never_read, bindingNameText(first(bindingElements).name)) - : createDiagnosticForNode(bindingPattern, Diagnostics.All_destructured_elements_are_unused), + ? createDiagnosticForNode( + bindingPattern, + Diagnostics._0_is_declared_but_its_value_is_never_read, + bindingNameText(first(bindingElements).name) + ) + : createDiagnosticForNode( + bindingPattern, + Diagnostics.All_destructured_elements_are_unused + ) ); } - } - else { + } else { for (const e of bindingElements) { - addDiagnostic(e, kind, createDiagnosticForNode(e, Diagnostics._0_is_declared_but_its_value_is_never_read, bindingNameText(e.name))); + addDiagnostic( + e, + kind, + createDiagnosticForNode( + e, + Diagnostics._0_is_declared_but_its_value_is_never_read, + bindingNameText(e.name) + ) + ); } } }); @@ -44426,13 +77314,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { declarationList, UnusedKind.Local, declarations.length === 1 - ? createDiagnosticForNode(first(declarations).name, Diagnostics._0_is_declared_but_its_value_is_never_read, bindingNameText(first(declarations).name)) - : createDiagnosticForNode(declarationList.parent.kind === SyntaxKind.VariableStatement ? declarationList.parent : declarationList, Diagnostics.All_variables_are_unused), + ? createDiagnosticForNode( + first(declarations).name, + Diagnostics._0_is_declared_but_its_value_is_never_read, + bindingNameText(first(declarations).name) + ) + : createDiagnosticForNode( + declarationList.parent.kind === + SyntaxKind.VariableStatement + ? declarationList.parent + : declarationList, + Diagnostics.All_variables_are_unused + ) ); - } - else { + } else { for (const decl of declarations) { - addDiagnostic(decl, UnusedKind.Local, createDiagnosticForNode(decl, Diagnostics._0_is_declared_but_its_value_is_never_read, bindingNameText(decl.name))); + addDiagnostic( + decl, + UnusedKind.Local, + createDiagnosticForNode( + decl, + Diagnostics._0_is_declared_but_its_value_is_never_read, + bindingNameText(decl.name) + ) + ); } } }); @@ -44441,14 +77346,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkPotentialUncheckedRenamedBindingElementsInTypes() { for (const node of potentialUnusedRenamedBindingElementsInTypes) { if (!getSymbolOfDeclaration(node)?.isReferenced) { - const wrappingDeclaration = walkUpBindingElementsAndPatterns(node); - Debug.assert(isPartOfParameterDeclaration(wrappingDeclaration), "Only parameter declaration should be checked here"); - 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)); + const wrappingDeclaration = + walkUpBindingElementsAndPatterns(node); + Debug.assert( + isPartOfParameterDeclaration(wrappingDeclaration), + "Only parameter declaration should be checked here" + ); + 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) + ); if (!wrappingDeclaration.type) { // entire parameter does not have type annotation, suggest adding an annotation addRelatedInfo( diagnostic, - createFileDiagnostic(getSourceFileOfNode(wrappingDeclaration), wrappingDeclaration.end, 0, Diagnostics.We_can_only_write_a_type_for_0_by_adding_a_type_for_the_entire_parameter_here, declarationNameToString(node.propertyName)), + createFileDiagnostic( + getSourceFileOfNode(wrappingDeclaration), + wrappingDeclaration.end, + 0, + Diagnostics.We_can_only_write_a_type_for_0_by_adding_a_type_for_the_entire_parameter_here, + declarationNameToString(node.propertyName) + ) ); } diagnostics.add(diagnostic); @@ -44462,7 +77382,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return idText(name); case SyntaxKind.ArrayBindingPattern: case SyntaxKind.ObjectBindingPattern: - return bindingNameText(cast(first(name.elements), isBindingElement).name); + return bindingNameText( + cast(first(name.elements), isBindingElement).name + ); default: return Debug.assertNever(name); } @@ -44470,10 +77392,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { type ImportedDeclaration = ImportClause | ImportSpecifier | NamespaceImport; function isImportedDeclaration(node: Node): node is ImportedDeclaration { - return node.kind === SyntaxKind.ImportClause || node.kind === SyntaxKind.ImportSpecifier || node.kind === SyntaxKind.NamespaceImport; + return ( + node.kind === SyntaxKind.ImportClause || + node.kind === SyntaxKind.ImportSpecifier || + node.kind === SyntaxKind.NamespaceImport + ); } function importClauseFromImported(decl: ImportedDeclaration): ImportClause { - return decl.kind === SyntaxKind.ImportClause ? decl : decl.kind === SyntaxKind.NamespaceImport ? decl.parent : decl.parent.parent; + return decl.kind === SyntaxKind.ImportClause + ? decl + : decl.kind === SyntaxKind.NamespaceImport + ? decl.parent + : decl.parent.parent; } function checkBlock(node: Block) { @@ -44485,8 +77415,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const saveFlowAnalysisDisabled = flowAnalysisDisabled; forEach(node.statements, checkSourceElement); flowAnalysisDisabled = saveFlowAnalysisDisabled; - } - else { + } else { forEach(node.statements, checkSourceElement); } if (node.locals) { @@ -44494,15 +77423,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function checkCollisionWithArgumentsInGeneratedCode(node: SignatureDeclaration) { + function checkCollisionWithArgumentsInGeneratedCode( + node: SignatureDeclaration + ) { // no rest parameters \ declaration context \ overload - no codegen impact - if (languageVersion >= ScriptTarget.ES2015 || !hasRestParameter(node) || node.flags & NodeFlags.Ambient || nodeIsMissing((node as FunctionLikeDeclaration).body)) { + if ( + languageVersion >= ScriptTarget.ES2015 || + !hasRestParameter(node) || + node.flags & NodeFlags.Ambient || + nodeIsMissing((node as FunctionLikeDeclaration).body) + ) { return; } - forEach(node.parameters, p => { - if (p.name && !isBindingPattern(p.name) && p.name.escapedText === argumentsSymbol.escapedName) { - errorSkippedOn("noEmit", p, Diagnostics.Duplicate_identifier_arguments_Compiler_uses_arguments_to_initialize_rest_parameters); + forEach(node.parameters, (p) => { + if ( + p.name && + !isBindingPattern(p.name) && + p.name.escapedText === argumentsSymbol.escapedName + ) { + errorSkippedOn( + "noEmit", + p, + Diagnostics.Duplicate_identifier_arguments_Compiler_uses_arguments_to_initialize_rest_parameters + ); } }); } @@ -44512,7 +77456,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * of {@link name} in an outer scope. This is used to check for collisions for downlevel transformations that * require names like `Object`, `Promise`, `Reflect`, `require`, `exports`, etc. */ - function needCollisionCheckForIdentifier(node: Node, identifier: Identifier | undefined, name: string): boolean { + function needCollisionCheckForIdentifier( + node: Node, + identifier: Identifier | undefined, + name: string + ): boolean { if (identifier?.escapedText !== name) { return false; } @@ -44535,7 +77483,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - if (isImportClause(node) || isImportEqualsDeclaration(node) || isImportSpecifier(node)) { + if ( + isImportClause(node) || + isImportEqualsDeclaration(node) || + isImportSpecifier(node) + ) { // type-only imports do not require collision checks against runtime values. if (isTypeOnlyImportOrExportDeclaration(node)) { return false; @@ -44543,7 +77495,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const root = getRootDeclaration(node); - if (isParameter(root) && nodeIsMissing((root.parent as FunctionLikeDeclaration).body)) { + if ( + isParameter(root) && + nodeIsMissing((root.parent as FunctionLikeDeclaration).body) + ) { // just an overload - no codegen impact return false; } @@ -44553,14 +77508,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // this function will run after checking the source file so 'CaptureThis' is correct for all nodes function checkIfThisIsCapturedInEnclosingScope(node: Node): void { - findAncestor(node, current => { + findAncestor(node, (current) => { if (getNodeCheckFlags(current) & NodeCheckFlags.CaptureThis) { const isDeclaration = node.kind !== SyntaxKind.Identifier; if (isDeclaration) { - error(getNameOfDeclaration(node as Declaration), Diagnostics.Duplicate_identifier_this_Compiler_uses_variable_declaration_this_to_capture_this_reference); - } - else { - error(node, Diagnostics.Expression_resolves_to_variable_declaration_this_that_compiler_uses_to_capture_this_reference); + error( + getNameOfDeclaration(node as Declaration), + Diagnostics.Duplicate_identifier_this_Compiler_uses_variable_declaration_this_to_capture_this_reference + ); + } else { + error( + node, + Diagnostics.Expression_resolves_to_variable_declaration_this_that_compiler_uses_to_capture_this_reference + ); } return true; } @@ -44569,14 +77529,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkIfNewTargetIsCapturedInEnclosingScope(node: Node): void { - findAncestor(node, current => { + findAncestor(node, (current) => { if (getNodeCheckFlags(current) & NodeCheckFlags.CaptureNewTarget) { const isDeclaration = node.kind !== SyntaxKind.Identifier; if (isDeclaration) { - error(getNameOfDeclaration(node as Declaration), Diagnostics.Duplicate_identifier_newTarget_Compiler_uses_variable_declaration_newTarget_to_capture_new_target_meta_property_reference); - } - else { - error(node, Diagnostics.Expression_resolves_to_variable_declaration_newTarget_that_compiler_uses_to_capture_new_target_meta_property_reference); + error( + getNameOfDeclaration(node as Declaration), + Diagnostics.Duplicate_identifier_newTarget_Compiler_uses_variable_declaration_newTarget_to_capture_new_target_meta_property_reference + ); + } else { + error( + node, + Diagnostics.Expression_resolves_to_variable_declaration_newTarget_that_compiler_uses_to_capture_new_target_meta_property_reference + ); } return true; } @@ -44584,51 +77549,97 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { }); } - function checkCollisionWithRequireExportsInGeneratedCode(node: Node, name: Identifier | undefined) { + function checkCollisionWithRequireExportsInGeneratedCode( + node: Node, + name: Identifier | undefined + ) { // No need to check for require or exports for ES6 modules and later - if (host.getEmitModuleFormatOfFile(getSourceFileOfNode(node)) >= ModuleKind.ES2015) { + if ( + host.getEmitModuleFormatOfFile(getSourceFileOfNode(node)) >= + ModuleKind.ES2015 + ) { return; } - if (!name || !needCollisionCheckForIdentifier(node, name, "require") && !needCollisionCheckForIdentifier(node, name, "exports")) { + if ( + !name || + (!needCollisionCheckForIdentifier(node, name, "require") && + !needCollisionCheckForIdentifier(node, name, "exports")) + ) { return; } // Uninstantiated modules shouldnt do this check - if (isModuleDeclaration(node) && getModuleInstanceState(node) !== ModuleInstanceState.Instantiated) { + if ( + isModuleDeclaration(node) && + getModuleInstanceState(node) !== ModuleInstanceState.Instantiated + ) { return; } // In case of variable declaration, node.parent is variable statement so look at the variable statement's parent const parent = getDeclarationContainer(node); - if (parent.kind === SyntaxKind.SourceFile && isExternalOrCommonJsModule(parent as SourceFile)) { + if ( + parent.kind === SyntaxKind.SourceFile && + isExternalOrCommonJsModule(parent as SourceFile) + ) { // If the declaration happens to be in external module, report error that require and exports are reserved keywords - errorSkippedOn("noEmit", name, Diagnostics.Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_a_module, declarationNameToString(name), declarationNameToString(name)); + errorSkippedOn( + "noEmit", + name, + Diagnostics.Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_a_module, + declarationNameToString(name), + declarationNameToString(name) + ); } } - function checkCollisionWithGlobalPromiseInGeneratedCode(node: Node, name: Identifier | undefined): void { - if (!name || languageVersion >= ScriptTarget.ES2017 || !needCollisionCheckForIdentifier(node, name, "Promise")) { + function checkCollisionWithGlobalPromiseInGeneratedCode( + node: Node, + name: Identifier | undefined + ): void { + if ( + !name || + languageVersion >= ScriptTarget.ES2017 || + !needCollisionCheckForIdentifier(node, name, "Promise") + ) { return; } // Uninstantiated modules shouldnt do this check - if (isModuleDeclaration(node) && getModuleInstanceState(node) !== ModuleInstanceState.Instantiated) { + if ( + isModuleDeclaration(node) && + getModuleInstanceState(node) !== ModuleInstanceState.Instantiated + ) { return; } // In case of variable declaration, node.parent is variable statement so look at the variable statement's parent const parent = getDeclarationContainer(node); - if (parent.kind === SyntaxKind.SourceFile && isExternalOrCommonJsModule(parent as SourceFile) && parent.flags & NodeFlags.HasAsyncFunctions) { + if ( + parent.kind === SyntaxKind.SourceFile && + isExternalOrCommonJsModule(parent as SourceFile) && + parent.flags & NodeFlags.HasAsyncFunctions + ) { // If the declaration happens to be in external module, report error that Promise is a reserved identifier. - errorSkippedOn("noEmit", name, Diagnostics.Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_a_module_containing_async_functions, declarationNameToString(name), declarationNameToString(name)); + errorSkippedOn( + "noEmit", + name, + Diagnostics.Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_a_module_containing_async_functions, + declarationNameToString(name), + declarationNameToString(name) + ); } } - function recordPotentialCollisionWithWeakMapSetInGeneratedCode(node: Node, name: Identifier): void { + function recordPotentialCollisionWithWeakMapSetInGeneratedCode( + node: Node, + name: Identifier + ): void { if ( - languageVersion <= ScriptTarget.ES2021 - && (needCollisionCheckForIdentifier(node, name, "WeakMap") || needCollisionCheckForIdentifier(node, name, "WeakSet")) + languageVersion <= ScriptTarget.ES2021 && + (needCollisionCheckForIdentifier(node, name, "WeakMap") || + needCollisionCheckForIdentifier(node, name, "WeakSet")) ) { potentialWeakMapSetCollisions.push(node); } @@ -44636,16 +77647,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkWeakMapSetCollision(node: Node) { const enclosingBlockScope = getEnclosingBlockScopeContainer(node); - if (getNodeCheckFlags(enclosingBlockScope) & NodeCheckFlags.ContainsClassWithPrivateIdentifiers) { - Debug.assert(isNamedDeclaration(node) && isIdentifier(node.name) && typeof node.name.escapedText === "string", "The target of a WeakMap/WeakSet collision check should be an identifier"); - errorSkippedOn("noEmit", node, Diagnostics.Compiler_reserves_name_0_when_emitting_private_identifier_downlevel, node.name.escapedText); + if ( + getNodeCheckFlags(enclosingBlockScope) & + NodeCheckFlags.ContainsClassWithPrivateIdentifiers + ) { + Debug.assert( + isNamedDeclaration(node) && + isIdentifier(node.name) && + typeof node.name.escapedText === "string", + "The target of a WeakMap/WeakSet collision check should be an identifier" + ); + errorSkippedOn( + "noEmit", + node, + Diagnostics.Compiler_reserves_name_0_when_emitting_private_identifier_downlevel, + node.name.escapedText + ); } } - function recordPotentialCollisionWithReflectInGeneratedCode(node: Node, name: Identifier | undefined): void { + function recordPotentialCollisionWithReflectInGeneratedCode( + node: Node, + name: Identifier | undefined + ): void { if ( - name && languageVersion >= ScriptTarget.ES2015 && languageVersion <= ScriptTarget.ES2021 - && needCollisionCheckForIdentifier(node, name, "Reflect") + name && + languageVersion >= ScriptTarget.ES2015 && + languageVersion <= ScriptTarget.ES2021 && + needCollisionCheckForIdentifier(node, name, "Reflect") ) { potentialReflectCollisions.push(node); } @@ -44656,31 +77685,51 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isClassExpression(node)) { // ClassExpression names don't contribute to their containers, but do matter for any of their block-scoped members. for (const member of node.members) { - if (getNodeCheckFlags(member) & NodeCheckFlags.ContainsSuperPropertyInStaticInitializer) { + if ( + getNodeCheckFlags(member) & + NodeCheckFlags.ContainsSuperPropertyInStaticInitializer + ) { hasCollision = true; break; } } - } - else if (isFunctionExpression(node)) { + } else if (isFunctionExpression(node)) { // FunctionExpression names don't contribute to their containers, but do matter for their contents - if (getNodeCheckFlags(node) & NodeCheckFlags.ContainsSuperPropertyInStaticInitializer) { + if ( + getNodeCheckFlags(node) & + NodeCheckFlags.ContainsSuperPropertyInStaticInitializer + ) { hasCollision = true; } - } - else { + } else { const container = getEnclosingBlockScopeContainer(node); - if (container && getNodeCheckFlags(container) & NodeCheckFlags.ContainsSuperPropertyInStaticInitializer) { + if ( + container && + getNodeCheckFlags(container) & + NodeCheckFlags.ContainsSuperPropertyInStaticInitializer + ) { hasCollision = true; } } if (hasCollision) { - Debug.assert(isNamedDeclaration(node) && isIdentifier(node.name), "The target of a Reflect collision check should be an identifier"); - errorSkippedOn("noEmit", node, Diagnostics.Duplicate_identifier_0_Compiler_reserves_name_1_when_emitting_super_references_in_static_initializers, declarationNameToString(node.name), "Reflect"); + Debug.assert( + isNamedDeclaration(node) && isIdentifier(node.name), + "The target of a Reflect collision check should be an identifier" + ); + errorSkippedOn( + "noEmit", + node, + Diagnostics.Duplicate_identifier_0_Compiler_reserves_name_1_when_emitting_super_references_in_static_initializers, + declarationNameToString(node.name), + "Reflect" + ); } } - function checkCollisionsForDeclarationName(node: Node, name: Identifier | undefined) { + function checkCollisionsForDeclarationName( + node: Node, + name: Identifier | undefined + ) { if (!name) return; checkCollisionWithRequireExportsInGeneratedCode(node, name); checkCollisionWithGlobalPromiseInGeneratedCode(node, name); @@ -44691,13 +77740,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!(node.flags & NodeFlags.Ambient)) { checkClassNameCollisionWithObject(name); } - } - else if (isEnumDeclaration(node)) { + } else if (isEnumDeclaration(node)) { checkTypeNameIsReserved(name, Diagnostics.Enum_name_cannot_be_0); } } - function checkVarDeclaredNamesNotShadowed(node: VariableDeclaration | BindingElement) { + function checkVarDeclaredNamesNotShadowed( + node: VariableDeclaration | BindingElement + ) { // - ScriptBody : StatementList // It is a Syntax Error if any element of the LexicallyDeclaredNames of StatementList // also occurs in the VarDeclaredNames of StatementList. @@ -44724,7 +77774,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // } // skip block-scoped variables and parameters - if ((getCombinedNodeFlagsCached(node) & NodeFlags.BlockScoped) !== 0 || isPartOfParameterDeclaration(node)) { + if ( + (getCombinedNodeFlagsCached(node) & NodeFlags.BlockScoped) !== 0 || + isPartOfParameterDeclaration(node) + ) { return; } @@ -44734,22 +77787,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const symbol = getSymbolOfDeclaration(node); if (symbol.flags & SymbolFlags.FunctionScopedVariable) { if (!isIdentifier(node.name)) return Debug.fail(); - const localDeclarationSymbol = resolveName(node, node.name.escapedText, SymbolFlags.Variable, /*nameNotFoundMessage*/ undefined, /*isUse*/ false); + const localDeclarationSymbol = resolveName( + node, + node.name.escapedText, + SymbolFlags.Variable, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ false + ); if ( localDeclarationSymbol && localDeclarationSymbol !== symbol && localDeclarationSymbol.flags & SymbolFlags.BlockScopedVariable ) { - if (getDeclarationNodeFlagsFromSymbol(localDeclarationSymbol) & NodeFlags.BlockScoped) { - const varDeclList = getAncestor(localDeclarationSymbol.valueDeclaration, SyntaxKind.VariableDeclarationList)!; - const container = varDeclList.parent.kind === SyntaxKind.VariableStatement && varDeclList.parent.parent - ? varDeclList.parent.parent - : undefined; + if ( + getDeclarationNodeFlagsFromSymbol(localDeclarationSymbol) & + NodeFlags.BlockScoped + ) { + const varDeclList = getAncestor( + localDeclarationSymbol.valueDeclaration, + SyntaxKind.VariableDeclarationList + )!; + const container = + varDeclList.parent.kind === + SyntaxKind.VariableStatement && + varDeclList.parent.parent + ? varDeclList.parent.parent + : undefined; // names of block-scoped and function scoped variables can collide only // if block scoped variable is defined in the function\module\source file scope (because of variable hoisting) - const namesShareScope = container && - (container.kind === SyntaxKind.Block && isFunctionLike(container.parent) || + const namesShareScope = + container && + ((container.kind === SyntaxKind.Block && + isFunctionLike(container.parent)) || container.kind === SyntaxKind.ModuleBlock || container.kind === SyntaxKind.ModuleDeclaration || container.kind === SyntaxKind.SourceFile); @@ -44758,7 +77828,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // a var declatation can't hoist past a lexical declaration and it results in a SyntaxError at runtime if (!namesShareScope) { const name = symbolToString(localDeclarationSymbol); - error(node, Diagnostics.Cannot_initialize_outer_scoped_variable_0_in_the_same_scope_as_block_scoped_declaration_1, name, name); + error( + node, + Diagnostics.Cannot_initialize_outer_scoped_variable_0_in_the_same_scope_as_block_scoped_declaration_1, + name, + name + ); } } } @@ -44766,11 +77841,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function convertAutoToAny(type: Type) { - return type === autoType ? anyType : type === autoArrayType ? anyArrayType : type; + return type === autoType + ? anyType + : type === autoArrayType + ? anyArrayType + : type; } // Check variable, parameter, or property declaration - function checkVariableLikeDeclaration(node: ParameterDeclaration | PropertyDeclaration | PropertySignature | VariableDeclaration | BindingElement) { + function checkVariableLikeDeclaration( + node: + | ParameterDeclaration + | PropertyDeclaration + | PropertySignature + | VariableDeclaration + | BindingElement + ) { checkDecorators(node); if (!isBindingElement(node)) { checkSourceElement(node.type); @@ -44797,7 +77883,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { node.propertyName && isIdentifier(node.name) && isPartOfParameterDeclaration(node) && - nodeIsMissing((getContainingFunction(node) as FunctionLikeDeclaration).body) + nodeIsMissing( + (getContainingFunction(node) as FunctionLikeDeclaration) + .body + ) ) { // type F = ({a: string}) => void; // ^^^^^^ @@ -44807,18 +77896,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return; } - if (isObjectBindingPattern(node.parent) && node.dotDotDotToken && languageVersion < LanguageFeatureMinimumTarget.ObjectSpreadRest) { + if ( + isObjectBindingPattern(node.parent) && + node.dotDotDotToken && + languageVersion < LanguageFeatureMinimumTarget.ObjectSpreadRest + ) { checkExternalEmitHelpers(node, ExternalEmitHelpers.Rest); } // check computed properties inside property names of binding elements - if (node.propertyName && node.propertyName.kind === SyntaxKind.ComputedPropertyName) { + if ( + node.propertyName && + node.propertyName.kind === SyntaxKind.ComputedPropertyName + ) { checkComputedPropertyName(node.propertyName); } // check private/protected variable access const parent = node.parent.parent; - const parentCheckMode = node.dotDotDotToken ? CheckMode.RestBindingElement : CheckMode.Normal; - const parentType = getTypeForBindingElementParent(parent, parentCheckMode); + const parentCheckMode = node.dotDotDotToken + ? CheckMode.RestBindingElement + : CheckMode.Normal; + const parentType = getTypeForBindingElementParent( + parent, + parentCheckMode + ); const name = node.propertyName || node.name; if (parentType && !isBindingPattern(name)) { const exprType = getLiteralTypeFromPropertyName(name); @@ -44826,8 +77927,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const nameText = getPropertyNameFromType(exprType); const property = getPropertyOfType(parentType, nameText); if (property) { - markPropertyAsReferenced(property, /*nodeForCheckWriteOnly*/ undefined, /*isSelfTypeAccess*/ false); // A destructuring is never a write-only reference. - checkPropertyAccessibility(node, !!parent.initializer && parent.initializer.kind === SyntaxKind.SuperKeyword, /*writing*/ false, parentType, property); + markPropertyAsReferenced( + property, + /*nodeForCheckWriteOnly*/ undefined, + /*isSelfTypeAccess*/ false + ); // A destructuring is never a write-only reference. + checkPropertyAccessibility( + node, + !!parent.initializer && + parent.initializer.kind === + SyntaxKind.SuperKeyword, + /*writing*/ false, + parentType, + property + ); } } } @@ -44835,15 +77948,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // For a binding pattern, check contained binding elements if (isBindingPattern(node.name)) { - if (node.name.kind === SyntaxKind.ArrayBindingPattern && languageVersion < LanguageFeatureMinimumTarget.BindingPatterns && compilerOptions.downlevelIteration) { + if ( + node.name.kind === SyntaxKind.ArrayBindingPattern && + languageVersion < + LanguageFeatureMinimumTarget.BindingPatterns && + compilerOptions.downlevelIteration + ) { checkExternalEmitHelpers(node, ExternalEmitHelpers.Read); } forEach(node.name.elements, checkSourceElement); } // For a parameter declaration with an initializer, error and exit if the containing function doesn't have a body - if (node.initializer && isPartOfParameterDeclaration(node) && nodeIsMissing((getContainingFunction(node) as FunctionLikeDeclaration).body)) { - error(node, Diagnostics.A_parameter_initializer_is_only_allowed_in_a_function_or_constructor_implementation); + if ( + node.initializer && + isPartOfParameterDeclaration(node) && + nodeIsMissing( + (getContainingFunction(node) as FunctionLikeDeclaration).body + ) + ) { + error( + node, + Diagnostics.A_parameter_initializer_is_only_allowed_in_a_function_or_constructor_implementation + ); return; } // For a binding pattern, validate the initializer and exit @@ -44851,26 +77978,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isInAmbientOrTypeNode(node)) { return; } - const needCheckInitializer = hasOnlyExpressionInitializer(node) && node.initializer && node.parent.parent.kind !== SyntaxKind.ForInStatement; - const needCheckWidenedType = !some(node.name.elements, not(isOmittedExpression)); + const needCheckInitializer = + hasOnlyExpressionInitializer(node) && + node.initializer && + node.parent.parent.kind !== SyntaxKind.ForInStatement; + const needCheckWidenedType = !some( + node.name.elements, + not(isOmittedExpression) + ); if (needCheckInitializer || needCheckWidenedType) { // Don't validate for-in initializer as it is already an error - const widenedType = getWidenedTypeForVariableLikeDeclaration(node); + const widenedType = + getWidenedTypeForVariableLikeDeclaration(node); if (needCheckInitializer) { - const initializerType = checkExpressionCached(node.initializer); + const initializerType = checkExpressionCached( + node.initializer + ); if (strictNullChecks && needCheckWidenedType) { checkNonNullNonVoidType(initializerType, node); - } - else { - checkTypeAssignableToAndOptionallyElaborate(initializerType, getWidenedTypeForVariableLikeDeclaration(node), node, node.initializer); + } else { + checkTypeAssignableToAndOptionallyElaborate( + initializerType, + getWidenedTypeForVariableLikeDeclaration(node), + node, + node.initializer + ); } } // check the binding pattern with empty elements if (needCheckWidenedType) { if (isArrayBindingPattern(node.name)) { - checkIteratedTypeOrElementType(IterationUse.Destructuring, widenedType, undefinedType, node); - } - else if (strictNullChecks) { + checkIteratedTypeOrElementType( + IterationUse.Destructuring, + widenedType, + undefinedType, + node + ); + } else if (strictNullChecks) { checkNonNullNonVoidType(widenedType, node); } } @@ -44879,103 +78023,214 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // For a commonjs `const x = require`, validate the alias and exit const symbol = getSymbolOfDeclaration(node); - if (symbol.flags & SymbolFlags.Alias && (isVariableDeclarationInitializedToBareOrAccessedRequire(node) || isBindingElementOfBareOrAccessedRequire(node))) { + if ( + symbol.flags & SymbolFlags.Alias && + (isVariableDeclarationInitializedToBareOrAccessedRequire(node) || + isBindingElementOfBareOrAccessedRequire(node)) + ) { checkAliasSymbol(node); return; } if (node.name.kind === SyntaxKind.BigIntLiteral) { - error(node.name, Diagnostics.A_bigint_literal_cannot_be_used_as_a_property_name); + error( + node.name, + Diagnostics.A_bigint_literal_cannot_be_used_as_a_property_name + ); } const type = convertAutoToAny(getTypeOfSymbol(symbol)); if (node === symbol.valueDeclaration) { // Node is the primary declaration of the symbol, just validate the initializer // Don't validate for-in initializer as it is already an error - const initializer = hasOnlyExpressionInitializer(node) && getEffectiveInitializer(node); + const initializer = + hasOnlyExpressionInitializer(node) && + getEffectiveInitializer(node); if (initializer) { - const isJSObjectLiteralInitializer = isInJSFile(node) && + const isJSObjectLiteralInitializer = + isInJSFile(node) && isObjectLiteralExpression(initializer) && - (initializer.properties.length === 0 || isPrototypeAccess(node.name)) && + (initializer.properties.length === 0 || + isPrototypeAccess(node.name)) && !!symbol.exports?.size; - if (!isJSObjectLiteralInitializer && node.parent.parent.kind !== SyntaxKind.ForInStatement) { + if ( + !isJSObjectLiteralInitializer && + node.parent.parent.kind !== SyntaxKind.ForInStatement + ) { const initializerType = checkExpressionCached(initializer); - checkTypeAssignableToAndOptionallyElaborate(initializerType, type, node, initializer, /*headMessage*/ undefined); - const blockScopeKind = getCombinedNodeFlagsCached(node) & NodeFlags.BlockScoped; + checkTypeAssignableToAndOptionallyElaborate( + initializerType, + type, + node, + initializer, + /*headMessage*/ undefined + ); + const blockScopeKind = + getCombinedNodeFlagsCached(node) & + NodeFlags.BlockScoped; if (blockScopeKind === NodeFlags.AwaitUsing) { - const globalAsyncDisposableType = getGlobalAsyncDisposableType(/*reportErrors*/ true); - const globalDisposableType = getGlobalDisposableType(/*reportErrors*/ true); - if (globalAsyncDisposableType !== emptyObjectType && globalDisposableType !== emptyObjectType) { - const optionalDisposableType = getUnionType([globalAsyncDisposableType, globalDisposableType, nullType, undefinedType]); - checkTypeAssignableTo(widenTypeForVariableLikeDeclaration(initializerType, node), optionalDisposableType, initializer, Diagnostics.The_initializer_of_an_await_using_declaration_must_be_either_an_object_with_a_Symbol_asyncDispose_or_Symbol_dispose_method_or_be_null_or_undefined); + const globalAsyncDisposableType = + getGlobalAsyncDisposableType(/*reportErrors*/ true); + const globalDisposableType = getGlobalDisposableType( + /*reportErrors*/ true + ); + if ( + globalAsyncDisposableType !== emptyObjectType && + globalDisposableType !== emptyObjectType + ) { + const optionalDisposableType = getUnionType([ + globalAsyncDisposableType, + globalDisposableType, + nullType, + undefinedType, + ]); + checkTypeAssignableTo( + widenTypeForVariableLikeDeclaration( + initializerType, + node + ), + optionalDisposableType, + initializer, + Diagnostics.The_initializer_of_an_await_using_declaration_must_be_either_an_object_with_a_Symbol_asyncDispose_or_Symbol_dispose_method_or_be_null_or_undefined + ); } - } - else if (blockScopeKind === NodeFlags.Using) { - const globalDisposableType = getGlobalDisposableType(/*reportErrors*/ true); + } else if (blockScopeKind === NodeFlags.Using) { + const globalDisposableType = getGlobalDisposableType( + /*reportErrors*/ true + ); if (globalDisposableType !== emptyObjectType) { - const optionalDisposableType = getUnionType([globalDisposableType, nullType, undefinedType]); - checkTypeAssignableTo(widenTypeForVariableLikeDeclaration(initializerType, node), optionalDisposableType, initializer, Diagnostics.The_initializer_of_a_using_declaration_must_be_either_an_object_with_a_Symbol_dispose_method_or_be_null_or_undefined); + const optionalDisposableType = getUnionType([ + globalDisposableType, + nullType, + undefinedType, + ]); + checkTypeAssignableTo( + widenTypeForVariableLikeDeclaration( + initializerType, + node + ), + optionalDisposableType, + initializer, + Diagnostics.The_initializer_of_a_using_declaration_must_be_either_an_object_with_a_Symbol_dispose_method_or_be_null_or_undefined + ); } } } } if (symbol.declarations && symbol.declarations.length > 1) { - if (some(symbol.declarations, d => d !== node && isVariableLike(d) && !areDeclarationFlagsIdentical(d, node))) { - error(node.name, Diagnostics.All_declarations_of_0_must_have_identical_modifiers, declarationNameToString(node.name)); + if ( + some( + symbol.declarations, + (d) => + d !== node && + isVariableLike(d) && + !areDeclarationFlagsIdentical(d, node) + ) + ) { + error( + node.name, + Diagnostics.All_declarations_of_0_must_have_identical_modifiers, + declarationNameToString(node.name) + ); } } - } - else { + } else { // Node is a secondary declaration, check that type is identical to primary declaration and check that // initializer is consistent with type associated with the node - const declarationType = convertAutoToAny(getWidenedTypeForVariableLikeDeclaration(node)); + const declarationType = convertAutoToAny( + getWidenedTypeForVariableLikeDeclaration(node) + ); if ( - !isErrorType(type) && !isErrorType(declarationType) && + !isErrorType(type) && + !isErrorType(declarationType) && !isTypeIdenticalTo(type, declarationType) && !(symbol.flags & SymbolFlags.Assignment) ) { - errorNextVariableOrPropertyDeclarationMustHaveSameType(symbol.valueDeclaration, type, node, declarationType); + errorNextVariableOrPropertyDeclarationMustHaveSameType( + symbol.valueDeclaration, + type, + node, + declarationType + ); } if (hasOnlyExpressionInitializer(node) && node.initializer) { - checkTypeAssignableToAndOptionallyElaborate(checkExpressionCached(node.initializer), declarationType, node, node.initializer, /*headMessage*/ undefined); + checkTypeAssignableToAndOptionallyElaborate( + checkExpressionCached(node.initializer), + declarationType, + node, + node.initializer, + /*headMessage*/ undefined + ); } - if (symbol.valueDeclaration && !areDeclarationFlagsIdentical(node, symbol.valueDeclaration)) { - error(node.name, Diagnostics.All_declarations_of_0_must_have_identical_modifiers, declarationNameToString(node.name)); + if ( + symbol.valueDeclaration && + !areDeclarationFlagsIdentical(node, symbol.valueDeclaration) + ) { + error( + node.name, + Diagnostics.All_declarations_of_0_must_have_identical_modifiers, + declarationNameToString(node.name) + ); } } - if (node.kind !== SyntaxKind.PropertyDeclaration && node.kind !== SyntaxKind.PropertySignature) { + if ( + node.kind !== SyntaxKind.PropertyDeclaration && + node.kind !== SyntaxKind.PropertySignature + ) { // We know we don't have a binding pattern or computed name here checkExportsOnMergedDeclarations(node); - if (node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement) { + if ( + node.kind === SyntaxKind.VariableDeclaration || + node.kind === SyntaxKind.BindingElement + ) { checkVarDeclaredNamesNotShadowed(node); } checkCollisionsForDeclarationName(node, node.name); } } - function errorNextVariableOrPropertyDeclarationMustHaveSameType(firstDeclaration: Declaration | undefined, firstType: Type, nextDeclaration: Declaration, nextType: Type): void { + function errorNextVariableOrPropertyDeclarationMustHaveSameType( + firstDeclaration: Declaration | undefined, + firstType: Type, + nextDeclaration: Declaration, + nextType: Type + ): void { const nextDeclarationName = getNameOfDeclaration(nextDeclaration); - const message = nextDeclaration.kind === SyntaxKind.PropertyDeclaration || nextDeclaration.kind === SyntaxKind.PropertySignature - ? Diagnostics.Subsequent_property_declarations_must_have_the_same_type_Property_0_must_be_of_type_1_but_here_has_type_2 - : Diagnostics.Subsequent_variable_declarations_must_have_the_same_type_Variable_0_must_be_of_type_1_but_here_has_type_2; + const message = + nextDeclaration.kind === SyntaxKind.PropertyDeclaration || + nextDeclaration.kind === SyntaxKind.PropertySignature + ? Diagnostics.Subsequent_property_declarations_must_have_the_same_type_Property_0_must_be_of_type_1_but_here_has_type_2 + : Diagnostics.Subsequent_variable_declarations_must_have_the_same_type_Variable_0_must_be_of_type_1_but_here_has_type_2; const declName = declarationNameToString(nextDeclarationName); const err = error( nextDeclarationName, message, declName, typeToString(firstType), - typeToString(nextType), + typeToString(nextType) ); if (firstDeclaration) { - addRelatedInfo(err, createDiagnosticForNode(firstDeclaration, Diagnostics._0_was_also_declared_here, declName)); + addRelatedInfo( + err, + createDiagnosticForNode( + firstDeclaration, + Diagnostics._0_was_also_declared_here, + declName + ) + ); } } - function areDeclarationFlagsIdentical(left: Declaration, right: Declaration) { + function areDeclarationFlagsIdentical( + left: Declaration, + right: Declaration + ) { if ( - (left.kind === SyntaxKind.Parameter && right.kind === SyntaxKind.VariableDeclaration) || - (left.kind === SyntaxKind.VariableDeclaration && right.kind === SyntaxKind.Parameter) + (left.kind === SyntaxKind.Parameter && + right.kind === SyntaxKind.VariableDeclaration) || + (left.kind === SyntaxKind.VariableDeclaration && + right.kind === SyntaxKind.Parameter) ) { // Differences in optionality between parameters and variables are allowed. return true; @@ -44985,18 +78240,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - const interestingFlags = ModifierFlags.Private | + const interestingFlags = + ModifierFlags.Private | ModifierFlags.Protected | ModifierFlags.Async | ModifierFlags.Abstract | ModifierFlags.Readonly | ModifierFlags.Static; - return getSelectedEffectiveModifierFlags(left, interestingFlags) === getSelectedEffectiveModifierFlags(right, interestingFlags); + return ( + getSelectedEffectiveModifierFlags(left, interestingFlags) === + getSelectedEffectiveModifierFlags(right, interestingFlags) + ); } function checkVariableDeclaration(node: VariableDeclaration) { - tracing?.push(tracing.Phase.Check, "checkVariableDeclaration", { kind: node.kind, pos: node.pos, end: node.end, path: (node as TracingNode).tracingPath }); + tracing?.push(tracing.Phase.Check, "checkVariableDeclaration", { + kind: node.kind, + pos: node.pos, + end: node.end, + path: (node as TracingNode).tracingPath, + }); checkGrammarVariableDeclaration(node); checkVariableLikeDeclaration(node); tracing?.pop(); @@ -45008,9 +78272,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkVariableDeclarationList(node: VariableDeclarationList) { - const blockScopeKind = getCombinedNodeFlags(node) & NodeFlags.BlockScoped; - if ((blockScopeKind === NodeFlags.Using || blockScopeKind === NodeFlags.AwaitUsing) && languageVersion < LanguageFeatureMinimumTarget.UsingAndAwaitUsing) { - checkExternalEmitHelpers(node, ExternalEmitHelpers.AddDisposableResourceAndDisposeResources); + const blockScopeKind = + getCombinedNodeFlags(node) & NodeFlags.BlockScoped; + if ( + (blockScopeKind === NodeFlags.Using || + blockScopeKind === NodeFlags.AwaitUsing) && + languageVersion < LanguageFeatureMinimumTarget.UsingAndAwaitUsing + ) { + checkExternalEmitHelpers( + node, + ExternalEmitHelpers.AddDisposableResourceAndDisposeResources + ); } forEach(node.declarations, checkSourceElement); @@ -45018,7 +78290,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkVariableStatement(node: VariableStatement) { // Grammar checking - if (!checkGrammarModifiers(node) && !checkGrammarVariableDeclarationList(node.declarationList)) checkGrammarForDisallowedBlockScopedVariableStatement(node); + if ( + !checkGrammarModifiers(node) && + !checkGrammarVariableDeclarationList(node.declarationList) + ) + checkGrammarForDisallowedBlockScopedVariableStatement(node); checkVariableDeclarationList(node.declarationList); } @@ -45033,33 +78309,57 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Grammar checking checkGrammarStatementInAmbientContext(node); const type = checkTruthinessExpression(node.expression); - checkTestingKnownTruthyCallableOrAwaitableOrEnumMemberType(node.expression, type, node.thenStatement); + checkTestingKnownTruthyCallableOrAwaitableOrEnumMemberType( + node.expression, + type, + node.thenStatement + ); checkSourceElement(node.thenStatement); if (node.thenStatement.kind === SyntaxKind.EmptyStatement) { - error(node.thenStatement, Diagnostics.The_body_of_an_if_statement_cannot_be_the_empty_statement); + error( + node.thenStatement, + Diagnostics.The_body_of_an_if_statement_cannot_be_the_empty_statement + ); } checkSourceElement(node.elseStatement); } - function checkTestingKnownTruthyCallableOrAwaitableOrEnumMemberType(condExpr: Expression, condType: Type, body?: Statement | Expression) { + function checkTestingKnownTruthyCallableOrAwaitableOrEnumMemberType( + condExpr: Expression, + condType: Type, + body?: Statement | Expression + ) { if (!strictNullChecks) return; bothHelper(condExpr, body); - function bothHelper(condExpr: Expression, body: Expression | Statement | undefined) { + function bothHelper( + condExpr: Expression, + body: Expression | Statement | undefined + ) { condExpr = skipParentheses(condExpr); helper(condExpr, body); - while (isBinaryExpression(condExpr) && (condExpr.operatorToken.kind === SyntaxKind.BarBarToken || condExpr.operatorToken.kind === SyntaxKind.QuestionQuestionToken)) { + while ( + isBinaryExpression(condExpr) && + (condExpr.operatorToken.kind === SyntaxKind.BarBarToken || + condExpr.operatorToken.kind === + SyntaxKind.QuestionQuestionToken) + ) { condExpr = skipParentheses(condExpr.left); helper(condExpr, body); } } - function helper(condExpr: Expression, body: Expression | Statement | undefined) { - const location = isLogicalOrCoalescingBinaryExpression(condExpr) ? skipParentheses(condExpr.right) : condExpr; + function helper( + condExpr: Expression, + body: Expression | Statement | undefined + ) { + const location = isLogicalOrCoalescingBinaryExpression(condExpr) + ? skipParentheses(condExpr.right) + : condExpr; if (isModuleExportsAccessExpression(location)) { return; } @@ -45067,59 +78367,108 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { bothHelper(location, body); return; } - const type = location === condExpr ? condType : checkExpression(location); - if (type.flags & TypeFlags.EnumLiteral && isPropertyAccessExpression(location) && (getNodeLinks(location.expression).resolvedSymbol ?? unknownSymbol).flags & SymbolFlags.Enum) { + const type = + location === condExpr ? condType : checkExpression(location); + if ( + type.flags & TypeFlags.EnumLiteral && + isPropertyAccessExpression(location) && + ( + getNodeLinks(location.expression).resolvedSymbol ?? + unknownSymbol + ).flags & SymbolFlags.Enum + ) { // EnumLiteral type at condition with known value is always truthy or always falsy, likely an error - error(location, Diagnostics.This_condition_will_always_return_0, !!(type as LiteralType).value ? "true" : "false"); + error( + location, + Diagnostics.This_condition_will_always_return_0, + !!(type as LiteralType).value ? "true" : "false" + ); return; } - const isPropertyExpressionCast = isPropertyAccessExpression(location) && isTypeAssertion(location.expression); - if (!hasTypeFacts(type, TypeFacts.Truthy) || isPropertyExpressionCast) return; + const isPropertyExpressionCast = + isPropertyAccessExpression(location) && + isTypeAssertion(location.expression); + if ( + !hasTypeFacts(type, TypeFacts.Truthy) || + isPropertyExpressionCast + ) + return; // While it technically should be invalid for any known-truthy value // to be tested, we de-scope to functions and Promises unreferenced in // the block as a heuristic to identify the most common bugs. There // are too many false positives for values sourced from type // definitions without strictNullChecks otherwise. - const callSignatures = getSignaturesOfType(type, SignatureKind.Call); + const callSignatures = getSignaturesOfType( + type, + SignatureKind.Call + ); const isPromise = !!getAwaitedTypeOfPromise(type); if (callSignatures.length === 0 && !isPromise) { return; } - const testedNode = isIdentifier(location) ? location - : isPropertyAccessExpression(location) ? location.name + const testedNode = isIdentifier(location) + ? location + : isPropertyAccessExpression(location) + ? location.name : undefined; const testedSymbol = testedNode && getSymbolAtLocation(testedNode); if (!testedSymbol && !isPromise) { return; } - const isUsed = testedSymbol && isBinaryExpression(condExpr.parent) && isSymbolUsedInBinaryExpressionChain(condExpr.parent, testedSymbol) - || testedSymbol && body && isSymbolUsedInConditionBody(condExpr, body, testedNode, testedSymbol); + const isUsed = + (testedSymbol && + isBinaryExpression(condExpr.parent) && + isSymbolUsedInBinaryExpressionChain( + condExpr.parent, + testedSymbol + )) || + (testedSymbol && + body && + isSymbolUsedInConditionBody( + condExpr, + body, + testedNode, + testedSymbol + )); if (!isUsed) { if (isPromise) { errorAndMaybeSuggestAwait( location, /*maybeMissingAwait*/ true, Diagnostics.This_condition_will_always_return_true_since_this_0_is_always_defined, - getTypeNameForErrorDisplay(type), + getTypeNameForErrorDisplay(type) + ); + } else { + error( + location, + Diagnostics.This_condition_will_always_return_true_since_this_function_is_always_defined_Did_you_mean_to_call_it_instead ); - } - else { - error(location, Diagnostics.This_condition_will_always_return_true_since_this_function_is_always_defined_Did_you_mean_to_call_it_instead); } } } } - function isSymbolUsedInConditionBody(expr: Expression, body: Statement | Expression, testedNode: Node, testedSymbol: Symbol): boolean { - return !!forEachChild(body, function check(childNode): boolean | undefined { + function isSymbolUsedInConditionBody( + expr: Expression, + body: Statement | Expression, + testedNode: Node, + testedSymbol: Symbol + ): boolean { + return !!forEachChild(body, function check(childNode): + | boolean + | undefined { if (isIdentifier(childNode)) { const childSymbol = getSymbolAtLocation(childNode); if (childSymbol && childSymbol === testedSymbol) { // If the test was a simple identifier, the above check is sufficient - if (isIdentifier(expr) || isIdentifier(testedNode) && isBinaryExpression(testedNode.parent)) { + if ( + isIdentifier(expr) || + (isIdentifier(testedNode) && + isBinaryExpression(testedNode.parent)) + ) { return true; } // Otherwise we need to ensure the symbol is called on the same target @@ -45127,23 +78476,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let childExpression = childNode.parent; while (testedExpression && childExpression) { if ( - isIdentifier(testedExpression) && isIdentifier(childExpression) || - testedExpression.kind === SyntaxKind.ThisKeyword && childExpression.kind === SyntaxKind.ThisKeyword + (isIdentifier(testedExpression) && + isIdentifier(childExpression)) || + (testedExpression.kind === SyntaxKind.ThisKeyword && + childExpression.kind === SyntaxKind.ThisKeyword) ) { - return getSymbolAtLocation(testedExpression) === getSymbolAtLocation(childExpression); - } - else if (isPropertyAccessExpression(testedExpression) && isPropertyAccessExpression(childExpression)) { - if (getSymbolAtLocation(testedExpression.name) !== getSymbolAtLocation(childExpression.name)) { + return ( + getSymbolAtLocation(testedExpression) === + getSymbolAtLocation(childExpression) + ); + } else if ( + isPropertyAccessExpression(testedExpression) && + isPropertyAccessExpression(childExpression) + ) { + if ( + getSymbolAtLocation(testedExpression.name) !== + getSymbolAtLocation(childExpression.name) + ) { return false; } childExpression = childExpression.expression; testedExpression = testedExpression.expression; - } - else if (isCallExpression(testedExpression) && isCallExpression(childExpression)) { + } else if ( + isCallExpression(testedExpression) && + isCallExpression(childExpression) + ) { childExpression = childExpression.expression; testedExpression = testedExpression.expression; - } - else { + } else { return false; } } @@ -45153,9 +78513,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { }); } - function isSymbolUsedInBinaryExpressionChain(node: Node, testedSymbol: Symbol): boolean { - while (isBinaryExpression(node) && node.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) { - const isUsed = forEachChild(node.right, function visit(child): boolean | undefined { + function isSymbolUsedInBinaryExpressionChain( + node: Node, + testedSymbol: Symbol + ): boolean { + while ( + isBinaryExpression(node) && + node.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken + ) { + const isUsed = forEachChild(node.right, function visit(child): + | boolean + | undefined { if (isIdentifier(child)) { const symbol = getSymbolAtLocation(child); if (symbol && symbol === testedSymbol) { @@ -45190,16 +78558,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkTruthinessOfType(type: Type, node: Node) { if (type.flags & TypeFlags.Void) { - error(node, Diagnostics.An_expression_of_type_void_cannot_be_tested_for_truthiness); - } - else { + error( + node, + Diagnostics.An_expression_of_type_void_cannot_be_tested_for_truthiness + ); + } else { const semantics = getSyntacticTruthySemantics(node); if (semantics !== PredicateSemantics.Sometimes) { error( node, - semantics === PredicateSemantics.Always ? - Diagnostics.This_kind_of_expression_is_always_truthy : - Diagnostics.This_kind_of_expression_is_always_falsy, + semantics === PredicateSemantics.Always + ? Diagnostics.This_kind_of_expression_is_always_truthy + : Diagnostics.This_kind_of_expression_is_always_falsy ); } } @@ -45212,7 +78582,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { switch (node.kind) { case SyntaxKind.NumericLiteral: // Allow `while(0)` or `while(1)` - if ((node as NumericLiteral).text === "0" || (node as NumericLiteral).text === "1") { + if ( + (node as NumericLiteral).text === "0" || + (node as NumericLiteral).text === "1" + ) { return PredicateSemantics.Sometimes; } return PredicateSemantics.Always; @@ -45231,9 +78604,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return PredicateSemantics.Never; case SyntaxKind.NoSubstitutionTemplateLiteral: case SyntaxKind.StringLiteral: - return !!(node as StringLiteral | NoSubstitutionTemplateLiteral).text ? PredicateSemantics.Always : PredicateSemantics.Never; + return !!(node as StringLiteral | NoSubstitutionTemplateLiteral) + .text + ? PredicateSemantics.Always + : PredicateSemantics.Never; case SyntaxKind.ConditionalExpression: - return getSyntacticTruthySemantics((node as ConditionalExpression).whenTrue) | getSyntacticTruthySemantics((node as ConditionalExpression).whenFalse); + return ( + getSyntacticTruthySemantics( + (node as ConditionalExpression).whenTrue + ) | + getSyntacticTruthySemantics( + (node as ConditionalExpression).whenFalse + ) + ); case SyntaxKind.Identifier: if (getResolvedSymbol(node as Identifier) === undefinedSymbol) { return PredicateSemantics.Never; @@ -45243,23 +78626,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return PredicateSemantics.Sometimes; } - function checkTruthinessExpression(node: Expression, checkMode?: CheckMode) { + function checkTruthinessExpression( + node: Expression, + checkMode?: CheckMode + ) { return checkTruthinessOfType(checkExpression(node, checkMode), node); } function checkForStatement(node: ForStatement) { // Grammar checking if (!checkGrammarStatementInAmbientContext(node)) { - if (node.initializer && node.initializer.kind === SyntaxKind.VariableDeclarationList) { - checkGrammarVariableDeclarationList(node.initializer as VariableDeclarationList); + if ( + node.initializer && + node.initializer.kind === SyntaxKind.VariableDeclarationList + ) { + checkGrammarVariableDeclarationList( + node.initializer as VariableDeclarationList + ); } } if (node.initializer) { if (node.initializer.kind === SyntaxKind.VariableDeclarationList) { - checkVariableDeclarationList(node.initializer as VariableDeclarationList); - } - else { + checkVariableDeclarationList( + node.initializer as VariableDeclarationList + ); + } else { checkExpression(node.initializer); } } @@ -45278,17 +78670,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const container = getContainingFunctionOrClassStaticBlock(node); if (node.awaitModifier) { if (container && isClassStaticBlockDeclaration(container)) { - grammarErrorOnNode(node.awaitModifier, Diagnostics.for_await_loops_cannot_be_used_inside_a_class_static_block); - } - else { + grammarErrorOnNode( + node.awaitModifier, + Diagnostics.for_await_loops_cannot_be_used_inside_a_class_static_block + ); + } else { const functionFlags = getFunctionFlags(container); - if ((functionFlags & (FunctionFlags.Invalid | FunctionFlags.Async)) === FunctionFlags.Async && languageVersion < LanguageFeatureMinimumTarget.ForAwaitOf) { + if ( + (functionFlags & + (FunctionFlags.Invalid | FunctionFlags.Async)) === + FunctionFlags.Async && + languageVersion < LanguageFeatureMinimumTarget.ForAwaitOf + ) { // for..await..of in an async function or async generator function prior to ESNext requires the __asyncValues helper - checkExternalEmitHelpers(node, ExternalEmitHelpers.ForAwaitOfIncludes); + checkExternalEmitHelpers( + node, + ExternalEmitHelpers.ForAwaitOfIncludes + ); } } - } - else if (compilerOptions.downlevelIteration && languageVersion < LanguageFeatureMinimumTarget.ForOf) { + } else if ( + compilerOptions.downlevelIteration && + languageVersion < LanguageFeatureMinimumTarget.ForOf + ) { // for..of prior to ES2015 requires the __values helper when downlevelIteration is enabled checkExternalEmitHelpers(node, ExternalEmitHelpers.ForOfIncludes); } @@ -45299,25 +78703,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If the LHS is an expression, check the LHS, as a destructuring assignment or as a reference. // Then check that the RHS is assignable to it. if (node.initializer.kind === SyntaxKind.VariableDeclarationList) { - checkVariableDeclarationList(node.initializer as VariableDeclarationList); - } - else { + checkVariableDeclarationList( + node.initializer as VariableDeclarationList + ); + } else { const varExpr = node.initializer; const iteratedType = checkRightHandSideOfForOf(node); // There may be a destructuring assignment on the left side - if (varExpr.kind === SyntaxKind.ArrayLiteralExpression || varExpr.kind === SyntaxKind.ObjectLiteralExpression) { + if ( + varExpr.kind === SyntaxKind.ArrayLiteralExpression || + varExpr.kind === SyntaxKind.ObjectLiteralExpression + ) { // iteratedType may be undefined. In this case, we still want to check the structure of // varExpr, in particular making sure it's a valid LeftHandSideExpression. But we'd like // to short circuit the type relation checking as much as possible, so we pass the unknownType. - checkDestructuringAssignment(varExpr, iteratedType || errorType); - } - else { + checkDestructuringAssignment( + varExpr, + iteratedType || errorType + ); + } else { const leftType = checkExpression(varExpr); checkReferenceExpression( varExpr, Diagnostics.The_left_hand_side_of_a_for_of_statement_must_be_a_variable_or_a_property_access, - Diagnostics.The_left_hand_side_of_a_for_of_statement_may_not_be_an_optional_property_access, + Diagnostics.The_left_hand_side_of_a_for_of_statement_may_not_be_an_optional_property_access ); // iteratedType will be undefined if the rightType was missing properties/signatures @@ -45325,7 +78735,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // because we accessed properties from anyType, or it may have led to an error inside // getElementTypeOfIterable. if (iteratedType) { - checkTypeAssignableToAndOptionallyElaborate(iteratedType, leftType, varExpr, node.expression); + checkTypeAssignableToAndOptionallyElaborate( + iteratedType, + leftType, + varExpr, + node.expression + ); } } } @@ -45340,46 +78755,72 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Grammar checking checkGrammarForInOrForOfStatement(node); - const rightType = getNonNullableTypeIfNeeded(checkExpression(node.expression)); + const rightType = getNonNullableTypeIfNeeded( + checkExpression(node.expression) + ); // TypeScript 1.0 spec (April 2014): 5.4 // In a 'for-in' statement of the form // for (let VarDecl in Expr) Statement // VarDecl must be a variable declaration without a type annotation that declares a variable of type Any, // and Expr must be an expression of type Any, an object type, or a type parameter type. if (node.initializer.kind === SyntaxKind.VariableDeclarationList) { - const variable = (node.initializer as VariableDeclarationList).declarations[0]; + const variable = (node.initializer as VariableDeclarationList) + .declarations[0]; if (variable && isBindingPattern(variable.name)) { - error(variable.name, Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_a_destructuring_pattern); + error( + variable.name, + Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_a_destructuring_pattern + ); } - checkVariableDeclarationList(node.initializer as VariableDeclarationList); - } - else { + checkVariableDeclarationList( + node.initializer as VariableDeclarationList + ); + } else { // In a 'for-in' statement of the form // for (Var in Expr) Statement // Var must be an expression classified as a reference of type Any or the String primitive type, // and Expr must be an expression of type Any, an object type, or a type parameter type. const varExpr = node.initializer; const leftType = checkExpression(varExpr); - if (varExpr.kind === SyntaxKind.ArrayLiteralExpression || varExpr.kind === SyntaxKind.ObjectLiteralExpression) { - error(varExpr, Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_a_destructuring_pattern); - } - else if (!isTypeAssignableTo(getIndexTypeOrString(rightType), leftType)) { - error(varExpr, Diagnostics.The_left_hand_side_of_a_for_in_statement_must_be_of_type_string_or_any); - } - else { + if ( + varExpr.kind === SyntaxKind.ArrayLiteralExpression || + varExpr.kind === SyntaxKind.ObjectLiteralExpression + ) { + error( + varExpr, + Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_a_destructuring_pattern + ); + } else if ( + !isTypeAssignableTo(getIndexTypeOrString(rightType), leftType) + ) { + error( + varExpr, + Diagnostics.The_left_hand_side_of_a_for_in_statement_must_be_of_type_string_or_any + ); + } else { // run check only former check succeeded to avoid cascading errors checkReferenceExpression( varExpr, Diagnostics.The_left_hand_side_of_a_for_in_statement_must_be_a_variable_or_a_property_access, - Diagnostics.The_left_hand_side_of_a_for_in_statement_may_not_be_an_optional_property_access, + Diagnostics.The_left_hand_side_of_a_for_in_statement_may_not_be_an_optional_property_access ); } } // unknownType is returned i.e. if node.expression is identifier whose name cannot be resolved // in this case error about missing name is already reported - do not report extra one - if (rightType === neverType || !isTypeAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive)) { - 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)); + if ( + rightType === neverType || + !isTypeAssignableToKind( + rightType, + TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive + ) + ) { + 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) + ); } checkSourceElement(node.statement); @@ -45389,15 +78830,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkRightHandSideOfForOf(statement: ForOfStatement): Type { - const use = statement.awaitModifier ? IterationUse.ForAwaitOf : IterationUse.ForOf; - return checkIteratedTypeOrElementType(use, checkNonNullExpression(statement.expression), undefinedType, statement.expression); + const use = statement.awaitModifier + ? IterationUse.ForAwaitOf + : IterationUse.ForOf; + return checkIteratedTypeOrElementType( + use, + checkNonNullExpression(statement.expression), + undefinedType, + statement.expression + ); } - function checkIteratedTypeOrElementType(use: IterationUse, inputType: Type, sentType: Type, errorNode: Node | undefined): Type { + function checkIteratedTypeOrElementType( + use: IterationUse, + inputType: Type, + sentType: Type, + errorNode: Node | undefined + ): Type { if (isTypeAny(inputType)) { return inputType; } - return getIteratedTypeOrElementType(use, inputType, sentType, errorNode, /*checkAssignability*/ true) || anyType; + return ( + getIteratedTypeOrElementType( + use, + inputType, + sentType, + errorNode, + /*checkAssignability*/ true + ) || anyType + ); } /** @@ -45405,39 +78866,71 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * we want to get the iterated type of an iterable for ES2015 or later, or the iterated type * of a iterable (if defined globally) or element type of an array like for ES2015 or earlier. */ - function getIteratedTypeOrElementType(use: IterationUse, inputType: Type, sentType: Type, errorNode: Node | undefined, checkAssignability: boolean): Type | undefined { - const allowAsyncIterables = (use & IterationUse.AllowsAsyncIterablesFlag) !== 0; + function getIteratedTypeOrElementType( + use: IterationUse, + inputType: Type, + sentType: Type, + errorNode: Node | undefined, + checkAssignability: boolean + ): Type | undefined { + const allowAsyncIterables = + (use & IterationUse.AllowsAsyncIterablesFlag) !== 0; if (inputType === neverType) { if (errorNode) { - reportTypeNotIterableError(errorNode, inputType, allowAsyncIterables); + reportTypeNotIterableError( + errorNode, + inputType, + allowAsyncIterables + ); } return undefined; } const uplevelIteration = languageVersion >= ScriptTarget.ES2015; - const downlevelIteration = !uplevelIteration && compilerOptions.downlevelIteration; - const possibleOutOfBounds = compilerOptions.noUncheckedIndexedAccess && !!(use & IterationUse.PossiblyOutOfBounds); + const downlevelIteration = + !uplevelIteration && compilerOptions.downlevelIteration; + const possibleOutOfBounds = + compilerOptions.noUncheckedIndexedAccess && + !!(use & IterationUse.PossiblyOutOfBounds); // Get the iterated type of an `Iterable` or `IterableIterator` only in ES2015 // or higher, when inside of an async generator or for-await-if, or when // downlevelIteration is requested. if (uplevelIteration || downlevelIteration || allowAsyncIterables) { // We only report errors for an invalid iterable type in ES2015 or higher. - const iterationTypes = getIterationTypesOfIterable(inputType, use, uplevelIteration ? errorNode : undefined); + const iterationTypes = getIterationTypesOfIterable( + inputType, + use, + uplevelIteration ? errorNode : undefined + ); if (checkAssignability) { if (iterationTypes) { - const diagnostic = use & IterationUse.ForOfFlag ? Diagnostics.Cannot_iterate_value_because_the_next_method_of_its_iterator_expects_type_1_but_for_of_will_always_send_0 : - use & IterationUse.SpreadFlag ? Diagnostics.Cannot_iterate_value_because_the_next_method_of_its_iterator_expects_type_1_but_array_spread_will_always_send_0 : - use & IterationUse.DestructuringFlag ? Diagnostics.Cannot_iterate_value_because_the_next_method_of_its_iterator_expects_type_1_but_array_destructuring_will_always_send_0 : - 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 : - undefined; + const diagnostic = + use & IterationUse.ForOfFlag + ? Diagnostics.Cannot_iterate_value_because_the_next_method_of_its_iterator_expects_type_1_but_for_of_will_always_send_0 + : use & IterationUse.SpreadFlag + ? Diagnostics.Cannot_iterate_value_because_the_next_method_of_its_iterator_expects_type_1_but_array_spread_will_always_send_0 + : use & IterationUse.DestructuringFlag + ? Diagnostics.Cannot_iterate_value_because_the_next_method_of_its_iterator_expects_type_1_but_array_destructuring_will_always_send_0 + : 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 + : undefined; if (diagnostic) { - checkTypeAssignableTo(sentType, iterationTypes.nextType, errorNode, diagnostic); + checkTypeAssignableTo( + sentType, + iterationTypes.nextType, + errorNode, + diagnostic + ); } } } if (iterationTypes || uplevelIteration) { - return possibleOutOfBounds ? includeUndefinedInIndexSignature(iterationTypes && iterationTypes.yieldType) : (iterationTypes && iterationTypes.yieldType); + return possibleOutOfBounds + ? includeUndefinedInIndexSignature( + iterationTypes && iterationTypes.yieldType + ) + : iterationTypes && iterationTypes.yieldType; } } @@ -45452,12 +78945,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // After we remove all types that are StringLike, we will know if there was a string constituent // based on whether the result of filter is a new array. const arrayTypes = (inputType as UnionType).types; - const filteredTypes = filter(arrayTypes, t => !(t.flags & TypeFlags.StringLike)); + const filteredTypes = filter( + arrayTypes, + (t) => !(t.flags & TypeFlags.StringLike) + ); if (filteredTypes !== arrayTypes) { - arrayType = getUnionType(filteredTypes, UnionReduction.Subtype); + arrayType = getUnionType( + filteredTypes, + UnionReduction.Subtype + ); } - } - else if (arrayType.flags & TypeFlags.StringLike) { + } else if (arrayType.flags & TypeFlags.StringLike) { arrayType = neverType; } @@ -45466,7 +78964,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Now that we've removed all the StringLike types, if no constituents remain, then the entire // arrayOrStringType was a string. if (arrayType.flags & TypeFlags.Never) { - return possibleOutOfBounds ? includeUndefinedInIndexSignature(stringType) : stringType; + return possibleOutOfBounds + ? includeUndefinedInIndexSignature(stringType) + : stringType; } } } @@ -45478,49 +78978,92 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // want to say that number is not an array type. But if the input was just // number and string input is allowed, we want to say that number is not an // array type or a string type. - const allowsStrings = !!(use & IterationUse.AllowsStringInputFlag) && !hasStringConstituent; - const [defaultDiagnostic, maybeMissingAwait] = getIterationDiagnosticDetails(allowsStrings, downlevelIteration); + const allowsStrings = + !!(use & IterationUse.AllowsStringInputFlag) && + !hasStringConstituent; + const [defaultDiagnostic, maybeMissingAwait] = + getIterationDiagnosticDetails( + allowsStrings, + downlevelIteration + ); errorAndMaybeSuggestAwait( errorNode, maybeMissingAwait && !!getAwaitedTypeOfPromise(arrayType), defaultDiagnostic, - typeToString(arrayType), + typeToString(arrayType) ); } - return hasStringConstituent ? possibleOutOfBounds ? includeUndefinedInIndexSignature(stringType) : stringType : undefined; + return hasStringConstituent + ? possibleOutOfBounds + ? includeUndefinedInIndexSignature(stringType) + : stringType + : undefined; } const arrayElementType = getIndexTypeOfType(arrayType, numberType); if (hasStringConstituent && arrayElementType) { // This is just an optimization for the case where arrayOrStringType is string | string[] - if (arrayElementType.flags & TypeFlags.StringLike && !compilerOptions.noUncheckedIndexedAccess) { + if ( + arrayElementType.flags & TypeFlags.StringLike && + !compilerOptions.noUncheckedIndexedAccess + ) { return stringType; } - return getUnionType(possibleOutOfBounds ? [arrayElementType, stringType, undefinedType] : [arrayElementType, stringType], UnionReduction.Subtype); + return getUnionType( + possibleOutOfBounds + ? [arrayElementType, stringType, undefinedType] + : [arrayElementType, stringType], + UnionReduction.Subtype + ); } - return (use & IterationUse.PossiblyOutOfBounds) ? includeUndefinedInIndexSignature(arrayElementType) : arrayElementType; + return use & IterationUse.PossiblyOutOfBounds + ? includeUndefinedInIndexSignature(arrayElementType) + : arrayElementType; - function getIterationDiagnosticDetails(allowsStrings: boolean, downlevelIteration: boolean | undefined): [error: DiagnosticMessage, maybeMissingAwait: boolean] { + function getIterationDiagnosticDetails( + allowsStrings: boolean, + downlevelIteration: boolean | undefined + ): [error: DiagnosticMessage, maybeMissingAwait: boolean] { if (downlevelIteration) { return allowsStrings - ? [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] - : [Diagnostics.Type_0_is_not_an_array_type_or_does_not_have_a_Symbol_iterator_method_that_returns_an_iterator, true]; - } - - const yieldType = getIterationTypeOfIterable(use, IterationTypeKind.Yield, inputType, /*errorNode*/ undefined); + ? [ + 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, + ] + : [ + Diagnostics.Type_0_is_not_an_array_type_or_does_not_have_a_Symbol_iterator_method_that_returns_an_iterator, + true, + ]; + } + + const yieldType = getIterationTypeOfIterable( + use, + IterationTypeKind.Yield, + inputType, + /*errorNode*/ undefined + ); if (yieldType) { - return [Diagnostics.Type_0_can_only_be_iterated_through_when_using_the_downlevelIteration_flag_or_with_a_target_of_es2015_or_higher, false]; + return [ + Diagnostics.Type_0_can_only_be_iterated_through_when_using_the_downlevelIteration_flag_or_with_a_target_of_es2015_or_higher, + false, + ]; } if (isES2015OrLaterIterable(inputType.symbol?.escapedName)) { - return [Diagnostics.Type_0_can_only_be_iterated_through_when_using_the_downlevelIteration_flag_or_with_a_target_of_es2015_or_higher, true]; + return [ + Diagnostics.Type_0_can_only_be_iterated_through_when_using_the_downlevelIteration_flag_or_with_a_target_of_es2015_or_higher, + true, + ]; } return allowsStrings - ? [Diagnostics.Type_0_is_not_an_array_type_or_a_string_type, true] + ? [ + Diagnostics.Type_0_is_not_an_array_type_or_a_string_type, + true, + ] : [Diagnostics.Type_0_is_not_an_array_type, true]; } } @@ -45545,16 +79088,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** * Gets the requested "iteration type" from an `Iterable`-like or `AsyncIterable`-like type. */ - function getIterationTypeOfIterable(use: IterationUse, typeKind: IterationTypeKind, inputType: Type, errorNode: Node | undefined): Type | undefined { + function getIterationTypeOfIterable( + use: IterationUse, + typeKind: IterationTypeKind, + inputType: Type, + errorNode: Node | undefined + ): Type | undefined { if (isTypeAny(inputType)) { return undefined; } - const iterationTypes = getIterationTypesOfIterable(inputType, use, errorNode); - return iterationTypes && iterationTypes[getIterationTypesKeyFromIterationTypeKind(typeKind)]; + const iterationTypes = getIterationTypesOfIterable( + inputType, + use, + errorNode + ); + return ( + iterationTypes && + iterationTypes[getIterationTypesKeyFromIterationTypeKind(typeKind)] + ); } - function createIterationTypes(yieldType: Type = neverType, returnType: Type = neverType, nextType: Type = unknownType): IterationTypes { + function createIterationTypes( + yieldType: Type = neverType, + returnType: Type = neverType, + nextType: Type = unknownType + ): IterationTypes { // `yieldType` and `returnType` are defaulted to `neverType` they each will be combined // via `getUnionType` when merging iteration types. `nextType` is defined as `unknownType` // as it is combined via `getIntersectionType` when merging iteration types. @@ -45565,8 +79124,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // the cache for less-frequently used types. if ( yieldType.flags & TypeFlags.Intrinsic && - returnType.flags & (TypeFlags.Any | TypeFlags.Never | TypeFlags.Unknown | TypeFlags.Void | TypeFlags.Undefined) && - nextType.flags & (TypeFlags.Any | TypeFlags.Never | TypeFlags.Unknown | TypeFlags.Void | TypeFlags.Undefined) + returnType.flags & + (TypeFlags.Any | + TypeFlags.Never | + TypeFlags.Unknown | + TypeFlags.Void | + TypeFlags.Undefined) && + nextType.flags & + (TypeFlags.Any | + TypeFlags.Never | + TypeFlags.Unknown | + TypeFlags.Void | + TypeFlags.Undefined) ) { const id = getTypeListId([yieldType, returnType, nextType]); let iterationTypes = iterationTypesCache.get(id); @@ -45591,7 +79160,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let returnTypes: Type[] | undefined; let nextTypes: Type[] | undefined; for (const iterationTypes of array) { - if (iterationTypes === undefined || iterationTypes === noIterationTypes) { + if ( + iterationTypes === undefined || + iterationTypes === noIterationTypes + ) { continue; } if (iterationTypes === anyIterationTypes) { @@ -45605,18 +79177,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return createIterationTypes( yieldTypes && getUnionType(yieldTypes), returnTypes && getUnionType(returnTypes), - nextTypes && getIntersectionType(nextTypes), + nextTypes && getIntersectionType(nextTypes) ); } return noIterationTypes; } - function getCachedIterationTypes(type: Type, cacheKey: MatchingKeys) { + function getCachedIterationTypes( + type: Type, + cacheKey: MatchingKeys< + IterableOrIteratorType, + IterationTypes | undefined + > + ) { return (type as IterableOrIteratorType)[cacheKey]; } - function setCachedIterationTypes(type: Type, cacheKey: MatchingKeys, cachedTypes: IterationTypes) { - return (type as IterableOrIteratorType)[cacheKey] = cachedTypes; + function setCachedIterationTypes( + type: Type, + cacheKey: MatchingKeys< + IterableOrIteratorType, + IterationTypes | undefined + >, + cachedTypes: IterationTypes + ) { + return ((type as IterableOrIteratorType)[cacheKey] = cachedTypes); } /** @@ -45640,24 +79225,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * For a **for-await-of** statement or a `yield*` in an async generator we will look for * the `[Symbol.asyncIterator]()` method first, and then the `[Symbol.iterator]()` method. */ - function getIterationTypesOfIterable(type: Type, use: IterationUse, errorNode: Node | undefined) { + function getIterationTypesOfIterable( + type: Type, + use: IterationUse, + errorNode: Node | undefined + ) { if (isTypeAny(type)) { return anyIterationTypes; } if (!(type.flags & TypeFlags.Union)) { - const errorOutputContainer: ErrorOutputContainer | undefined = errorNode ? { errors: undefined, skipLogging: true } : undefined; - const iterationTypes = getIterationTypesOfIterableWorker(type, use, errorNode, errorOutputContainer); + const errorOutputContainer: ErrorOutputContainer | undefined = + errorNode + ? { errors: undefined, skipLogging: true } + : undefined; + const iterationTypes = getIterationTypesOfIterableWorker( + type, + use, + errorNode, + errorOutputContainer + ); if (iterationTypes === noIterationTypes) { if (errorNode) { - const rootDiag = reportTypeNotIterableError(errorNode, type, !!(use & IterationUse.AllowsAsyncIterablesFlag)); + const rootDiag = reportTypeNotIterableError( + errorNode, + type, + !!(use & IterationUse.AllowsAsyncIterablesFlag) + ); if (errorOutputContainer?.errors) { - addRelatedInfo(rootDiag, ...errorOutputContainer.errors); + addRelatedInfo( + rootDiag, + ...errorOutputContainer.errors + ); } } return undefined; - } - else if (errorOutputContainer?.errors?.length) { + } else if (errorOutputContainer?.errors?.length) { for (const diag of errorOutputContainer.errors) { diagnostics.add(diag); } @@ -45665,25 +79268,41 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return iterationTypes; } - const cacheKey = use & IterationUse.AllowsAsyncIterablesFlag ? "iterationTypesOfAsyncIterable" : "iterationTypesOfIterable"; + const cacheKey = + use & IterationUse.AllowsAsyncIterablesFlag + ? "iterationTypesOfAsyncIterable" + : "iterationTypesOfIterable"; const cachedTypes = getCachedIterationTypes(type, cacheKey); - if (cachedTypes) return cachedTypes === noIterationTypes ? undefined : cachedTypes; + if (cachedTypes) + return cachedTypes === noIterationTypes ? undefined : cachedTypes; let allIterationTypes: IterationTypes[] | undefined; for (const constituent of (type as UnionType).types) { - const errorOutputContainer: ErrorOutputContainer | undefined = errorNode ? { errors: undefined } : undefined; - const iterationTypes = getIterationTypesOfIterableWorker(constituent, use, errorNode, errorOutputContainer); + const errorOutputContainer: ErrorOutputContainer | undefined = + errorNode ? { errors: undefined } : undefined; + const iterationTypes = getIterationTypesOfIterableWorker( + constituent, + use, + errorNode, + errorOutputContainer + ); if (iterationTypes === noIterationTypes) { if (errorNode) { - const rootDiag = reportTypeNotIterableError(errorNode, type, !!(use & IterationUse.AllowsAsyncIterablesFlag)); + const rootDiag = reportTypeNotIterableError( + errorNode, + type, + !!(use & IterationUse.AllowsAsyncIterablesFlag) + ); if (errorOutputContainer?.errors) { - addRelatedInfo(rootDiag, ...errorOutputContainer.errors); + addRelatedInfo( + rootDiag, + ...errorOutputContainer.errors + ); } } setCachedIterationTypes(type, cacheKey, noIterationTypes); return undefined; - } - else if (errorOutputContainer?.errors?.length) { + } else if (errorOutputContainer?.errors?.length) { for (const diag of errorOutputContainer.errors) { diagnostics.add(diag); } @@ -45692,12 +79311,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { allIterationTypes = append(allIterationTypes, iterationTypes); } - const iterationTypes = allIterationTypes ? combineIterationTypes(allIterationTypes) : noIterationTypes; + const iterationTypes = allIterationTypes + ? combineIterationTypes(allIterationTypes) + : noIterationTypes; setCachedIterationTypes(type, cacheKey, iterationTypes); return iterationTypes === noIterationTypes ? undefined : iterationTypes; } - function getAsyncFromSyncIterationTypes(iterationTypes: IterationTypes, errorNode: Node | undefined) { + function getAsyncFromSyncIterationTypes( + iterationTypes: IterationTypes, + errorNode: Node | undefined + ) { if (iterationTypes === noIterationTypes) return noIterationTypes; if (iterationTypes === anyIterationTypes) return anyIterationTypes; const { yieldType, returnType, nextType } = iterationTypes; @@ -45708,7 +79332,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return createIterationTypes( getAwaitedType(yieldType, errorNode) || anyType, getAwaitedType(returnType, errorNode) || anyType, - nextType, + nextType ); } @@ -45722,7 +79346,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * NOTE: You probably don't want to call this directly and should be calling * `getIterationTypesOfIterable` instead. */ - function getIterationTypesOfIterableWorker(type: Type, use: IterationUse, errorNode: Node | undefined, errorOutputContainer: ErrorOutputContainer | undefined) { + function getIterationTypesOfIterableWorker( + type: Type, + use: IterationUse, + errorNode: Node | undefined, + errorOutputContainer: ErrorOutputContainer | undefined + ) { if (isTypeAny(type)) { return anyIterationTypes; } @@ -45732,38 +79361,61 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let noCache = false; if (use & IterationUse.AllowsAsyncIterablesFlag) { - const iterationTypes = getIterationTypesOfIterableCached(type, asyncIterationTypesResolver) || - getIterationTypesOfIterableFast(type, asyncIterationTypesResolver); + const iterationTypes = + getIterationTypesOfIterableCached( + type, + asyncIterationTypesResolver + ) || + getIterationTypesOfIterableFast( + type, + asyncIterationTypesResolver + ); if (iterationTypes) { if (iterationTypes === noIterationTypes && errorNode) { // ignore the cached value noCache = true; - } - else { - return use & IterationUse.ForOfFlag ? - getAsyncFromSyncIterationTypes(iterationTypes, errorNode) : - iterationTypes; + } else { + return use & IterationUse.ForOfFlag + ? getAsyncFromSyncIterationTypes( + iterationTypes, + errorNode + ) + : iterationTypes; } } } if (use & IterationUse.AllowsSyncIterablesFlag) { - let iterationTypes = getIterationTypesOfIterableCached(type, syncIterationTypesResolver) || - getIterationTypesOfIterableFast(type, syncIterationTypesResolver); + let iterationTypes = + getIterationTypesOfIterableCached( + type, + syncIterationTypesResolver + ) || + getIterationTypesOfIterableFast( + type, + syncIterationTypesResolver + ); if (iterationTypes) { if (iterationTypes === noIterationTypes && errorNode) { // ignore the cached value noCache = true; - } - else { + } else { if (use & IterationUse.AllowsAsyncIterablesFlag) { // for a sync iterable in an async context, only use the cached types if they are valid. if (iterationTypes !== noIterationTypes) { - iterationTypes = getAsyncFromSyncIterationTypes(iterationTypes, errorNode); - return noCache ? iterationTypes : setCachedIterationTypes(type, "iterationTypesOfAsyncIterable", iterationTypes); + iterationTypes = getAsyncFromSyncIterationTypes( + iterationTypes, + errorNode + ); + return noCache + ? iterationTypes + : setCachedIterationTypes( + type, + "iterationTypesOfAsyncIterable", + iterationTypes + ); } - } - else { + } else { return iterationTypes; } } @@ -45771,20 +79423,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (use & IterationUse.AllowsAsyncIterablesFlag) { - const iterationTypes = getIterationTypesOfIterableSlow(type, asyncIterationTypesResolver, errorNode, errorOutputContainer, noCache); + const iterationTypes = getIterationTypesOfIterableSlow( + type, + asyncIterationTypesResolver, + errorNode, + errorOutputContainer, + noCache + ); if (iterationTypes !== noIterationTypes) { return iterationTypes; } } if (use & IterationUse.AllowsSyncIterablesFlag) { - let iterationTypes = getIterationTypesOfIterableSlow(type, syncIterationTypesResolver, errorNode, errorOutputContainer, noCache); + let iterationTypes = getIterationTypesOfIterableSlow( + type, + syncIterationTypesResolver, + errorNode, + errorOutputContainer, + noCache + ); if (iterationTypes !== noIterationTypes) { if (use & IterationUse.AllowsAsyncIterablesFlag) { - iterationTypes = getAsyncFromSyncIterationTypes(iterationTypes, errorNode); - return noCache ? iterationTypes : setCachedIterationTypes(type, "iterationTypesOfAsyncIterable", iterationTypes); - } - else { + iterationTypes = getAsyncFromSyncIterationTypes( + iterationTypes, + errorNode + ); + return noCache + ? iterationTypes + : setCachedIterationTypes( + type, + "iterationTypesOfAsyncIterable", + iterationTypes + ); + } else { return iterationTypes; } } @@ -45800,7 +79472,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * NOTE: You probably don't want to call this directly and should be calling * `getIterationTypesOfIterable` instead. */ - function getIterationTypesOfIterableCached(type: Type, resolver: IterationTypesResolver) { + function getIterationTypesOfIterableCached( + type: Type, + resolver: IterationTypesResolver + ) { return getCachedIterationTypes(type, resolver.iterableCacheKey); } @@ -45816,7 +79491,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * NOTE: You probably don't want to call this directly and should be calling * `getIterationTypesOfIterable` instead. */ - function getIterationTypesOfIterableFast(type: Type, resolver: IterationTypesResolver) { + function getIterationTypesOfIterableFast( + type: Type, + resolver: IterationTypesResolver + ) { // As an optimization, if the type is an instantiation of the following global type, then // just grab its related type arguments: // - `Iterable` or `AsyncIterable` @@ -45824,13 +79502,41 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // - `IterableIterator` or `AsyncIterableIterator` // - `Generator` or `AsyncGenerator` if ( - isReferenceToType(type, resolver.getGlobalIterableType(/*reportErrors*/ false)) || - isReferenceToType(type, resolver.getGlobalIteratorObjectType(/*reportErrors*/ false)) || - isReferenceToType(type, resolver.getGlobalIterableIteratorType(/*reportErrors*/ false)) || - isReferenceToType(type, resolver.getGlobalGeneratorType(/*reportErrors*/ false)) + isReferenceToType( + type, + resolver.getGlobalIterableType(/*reportErrors*/ false) + ) || + isReferenceToType( + type, + resolver.getGlobalIteratorObjectType(/*reportErrors*/ false) + ) || + isReferenceToType( + type, + resolver.getGlobalIterableIteratorType(/*reportErrors*/ false) + ) || + isReferenceToType( + type, + resolver.getGlobalGeneratorType(/*reportErrors*/ false) + ) ) { - const [yieldType, returnType, nextType] = getTypeArguments(type as GenericType); - return setCachedIterationTypes(type, resolver.iterableCacheKey, createIterationTypes(resolver.resolveIterationType(yieldType, /*errorNode*/ undefined) || yieldType, resolver.resolveIterationType(returnType, /*errorNode*/ undefined) || returnType, nextType)); + const [yieldType, returnType, nextType] = getTypeArguments( + type as GenericType + ); + return setCachedIterationTypes( + type, + resolver.iterableCacheKey, + createIterationTypes( + resolver.resolveIterationType( + yieldType, + /*errorNode*/ undefined + ) || yieldType, + resolver.resolveIterationType( + returnType, + /*errorNode*/ undefined + ) || returnType, + nextType + ) + ); } // As an optimization, if the type is an instantiation of one of the following global types, then @@ -45840,18 +79546,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // - `SetIterator` // - `StringIterator` // - `ReadableStreamAsyncIterator` - if (isReferenceToSomeType(type, resolver.getGlobalBuiltinIteratorTypes())) { + if ( + isReferenceToSomeType( + type, + resolver.getGlobalBuiltinIteratorTypes() + ) + ) { const [yieldType] = getTypeArguments(type as GenericType); const returnType = getBuiltinIteratorReturnType(); const nextType = unknownType; - return setCachedIterationTypes(type, resolver.iterableCacheKey, createIterationTypes(resolver.resolveIterationType(yieldType, /*errorNode*/ undefined) || yieldType, resolver.resolveIterationType(returnType, /*errorNode*/ undefined) || returnType, nextType)); + return setCachedIterationTypes( + type, + resolver.iterableCacheKey, + createIterationTypes( + resolver.resolveIterationType( + yieldType, + /*errorNode*/ undefined + ) || yieldType, + resolver.resolveIterationType( + returnType, + /*errorNode*/ undefined + ) || returnType, + nextType + ) + ); } } function getPropertyNameForKnownSymbolName(symbolName: string): __String { - const ctorType = getGlobalESSymbolConstructorSymbol(/*reportErrors*/ false); - const uniqueType = ctorType && getTypeOfPropertyOfType(getTypeOfSymbol(ctorType), escapeLeadingUnderscores(symbolName)); - return uniqueType && isTypeUsableAsPropertyName(uniqueType) ? getPropertyNameFromType(uniqueType) : `__@${symbolName}` as __String; + const ctorType = getGlobalESSymbolConstructorSymbol( + /*reportErrors*/ false + ); + const uniqueType = + ctorType && + getTypeOfPropertyOfType( + getTypeOfSymbol(ctorType), + escapeLeadingUnderscores(symbolName) + ); + return uniqueType && isTypeUsableAsPropertyName(uniqueType) + ? getPropertyNameFromType(uniqueType) + : (`__@${symbolName}` as __String); } /** @@ -45864,43 +79598,108 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * NOTE: You probably don't want to call this directly and should be calling * `getIterationTypesOfIterable` instead. */ - function getIterationTypesOfIterableSlow(type: Type, resolver: IterationTypesResolver, errorNode: Node | undefined, errorOutputContainer: ErrorOutputContainer | undefined, noCache: boolean) { - const method = getPropertyOfType(type, getPropertyNameForKnownSymbolName(resolver.iteratorSymbolName)); - const methodType = method && !(method.flags & SymbolFlags.Optional) ? getTypeOfSymbol(method) : undefined; + function getIterationTypesOfIterableSlow( + type: Type, + resolver: IterationTypesResolver, + errorNode: Node | undefined, + errorOutputContainer: ErrorOutputContainer | undefined, + noCache: boolean + ) { + const method = getPropertyOfType( + type, + getPropertyNameForKnownSymbolName(resolver.iteratorSymbolName) + ); + const methodType = + method && !(method.flags & SymbolFlags.Optional) + ? getTypeOfSymbol(method) + : undefined; if (isTypeAny(methodType)) { - return noCache ? anyIterationTypes : setCachedIterationTypes(type, resolver.iterableCacheKey, anyIterationTypes); + return noCache + ? anyIterationTypes + : setCachedIterationTypes( + type, + resolver.iterableCacheKey, + anyIterationTypes + ); } - const allSignatures = methodType ? getSignaturesOfType(methodType, SignatureKind.Call) : undefined; - const validSignatures = filter(allSignatures, sig => getMinArgumentCount(sig) === 0); + const allSignatures = methodType + ? getSignaturesOfType(methodType, SignatureKind.Call) + : undefined; + const validSignatures = filter( + allSignatures, + (sig) => getMinArgumentCount(sig) === 0 + ); if (!some(validSignatures)) { if (errorNode && some(allSignatures)) { - checkTypeAssignableTo(type, resolver.getGlobalIterableType(/*reportErrors*/ true), errorNode, /*headMessage*/ undefined, /*containingMessageChain*/ undefined, errorOutputContainer); + checkTypeAssignableTo( + type, + resolver.getGlobalIterableType(/*reportErrors*/ true), + errorNode, + /*headMessage*/ undefined, + /*containingMessageChain*/ undefined, + errorOutputContainer + ); } - return noCache ? noIterationTypes : setCachedIterationTypes(type, resolver.iterableCacheKey, noIterationTypes); + return noCache + ? noIterationTypes + : setCachedIterationTypes( + type, + resolver.iterableCacheKey, + noIterationTypes + ); } - const iteratorType = getIntersectionType(map(validSignatures, getReturnTypeOfSignature)); - const iterationTypes = getIterationTypesOfIteratorWorker(iteratorType, resolver, errorNode, errorOutputContainer, noCache) ?? noIterationTypes; - return noCache ? iterationTypes : setCachedIterationTypes(type, resolver.iterableCacheKey, iterationTypes); - } - - function reportTypeNotIterableError(errorNode: Node, type: Type, allowAsyncIterables: boolean): Diagnostic { + const iteratorType = getIntersectionType( + map(validSignatures, getReturnTypeOfSignature) + ); + const iterationTypes = + getIterationTypesOfIteratorWorker( + iteratorType, + resolver, + errorNode, + errorOutputContainer, + noCache + ) ?? noIterationTypes; + return noCache + ? iterationTypes + : setCachedIterationTypes( + type, + resolver.iterableCacheKey, + iterationTypes + ); + } + + function reportTypeNotIterableError( + errorNode: Node, + type: Type, + allowAsyncIterables: boolean + ): Diagnostic { const message = allowAsyncIterables ? Diagnostics.Type_0_must_have_a_Symbol_asyncIterator_method_that_returns_an_async_iterator : Diagnostics.Type_0_must_have_a_Symbol_iterator_method_that_returns_an_iterator; const suggestAwait = // for (const x of Promise<...>) or [...Promise<...>] - !!getAwaitedTypeOfPromise(type) + !!getAwaitedTypeOfPromise(type) || // for (const x of AsyncIterable<...>) - || ( - !allowAsyncIterables && + (!allowAsyncIterables && isForOfStatement(errorNode.parent) && errorNode.parent.expression === errorNode && - getGlobalAsyncIterableType(/*reportErrors*/ false) !== emptyGenericType && - isTypeAssignableTo(type, createTypeFromGenericGlobalType(getGlobalAsyncIterableType(/*reportErrors*/ false), [anyType, anyType, anyType])) - ); - return errorAndMaybeSuggestAwait(errorNode, suggestAwait, message, typeToString(type)); + getGlobalAsyncIterableType(/*reportErrors*/ false) !== + emptyGenericType && + isTypeAssignableTo( + type, + createTypeFromGenericGlobalType( + getGlobalAsyncIterableType(/*reportErrors*/ false), + [anyType, anyType, anyType] + ) + )); + return errorAndMaybeSuggestAwait( + errorNode, + suggestAwait, + message, + typeToString(type) + ); } /** @@ -45909,8 +79708,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * If we successfully found the *yield*, *return*, and *next* types, an `IterationTypes` * record is returned. Otherwise, `undefined` is returned. */ - function getIterationTypesOfIterator(type: Type, resolver: IterationTypesResolver, errorNode: Node | undefined, errorOutputContainer: ErrorOutputContainer | undefined) { - return getIterationTypesOfIteratorWorker(type, resolver, errorNode, errorOutputContainer, /*noCache*/ false); + function getIterationTypesOfIterator( + type: Type, + resolver: IterationTypesResolver, + errorNode: Node | undefined, + errorOutputContainer: ErrorOutputContainer | undefined + ) { + return getIterationTypesOfIteratorWorker( + type, + resolver, + errorNode, + errorOutputContainer, + /*noCache*/ false + ); } /** @@ -45922,12 +79732,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * NOTE: You probably don't want to call this directly and should be calling * `getIterationTypesOfIterator` instead. */ - function getIterationTypesOfIteratorWorker(type: Type, resolver: IterationTypesResolver, errorNode: Node | undefined, errorOutputContainer: ErrorOutputContainer | undefined, noCache: boolean) { + function getIterationTypesOfIteratorWorker( + type: Type, + resolver: IterationTypesResolver, + errorNode: Node | undefined, + errorOutputContainer: ErrorOutputContainer | undefined, + noCache: boolean + ) { if (isTypeAny(type)) { return anyIterationTypes; } - let iterationTypes = getIterationTypesOfIteratorCached(type, resolver) || + let iterationTypes = + getIterationTypesOfIteratorCached(type, resolver) || getIterationTypesOfIteratorFast(type, resolver); if (iterationTypes === noIterationTypes && errorNode) { @@ -45935,7 +79752,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { noCache = true; } - iterationTypes ??= getIterationTypesOfIteratorSlow(type, resolver, errorNode, errorOutputContainer, noCache); + iterationTypes ??= getIterationTypesOfIteratorSlow( + type, + resolver, + errorNode, + errorOutputContainer, + noCache + ); return iterationTypes === noIterationTypes ? undefined : iterationTypes; } @@ -45946,7 +79769,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * NOTE: You probably don't want to call this directly and should be calling * `getIterationTypesOfIterator` instead. */ - function getIterationTypesOfIteratorCached(type: Type, resolver: IterationTypesResolver) { + function getIterationTypesOfIteratorCached( + type: Type, + resolver: IterationTypesResolver + ) { return getCachedIterationTypes(type, resolver.iteratorCacheKey); } @@ -45962,7 +79788,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * NOTE: You probably don't want to call this directly and should be calling * `getIterationTypesOfIterator` instead. */ - function getIterationTypesOfIteratorFast(type: Type, resolver: IterationTypesResolver) { + function getIterationTypesOfIteratorFast( + type: Type, + resolver: IterationTypesResolver + ) { // As an optimization, if the type is an instantiation of one of the following global types, // then just grab its related type arguments: // - `IterableIterator` or `AsyncIterableIterator` @@ -45970,13 +79799,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // - `Iterator` or `AsyncIterator` // - `Generator` or `AsyncGenerator` if ( - isReferenceToType(type, resolver.getGlobalIterableIteratorType(/*reportErrors*/ false)) || - isReferenceToType(type, resolver.getGlobalIteratorType(/*reportErrors*/ false)) || - isReferenceToType(type, resolver.getGlobalIteratorObjectType(/*reportErrors*/ false)) || - isReferenceToType(type, resolver.getGlobalGeneratorType(/*reportErrors*/ false)) + isReferenceToType( + type, + resolver.getGlobalIterableIteratorType(/*reportErrors*/ false) + ) || + isReferenceToType( + type, + resolver.getGlobalIteratorType(/*reportErrors*/ false) + ) || + isReferenceToType( + type, + resolver.getGlobalIteratorObjectType(/*reportErrors*/ false) + ) || + isReferenceToType( + type, + resolver.getGlobalGeneratorType(/*reportErrors*/ false) + ) ) { - const [yieldType, returnType, nextType] = getTypeArguments(type as GenericType); - return setCachedIterationTypes(type, resolver.iteratorCacheKey, createIterationTypes(yieldType, returnType, nextType)); + const [yieldType, returnType, nextType] = getTypeArguments( + type as GenericType + ); + return setCachedIterationTypes( + type, + resolver.iteratorCacheKey, + createIterationTypes(yieldType, returnType, nextType) + ); } // As an optimization, if the type is an instantiation of one of the following global types, then @@ -45986,21 +79833,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // - `SetIterator` // - `StringIterator` // - `ReadableStreamAsyncIterator` - if (isReferenceToSomeType(type, resolver.getGlobalBuiltinIteratorTypes())) { + if ( + isReferenceToSomeType( + type, + resolver.getGlobalBuiltinIteratorTypes() + ) + ) { const [yieldType] = getTypeArguments(type as GenericType); const returnType = getBuiltinIteratorReturnType(); const nextType = unknownType; - return setCachedIterationTypes(type, resolver.iteratorCacheKey, createIterationTypes(yieldType, returnType, nextType)); + return setCachedIterationTypes( + type, + resolver.iteratorCacheKey, + createIterationTypes(yieldType, returnType, nextType) + ); } } - function isIteratorResult(type: Type, kind: IterationTypeKind.Yield | IterationTypeKind.Return) { + function isIteratorResult( + type: Type, + kind: IterationTypeKind.Yield | IterationTypeKind.Return + ) { // From https://tc39.github.io/ecma262/#sec-iteratorresult-interface: // > [done] is the result status of an iterator `next` method call. If the end of the iterator was reached `done` is `true`. // > If the end was not reached `done` is `false` and a value is available. // > If a `done` property (either own or inherited) does not exist, it is consider to have the value `false`. - const doneType = getTypeOfPropertyOfType(type, "done" as __String) || falseType; - return isTypeAssignableTo(kind === IterationTypeKind.Yield ? falseType : trueType, doneType); + const doneType = + getTypeOfPropertyOfType(type, "done" as __String) || falseType; + return isTypeAssignableTo( + kind === IterationTypeKind.Yield ? falseType : trueType, + doneType + ); } function isYieldIteratorResult(type: Type) { @@ -46023,38 +79886,91 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return anyIterationTypes; } - const cachedTypes = getCachedIterationTypes(type, "iterationTypesOfIteratorResult"); + const cachedTypes = getCachedIterationTypes( + type, + "iterationTypesOfIteratorResult" + ); if (cachedTypes) { return cachedTypes; } // As an optimization, if the type is an instantiation of one of the global `IteratorYieldResult` // or `IteratorReturnResult` types, then just grab its type argument. - if (isReferenceToType(type, getGlobalIteratorYieldResultType(/*reportErrors*/ false))) { + if ( + isReferenceToType( + type, + getGlobalIteratorYieldResultType(/*reportErrors*/ false) + ) + ) { const yieldType = getTypeArguments(type as GenericType)[0]; - return setCachedIterationTypes(type, "iterationTypesOfIteratorResult", createIterationTypes(yieldType, /*returnType*/ undefined, /*nextType*/ undefined)); + return setCachedIterationTypes( + type, + "iterationTypesOfIteratorResult", + createIterationTypes( + yieldType, + /*returnType*/ undefined, + /*nextType*/ undefined + ) + ); } - if (isReferenceToType(type, getGlobalIteratorReturnResultType(/*reportErrors*/ false))) { + if ( + isReferenceToType( + type, + getGlobalIteratorReturnResultType(/*reportErrors*/ false) + ) + ) { const returnType = getTypeArguments(type as GenericType)[0]; - return setCachedIterationTypes(type, "iterationTypesOfIteratorResult", createIterationTypes(/*yieldType*/ undefined, returnType, /*nextType*/ undefined)); + return setCachedIterationTypes( + type, + "iterationTypesOfIteratorResult", + createIterationTypes( + /*yieldType*/ undefined, + returnType, + /*nextType*/ undefined + ) + ); } // Choose any constituents that can produce the requested iteration type. const yieldIteratorResult = filterType(type, isYieldIteratorResult); - const yieldType = yieldIteratorResult !== neverType ? getTypeOfPropertyOfType(yieldIteratorResult, "value" as __String) : undefined; + const yieldType = + yieldIteratorResult !== neverType + ? getTypeOfPropertyOfType( + yieldIteratorResult, + "value" as __String + ) + : undefined; const returnIteratorResult = filterType(type, isReturnIteratorResult); - const returnType = returnIteratorResult !== neverType ? getTypeOfPropertyOfType(returnIteratorResult, "value" as __String) : undefined; + const returnType = + returnIteratorResult !== neverType + ? getTypeOfPropertyOfType( + returnIteratorResult, + "value" as __String + ) + : undefined; if (!yieldType && !returnType) { - return setCachedIterationTypes(type, "iterationTypesOfIteratorResult", noIterationTypes); + return setCachedIterationTypes( + type, + "iterationTypesOfIteratorResult", + noIterationTypes + ); } // From https://tc39.github.io/ecma262/#sec-iteratorresult-interface // > ... If the iterator does not have a return value, `value` is `undefined`. In that case, the // > `value` property may be absent from the conforming object if it does not inherit an explicit // > `value` property. - return setCachedIterationTypes(type, "iterationTypesOfIteratorResult", createIterationTypes(yieldType, returnType || voidType, /*nextType*/ undefined)); + return setCachedIterationTypes( + type, + "iterationTypesOfIteratorResult", + createIterationTypes( + yieldType, + returnType || voidType, + /*nextType*/ undefined + ) + ); } /** @@ -46064,7 +79980,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * If we successfully found the *yield*, *return*, and *next* types, an `IterationTypes` * record is returned. Otherwise, we return `undefined`. */ - function getIterationTypesOfMethod(type: Type, resolver: IterationTypesResolver, methodName: "next" | "return" | "throw", errorNode: Node | undefined, errorOutputContainer: ErrorOutputContainer | undefined): IterationTypes | undefined { + function getIterationTypesOfMethod( + type: Type, + resolver: IterationTypesResolver, + methodName: "next" | "return" | "throw", + errorNode: Node | undefined, + errorOutputContainer: ErrorOutputContainer | undefined + ): IterationTypes | undefined { const method = getPropertyOfType(type, methodName as __String); // Ignore 'return' or 'throw' if they are missing. @@ -46072,26 +79994,41 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - const methodType = method && !(methodName === "next" && (method.flags & SymbolFlags.Optional)) - ? methodName === "next" ? getTypeOfSymbol(method) : getTypeWithFacts(getTypeOfSymbol(method), TypeFacts.NEUndefinedOrNull) - : undefined; + const methodType = + method && + !(methodName === "next" && method.flags & SymbolFlags.Optional) + ? methodName === "next" + ? getTypeOfSymbol(method) + : getTypeWithFacts( + getTypeOfSymbol(method), + TypeFacts.NEUndefinedOrNull + ) + : undefined; if (isTypeAny(methodType)) { return anyIterationTypes; } // Both async and non-async iterators *must* have a `next` method. - const methodSignatures = methodType ? getSignaturesOfType(methodType, SignatureKind.Call) : emptyArray; + const methodSignatures = methodType + ? getSignaturesOfType(methodType, SignatureKind.Call) + : emptyArray; if (methodSignatures.length === 0) { if (errorNode) { - const diagnostic = methodName === "next" - ? resolver.mustHaveANextMethodDiagnostic - : resolver.mustBeAMethodDiagnostic; + const diagnostic = + methodName === "next" + ? resolver.mustHaveANextMethodDiagnostic + : resolver.mustBeAMethodDiagnostic; if (errorOutputContainer) { errorOutputContainer.errors ??= []; - errorOutputContainer.errors.push(createDiagnosticForNode(errorNode, diagnostic, methodName)); - } - else { + errorOutputContainer.errors.push( + createDiagnosticForNode( + errorNode, + diagnostic, + methodName + ) + ); + } else { error(errorNode, diagnostic, methodName); } } @@ -46106,17 +80043,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // `interface SpecialIterator extends Iterator {}`, `SpecialIterator` is not a // reference to `Iterator`, but its `next` member derives exclusively from `Iterator`. if (methodType?.symbol && methodSignatures.length === 1) { - const globalGeneratorType = resolver.getGlobalGeneratorType(/*reportErrors*/ false); - const globalIteratorType = resolver.getGlobalIteratorType(/*reportErrors*/ false); - const isGeneratorMethod = globalGeneratorType.symbol?.members?.get(methodName as __String) === methodType.symbol; - const isIteratorMethod = !isGeneratorMethod && globalIteratorType.symbol?.members?.get(methodName as __String) === methodType.symbol; + const globalGeneratorType = resolver.getGlobalGeneratorType( + /*reportErrors*/ false + ); + const globalIteratorType = resolver.getGlobalIteratorType( + /*reportErrors*/ false + ); + const isGeneratorMethod = + globalGeneratorType.symbol?.members?.get( + methodName as __String + ) === methodType.symbol; + const isIteratorMethod = + !isGeneratorMethod && + globalIteratorType.symbol?.members?.get( + methodName as __String + ) === methodType.symbol; if (isGeneratorMethod || isIteratorMethod) { - const globalType = isGeneratorMethod ? globalGeneratorType : globalIteratorType; + const globalType = isGeneratorMethod + ? globalGeneratorType + : globalIteratorType; const { mapper } = methodType as AnonymousType; return createIterationTypes( getMappedType(globalType.typeParameters![0], mapper!), getMappedType(globalType.typeParameters![1], mapper!), - methodName === "next" ? getMappedType(globalType.typeParameters![2], mapper!) : undefined, + methodName === "next" + ? getMappedType(globalType.typeParameters![2], mapper!) + : undefined ); } } @@ -46126,9 +80078,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let methodReturnTypes: Type[] | undefined; for (const signature of methodSignatures) { if (methodName !== "throw" && some(signature.parameters)) { - methodParameterTypes = append(methodParameterTypes, getTypeAtPosition(signature, 0)); + methodParameterTypes = append( + methodParameterTypes, + getTypeAtPosition(signature, 0) + ); } - methodReturnTypes = append(methodReturnTypes, getReturnTypeOfSignature(signature)); + methodReturnTypes = append( + methodReturnTypes, + getReturnTypeOfSignature(signature) + ); } // Resolve the *next* or *return* type from the first parameter of a `next()` or @@ -46136,42 +80094,65 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let returnTypes: Type[] | undefined; let nextType: Type | undefined; if (methodName !== "throw") { - const methodParameterType = methodParameterTypes ? getUnionType(methodParameterTypes) : unknownType; + const methodParameterType = methodParameterTypes + ? getUnionType(methodParameterTypes) + : unknownType; if (methodName === "next") { // The value of `next(value)` is *not* awaited by async generators nextType = methodParameterType; - } - else if (methodName === "return") { + } else if (methodName === "return") { // The value of `return(value)` *is* awaited by async generators - const resolvedMethodParameterType = resolver.resolveIterationType(methodParameterType, errorNode) || anyType; + const resolvedMethodParameterType = + resolver.resolveIterationType( + methodParameterType, + errorNode + ) || anyType; returnTypes = append(returnTypes, resolvedMethodParameterType); } } // Resolve the *yield* and *return* types from the return type of the method (i.e. `IteratorResult`) let yieldType: Type; - const methodReturnType = methodReturnTypes ? getIntersectionType(methodReturnTypes) : neverType; - const resolvedMethodReturnType = resolver.resolveIterationType(methodReturnType, errorNode) || anyType; - const iterationTypes = getIterationTypesOfIteratorResult(resolvedMethodReturnType); + const methodReturnType = methodReturnTypes + ? getIntersectionType(methodReturnTypes) + : neverType; + const resolvedMethodReturnType = + resolver.resolveIterationType(methodReturnType, errorNode) || + anyType; + const iterationTypes = getIterationTypesOfIteratorResult( + resolvedMethodReturnType + ); if (iterationTypes === noIterationTypes) { if (errorNode) { if (errorOutputContainer) { errorOutputContainer.errors ??= []; - errorOutputContainer.errors.push(createDiagnosticForNode(errorNode, resolver.mustHaveAValueDiagnostic, methodName)); - } - else { - error(errorNode, resolver.mustHaveAValueDiagnostic, methodName); + errorOutputContainer.errors.push( + createDiagnosticForNode( + errorNode, + resolver.mustHaveAValueDiagnostic, + methodName + ) + ); + } else { + error( + errorNode, + resolver.mustHaveAValueDiagnostic, + methodName + ); } } yieldType = anyType; returnTypes = append(returnTypes, anyType); - } - else { + } else { yieldType = iterationTypes.yieldType; returnTypes = append(returnTypes, iterationTypes.returnType); } - return createIterationTypes(yieldType, getUnionType(returnTypes), nextType); + return createIterationTypes( + yieldType, + getUnionType(returnTypes), + nextType + ); } /** @@ -46184,13 +80165,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * NOTE: You probably don't want to call this directly and should be calling * `getIterationTypesOfIterator` instead. */ - function getIterationTypesOfIteratorSlow(type: Type, resolver: IterationTypesResolver, errorNode: Node | undefined, errorOutputContainer: ErrorOutputContainer | undefined, noCache: boolean) { + function getIterationTypesOfIteratorSlow( + type: Type, + resolver: IterationTypesResolver, + errorNode: Node | undefined, + errorOutputContainer: ErrorOutputContainer | undefined, + noCache: boolean + ) { const iterationTypes = combineIterationTypes([ - getIterationTypesOfMethod(type, resolver, "next", errorNode, errorOutputContainer), - getIterationTypesOfMethod(type, resolver, "return", errorNode, errorOutputContainer), - getIterationTypesOfMethod(type, resolver, "throw", errorNode, errorOutputContainer), + getIterationTypesOfMethod( + type, + resolver, + "next", + errorNode, + errorOutputContainer + ), + getIterationTypesOfMethod( + type, + resolver, + "return", + errorNode, + errorOutputContainer + ), + getIterationTypesOfMethod( + type, + resolver, + "throw", + errorNode, + errorOutputContainer + ), ]); - return noCache ? iterationTypes : setCachedIterationTypes(type, resolver.iteratorCacheKey, iterationTypes); + return noCache + ? iterationTypes + : setCachedIterationTypes( + type, + resolver.iteratorCacheKey, + iterationTypes + ); } /** @@ -46198,29 +80209,54 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * `IterableIterator`-like, or `Generator`-like (for a non-async generator); or `AsyncIterable`-like, * `AsyncIterator`-like, `AsyncIterableIterator`-like, or `AsyncGenerator`-like (for an async generator). */ - function getIterationTypeOfGeneratorFunctionReturnType(kind: IterationTypeKind, returnType: Type, isAsyncGenerator: boolean): Type | undefined { + function getIterationTypeOfGeneratorFunctionReturnType( + kind: IterationTypeKind, + returnType: Type, + isAsyncGenerator: boolean + ): Type | undefined { if (isTypeAny(returnType)) { return undefined; } - const iterationTypes = getIterationTypesOfGeneratorFunctionReturnType(returnType, isAsyncGenerator); - return iterationTypes && iterationTypes[getIterationTypesKeyFromIterationTypeKind(kind)]; + const iterationTypes = getIterationTypesOfGeneratorFunctionReturnType( + returnType, + isAsyncGenerator + ); + return ( + iterationTypes && + iterationTypes[getIterationTypesKeyFromIterationTypeKind(kind)] + ); } - function getIterationTypesOfGeneratorFunctionReturnType(type: Type, isAsyncGenerator: boolean) { + function getIterationTypesOfGeneratorFunctionReturnType( + type: Type, + isAsyncGenerator: boolean + ) { if (isTypeAny(type)) { return anyIterationTypes; } - const use = isAsyncGenerator ? IterationUse.AsyncGeneratorReturnType : IterationUse.GeneratorReturnType; - const resolver = isAsyncGenerator ? asyncIterationTypesResolver : syncIterationTypesResolver; - return getIterationTypesOfIterable(type, use, /*errorNode*/ undefined) || - getIterationTypesOfIterator(type, resolver, /*errorNode*/ undefined, /*errorOutputContainer*/ undefined); + const use = isAsyncGenerator + ? IterationUse.AsyncGeneratorReturnType + : IterationUse.GeneratorReturnType; + const resolver = isAsyncGenerator + ? asyncIterationTypesResolver + : syncIterationTypesResolver; + return ( + getIterationTypesOfIterable(type, use, /*errorNode*/ undefined) || + getIterationTypesOfIterator( + type, + resolver, + /*errorNode*/ undefined, + /*errorOutputContainer*/ undefined + ) + ); } function checkBreakOrContinueStatement(node: BreakOrContinueStatement) { // Grammar checking - if (!checkGrammarStatementInAmbientContext(node)) checkGrammarBreakOrContinueStatement(node); + if (!checkGrammarStatementInAmbientContext(node)) + checkGrammarBreakOrContinueStatement(node); // TODO: Check that target label is valid } @@ -46229,18 +80265,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const isGenerator = !!(functionFlags & FunctionFlags.Generator); const isAsync = !!(functionFlags & FunctionFlags.Async); if (isGenerator) { - const returnIterationType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, returnType, isAsync); + const returnIterationType = + getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Return, + returnType, + isAsync + ); if (!returnIterationType) { return errorType; } - return isAsync ? getAwaitedTypeNoAlias(unwrapAwaitedType(returnIterationType)) : returnIterationType; + return isAsync + ? getAwaitedTypeNoAlias(unwrapAwaitedType(returnIterationType)) + : returnIterationType; } - return isAsync ? getAwaitedTypeNoAlias(returnType) || errorType : returnType; + return isAsync + ? getAwaitedTypeNoAlias(returnType) || errorType + : returnType; } - function isUnwrappedReturnTypeUndefinedVoidOrAny(func: SignatureDeclaration, returnType: Type): boolean { + function isUnwrappedReturnTypeUndefinedVoidOrAny( + func: SignatureDeclaration, + returnType: Type + ): boolean { const type = unwrapReturnType(returnType, getFunctionFlags(func)); - return !!(type && (maybeTypeOfKind(type, TypeFlags.Void) || type.flags & (TypeFlags.Any | TypeFlags.Undefined))); + return !!( + type && + (maybeTypeOfKind(type, TypeFlags.Void) || + type.flags & (TypeFlags.Any | TypeFlags.Undefined)) + ); } function checkReturnStatement(node: ReturnStatement) { @@ -46251,36 +80303,70 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const container = getContainingFunctionOrClassStaticBlock(node); if (container && isClassStaticBlockDeclaration(container)) { - grammarErrorOnFirstToken(node, Diagnostics.A_return_statement_cannot_be_used_inside_a_class_static_block); + grammarErrorOnFirstToken( + node, + Diagnostics.A_return_statement_cannot_be_used_inside_a_class_static_block + ); return; } if (!container) { - grammarErrorOnFirstToken(node, Diagnostics.A_return_statement_can_only_be_used_within_a_function_body); + grammarErrorOnFirstToken( + node, + Diagnostics.A_return_statement_can_only_be_used_within_a_function_body + ); return; } const signature = getSignatureFromDeclaration(container); const returnType = getReturnTypeOfSignature(signature); - if (strictNullChecks || node.expression || returnType.flags & TypeFlags.Never) { - const exprType = node.expression ? checkExpressionCached(node.expression) : undefinedType; + if ( + strictNullChecks || + node.expression || + returnType.flags & TypeFlags.Never + ) { + const exprType = node.expression + ? checkExpressionCached(node.expression) + : undefinedType; if (container.kind === SyntaxKind.SetAccessor) { if (node.expression) { error(node, Diagnostics.Setters_cannot_return_a_value); } - } - else if (container.kind === SyntaxKind.Constructor) { - const exprType = node.expression ? checkExpressionCached(node.expression) : undefinedType; - if (node.expression && !checkTypeAssignableToAndOptionallyElaborate(exprType, returnType, node, node.expression)) { - error(node, Diagnostics.Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class); + } else if (container.kind === SyntaxKind.Constructor) { + const exprType = node.expression + ? checkExpressionCached(node.expression) + : undefinedType; + if ( + node.expression && + !checkTypeAssignableToAndOptionallyElaborate( + exprType, + returnType, + node, + node.expression + ) + ) { + error( + node, + Diagnostics.Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class + ); } + } else if (getReturnTypeFromAnnotation(container)) { + const unwrappedReturnType = + unwrapReturnType(returnType, getFunctionFlags(container)) ?? + returnType; + checkReturnExpression( + container, + unwrappedReturnType, + node, + node.expression, + exprType + ); } - else if (getReturnTypeFromAnnotation(container)) { - const unwrappedReturnType = unwrapReturnType(returnType, getFunctionFlags(container)) ?? returnType; - checkReturnExpression(container, unwrappedReturnType, node, node.expression, exprType); - } - } - else if (container.kind !== SyntaxKind.Constructor && compilerOptions.noImplicitReturns && !isUnwrappedReturnTypeUndefinedVoidOrAny(container, returnType)) { + } else if ( + container.kind !== SyntaxKind.Constructor && + compilerOptions.noImplicitReturns && + !isUnwrappedReturnTypeUndefinedVoidOrAny(container, returnType) + ) { // The function has a return type, but the return statement doesn't have an expression. error(node, Diagnostics.Not_all_code_paths_return_a_value); } @@ -46294,40 +80380,69 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { node: ReturnStatement | Expression, expr: Expression | undefined, exprType: Type, - inConditionalExpression = false, + inConditionalExpression = false ): void { const excludeJSDocTypeAssertions = isInJSFile(node); const functionFlags = getFunctionFlags(container); if (expr) { - const unwrappedExpr = skipParentheses(expr, excludeJSDocTypeAssertions); + const unwrappedExpr = skipParentheses( + expr, + excludeJSDocTypeAssertions + ); if (isConditionalExpression(unwrappedExpr)) { - checkReturnExpression(container, unwrappedReturnType, node, unwrappedExpr.whenTrue, checkExpression(unwrappedExpr.whenTrue), /*inConditionalExpression*/ true); - checkReturnExpression(container, unwrappedReturnType, node, unwrappedExpr.whenFalse, checkExpression(unwrappedExpr.whenFalse), /*inConditionalExpression*/ true); + checkReturnExpression( + container, + unwrappedReturnType, + node, + unwrappedExpr.whenTrue, + checkExpression(unwrappedExpr.whenTrue), + /*inConditionalExpression*/ true + ); + checkReturnExpression( + container, + unwrappedReturnType, + node, + unwrappedExpr.whenFalse, + checkExpression(unwrappedExpr.whenFalse), + /*inConditionalExpression*/ true + ); return; } } const inReturnStatement = node.kind === SyntaxKind.ReturnStatement; - const unwrappedExprType = functionFlags & FunctionFlags.Async - ? 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, - ) - : exprType; + const unwrappedExprType = + functionFlags & FunctionFlags.Async + ? 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 + ) + : exprType; const effectiveExpr = expr && getEffectiveCheckNode(expr); // The effective expression for diagnostics purposes. - const errorNode = inReturnStatement && !inConditionalExpression ? node : effectiveExpr; - - checkTypeAssignableToAndOptionallyElaborate(unwrappedExprType, unwrappedReturnType, errorNode, effectiveExpr); + const errorNode = + inReturnStatement && !inConditionalExpression + ? node + : effectiveExpr; + + checkTypeAssignableToAndOptionallyElaborate( + unwrappedExprType, + unwrappedReturnType, + errorNode, + effectiveExpr + ); } function checkWithStatement(node: WithStatement) { // Grammar checking for withStatement if (!checkGrammarStatementInAmbientContext(node)) { if (node.flags & NodeFlags.AwaitContext) { - grammarErrorOnFirstToken(node, Diagnostics.with_statements_are_not_allowed_in_an_async_function_block); + grammarErrorOnFirstToken( + node, + Diagnostics.with_statements_are_not_allowed_in_an_async_function_block + ); } } @@ -46337,7 +80452,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!hasParseDiagnostics(sourceFile)) { const start = getSpanOfTokenAtPosition(sourceFile, node.pos).start; const end = node.statement.pos; - grammarErrorAtPos(sourceFile, start, end - start, Diagnostics.The_with_statement_is_not_supported_All_symbols_in_a_with_block_will_have_type_any); + grammarErrorAtPos( + sourceFile, + start, + end - start, + Diagnostics.The_with_statement_is_not_supported_All_symbols_in_a_with_block_will_have_type_any + ); } } @@ -46350,14 +80470,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const expressionType = checkExpression(node.expression); - forEach(node.caseBlock.clauses, clause => { + forEach(node.caseBlock.clauses, (clause) => { // Grammar check for duplicate default clauses, skip if we already report duplicate default clause - if (clause.kind === SyntaxKind.DefaultClause && !hasDuplicateDefaultClause) { + if ( + clause.kind === SyntaxKind.DefaultClause && + !hasDuplicateDefaultClause + ) { if (firstDefaultClause === undefined) { firstDefaultClause = clause; - } - else { - grammarErrorOnNode(clause, Diagnostics.A_default_clause_cannot_appear_more_than_once_in_a_switch_statement); + } else { + grammarErrorOnNode( + clause, + Diagnostics.A_default_clause_cannot_appear_more_than_once_in_a_switch_statement + ); hasDuplicateDefaultClause = true; } } @@ -46366,7 +80491,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { addLazyDiagnostic(createLazyCaseClauseDiagnostics(clause)); } forEach(clause.statements, checkSourceElement); - if (compilerOptions.noFallthroughCasesInSwitch && clause.fallthroughFlowNode && isReachableFlowNode(clause.fallthroughFlowNode)) { + if ( + compilerOptions.noFallthroughCasesInSwitch && + clause.fallthroughFlowNode && + isReachableFlowNode(clause.fallthroughFlowNode) + ) { error(clause, Diagnostics.Fallthrough_case_in_switch); } @@ -46379,7 +80508,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!isTypeEqualityComparableTo(expressionType, caseType)) { // expressionType is not comparable to caseType, try the reversed check and report errors if it fails - checkTypeComparableTo(caseType, expressionType, clause.expression, /*headMessage*/ undefined); + checkTypeComparableTo( + caseType, + expressionType, + clause.expression, + /*headMessage*/ undefined + ); } }; } @@ -46392,12 +80526,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkLabeledStatement(node: LabeledStatement) { // Grammar checking if (!checkGrammarStatementInAmbientContext(node)) { - findAncestor(node.parent, current => { + findAncestor(node.parent, (current) => { if (isFunctionLike(current)) { return "quit"; } - if (current.kind === SyntaxKind.LabeledStatement && (current as LabeledStatement).label.escapedText === node.label.escapedText) { - grammarErrorOnNode(node.label, Diagnostics.Duplicate_label_0, getTextOfNode(node.label)); + if ( + current.kind === SyntaxKind.LabeledStatement && + (current as LabeledStatement).label.escapedText === + node.label.escapedText + ) { + grammarErrorOnNode( + node.label, + Diagnostics.Duplicate_label_0, + getTextOfNode(node.label) + ); return true; } return false; @@ -46412,7 +80554,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Grammar checking if (!checkGrammarStatementInAmbientContext(node)) { if (isIdentifier(node.expression) && !node.expression.escapedText) { - grammarErrorAfterFirstToken(node, Diagnostics.Line_break_not_permitted_here); + grammarErrorAfterFirstToken( + node, + Diagnostics.Line_break_not_permitted_here + ); } } @@ -46436,19 +80581,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (typeNode) { const type = getTypeFromTypeNode(typeNode); if (type && !(type.flags & TypeFlags.AnyOrUnknown)) { - grammarErrorOnFirstToken(typeNode, Diagnostics.Catch_clause_variable_type_annotation_must_be_any_or_unknown_if_specified); + grammarErrorOnFirstToken( + typeNode, + Diagnostics.Catch_clause_variable_type_annotation_must_be_any_or_unknown_if_specified + ); } - } - else if (declaration.initializer) { - grammarErrorOnFirstToken(declaration.initializer, Diagnostics.Catch_clause_variable_cannot_have_an_initializer); - } - else { + } else if (declaration.initializer) { + grammarErrorOnFirstToken( + declaration.initializer, + Diagnostics.Catch_clause_variable_cannot_have_an_initializer + ); + } else { const blockLocals = catchClause.block.locals; if (blockLocals) { - forEachKey(catchClause.locals!, caughtName => { + forEachKey(catchClause.locals!, (caughtName) => { const blockLocal = blockLocals.get(caughtName); - if (blockLocal?.valueDeclaration && (blockLocal.flags & SymbolFlags.BlockScopedVariable) !== 0) { - grammarErrorOnNode(blockLocal.valueDeclaration, Diagnostics.Cannot_redeclare_identifier_0_in_catch_clause, unescapeLeadingUnderscores(caughtName)); + if ( + blockLocal?.valueDeclaration && + (blockLocal.flags & + SymbolFlags.BlockScopedVariable) !== + 0 + ) { + grammarErrorOnNode( + blockLocal.valueDeclaration, + Diagnostics.Cannot_redeclare_identifier_0_in_catch_clause, + unescapeLeadingUnderscores(caughtName) + ); } }); } @@ -46463,14 +80621,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function checkIndexConstraints(type: Type, symbol: Symbol, isStaticIndex?: boolean) { + function checkIndexConstraints( + type: Type, + symbol: Symbol, + isStaticIndex?: boolean + ) { const indexInfos = getIndexInfosOfType(type); if (indexInfos.length === 0) { return; } for (const prop of getPropertiesOfObjectType(type)) { if (!(isStaticIndex && prop.flags & SymbolFlags.Prototype)) { - checkIndexConstraintForProperty(type, prop, getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique, /*includeNonPublic*/ true), getNonMissingTypeOfSymbol(prop)); + checkIndexConstraintForProperty( + type, + prop, + getLiteralTypeFromProperty( + prop, + TypeFlags.StringOrNumberLiteralOrUnique, + /*includeNonPublic*/ true + ), + getNonMissingTypeOfSymbol(prop) + ); } } const typeDeclaration = symbol.valueDeclaration; @@ -46478,13 +80649,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (const member of typeDeclaration.members) { // Only process instance properties against instance index signatures and static properties against static index signatures if ( - ( - (!isStaticIndex && !isStatic(member)) || - (isStaticIndex && isStatic(member)) - ) && !hasBindableName(member) + ((!isStaticIndex && !isStatic(member)) || + (isStaticIndex && isStatic(member))) && + !hasBindableName(member) ) { const symbol = getSymbolOfDeclaration(member); - checkIndexConstraintForProperty(type, symbol, getTypeOfExpression((member as DynamicNamedDeclaration).name.expression), getNonMissingTypeOfSymbol(symbol)); + checkIndexConstraintForProperty( + type, + symbol, + getTypeOfExpression( + (member as DynamicNamedDeclaration).name.expression + ), + getNonMissingTypeOfSymbol(symbol) + ); } } } @@ -46495,54 +80672,137 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function checkIndexConstraintForProperty(type: Type, prop: Symbol, propNameType: Type, propType: Type) { + function checkIndexConstraintForProperty( + type: Type, + prop: Symbol, + propNameType: Type, + propType: Type + ) { const declaration = prop.valueDeclaration; const name = getNameOfDeclaration(declaration); if (name && isPrivateIdentifier(name)) { return; } const indexInfos = getApplicableIndexInfos(type, propNameType); - const interfaceDeclaration = getObjectFlags(type) & ObjectFlags.Interface ? getDeclarationOfKind(type.symbol, SyntaxKind.InterfaceDeclaration) : undefined; - const propDeclaration = declaration && declaration.kind === SyntaxKind.BinaryExpression || - name && name.kind === SyntaxKind.ComputedPropertyName ? declaration : undefined; - const localPropDeclaration = getParentOfSymbol(prop) === type.symbol ? declaration : undefined; + const interfaceDeclaration = + getObjectFlags(type) & ObjectFlags.Interface + ? getDeclarationOfKind( + type.symbol, + SyntaxKind.InterfaceDeclaration + ) + : undefined; + const propDeclaration = + (declaration && declaration.kind === SyntaxKind.BinaryExpression) || + (name && name.kind === SyntaxKind.ComputedPropertyName) + ? declaration + : undefined; + const localPropDeclaration = + getParentOfSymbol(prop) === type.symbol ? declaration : undefined; for (const info of indexInfos) { - const localIndexDeclaration = info.declaration && getParentOfSymbol(getSymbolOfDeclaration(info.declaration)) === type.symbol ? info.declaration : undefined; + const localIndexDeclaration = + info.declaration && + getParentOfSymbol(getSymbolOfDeclaration(info.declaration)) === + type.symbol + ? info.declaration + : undefined; // We check only when (a) the property is declared in the containing type, or (b) the applicable index signature is declared // in the containing type, or (c) the containing type is an interface and no base interface contains both the property and // the index signature (i.e. property and index signature are declared in separate inherited interfaces). - const errorNode = localPropDeclaration || localIndexDeclaration || - (interfaceDeclaration && !some(getBaseTypes(type as InterfaceType), base => !!getPropertyOfObjectType(base, prop.escapedName) && !!getIndexTypeOfType(base, info.keyType)) ? interfaceDeclaration : undefined); + const errorNode = + localPropDeclaration || + localIndexDeclaration || + (interfaceDeclaration && + !some( + getBaseTypes(type as InterfaceType), + (base) => + !!getPropertyOfObjectType(base, prop.escapedName) && + !!getIndexTypeOfType(base, info.keyType) + ) + ? interfaceDeclaration + : undefined); if (errorNode && !isTypeAssignableTo(propType, info.type)) { - const diagnostic = createError(errorNode, Diagnostics.Property_0_of_type_1_is_not_assignable_to_2_index_type_3, symbolToString(prop), typeToString(propType), typeToString(info.keyType), typeToString(info.type)); + const diagnostic = createError( + errorNode, + Diagnostics.Property_0_of_type_1_is_not_assignable_to_2_index_type_3, + symbolToString(prop), + typeToString(propType), + typeToString(info.keyType), + typeToString(info.type) + ); if (propDeclaration && errorNode !== propDeclaration) { - addRelatedInfo(diagnostic, createDiagnosticForNode(propDeclaration, Diagnostics._0_is_declared_here, symbolToString(prop))); + addRelatedInfo( + diagnostic, + createDiagnosticForNode( + propDeclaration, + Diagnostics._0_is_declared_here, + symbolToString(prop) + ) + ); } diagnostics.add(diagnostic); } } } - function checkIndexConstraintForIndexSignature(type: Type, checkInfo: IndexInfo) { + function checkIndexConstraintForIndexSignature( + type: Type, + checkInfo: IndexInfo + ) { const declaration = checkInfo.declaration; const indexInfos = getApplicableIndexInfos(type, checkInfo.keyType); - const interfaceDeclaration = getObjectFlags(type) & ObjectFlags.Interface ? getDeclarationOfKind(type.symbol, SyntaxKind.InterfaceDeclaration) : undefined; - const localCheckDeclaration = declaration && getParentOfSymbol(getSymbolOfDeclaration(declaration)) === type.symbol ? declaration : undefined; + const interfaceDeclaration = + getObjectFlags(type) & ObjectFlags.Interface + ? getDeclarationOfKind( + type.symbol, + SyntaxKind.InterfaceDeclaration + ) + : undefined; + const localCheckDeclaration = + declaration && + getParentOfSymbol(getSymbolOfDeclaration(declaration)) === + type.symbol + ? declaration + : undefined; for (const info of indexInfos) { if (info === checkInfo) continue; - const localIndexDeclaration = info.declaration && getParentOfSymbol(getSymbolOfDeclaration(info.declaration)) === type.symbol ? info.declaration : undefined; + const localIndexDeclaration = + info.declaration && + getParentOfSymbol(getSymbolOfDeclaration(info.declaration)) === + type.symbol + ? info.declaration + : undefined; // We check only when (a) the check index signature is declared in the containing type, or (b) the applicable index // signature is declared in the containing type, or (c) the containing type is an interface and no base interface contains // both index signatures (i.e. the index signatures are declared in separate inherited interfaces). - const errorNode = localCheckDeclaration || localIndexDeclaration || - (interfaceDeclaration && !some(getBaseTypes(type as InterfaceType), base => !!getIndexInfoOfType(base, checkInfo.keyType) && !!getIndexTypeOfType(base, info.keyType)) ? interfaceDeclaration : undefined); + const errorNode = + localCheckDeclaration || + localIndexDeclaration || + (interfaceDeclaration && + !some( + getBaseTypes(type as InterfaceType), + (base) => + !!getIndexInfoOfType(base, checkInfo.keyType) && + !!getIndexTypeOfType(base, info.keyType) + ) + ? interfaceDeclaration + : undefined); if (errorNode && !isTypeAssignableTo(checkInfo.type, info.type)) { - error(errorNode, Diagnostics._0_index_type_1_is_not_assignable_to_2_index_type_3, typeToString(checkInfo.keyType), typeToString(checkInfo.type), typeToString(info.keyType), typeToString(info.type)); + error( + errorNode, + Diagnostics._0_index_type_1_is_not_assignable_to_2_index_type_3, + typeToString(checkInfo.keyType), + typeToString(checkInfo.type), + typeToString(info.keyType), + typeToString(info.type) + ); } } } - function checkTypeNameIsReserved(name: Identifier, message: DiagnosticMessage): void { + function checkTypeNameIsReserved( + name: Identifier, + message: DiagnosticMessage + ): void { // TS 1.0 spec (April 2014): 3.6.1 // The predefined type keywords are reserved and cannot be used as names of user defined types. switch (name.escapedText) { @@ -46566,10 +80826,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { */ function checkClassNameCollisionWithObject(name: Identifier): void { if ( - languageVersion >= ScriptTarget.ES5 && name.escapedText === "Object" - && host.getEmitModuleFormatOfFile(getSourceFileOfNode(name)) < ModuleKind.ES2015 + languageVersion >= ScriptTarget.ES5 && + name.escapedText === "Object" && + host.getEmitModuleFormatOfFile(getSourceFileOfNode(name)) < + ModuleKind.ES2015 ) { - error(name, Diagnostics.Class_name_cannot_be_Object_when_targeting_ES5_with_module_0, ModuleKind[moduleKind]); // https://github.com/Microsoft/TypeScript/issues/17494 + error( + name, + Diagnostics.Class_name_cannot_be_Object_when_targeting_ES5_with_module_0, + ModuleKind[moduleKind] + ); // https://github.com/Microsoft/TypeScript/issues/17494 } } @@ -46594,25 +80860,48 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const lastJSDocParamIndex = jsdocParameters.length - 1; const lastJSDocParam = jsdocParameters[lastJSDocParamIndex]; if ( - isJs && lastJSDocParam && isIdentifier(lastJSDocParam.name) && lastJSDocParam.typeExpression && - lastJSDocParam.typeExpression.type && !parameters.has(lastJSDocParam.name.escapedText) && !excludedParameters.has(lastJSDocParamIndex) && !isArrayType(getTypeFromTypeNode(lastJSDocParam.typeExpression.type)) + isJs && + lastJSDocParam && + isIdentifier(lastJSDocParam.name) && + lastJSDocParam.typeExpression && + lastJSDocParam.typeExpression.type && + !parameters.has(lastJSDocParam.name.escapedText) && + !excludedParameters.has(lastJSDocParamIndex) && + !isArrayType( + getTypeFromTypeNode(lastJSDocParam.typeExpression.type) + ) ) { - 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)); + 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) + ); } - } - else { + } else { forEach(jsdocParameters, ({ name, isNameFirst }, index) => { - if (excludedParameters.has(index) || isIdentifier(name) && parameters.has(name.escapedText)) { + if ( + excludedParameters.has(index) || + (isIdentifier(name) && parameters.has(name.escapedText)) + ) { return; } if (isQualifiedName(name)) { if (isJs) { - error(name, Diagnostics.Qualified_name_0_is_not_allowed_without_a_leading_param_object_1, entityNameToString(name), entityNameToString(name.left)); + error( + name, + Diagnostics.Qualified_name_0_is_not_allowed_without_a_leading_param_object_1, + entityNameToString(name), + entityNameToString(name.left) + ); } - } - else { + } else { if (!isNameFirst) { - errorOrSuggestion(isJs, name, Diagnostics.JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name, idText(name)); + errorOrSuggestion( + isJs, + name, + Diagnostics.JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name, + idText(name) + ); } } }); @@ -46622,7 +80911,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** * Check each type parameter and check that type parameters have no duplicate type parameter declarations */ - function checkTypeParameters(typeParameterDeclarations: readonly TypeParameterDeclaration[] | undefined) { + function checkTypeParameters( + typeParameterDeclarations: + | readonly TypeParameterDeclaration[] + | undefined + ) { let seenDefault = false; if (typeParameterDeclarations) { for (let i = 0; i < typeParameterDeclarations.length; i++) { @@ -46633,18 +80926,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function createCheckTypeParameterDiagnostic(node: TypeParameterDeclaration, i: number) { + function createCheckTypeParameterDiagnostic( + node: TypeParameterDeclaration, + i: number + ) { return () => { if (node.default) { seenDefault = true; - checkTypeParametersNotReferenced(node.default, typeParameterDeclarations!, i); - } - else if (seenDefault) { - error(node, Diagnostics.Required_type_parameters_may_not_follow_optional_type_parameters); + checkTypeParametersNotReferenced( + node.default, + typeParameterDeclarations!, + i + ); + } else if (seenDefault) { + error( + node, + Diagnostics.Required_type_parameters_may_not_follow_optional_type_parameters + ); } for (let j = 0; j < i; j++) { if (typeParameterDeclarations![j].symbol === node.symbol) { - error(node.name, Diagnostics.Duplicate_identifier_0, declarationNameToString(node.name)); + error( + node.name, + Diagnostics.Duplicate_identifier_0, + declarationNameToString(node.name) + ); } } }; @@ -46652,15 +80958,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } /** Check that type parameter defaults only reference previously declared type parameters */ - function checkTypeParametersNotReferenced(root: TypeNode, typeParameters: readonly TypeParameterDeclaration[], index: number) { + function checkTypeParametersNotReferenced( + root: TypeNode, + typeParameters: readonly TypeParameterDeclaration[], + index: number + ) { visit(root); function visit(node: Node) { if (node.kind === SyntaxKind.TypeReference) { - const type = getTypeFromTypeReference(node as TypeReferenceNode); + const type = getTypeFromTypeReference( + node as TypeReferenceNode + ); if (type.flags & TypeFlags.TypeParameter) { for (let i = index; i < typeParameters.length; i++) { - if (type.symbol === getSymbolOfDeclaration(typeParameters[i])) { - error(node, Diagnostics.Type_parameter_defaults_can_only_reference_previously_declared_type_parameters); + if ( + type.symbol === + getSymbolOfDeclaration(typeParameters[i]) + ) { + error( + node, + Diagnostics.Type_parameter_defaults_can_only_reference_previously_declared_type_parameters + ); } } } @@ -46678,23 +80996,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const links = getSymbolLinks(symbol); if (!links.typeParametersChecked) { links.typeParametersChecked = true; - const declarations = getClassOrInterfaceDeclarationsOfSymbol(symbol); + const declarations = + getClassOrInterfaceDeclarationsOfSymbol(symbol); if (!declarations || declarations.length <= 1) { return; } const type = getDeclaredTypeOfSymbol(symbol) as InterfaceType; - if (!areTypeParametersIdentical(declarations, type.localTypeParameters!, getEffectiveTypeParameterDeclarations)) { + if ( + !areTypeParametersIdentical( + declarations, + type.localTypeParameters!, + getEffectiveTypeParameterDeclarations + ) + ) { // Report an error on every conflicting declaration. const name = symbolToString(symbol); for (const declaration of declarations) { - error(declaration.name, Diagnostics.All_declarations_of_0_must_have_identical_type_parameters, name); + error( + declaration.name, + Diagnostics.All_declarations_of_0_must_have_identical_type_parameters, + name + ); } } } } - function areTypeParametersIdentical(declarations: readonly T[], targetParameters: TypeParameter[], getTypeParameterDeclarations: (node: T) => readonly TypeParameterDeclaration[]) { + function areTypeParametersIdentical< + T extends DeclarationWithTypeParameters | TypeParameterDeclaration + >( + declarations: readonly T[], + targetParameters: TypeParameter[], + getTypeParameterDeclarations: ( + node: T + ) => readonly TypeParameterDeclaration[] + ) { const maxTypeArgumentCount = length(targetParameters); const minTypeArgumentCount = getMinTypeArgumentCount(targetParameters); @@ -46702,7 +81039,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If this declaration has too few or too many type parameters, we report an error const sourceParameters = getTypeParameterDeclarations(declaration); const numTypeParameters = sourceParameters.length; - if (numTypeParameters < minTypeArgumentCount || numTypeParameters > maxTypeArgumentCount) { + if ( + numTypeParameters < minTypeArgumentCount || + numTypeParameters > maxTypeArgumentCount + ) { return false; } @@ -46718,20 +81058,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If the type parameter node does not have an identical constraint as the resolved // type parameter at this position, we report an error. - const constraint = getEffectiveConstraintOfTypeParameter(source); - const sourceConstraint = constraint && getTypeFromTypeNode(constraint); + const constraint = + getEffectiveConstraintOfTypeParameter(source); + const sourceConstraint = + constraint && getTypeFromTypeNode(constraint); const targetConstraint = getConstraintOfTypeParameter(target); // relax check if later interface augmentation has no constraint, it's more broad and is OK to merge with // a more constrained interface (this could be generalized to a full hierarchy check, but that's maybe overkill) - if (sourceConstraint && targetConstraint && !isTypeIdenticalTo(sourceConstraint, targetConstraint)) { + if ( + sourceConstraint && + targetConstraint && + !isTypeIdenticalTo(sourceConstraint, targetConstraint) + ) { return false; } // If the type parameter node has a default and it is not identical to the default // for the type parameter at this position, we report an error. - const sourceDefault = source.default && getTypeFromTypeNode(source.default); + const sourceDefault = + source.default && getTypeFromTypeNode(source.default); const targetDefault = getDefaultFromTypeParameter(target); - if (sourceDefault && targetDefault && !isTypeIdenticalTo(sourceDefault, targetDefault)) { + if ( + sourceDefault && + targetDefault && + !isTypeIdenticalTo(sourceDefault, targetDefault) + ) { return false; } } @@ -46740,25 +81091,47 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; } - function getFirstTransformableStaticClassElement(node: ClassLikeDeclaration) { - const willTransformStaticElementsOfDecoratedClass = !legacyDecorators && languageVersion < LanguageFeatureMinimumTarget.ClassAndClassElementDecorators && - classOrConstructorParameterIsDecorated(/*useLegacyDecorators*/ false, node); - const willTransformPrivateElementsOrClassStaticBlocks = languageVersion < LanguageFeatureMinimumTarget.PrivateNamesAndClassStaticBlocks || - languageVersion < LanguageFeatureMinimumTarget.ClassAndClassElementDecorators; + function getFirstTransformableStaticClassElement( + node: ClassLikeDeclaration + ) { + const willTransformStaticElementsOfDecoratedClass = + !legacyDecorators && + languageVersion < + LanguageFeatureMinimumTarget.ClassAndClassElementDecorators && + classOrConstructorParameterIsDecorated( + /*useLegacyDecorators*/ false, + node + ); + const willTransformPrivateElementsOrClassStaticBlocks = + languageVersion < + LanguageFeatureMinimumTarget.PrivateNamesAndClassStaticBlocks || + languageVersion < + LanguageFeatureMinimumTarget.ClassAndClassElementDecorators; const willTransformInitializers = !emitStandardClassFields; - if (willTransformStaticElementsOfDecoratedClass || willTransformPrivateElementsOrClassStaticBlocks) { + if ( + willTransformStaticElementsOfDecoratedClass || + willTransformPrivateElementsOrClassStaticBlocks + ) { for (const member of node.members) { - if (willTransformStaticElementsOfDecoratedClass && classElementOrClassElementParameterIsDecorated(/*useLegacyDecorators*/ false, member, node)) { + if ( + willTransformStaticElementsOfDecoratedClass && + classElementOrClassElementParameterIsDecorated( + /*useLegacyDecorators*/ false, + member, + node + ) + ) { return firstOrUndefined(getDecorators(node)) ?? node; - } - else if (willTransformPrivateElementsOrClassStaticBlocks) { + } else if (willTransformPrivateElementsOrClassStaticBlocks) { if (isClassStaticBlockDeclaration(member)) { return member; - } - else if (isStatic(member)) { + } else if (isStatic(member)) { if ( - isPrivateIdentifierClassElementDeclaration(member) || - willTransformInitializers && isInitializedProperty(member) + isPrivateIdentifierClassElementDeclaration( + member + ) || + (willTransformInitializers && + isInitializedProperty(member)) ) { return member; } @@ -46774,18 +81147,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const parent = walkUpOuterExpressions(node); if (!isNamedEvaluationSource(parent)) return; - const willTransformESDecorators = !legacyDecorators && languageVersion < LanguageFeatureMinimumTarget.ClassAndClassElementDecorators; + const willTransformESDecorators = + !legacyDecorators && + languageVersion < + LanguageFeatureMinimumTarget.ClassAndClassElementDecorators; let location: Node | undefined; - if (willTransformESDecorators && classOrConstructorParameterIsDecorated(/*useLegacyDecorators*/ false, node)) { + if ( + willTransformESDecorators && + classOrConstructorParameterIsDecorated( + /*useLegacyDecorators*/ false, + node + ) + ) { location = firstOrUndefined(getDecorators(node)) ?? node; - } - else { + } else { location = getFirstTransformableStaticClassElement(node); } if (location) { - checkExternalEmitHelpers(location, ExternalEmitHelpers.SetFunctionName); - if ((isPropertyAssignment(parent) || isPropertyDeclaration(parent) || isBindingElement(parent)) && isComputedPropertyName(parent.name)) { + checkExternalEmitHelpers( + location, + ExternalEmitHelpers.SetFunctionName + ); + if ( + (isPropertyAssignment(parent) || + isPropertyDeclaration(parent) || + isBindingElement(parent)) && + isComputedPropertyName(parent.name) + ) { checkExternalEmitHelpers(location, ExternalEmitHelpers.PropKey); } } @@ -46805,11 +81194,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkClassDeclaration(node: ClassDeclaration) { const firstDecorator = find(node.modifiers, isDecorator); - if (legacyDecorators && firstDecorator && some(node.members, p => hasStaticModifier(p) && isPrivateIdentifierClassElementDeclaration(p))) { - grammarErrorOnNode(firstDecorator, Diagnostics.Class_decorators_can_t_be_used_with_static_private_identifier_Consider_removing_the_experimental_decorator); + if ( + legacyDecorators && + firstDecorator && + some( + node.members, + (p) => + hasStaticModifier(p) && + isPrivateIdentifierClassElementDeclaration(p) + ) + ) { + grammarErrorOnNode( + firstDecorator, + Diagnostics.Class_decorators_can_t_be_used_with_static_private_identifier_Consider_removing_the_experimental_decorator + ); } if (!node.name && !hasSyntacticModifier(node, ModifierFlags.Default)) { - grammarErrorOnFirstToken(node, Diagnostics.A_class_declaration_without_the_default_modifier_must_have_a_name); + grammarErrorOnFirstToken( + node, + Diagnostics.A_class_declaration_without_the_default_modifier_must_have_a_name + ); } checkClassLikeDeclaration(node); forEach(node.members, checkSourceElement); @@ -46841,7 +81245,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (baseTypeNode) { forEach(baseTypeNode.typeArguments, checkSourceElement); if (languageVersion < LanguageFeatureMinimumTarget.Classes) { - checkExternalEmitHelpers(baseTypeNode.parent, ExternalEmitHelpers.Extends); + checkExternalEmitHelpers( + baseTypeNode.parent, + ExternalEmitHelpers.Extends + ); } // check both @extends and extends if both are specified. const extendsNode = getClassExtendsHeritageElement(node); @@ -46853,44 +81260,114 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (baseTypes.length) { addLazyDiagnostic(() => { const baseType = baseTypes[0]; - const baseConstructorType = getBaseConstructorTypeOfClass(type); + const baseConstructorType = + getBaseConstructorTypeOfClass(type); const staticBaseType = getApparentType(baseConstructorType); checkBaseTypeAccessibility(staticBaseType, baseTypeNode); checkSourceElement(baseTypeNode.expression); if (some(baseTypeNode.typeArguments)) { forEach(baseTypeNode.typeArguments, checkSourceElement); - for (const constructor of getConstructorsForTypeArguments(staticBaseType, baseTypeNode.typeArguments, baseTypeNode)) { - if (!checkTypeArgumentConstraints(baseTypeNode, constructor.typeParameters!)) { + for (const constructor of getConstructorsForTypeArguments( + staticBaseType, + baseTypeNode.typeArguments, + baseTypeNode + )) { + if ( + !checkTypeArgumentConstraints( + baseTypeNode, + constructor.typeParameters! + ) + ) { break; } } } - const baseWithThis = getTypeWithThisArgument(baseType, type.thisType); - if (!checkTypeAssignableTo(typeWithThis, baseWithThis, /*errorNode*/ undefined)) { - issueMemberSpecificError(node, typeWithThis, baseWithThis, Diagnostics.Class_0_incorrectly_extends_base_class_1); - } - else { + const baseWithThis = getTypeWithThisArgument( + baseType, + type.thisType + ); + if ( + !checkTypeAssignableTo( + typeWithThis, + baseWithThis, + /*errorNode*/ undefined + ) + ) { + issueMemberSpecificError( + node, + typeWithThis, + baseWithThis, + Diagnostics.Class_0_incorrectly_extends_base_class_1 + ); + } else { // Report static side error only when instance type is assignable - checkTypeAssignableTo(staticType, getTypeWithoutSignatures(staticBaseType), node.name || node, Diagnostics.Class_static_side_0_incorrectly_extends_base_class_static_side_1); + checkTypeAssignableTo( + staticType, + getTypeWithoutSignatures(staticBaseType), + node.name || node, + Diagnostics.Class_static_side_0_incorrectly_extends_base_class_static_side_1 + ); } if (baseConstructorType.flags & TypeFlags.TypeVariable) { if (!isMixinConstructorType(staticType)) { - error(node.name || node, Diagnostics.A_mixin_class_must_have_a_constructor_with_a_single_rest_parameter_of_type_any); - } - else { - const constructSignatures = getSignaturesOfType(baseConstructorType, SignatureKind.Construct); - if (constructSignatures.some(signature => signature.flags & SignatureFlags.Abstract) && !hasSyntacticModifier(node, ModifierFlags.Abstract)) { - error(node.name || node, Diagnostics.A_mixin_class_that_extends_from_a_type_variable_containing_an_abstract_construct_signature_must_also_be_declared_abstract); + error( + node.name || node, + Diagnostics.A_mixin_class_must_have_a_constructor_with_a_single_rest_parameter_of_type_any + ); + } else { + const constructSignatures = getSignaturesOfType( + baseConstructorType, + SignatureKind.Construct + ); + if ( + constructSignatures.some( + (signature) => + signature.flags & + SignatureFlags.Abstract + ) && + !hasSyntacticModifier( + node, + ModifierFlags.Abstract + ) + ) { + error( + node.name || node, + Diagnostics.A_mixin_class_that_extends_from_a_type_variable_containing_an_abstract_construct_signature_must_also_be_declared_abstract + ); } } } - if (!(staticBaseType.symbol && staticBaseType.symbol.flags & SymbolFlags.Class) && !(baseConstructorType.flags & TypeFlags.TypeVariable)) { + if ( + !( + staticBaseType.symbol && + staticBaseType.symbol.flags & SymbolFlags.Class + ) && + !(baseConstructorType.flags & TypeFlags.TypeVariable) + ) { // When the static base type is a "class-like" constructor function (but not actually a class), we verify // that all instantiated base constructor signatures return the same type. - const constructors = getInstantiatedConstructorsForTypeArguments(staticBaseType, baseTypeNode.typeArguments, baseTypeNode); - if (forEach(constructors, sig => !isJSConstructor(sig.declaration) && !isTypeIdenticalTo(getReturnTypeOfSignature(sig), baseType))) { - error(baseTypeNode.expression, Diagnostics.Base_constructors_must_all_have_the_same_return_type); + const constructors = + getInstantiatedConstructorsForTypeArguments( + staticBaseType, + baseTypeNode.typeArguments, + baseTypeNode + ); + if ( + forEach( + constructors, + (sig) => + !isJSConstructor(sig.declaration) && + !isTypeIdenticalTo( + getReturnTypeOfSignature(sig), + baseType + ) + ) + ) { + error( + baseTypeNode.expression, + Diagnostics.Base_constructors_must_all_have_the_same_return_type + ); } } checkKindsOfPropertyMemberOverrides(type, baseType); @@ -46903,8 +81380,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const implementedTypeNodes = getEffectiveImplementsTypeNodes(node); if (implementedTypeNodes) { for (const typeRefNode of implementedTypeNodes) { - if (!isEntityNameExpression(typeRefNode.expression) || isOptionalChain(typeRefNode.expression)) { - error(typeRefNode.expression, Diagnostics.A_class_can_only_implement_an_identifier_Slashqualified_name_with_optional_type_arguments); + if ( + !isEntityNameExpression(typeRefNode.expression) || + isOptionalChain(typeRefNode.expression) + ) { + error( + typeRefNode.expression, + Diagnostics.A_class_can_only_implement_an_identifier_Slashqualified_name_with_optional_type_arguments + ); } checkTypeReferenceNode(typeRefNode); addLazyDiagnostic(createImplementsDiagnostics(typeRefNode)); @@ -46918,31 +81401,57 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkPropertyInitialization(node); }); - function createImplementsDiagnostics(typeRefNode: ExpressionWithTypeArguments) { + function createImplementsDiagnostics( + typeRefNode: ExpressionWithTypeArguments + ) { return () => { const t = getReducedType(getTypeFromTypeNode(typeRefNode)); if (!isErrorType(t)) { if (isValidBaseType(t)) { - const genericDiag = t.symbol && t.symbol.flags & SymbolFlags.Class ? - Diagnostics.Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass : - Diagnostics.Class_0_incorrectly_implements_interface_1; - const baseWithThis = getTypeWithThisArgument(t, type.thisType); - if (!checkTypeAssignableTo(typeWithThis, baseWithThis, /*errorNode*/ undefined)) { - issueMemberSpecificError(node, typeWithThis, baseWithThis, genericDiag); + const genericDiag = + t.symbol && t.symbol.flags & SymbolFlags.Class + ? Diagnostics.Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass + : Diagnostics.Class_0_incorrectly_implements_interface_1; + const baseWithThis = getTypeWithThisArgument( + t, + type.thisType + ); + if ( + !checkTypeAssignableTo( + typeWithThis, + baseWithThis, + /*errorNode*/ undefined + ) + ) { + issueMemberSpecificError( + node, + typeWithThis, + baseWithThis, + genericDiag + ); } - } - else { - error(typeRefNode, Diagnostics.A_class_can_only_implement_an_object_type_or_intersection_of_object_types_with_statically_known_members); + } else { + error( + typeRefNode, + Diagnostics.A_class_can_only_implement_an_object_type_or_intersection_of_object_types_with_statically_known_members + ); } } }; } } - function checkMembersForOverrideModifier(node: ClassLikeDeclaration, type: InterfaceType, typeWithThis: Type, staticType: ObjectType) { + function checkMembersForOverrideModifier( + node: ClassLikeDeclaration, + type: InterfaceType, + typeWithThis: Type, + staticType: ObjectType + ) { const baseTypeNode = getEffectiveBaseTypeNode(node); const baseTypes = baseTypeNode && getBaseTypes(type); - const baseWithThis = baseTypes?.length ? getTypeWithThisArgument(first(baseTypes), type.thisType) : undefined; + const baseWithThis = baseTypes?.length + ? getTypeWithThisArgument(first(baseTypes), type.thisType) + : undefined; const baseStaticType = getBaseConstructorTypeOfClass(type); for (const member of node.members) { @@ -46951,7 +81460,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (isConstructorDeclaration(member)) { - forEach(member.parameters, param => { + forEach(member.parameters, (param) => { if (isParameterPropertyDeclaration(param, member)) { checkExistingMemberForOverrideModifier( node, @@ -46961,7 +81470,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { type, typeWithThis, param, - /*memberIsParameterProperty*/ true, + /*memberIsParameterProperty*/ true ); } }); @@ -46974,7 +81483,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { type, typeWithThis, member, - /*memberIsParameterProperty*/ false, + /*memberIsParameterProperty*/ false ); } } @@ -46992,11 +81501,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { typeWithThis: Type, member: ClassElement | ParameterPropertyDeclaration, memberIsParameterProperty: boolean, - reportErrors = true, + reportErrors = true ): MemberOverrideStatus { - const declaredProp = member.name - && getSymbolAtLocation(member.name) - || getSymbolAtLocation(member); + const declaredProp = + (member.name && getSymbolAtLocation(member.name)) || + getSymbolAtLocation(member); if (!declaredProp) { return MemberOverrideStatus.Ok; } @@ -47013,7 +81522,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { isStatic(member), memberIsParameterProperty, declaredProp, - reportErrors ? member : undefined, + reportErrors ? member : undefined ); } @@ -47037,20 +81546,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { memberIsStatic: boolean, memberIsParameterProperty: boolean, member: Symbol, - errorNode?: Node, + errorNode?: Node ): MemberOverrideStatus { const isJs = isInJSFile(node); const nodeInAmbientContext = !!(node.flags & NodeFlags.Ambient); - if (memberHasOverrideModifier && member?.valueDeclaration && isClassElement(member.valueDeclaration) && member.valueDeclaration.name && isNonBindableDynamicName(member.valueDeclaration.name)) { + if ( + memberHasOverrideModifier && + member?.valueDeclaration && + isClassElement(member.valueDeclaration) && + member.valueDeclaration.name && + isNonBindableDynamicName(member.valueDeclaration.name) + ) { error( errorNode, - isJs ? - Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_its_name_is_dynamic : - Diagnostics.This_member_cannot_have_an_override_modifier_because_its_name_is_dynamic, + isJs + ? Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_its_name_is_dynamic + : Diagnostics.This_member_cannot_have_an_override_modifier_because_its_name_is_dynamic ); return MemberOverrideStatus.HasInvalidOverride; } - if (baseWithThis && (memberHasOverrideModifier || compilerOptions.noImplicitOverride)) { + if ( + baseWithThis && + (memberHasOverrideModifier || compilerOptions.noImplicitOverride) + ) { const thisType = memberIsStatic ? staticType : typeWithThis; const baseType = memberIsStatic ? baseStaticType : baseWithThis; const prop = getPropertyOfType(thisType, member.escapedName); @@ -47059,62 +81577,75 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const baseClassName = typeToString(baseWithThis); if (prop && !baseProp && memberHasOverrideModifier) { if (errorNode) { - const suggestion = getSuggestedSymbolForNonexistentClassMember(symbolName(member), baseType); // Again, using symbol name: note that's different from `symbol.escapedName` - suggestion ? - error( - errorNode, - isJs ? - 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 : - Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0_Did_you_mean_1, - baseClassName, - symbolToString(suggestion), - ) : - error( - errorNode, - isJs ? - Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0 : - Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0, - baseClassName, - ); + const suggestion = + getSuggestedSymbolForNonexistentClassMember( + symbolName(member), + baseType + ); // Again, using symbol name: note that's different from `symbol.escapedName` + suggestion + ? error( + errorNode, + isJs + ? 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 + : Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0_Did_you_mean_1, + baseClassName, + symbolToString(suggestion) + ) + : error( + errorNode, + isJs + ? Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0 + : Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0, + baseClassName + ); } return MemberOverrideStatus.HasInvalidOverride; - } - else if (prop && baseProp?.declarations && compilerOptions.noImplicitOverride && !nodeInAmbientContext) { - const baseHasAbstract = some(baseProp.declarations, hasAbstractModifier); + } else if ( + prop && + baseProp?.declarations && + compilerOptions.noImplicitOverride && + !nodeInAmbientContext + ) { + const baseHasAbstract = some( + baseProp.declarations, + hasAbstractModifier + ); if (memberHasOverrideModifier) { return MemberOverrideStatus.Ok; } if (!baseHasAbstract) { if (errorNode) { - const diag = memberIsParameterProperty ? - isJs ? - Diagnostics.This_parameter_property_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0 : - Diagnostics.This_parameter_property_must_have_an_override_modifier_because_it_overrides_a_member_in_base_class_0 : - isJs ? - Diagnostics.This_member_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0 : - Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_a_member_in_the_base_class_0; + const diag = memberIsParameterProperty + ? isJs + ? Diagnostics.This_parameter_property_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0 + : Diagnostics.This_parameter_property_must_have_an_override_modifier_because_it_overrides_a_member_in_base_class_0 + : isJs + ? Diagnostics.This_member_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0 + : Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_a_member_in_the_base_class_0; error(errorNode, diag, baseClassName); } return MemberOverrideStatus.NeedsOverride; - } - else if (memberHasAbstractModifier && baseHasAbstract) { + } else if (memberHasAbstractModifier && baseHasAbstract) { if (errorNode) { - 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); + 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 + ); } return MemberOverrideStatus.NeedsOverride; } } - } - else if (memberHasOverrideModifier) { + } else if (memberHasOverrideModifier) { if (errorNode) { const className = typeToString(type); error( errorNode, - isJs ? - Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_its_containing_class_0_does_not_extend_another_class : - Diagnostics.This_member_cannot_have_an_override_modifier_because_its_containing_class_0_does_not_extend_another_class, - className, + isJs + ? Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_its_containing_class_0_does_not_extend_another_class + : Diagnostics.This_member_cannot_have_an_override_modifier_because_its_containing_class_0_does_not_extend_another_class, + className ); } return MemberOverrideStatus.HasInvalidOverride; @@ -47123,17 +81654,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return MemberOverrideStatus.Ok; } - function issueMemberSpecificError(node: ClassLikeDeclaration, typeWithThis: Type, baseWithThis: Type, broadDiag: DiagnosticMessage) { + function issueMemberSpecificError( + node: ClassLikeDeclaration, + typeWithThis: Type, + baseWithThis: Type, + broadDiag: DiagnosticMessage + ) { // iterate over all implemented properties and issue errors on each one which isn't compatible, rather than the class as a whole, if possible let issuedMemberError = false; for (const member of node.members) { if (isStatic(member)) { continue; } - const declaredProp = member.name && getSymbolAtLocation(member.name) || getSymbolAtLocation(member); + const declaredProp = + (member.name && getSymbolAtLocation(member.name)) || + getSymbolAtLocation(member); if (declaredProp) { - const prop = getPropertyOfType(typeWithThis, declaredProp.escapedName); - const baseProp = getPropertyOfType(baseWithThis, declaredProp.escapedName); + const prop = getPropertyOfType( + typeWithThis, + declaredProp.escapedName + ); + const baseProp = getPropertyOfType( + baseWithThis, + declaredProp.escapedName + ); if (prop && baseProp) { const rootChain = () => chainDiagnosticMessages( @@ -47141,9 +81685,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { Diagnostics.Property_0_in_type_1_is_not_assignable_to_the_same_property_in_base_type_2, symbolToString(declaredProp), typeToString(typeWithThis), - typeToString(baseWithThis), + typeToString(baseWithThis) ); - if (!checkTypeAssignableTo(getTypeOfSymbol(prop), getTypeOfSymbol(baseProp), member.name || member, /*headMessage*/ undefined, rootChain)) { + if ( + !checkTypeAssignableTo( + getTypeOfSymbol(prop), + getTypeOfSymbol(baseProp), + member.name || member, + /*headMessage*/ undefined, + rootChain + ) + ) { issuedMemberError = true; } } @@ -47151,18 +81703,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (!issuedMemberError) { // check again with diagnostics to generate a less-specific error - checkTypeAssignableTo(typeWithThis, baseWithThis, node.name || node, broadDiag); + checkTypeAssignableTo( + typeWithThis, + baseWithThis, + node.name || node, + broadDiag + ); } } - function checkBaseTypeAccessibility(type: Type, node: ExpressionWithTypeArguments) { + function checkBaseTypeAccessibility( + type: Type, + node: ExpressionWithTypeArguments + ) { const signatures = getSignaturesOfType(type, SignatureKind.Construct); if (signatures.length) { const declaration = signatures[0].declaration; - if (declaration && hasEffectiveModifier(declaration, ModifierFlags.Private)) { - const typeClassDeclaration = getClassLikeDeclarationOfSymbol(type.symbol)!; + if ( + declaration && + hasEffectiveModifier(declaration, ModifierFlags.Private) + ) { + const typeClassDeclaration = getClassLikeDeclarationOfSymbol( + type.symbol + )!; if (!isNodeWithinClass(node, typeClassDeclaration)) { - error(node, Diagnostics.Cannot_extend_a_class_0_Class_constructor_is_marked_as_private, getFullyQualifiedName(type.symbol)); + error( + node, + Diagnostics.Cannot_extend_a_class_0_Class_constructor_is_marked_as_private, + getFullyQualifiedName(type.symbol) + ); } } } @@ -47175,7 +81744,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param memberSymbol Member symbol. * Note: `member` can be a synthetic node without a parent. */ - function getMemberOverrideModifierStatus(node: ClassLikeDeclaration, member: ClassElement, memberSymbol: Symbol): MemberOverrideStatus { + function getMemberOverrideModifierStatus( + node: ClassLikeDeclaration, + member: ClassElement, + memberSymbol: Symbol + ): MemberOverrideStatus { if (!member.name) { return MemberOverrideStatus.Ok; } @@ -47187,7 +81760,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const baseTypeNode = getEffectiveBaseTypeNode(node); const baseTypes = baseTypeNode && getBaseTypes(type); - const baseWithThis = baseTypes?.length ? getTypeWithThisArgument(first(baseTypes), type.thisType) : undefined; + const baseWithThis = baseTypes?.length + ? getTypeWithThisArgument(first(baseTypes), type.thisType) + : undefined; const baseStaticType = getBaseConstructorTypeOfClass(type); const memberHasOverrideModifier = member.parent @@ -47205,7 +81780,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { hasAbstractModifier(member), isStatic(member), /*memberIsParameterProperty*/ false, - memberSymbol, + memberSymbol ); } @@ -47213,14 +81788,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // if symbol is instantiated its flags are not copied from the 'target' // so we'll need to get back original 'target' symbol to work with correct set of flags // NOTE: cast to TransientSymbol should be safe because only TransientSymbols have CheckFlags.Instantiated - return getCheckFlags(s) & CheckFlags.Instantiated ? (s as TransientSymbol).links.target! : s; + return getCheckFlags(s) & CheckFlags.Instantiated + ? (s as TransientSymbol).links.target! + : s; } function getClassOrInterfaceDeclarationsOfSymbol(symbol: Symbol) { - return filter(symbol.declarations, (d: Declaration): d is ClassDeclaration | InterfaceDeclaration => d.kind === SyntaxKind.ClassDeclaration || d.kind === SyntaxKind.InterfaceDeclaration); + return filter( + symbol.declarations, + (d: Declaration): d is ClassDeclaration | InterfaceDeclaration => + d.kind === SyntaxKind.ClassDeclaration || + d.kind === SyntaxKind.InterfaceDeclaration + ); } - function checkKindsOfPropertyMemberOverrides(type: InterfaceType, baseType: BaseType): void { + function checkKindsOfPropertyMemberOverrides( + type: InterfaceType, + baseType: BaseType + ): void { // TypeScript 1.0 spec (April 2014): 8.2.3 // A derived class inherits all members from its base class it doesn't override. // Inheritance means that a derived class implicitly contains all non - overridden members of the base class. @@ -47256,28 +81841,45 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { continue; } const derived = getTargetSymbol(baseSymbol); - const baseDeclarationFlags = getDeclarationModifierFlagsFromSymbol(base); + const baseDeclarationFlags = + getDeclarationModifierFlagsFromSymbol(base); - Debug.assert(!!derived, "derived should point to something, even if it is the base class' declaration."); + Debug.assert( + !!derived, + "derived should point to something, even if it is the base class' declaration." + ); // In order to resolve whether the inherited method was overridden in the base class or not, // we compare the Symbols obtained. Since getTargetSymbol returns the symbol on the *uninstantiated* // type declaration, derived and base resolve to the same symbol even in the case of generic classes. if (derived === base) { // derived class inherits base without override/redeclaration - const derivedClassDecl = getClassLikeDeclarationOfSymbol(type.symbol)!; + const derivedClassDecl = getClassLikeDeclarationOfSymbol( + type.symbol + )!; // It is an error to inherit an abstract member without implementing it or being declared abstract. // If there is no declaration for the derived class (as in the case of class expressions), // then the class cannot be declared abstract. - if (baseDeclarationFlags & ModifierFlags.Abstract && (!derivedClassDecl || !hasSyntacticModifier(derivedClassDecl, ModifierFlags.Abstract))) { + if ( + baseDeclarationFlags & ModifierFlags.Abstract && + (!derivedClassDecl || + !hasSyntacticModifier( + derivedClassDecl, + ModifierFlags.Abstract + )) + ) { // Searches other base types for a declaration that would satisfy the inherited abstract member. // (The class may have more than one base type via declaration merging with an interface with the // same name.) for (const otherBaseType of getBaseTypes(type)) { if (otherBaseType === baseType) continue; - const baseSymbol = getPropertyOfObjectType(otherBaseType, base.escapedName); - const derivedElsewhere = baseSymbol && getTargetSymbol(baseSymbol); + const baseSymbol = getPropertyOfObjectType( + otherBaseType, + base.escapedName + ); + const derivedElsewhere = + baseSymbol && getTargetSymbol(baseSymbol); if (derivedElsewhere && derivedElsewhere !== base) { continue basePropertyCheck; } @@ -47285,29 +81887,53 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const baseTypeName = typeToString(baseType); const typeName = typeToString(type); const basePropertyName = symbolToString(baseProperty); - const missedProperties = append(notImplementedInfo.get(derivedClassDecl)?.missedProperties, basePropertyName); - notImplementedInfo.set(derivedClassDecl, { baseTypeName, typeName, missedProperties }); + const missedProperties = append( + notImplementedInfo.get(derivedClassDecl) + ?.missedProperties, + basePropertyName + ); + notImplementedInfo.set(derivedClassDecl, { + baseTypeName, + typeName, + missedProperties, + }); } - } - else { + } else { // derived overrides base. - const derivedDeclarationFlags = getDeclarationModifierFlagsFromSymbol(derived); - if (baseDeclarationFlags & ModifierFlags.Private || derivedDeclarationFlags & ModifierFlags.Private) { + const derivedDeclarationFlags = + getDeclarationModifierFlagsFromSymbol(derived); + if ( + baseDeclarationFlags & ModifierFlags.Private || + derivedDeclarationFlags & ModifierFlags.Private + ) { // either base or derived property is private - not override, skip it continue; } let errorMessage: DiagnosticMessage; - const basePropertyFlags = base.flags & SymbolFlags.PropertyOrAccessor; - const derivedPropertyFlags = derived.flags & SymbolFlags.PropertyOrAccessor; + const basePropertyFlags = + base.flags & SymbolFlags.PropertyOrAccessor; + const derivedPropertyFlags = + derived.flags & SymbolFlags.PropertyOrAccessor; if (basePropertyFlags && derivedPropertyFlags) { // property/accessor is overridden with property/accessor if ( (getCheckFlags(base) & CheckFlags.Synthetic - ? base.declarations?.some(d => isPropertyAbstractOrInterface(d, baseDeclarationFlags)) - : base.declarations?.every(d => isPropertyAbstractOrInterface(d, baseDeclarationFlags))) - || getCheckFlags(base) & CheckFlags.Mapped - || derived.valueDeclaration && isBinaryExpression(derived.valueDeclaration) + ? base.declarations?.some((d) => + isPropertyAbstractOrInterface( + d, + baseDeclarationFlags + ) + ) + : base.declarations?.every((d) => + isPropertyAbstractOrInterface( + d, + baseDeclarationFlags + ) + )) || + getCheckFlags(base) & CheckFlags.Mapped || + (derived.valueDeclaration && + isBinaryExpression(derived.valueDeclaration)) ) { // when the base property is abstract or from an interface, base/derived flags don't need to match // for intersection properties, this must be true of *any* of the declarations, for others it must be true of *all* @@ -47315,109 +81941,206 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { continue; } - const overriddenInstanceProperty = basePropertyFlags !== SymbolFlags.Property && derivedPropertyFlags === SymbolFlags.Property; - const overriddenInstanceAccessor = basePropertyFlags === SymbolFlags.Property && derivedPropertyFlags !== SymbolFlags.Property; - if (overriddenInstanceProperty || overriddenInstanceAccessor) { - const errorMessage = overriddenInstanceProperty ? - Diagnostics._0_is_defined_as_an_accessor_in_class_1_but_is_overridden_here_in_2_as_an_instance_property : - Diagnostics._0_is_defined_as_a_property_in_class_1_but_is_overridden_here_in_2_as_an_accessor; - error(getNameOfDeclaration(derived.valueDeclaration) || derived.valueDeclaration, errorMessage, symbolToString(base), typeToString(baseType), typeToString(type)); - } - else if (useDefineForClassFields) { - const uninitialized = derived.declarations?.find(d => d.kind === SyntaxKind.PropertyDeclaration && !(d as PropertyDeclaration).initializer); + const overriddenInstanceProperty = + basePropertyFlags !== SymbolFlags.Property && + derivedPropertyFlags === SymbolFlags.Property; + const overriddenInstanceAccessor = + basePropertyFlags === SymbolFlags.Property && + derivedPropertyFlags !== SymbolFlags.Property; + if ( + overriddenInstanceProperty || + overriddenInstanceAccessor + ) { + const errorMessage = overriddenInstanceProperty + ? Diagnostics._0_is_defined_as_an_accessor_in_class_1_but_is_overridden_here_in_2_as_an_instance_property + : Diagnostics._0_is_defined_as_a_property_in_class_1_but_is_overridden_here_in_2_as_an_accessor; + error( + getNameOfDeclaration(derived.valueDeclaration) || + derived.valueDeclaration, + errorMessage, + symbolToString(base), + typeToString(baseType), + typeToString(type) + ); + } else if (useDefineForClassFields) { + const uninitialized = derived.declarations?.find( + (d) => + d.kind === SyntaxKind.PropertyDeclaration && + !(d as PropertyDeclaration).initializer + ); if ( - uninitialized - && !(derived.flags & SymbolFlags.Transient) - && !(baseDeclarationFlags & ModifierFlags.Abstract) - && !(derivedDeclarationFlags & ModifierFlags.Abstract) - && !derived.declarations?.some(d => !!(d.flags & NodeFlags.Ambient)) + uninitialized && + !(derived.flags & SymbolFlags.Transient) && + !(baseDeclarationFlags & ModifierFlags.Abstract) && + !( + derivedDeclarationFlags & ModifierFlags.Abstract + ) && + !derived.declarations?.some( + (d) => !!(d.flags & NodeFlags.Ambient) + ) ) { - const constructor = findConstructorDeclaration(getClassLikeDeclarationOfSymbol(type.symbol)!); - const propName = (uninitialized as PropertyDeclaration).name; + const constructor = findConstructorDeclaration( + getClassLikeDeclarationOfSymbol(type.symbol)! + ); + const propName = ( + uninitialized as PropertyDeclaration + ).name; if ( - (uninitialized as PropertyDeclaration).exclamationToken - || !constructor - || !isIdentifier(propName) - || !strictNullChecks - || !isPropertyInitializedInConstructor(propName, type, constructor) + (uninitialized as PropertyDeclaration) + .exclamationToken || + !constructor || + !isIdentifier(propName) || + !strictNullChecks || + !isPropertyInitializedInConstructor( + propName, + type, + constructor + ) ) { - 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; - error(getNameOfDeclaration(derived.valueDeclaration) || derived.valueDeclaration, errorMessage, symbolToString(base), typeToString(baseType)); + 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; + error( + getNameOfDeclaration( + derived.valueDeclaration + ) || derived.valueDeclaration, + errorMessage, + symbolToString(base), + typeToString(baseType) + ); } } } // correct case continue; - } - else if (isPrototypeProperty(base)) { - if (isPrototypeProperty(derived) || derived.flags & SymbolFlags.Property) { + } else if (isPrototypeProperty(base)) { + if ( + isPrototypeProperty(derived) || + derived.flags & SymbolFlags.Property + ) { // method is overridden with method or property -- correct case continue; - } - else { + } else { Debug.assert(!!(derived.flags & SymbolFlags.Accessor)); - errorMessage = Diagnostics.Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_accessor; + errorMessage = + Diagnostics.Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_accessor; } - } - else if (base.flags & SymbolFlags.Accessor) { - errorMessage = Diagnostics.Class_0_defines_instance_member_accessor_1_but_extended_class_2_defines_it_as_instance_member_function; - } - else { - errorMessage = Diagnostics.Class_0_defines_instance_member_property_1_but_extended_class_2_defines_it_as_instance_member_function; + } else if (base.flags & SymbolFlags.Accessor) { + errorMessage = + Diagnostics.Class_0_defines_instance_member_accessor_1_but_extended_class_2_defines_it_as_instance_member_function; + } else { + errorMessage = + Diagnostics.Class_0_defines_instance_member_property_1_but_extended_class_2_defines_it_as_instance_member_function; } - error(getNameOfDeclaration(derived.valueDeclaration) || derived.valueDeclaration, errorMessage, typeToString(baseType), symbolToString(base), typeToString(type)); + error( + getNameOfDeclaration(derived.valueDeclaration) || + derived.valueDeclaration, + errorMessage, + typeToString(baseType), + symbolToString(base), + typeToString(type) + ); } } for (const [errorNode, memberInfo] of notImplementedInfo) { if (length(memberInfo.missedProperties) === 1) { if (isClassExpression(errorNode)) { - error(errorNode, Diagnostics.Non_abstract_class_expression_does_not_implement_inherited_abstract_member_0_from_class_1, first(memberInfo.missedProperties), memberInfo.baseTypeName); - } - else { - error(errorNode, Diagnostics.Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2, memberInfo.typeName, first(memberInfo.missedProperties), memberInfo.baseTypeName); + error( + errorNode, + Diagnostics.Non_abstract_class_expression_does_not_implement_inherited_abstract_member_0_from_class_1, + first(memberInfo.missedProperties), + memberInfo.baseTypeName + ); + } else { + error( + errorNode, + Diagnostics.Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2, + memberInfo.typeName, + first(memberInfo.missedProperties), + memberInfo.baseTypeName + ); } - } - else if (length(memberInfo.missedProperties) > 5) { - const missedProperties = map(memberInfo.missedProperties.slice(0, 4), prop => `'${prop}'`).join(", "); - const remainingMissedProperties = length(memberInfo.missedProperties) - 4; + } else if (length(memberInfo.missedProperties) > 5) { + const missedProperties = map( + memberInfo.missedProperties.slice(0, 4), + (prop) => `'${prop}'` + ).join(", "); + const remainingMissedProperties = + length(memberInfo.missedProperties) - 4; if (isClassExpression(errorNode)) { - error(errorNode, Diagnostics.Non_abstract_class_expression_is_missing_implementations_for_the_following_members_of_0_Colon_1_and_2_more, memberInfo.baseTypeName, missedProperties, remainingMissedProperties); - } - else { - error(errorNode, Diagnostics.Non_abstract_class_0_is_missing_implementations_for_the_following_members_of_1_Colon_2_and_3_more, memberInfo.typeName, memberInfo.baseTypeName, missedProperties, remainingMissedProperties); + error( + errorNode, + Diagnostics.Non_abstract_class_expression_is_missing_implementations_for_the_following_members_of_0_Colon_1_and_2_more, + memberInfo.baseTypeName, + missedProperties, + remainingMissedProperties + ); + } else { + error( + errorNode, + Diagnostics.Non_abstract_class_0_is_missing_implementations_for_the_following_members_of_1_Colon_2_and_3_more, + memberInfo.typeName, + memberInfo.baseTypeName, + missedProperties, + remainingMissedProperties + ); } - } - else { - const missedProperties = map(memberInfo.missedProperties, prop => `'${prop}'`).join(", "); + } else { + const missedProperties = map( + memberInfo.missedProperties, + (prop) => `'${prop}'` + ).join(", "); if (isClassExpression(errorNode)) { - error(errorNode, Diagnostics.Non_abstract_class_expression_is_missing_implementations_for_the_following_members_of_0_Colon_1, memberInfo.baseTypeName, missedProperties); - } - else { - error(errorNode, Diagnostics.Non_abstract_class_0_is_missing_implementations_for_the_following_members_of_1_Colon_2, memberInfo.typeName, memberInfo.baseTypeName, missedProperties); + error( + errorNode, + Diagnostics.Non_abstract_class_expression_is_missing_implementations_for_the_following_members_of_0_Colon_1, + memberInfo.baseTypeName, + missedProperties + ); + } else { + error( + errorNode, + Diagnostics.Non_abstract_class_0_is_missing_implementations_for_the_following_members_of_1_Colon_2, + memberInfo.typeName, + memberInfo.baseTypeName, + missedProperties + ); } } } } - function isPropertyAbstractOrInterface(declaration: Declaration, baseDeclarationFlags: ModifierFlags) { - return baseDeclarationFlags & ModifierFlags.Abstract && (!isPropertyDeclaration(declaration) || !declaration.initializer) - || isInterfaceDeclaration(declaration.parent); + function isPropertyAbstractOrInterface( + declaration: Declaration, + baseDeclarationFlags: ModifierFlags + ) { + return ( + (baseDeclarationFlags & ModifierFlags.Abstract && + (!isPropertyDeclaration(declaration) || + !declaration.initializer)) || + isInterfaceDeclaration(declaration.parent) + ); } - function getNonInheritedProperties(type: InterfaceType, baseTypes: BaseType[], properties: Symbol[]) { + function getNonInheritedProperties( + type: InterfaceType, + baseTypes: BaseType[], + properties: Symbol[] + ) { if (!length(baseTypes)) { return properties; } const seen = new Map<__String, Symbol>(); - forEach(properties, p => { + forEach(properties, (p) => { seen.set(p.escapedName, p); }); for (const base of baseTypes) { - const properties = getPropertiesOfType(getTypeWithThisArgument(base, type.thisType)); + const properties = getPropertiesOfType( + getTypeWithThisArgument(base, type.thisType) + ); for (const prop of properties) { const existing = seen.get(prop.escapedName); if (existing && prop.parent === existing.parent) { @@ -47429,7 +82152,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return arrayFrom(seen.values()); } - function checkInheritedPropertiesAreIdentical(type: InterfaceType, typeNode: Node): boolean { + function checkInheritedPropertiesAreIdentical( + type: InterfaceType, + typeNode: Node + ): boolean { const baseTypes = getBaseTypes(type); if (baseTypes.length < 2) { return true; @@ -47440,29 +82166,52 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { containingType: Type; } const seen = new Map<__String, InheritanceInfoMap>(); - forEach(resolveDeclaredMembers(type).declaredProperties, p => { + forEach(resolveDeclaredMembers(type).declaredProperties, (p) => { seen.set(p.escapedName, { prop: p, containingType: type }); }); let ok = true; for (const base of baseTypes) { - const properties = getPropertiesOfType(getTypeWithThisArgument(base, type.thisType)); + const properties = getPropertiesOfType( + getTypeWithThisArgument(base, type.thisType) + ); for (const prop of properties) { const existing = seen.get(prop.escapedName); if (!existing) { seen.set(prop.escapedName, { prop, containingType: base }); - } - else { - const isInheritedProperty = existing.containingType !== type; - if (isInheritedProperty && !isPropertyIdenticalTo(existing.prop, prop)) { + } else { + const isInheritedProperty = + existing.containingType !== type; + if ( + isInheritedProperty && + !isPropertyIdenticalTo(existing.prop, prop) + ) { ok = false; const typeName1 = typeToString(existing.containingType); const typeName2 = typeToString(base); - let errorInfo = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Named_property_0_of_types_1_and_2_are_not_identical, symbolToString(prop), typeName1, typeName2); - errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Interface_0_cannot_simultaneously_extend_types_1_and_2, typeToString(type), typeName1, typeName2); - diagnostics.add(createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(typeNode), typeNode, errorInfo)); + let errorInfo = chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Named_property_0_of_types_1_and_2_are_not_identical, + symbolToString(prop), + typeName1, + typeName2 + ); + errorInfo = chainDiagnosticMessages( + errorInfo, + Diagnostics.Interface_0_cannot_simultaneously_extend_types_1_and_2, + typeToString(type), + typeName1, + typeName2 + ); + diagnostics.add( + createDiagnosticForNodeFromMessageChain( + getSourceFileOfNode(typeNode), + typeNode, + errorInfo + ) + ); } } } @@ -47472,7 +82221,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkPropertyInitialization(node: ClassLikeDeclaration) { - if (!strictNullChecks || !strictPropertyInitialization || node.flags & NodeFlags.Ambient) { + if ( + !strictNullChecks || + !strictPropertyInitialization || + node.flags & NodeFlags.Ambient + ) { return; } const constructor = findConstructorDeclaration(node); @@ -47482,11 +82235,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (!isStatic(member) && isPropertyWithoutInitializer(member)) { const propName = (member as PropertyDeclaration).name; - if (isIdentifier(propName) || isPrivateIdentifier(propName) || isComputedPropertyName(propName)) { - const type = getTypeOfSymbol(getSymbolOfDeclaration(member)); - if (!(type.flags & TypeFlags.AnyOrUnknown || containsUndefinedType(type))) { - if (!constructor || !isPropertyInitializedInConstructor(propName, type, constructor)) { - error(member.name, Diagnostics.Property_0_has_no_initializer_and_is_not_definitely_assigned_in_the_constructor, declarationNameToString(propName)); + if ( + isIdentifier(propName) || + isPrivateIdentifier(propName) || + isComputedPropertyName(propName) + ) { + const type = getTypeOfSymbol( + getSymbolOfDeclaration(member) + ); + if ( + !( + type.flags & TypeFlags.AnyOrUnknown || + containsUndefinedType(type) + ) + ) { + if ( + !constructor || + !isPropertyInitializedInConstructor( + propName, + type, + constructor + ) + ) { + error( + member.name, + Diagnostics.Property_0_has_no_initializer_and_is_not_definitely_assigned_in_the_constructor, + declarationNameToString(propName) + ); } } } @@ -47495,21 +82270,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isPropertyWithoutInitializer(node: Node) { - return node.kind === SyntaxKind.PropertyDeclaration && + return ( + node.kind === SyntaxKind.PropertyDeclaration && !hasAbstractModifier(node) && !(node as PropertyDeclaration).exclamationToken && - !(node as PropertyDeclaration).initializer; + !(node as PropertyDeclaration).initializer + ); } - function isPropertyInitializedInStaticBlocks(propName: Identifier | PrivateIdentifier, propType: Type, staticBlocks: readonly ClassStaticBlockDeclaration[], startPos: number, endPos: number) { + function isPropertyInitializedInStaticBlocks( + propName: Identifier | PrivateIdentifier, + propType: Type, + staticBlocks: readonly ClassStaticBlockDeclaration[], + startPos: number, + endPos: number + ) { for (const staticBlock of staticBlocks) { // static block must be within the provided range as they are evaluated in document order (unlike constructors) if (staticBlock.pos >= startPos && staticBlock.pos <= endPos) { - const reference = factory.createPropertyAccessExpression(factory.createThis(), propName); + const reference = factory.createPropertyAccessExpression( + factory.createThis(), + propName + ); setParent(reference.expression, reference); setParent(reference, staticBlock); reference.flowNode = staticBlock.returnFlowNode; - const flowType = getFlowTypeOfReference(reference, propType, getOptionalType(propType)); + const flowType = getFlowTypeOfReference( + reference, + propType, + getOptionalType(propType) + ); if (!containsUndefinedType(flowType)) { return true; } @@ -47518,50 +82308,87 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function isPropertyInitializedInConstructor(propName: Identifier | PrivateIdentifier | ComputedPropertyName, propType: Type, constructor: ConstructorDeclaration) { + function isPropertyInitializedInConstructor( + propName: Identifier | PrivateIdentifier | ComputedPropertyName, + propType: Type, + constructor: ConstructorDeclaration + ) { const reference = isComputedPropertyName(propName) - ? factory.createElementAccessExpression(factory.createThis(), propName.expression) - : factory.createPropertyAccessExpression(factory.createThis(), propName); + ? factory.createElementAccessExpression( + factory.createThis(), + propName.expression + ) + : factory.createPropertyAccessExpression( + factory.createThis(), + propName + ); setParent(reference.expression, reference); setParent(reference, constructor); reference.flowNode = constructor.returnFlowNode; - const flowType = getFlowTypeOfReference(reference, propType, getOptionalType(propType)); + const flowType = getFlowTypeOfReference( + reference, + propType, + getOptionalType(propType) + ); return !containsUndefinedType(flowType); } function checkInterfaceDeclaration(node: InterfaceDeclaration) { // Grammar checking - if (!checkGrammarModifiers(node)) checkGrammarInterfaceDeclaration(node); + if (!checkGrammarModifiers(node)) + checkGrammarInterfaceDeclaration(node); if (!allowBlockDeclarations(node.parent)) { - grammarErrorOnNode(node, Diagnostics._0_declarations_can_only_be_declared_inside_a_block, "interface"); + grammarErrorOnNode( + node, + Diagnostics._0_declarations_can_only_be_declared_inside_a_block, + "interface" + ); } checkTypeParameters(node.typeParameters); addLazyDiagnostic(() => { - checkTypeNameIsReserved(node.name, Diagnostics.Interface_name_cannot_be_0); + checkTypeNameIsReserved( + node.name, + Diagnostics.Interface_name_cannot_be_0 + ); checkExportsOnMergedDeclarations(node); const symbol = getSymbolOfDeclaration(node); checkTypeParameterListsIdentical(symbol); // Only check this symbol once - const firstInterfaceDecl = getDeclarationOfKind(symbol, SyntaxKind.InterfaceDeclaration); + const firstInterfaceDecl = + getDeclarationOfKind( + symbol, + SyntaxKind.InterfaceDeclaration + ); if (node === firstInterfaceDecl) { const type = getDeclaredTypeOfSymbol(symbol) as InterfaceType; const typeWithThis = getTypeWithThisArgument(type); // run subsequent checks only if first set succeeded if (checkInheritedPropertiesAreIdentical(type, node.name)) { for (const baseType of getBaseTypes(type)) { - checkTypeAssignableTo(typeWithThis, getTypeWithThisArgument(baseType, type.thisType), node.name, Diagnostics.Interface_0_incorrectly_extends_interface_1); + checkTypeAssignableTo( + typeWithThis, + getTypeWithThisArgument(baseType, type.thisType), + node.name, + Diagnostics.Interface_0_incorrectly_extends_interface_1 + ); } checkIndexConstraints(type, symbol); } } checkObjectTypeForDuplicateDeclarations(node); }); - forEach(getInterfaceBaseTypeNodes(node), heritageElement => { - if (!isEntityNameExpression(heritageElement.expression) || isOptionalChain(heritageElement.expression)) { - error(heritageElement.expression, Diagnostics.An_interface_can_only_extend_an_identifier_Slashqualified_name_with_optional_type_arguments); + forEach(getInterfaceBaseTypeNodes(node), (heritageElement) => { + if ( + !isEntityNameExpression(heritageElement.expression) || + isOptionalChain(heritageElement.expression) + ) { + error( + heritageElement.expression, + Diagnostics.An_interface_can_only_extend_an_identifier_Slashqualified_name_with_optional_type_arguments + ); } checkTypeReferenceNode(heritageElement); }); @@ -47577,21 +82404,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkTypeAliasDeclaration(node: TypeAliasDeclaration) { // Grammar checking checkGrammarModifiers(node); - checkTypeNameIsReserved(node.name, Diagnostics.Type_alias_name_cannot_be_0); + checkTypeNameIsReserved( + node.name, + Diagnostics.Type_alias_name_cannot_be_0 + ); if (!allowBlockDeclarations(node.parent)) { - grammarErrorOnNode(node, Diagnostics._0_declarations_can_only_be_declared_inside_a_block, "type"); + grammarErrorOnNode( + node, + Diagnostics._0_declarations_can_only_be_declared_inside_a_block, + "type" + ); } checkExportsOnMergedDeclarations(node); checkTypeParameters(node.typeParameters); if (node.type.kind === SyntaxKind.IntrinsicKeyword) { const typeParameterCount = length(node.typeParameters); - const valid = typeParameterCount === 0 ? node.name.escapedText === "BuiltinIteratorReturn" : - typeParameterCount === 1 && intrinsicTypeKinds.has(node.name.escapedText as string); + const valid = + typeParameterCount === 0 + ? node.name.escapedText === "BuiltinIteratorReturn" + : typeParameterCount === 1 && + intrinsicTypeKinds.has(node.name.escapedText as string); if (!valid) { - error(node.type, Diagnostics.The_intrinsic_keyword_can_only_be_used_to_declare_compiler_provided_intrinsic_types); + error( + node.type, + Diagnostics.The_intrinsic_keyword_can_only_be_used_to_declare_compiler_provided_intrinsic_types + ); } - } - else { + } else { checkSourceElement(node.type); registerForUnusedIdentifiersCheck(node); } @@ -47604,25 +82443,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let autoValue: number | undefined = 0; let previous: EnumMember | undefined; for (const member of node.members) { - const result = computeEnumMemberValue(member, autoValue, previous); + const result = computeEnumMemberValue( + member, + autoValue, + previous + ); getNodeLinks(member).enumMemberValue = result; - autoValue = typeof result.value === "number" ? result.value + 1 : undefined; + autoValue = + typeof result.value === "number" + ? result.value + 1 + : undefined; previous = member; } } } - function computeEnumMemberValue(member: EnumMember, autoValue: number | undefined, previous: EnumMember | undefined): EvaluatorResult { + function computeEnumMemberValue( + member: EnumMember, + autoValue: number | undefined, + previous: EnumMember | undefined + ): EvaluatorResult { if (isComputedNonLiteralName(member.name)) { - error(member.name, Diagnostics.Computed_property_names_are_not_allowed_in_enums); - } - else if (isBigIntLiteral(member.name)) { - error(member.name, Diagnostics.An_enum_member_cannot_have_a_numeric_name); - } - else { + error( + member.name, + Diagnostics.Computed_property_names_are_not_allowed_in_enums + ); + } else if (isBigIntLiteral(member.name)) { + error( + member.name, + Diagnostics.An_enum_member_cannot_have_a_numeric_name + ); + } else { const text = getTextOfPropertyName(member.name); if (isNumericLiteralName(text) && !isInfinityOrNaNString(text)) { - error(member.name, Diagnostics.An_enum_member_cannot_have_a_numeric_name); + error( + member.name, + Diagnostics.An_enum_member_cannot_have_a_numeric_name + ); } } if (member.initializer) { @@ -47630,7 +82487,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // In ambient non-const numeric enum declarations, enum members without initializers are // considered computed members (as opposed to having auto-incremented values). - if (member.parent.flags & NodeFlags.Ambient && !isEnumConst(member.parent)) { + if ( + member.parent.flags & NodeFlags.Ambient && + !isEnumConst(member.parent) + ) { return evaluatorResult(/*value*/ undefined); } // If the member declaration specifies no value, the member is considered a constant enum member. @@ -47643,113 +82503,212 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (getIsolatedModules(compilerOptions) && previous?.initializer) { const prevValue = getEnumMemberValue(previous); - if (!(typeof prevValue.value === "number" && !prevValue.resolvedOtherFiles)) { + if ( + !( + typeof prevValue.value === "number" && + !prevValue.resolvedOtherFiles + ) + ) { error( member.name, - Diagnostics.Enum_member_following_a_non_literal_numeric_member_must_have_an_initializer_when_isolatedModules_is_enabled, + Diagnostics.Enum_member_following_a_non_literal_numeric_member_must_have_an_initializer_when_isolatedModules_is_enabled ); } } return evaluatorResult(autoValue); } - function computeConstantEnumMemberValue(member: EnumMember): EvaluatorResult { + function computeConstantEnumMemberValue( + member: EnumMember + ): EvaluatorResult { const isConstEnum = isEnumConst(member.parent); const initializer = member.initializer!; const result = evaluate(initializer, member); if (result.value !== undefined) { - if (isConstEnum && typeof result.value === "number" && !isFinite(result.value)) { + if ( + isConstEnum && + typeof result.value === "number" && + !isFinite(result.value) + ) { error( initializer, - isNaN(result.value) ? - Diagnostics.const_enum_member_initializer_was_evaluated_to_disallowed_value_NaN : - Diagnostics.const_enum_member_initializer_was_evaluated_to_a_non_finite_value, + isNaN(result.value) + ? Diagnostics.const_enum_member_initializer_was_evaluated_to_disallowed_value_NaN + : Diagnostics.const_enum_member_initializer_was_evaluated_to_a_non_finite_value ); - } - else if (getIsolatedModules(compilerOptions) && typeof result.value === "string" && !result.isSyntacticallyString) { + } else if ( + getIsolatedModules(compilerOptions) && + typeof result.value === "string" && + !result.isSyntacticallyString + ) { error( initializer, Diagnostics._0_has_a_string_type_but_must_have_syntactically_recognizable_string_syntax_when_isolatedModules_is_enabled, - `${idText(member.parent.name)}.${getTextOfPropertyName(member.name)}`, + `${idText(member.parent.name)}.${getTextOfPropertyName( + member.name + )}` ); } - } - else if (isConstEnum) { - error(initializer, Diagnostics.const_enum_member_initializers_must_be_constant_expressions); - } - else if (member.parent.flags & NodeFlags.Ambient) { - error(initializer, Diagnostics.In_ambient_enum_declarations_member_initializer_must_be_constant_expression); - } - else { - checkTypeAssignableTo(checkExpression(initializer), numberType, initializer, Diagnostics.Type_0_is_not_assignable_to_type_1_as_required_for_computed_enum_member_values); + } else if (isConstEnum) { + error( + initializer, + Diagnostics.const_enum_member_initializers_must_be_constant_expressions + ); + } else if (member.parent.flags & NodeFlags.Ambient) { + error( + initializer, + Diagnostics.In_ambient_enum_declarations_member_initializer_must_be_constant_expression + ); + } else { + checkTypeAssignableTo( + checkExpression(initializer), + numberType, + initializer, + Diagnostics.Type_0_is_not_assignable_to_type_1_as_required_for_computed_enum_member_values + ); } return result; } - function evaluateEntityNameExpression(expr: EntityNameExpression, location?: Declaration) { - const symbol = resolveEntityName(expr, SymbolFlags.Value, /*ignoreErrors*/ true); + function evaluateEntityNameExpression( + expr: EntityNameExpression, + location?: Declaration + ) { + const symbol = resolveEntityName( + expr, + SymbolFlags.Value, + /*ignoreErrors*/ true + ); if (!symbol) return evaluatorResult(/*value*/ undefined); if (expr.kind === SyntaxKind.Identifier) { const identifier = expr; - if (isInfinityOrNaNString(identifier.escapedText) && (symbol === getGlobalSymbol(identifier.escapedText, SymbolFlags.Value, /*diagnostic*/ undefined))) { + if ( + isInfinityOrNaNString(identifier.escapedText) && + symbol === + getGlobalSymbol( + identifier.escapedText, + SymbolFlags.Value, + /*diagnostic*/ undefined + ) + ) { // Technically we resolved a global lib file here, but the decision to treat this as numeric // is more predicated on the fact that the single-file resolution *didn't* resolve to a // different meaning of `Infinity` or `NaN`. Transpilers handle this no problem. - return evaluatorResult(+(identifier.escapedText), /*isSyntacticallyString*/ false); + return evaluatorResult( + +identifier.escapedText, + /*isSyntacticallyString*/ false + ); } } if (symbol.flags & SymbolFlags.EnumMember) { - return location ? evaluateEnumMember(expr, symbol, location) : getEnumMemberValue(symbol.valueDeclaration as EnumMember); + return location + ? evaluateEnumMember(expr, symbol, location) + : getEnumMemberValue(symbol.valueDeclaration as EnumMember); } if (isConstantVariable(symbol)) { const declaration = symbol.valueDeclaration; - if (declaration && isVariableDeclaration(declaration) && !declaration.type && declaration.initializer && (!location || declaration !== location && isBlockScopedNameDeclaredBeforeUse(declaration, location))) { + if ( + declaration && + isVariableDeclaration(declaration) && + !declaration.type && + declaration.initializer && + (!location || + (declaration !== location && + isBlockScopedNameDeclaredBeforeUse( + declaration, + location + ))) + ) { const result = evaluate(declaration.initializer, declaration); - if (location && getSourceFileOfNode(location) !== getSourceFileOfNode(declaration)) { + if ( + location && + getSourceFileOfNode(location) !== + getSourceFileOfNode(declaration) + ) { return evaluatorResult( result.value, /*isSyntacticallyString*/ false, /*resolvedOtherFiles*/ true, - /*hasExternalReferences*/ true, + /*hasExternalReferences*/ true ); } - return evaluatorResult(result.value, result.isSyntacticallyString, result.resolvedOtherFiles, /*hasExternalReferences*/ true); + return evaluatorResult( + result.value, + result.isSyntacticallyString, + result.resolvedOtherFiles, + /*hasExternalReferences*/ true + ); } } return evaluatorResult(/*value*/ undefined); } - function evaluateElementAccessExpression(expr: ElementAccessExpression, location?: Declaration) { + function evaluateElementAccessExpression( + expr: ElementAccessExpression, + location?: Declaration + ) { const root = expr.expression; - if (isEntityNameExpression(root) && isStringLiteralLike(expr.argumentExpression)) { - const rootSymbol = resolveEntityName(root, SymbolFlags.Value, /*ignoreErrors*/ true); + if ( + isEntityNameExpression(root) && + isStringLiteralLike(expr.argumentExpression) + ) { + const rootSymbol = resolveEntityName( + root, + SymbolFlags.Value, + /*ignoreErrors*/ true + ); if (rootSymbol && rootSymbol.flags & SymbolFlags.Enum) { - const name = escapeLeadingUnderscores(expr.argumentExpression.text); + const name = escapeLeadingUnderscores( + expr.argumentExpression.text + ); const member = rootSymbol.exports!.get(name); if (member) { - Debug.assert(getSourceFileOfNode(member.valueDeclaration) === getSourceFileOfNode(rootSymbol.valueDeclaration)); - return location ? evaluateEnumMember(expr, member, location) : getEnumMemberValue(member.valueDeclaration as EnumMember); + Debug.assert( + getSourceFileOfNode(member.valueDeclaration) === + getSourceFileOfNode(rootSymbol.valueDeclaration) + ); + return location + ? evaluateEnumMember(expr, member, location) + : getEnumMemberValue( + member.valueDeclaration as EnumMember + ); } } } return evaluatorResult(/*value*/ undefined); } - function evaluateEnumMember(expr: Expression, symbol: Symbol, location: Declaration) { + function evaluateEnumMember( + expr: Expression, + symbol: Symbol, + location: Declaration + ) { const declaration = symbol.valueDeclaration; if (!declaration || declaration === location) { - error(expr, Diagnostics.Property_0_is_used_before_being_assigned, symbolToString(symbol)); + error( + expr, + Diagnostics.Property_0_is_used_before_being_assigned, + symbolToString(symbol) + ); return evaluatorResult(/*value*/ undefined); } if (!isBlockScopedNameDeclaredBeforeUse(declaration, location)) { - error(expr, Diagnostics.A_member_initializer_in_a_enum_declaration_cannot_reference_members_declared_after_it_including_members_defined_in_other_enums); + error( + expr, + Diagnostics.A_member_initializer_in_a_enum_declaration_cannot_reference_members_declared_after_it_including_members_defined_in_other_enums + ); return evaluatorResult(/*value*/ 0); } const value = getEnumMemberValue(declaration as EnumMember); if (location.parent !== declaration.parent) { - return evaluatorResult(value.value, value.isSyntacticallyString, value.resolvedOtherFiles, /*hasExternalReferences*/ true); + return evaluatorResult( + value.value, + value.isSyntacticallyString, + value.resolvedOtherFiles, + /*hasExternalReferences*/ true + ); } return value; } @@ -47766,8 +82725,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkExportsOnMergedDeclarations(node); node.members.forEach(checkSourceElement); - if (compilerOptions.erasableSyntaxOnly && !(node.flags & NodeFlags.Ambient)) { - error(node, Diagnostics.This_syntax_is_not_allowed_when_erasableSyntaxOnly_is_enabled); + if ( + compilerOptions.erasableSyntaxOnly && + !(node.flags & NodeFlags.Ambient) + ) { + error( + node, + Diagnostics.This_syntax_is_not_allowed_when_erasableSyntaxOnly_is_enabled + ); } computeEnumMemberValues(node); @@ -47784,15 +82749,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (enumSymbol.declarations && enumSymbol.declarations.length > 1) { const enumIsConst = isEnumConst(node); // check that const is placed\omitted on all enum declarations - forEach(enumSymbol.declarations, decl => { - if (isEnumDeclaration(decl) && isEnumConst(decl) !== enumIsConst) { - error(getNameOfDeclaration(decl), Diagnostics.Enum_declarations_must_all_be_const_or_non_const); + forEach(enumSymbol.declarations, (decl) => { + if ( + isEnumDeclaration(decl) && + isEnumConst(decl) !== enumIsConst + ) { + error( + getNameOfDeclaration(decl), + Diagnostics.Enum_declarations_must_all_be_const_or_non_const + ); } }); } let seenEnumMissingInitialInitializer = false; - forEach(enumSymbol.declarations, declaration => { + forEach(enumSymbol.declarations, (declaration) => { // return true if we hit a violation of the rule, false otherwise if (declaration.kind !== SyntaxKind.EnumDeclaration) { return false; @@ -47806,9 +82777,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const firstEnumMember = enumDeclaration.members[0]; if (!firstEnumMember.initializer) { if (seenEnumMissingInitialInitializer) { - error(firstEnumMember.name, Diagnostics.In_an_enum_with_multiple_declarations_only_one_declaration_can_omit_an_initializer_for_its_first_enum_element); - } - else { + error( + firstEnumMember.name, + Diagnostics.In_an_enum_with_multiple_declarations_only_one_declaration_can_omit_an_initializer_for_its_first_enum_element + ); + } else { seenEnumMissingInitialInitializer = true; } } @@ -47818,20 +82791,41 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkEnumMember(node: EnumMember) { if (isPrivateIdentifier(node.name)) { - error(node, Diagnostics.An_enum_member_cannot_be_named_with_a_private_identifier); + error( + node, + Diagnostics.An_enum_member_cannot_be_named_with_a_private_identifier + ); + } + + if ( + isComputedPropertyName(node.name) && + isStringLiteralLike(node.name.expression) + ) { + suggestionDiagnostics.add( + createDiagnosticForNode( + node.name, + Diagnostics.Enum_member_keys_should_not_use_computed_strings_like_A_Use_a_string_literal_instead_for_clarity_and_compatibility + ) + ); } + if (node.initializer) { checkExpression(node.initializer); } } - function getFirstNonAmbientClassOrFunctionDeclaration(symbol: Symbol): Declaration | undefined { + function getFirstNonAmbientClassOrFunctionDeclaration( + symbol: Symbol + ): Declaration | undefined { const declarations = symbol.declarations; if (declarations) { for (const declaration of declarations) { if ( (declaration.kind === SyntaxKind.ClassDeclaration || - (declaration.kind === SyntaxKind.FunctionDeclaration && nodeIsPresent((declaration as FunctionLikeDeclaration).body))) && + (declaration.kind === SyntaxKind.FunctionDeclaration && + nodeIsPresent( + (declaration as FunctionLikeDeclaration).body + ))) && !(declaration.flags & NodeFlags.Ambient) ) { return declaration; @@ -47846,11 +82840,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const container2 = getEnclosingBlockScopeContainer(node2); if (isGlobalSourceFile(container1)) { return isGlobalSourceFile(container2); - } - else if (isGlobalSourceFile(container2)) { + } else if (isGlobalSourceFile(container2)) { return false; - } - else { + } else { return container1 === container2; } } @@ -47870,7 +82862,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const isGlobalAugmentation = isGlobalScopeAugmentation(node); const inAmbientContext = node.flags & NodeFlags.Ambient; if (isGlobalAugmentation && !inAmbientContext) { - error(node.name, Diagnostics.Augmentations_for_the_global_scope_should_have_declare_modifier_unless_they_appear_in_already_ambient_context); + error( + node.name, + Diagnostics.Augmentations_for_the_global_scope_should_have_declare_modifier_unless_they_appear_in_already_ambient_context + ); } const isAmbientExternalModule: boolean = isAmbientModule(node); @@ -47883,19 +82878,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (!checkGrammarModifiers(node)) { - if (!inAmbientContext && node.name.kind === SyntaxKind.StringLiteral) { - grammarErrorOnNode(node.name, Diagnostics.Only_ambient_modules_can_use_quoted_names); + if ( + !inAmbientContext && + node.name.kind === SyntaxKind.StringLiteral + ) { + grammarErrorOnNode( + node.name, + Diagnostics.Only_ambient_modules_can_use_quoted_names + ); } } if (isIdentifier(node.name)) { checkCollisionsForDeclarationName(node, node.name); - if (!(node.flags & (NodeFlags.Namespace | NodeFlags.GlobalAugmentation))) { + if ( + !( + node.flags & + (NodeFlags.Namespace | NodeFlags.GlobalAugmentation) + ) + ) { const sourceFile = getSourceFileOfNode(node); const pos = getNonModifierTokenPosOfNode(node); const span = getSpanOfTokenAtPosition(sourceFile, pos); suggestionDiagnostics.add( - createFileDiagnostic(sourceFile, span.start, span.length, Diagnostics.A_namespace_declaration_should_not_be_declared_using_the_module_keyword_Please_use_the_namespace_keyword_instead), + createFileDiagnostic( + sourceFile, + span.start, + span.length, + Diagnostics.A_namespace_declaration_should_not_be_declared_using_the_module_keyword_Please_use_the_namespace_keyword_instead + ) ); } } @@ -47905,49 +82916,78 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // The following checks only apply on a non-ambient instantiated module declaration. if ( - symbol.flags & SymbolFlags.ValueModule - && !inAmbientContext - && isInstantiatedModule(node, shouldPreserveConstEnums(compilerOptions)) + symbol.flags & SymbolFlags.ValueModule && + !inAmbientContext && + isInstantiatedModule( + node, + shouldPreserveConstEnums(compilerOptions) + ) ) { if (compilerOptions.erasableSyntaxOnly) { - error(node.name, Diagnostics.This_syntax_is_not_allowed_when_erasableSyntaxOnly_is_enabled); + error( + node.name, + Diagnostics.This_syntax_is_not_allowed_when_erasableSyntaxOnly_is_enabled + ); } - if (getIsolatedModules(compilerOptions) && !getSourceFileOfNode(node).externalModuleIndicator) { + if ( + getIsolatedModules(compilerOptions) && + !getSourceFileOfNode(node).externalModuleIndicator + ) { // This could be loosened a little if needed. The only problem we are trying to avoid is unqualified // references to namespace members declared in other files. But use of namespaces is discouraged anyway, // so for now we will just not allow them in scripts, which is the only place they can merge cross-file. - error(node.name, Diagnostics.Namespaces_are_not_allowed_in_global_script_files_when_0_is_enabled_If_this_file_is_not_intended_to_be_a_global_script_set_moduleDetection_to_force_or_add_an_empty_export_statement, isolatedModulesLikeFlagName); + error( + node.name, + Diagnostics.Namespaces_are_not_allowed_in_global_script_files_when_0_is_enabled_If_this_file_is_not_intended_to_be_a_global_script_set_moduleDetection_to_force_or_add_an_empty_export_statement, + isolatedModulesLikeFlagName + ); } if (symbol.declarations?.length! > 1) { - const firstNonAmbientClassOrFunc = getFirstNonAmbientClassOrFunctionDeclaration(symbol); + const firstNonAmbientClassOrFunc = + getFirstNonAmbientClassOrFunctionDeclaration(symbol); if (firstNonAmbientClassOrFunc) { - if (getSourceFileOfNode(node) !== getSourceFileOfNode(firstNonAmbientClassOrFunc)) { - error(node.name, Diagnostics.A_namespace_declaration_cannot_be_in_a_different_file_from_a_class_or_function_with_which_it_is_merged); - } - else if (node.pos < firstNonAmbientClassOrFunc.pos) { - error(node.name, Diagnostics.A_namespace_declaration_cannot_be_located_prior_to_a_class_or_function_with_which_it_is_merged); + if ( + getSourceFileOfNode(node) !== + getSourceFileOfNode(firstNonAmbientClassOrFunc) + ) { + error( + node.name, + Diagnostics.A_namespace_declaration_cannot_be_in_a_different_file_from_a_class_or_function_with_which_it_is_merged + ); + } else if (node.pos < firstNonAmbientClassOrFunc.pos) { + error( + node.name, + Diagnostics.A_namespace_declaration_cannot_be_located_prior_to_a_class_or_function_with_which_it_is_merged + ); } } // if the module merges with a class declaration in the same lexical scope, // we need to track this to ensure the correct emit. - const mergedClass = getDeclarationOfKind(symbol, SyntaxKind.ClassDeclaration); - if ( - mergedClass && - inSameLexicalScope(node, mergedClass) - ) { - getNodeLinks(node).flags |= NodeCheckFlags.LexicalModuleMergesWithClass; + const mergedClass = getDeclarationOfKind( + symbol, + SyntaxKind.ClassDeclaration + ); + if (mergedClass && inSameLexicalScope(node, mergedClass)) { + getNodeLinks(node).flags |= + NodeCheckFlags.LexicalModuleMergesWithClass; } } if ( compilerOptions.verbatimModuleSyntax && node.parent.kind === SyntaxKind.SourceFile && - host.getEmitModuleFormatOfFile(node.parent) === ModuleKind.CommonJS + host.getEmitModuleFormatOfFile(node.parent) === + ModuleKind.CommonJS ) { - const exportModifier = node.modifiers?.find(m => m.kind === SyntaxKind.ExportKeyword); + const exportModifier = node.modifiers?.find( + (m) => m.kind === SyntaxKind.ExportKeyword + ); if (exportModifier) { - error(exportModifier, Diagnostics.A_top_level_export_modifier_cannot_be_used_on_value_declarations_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled); + error( + exportModifier, + Diagnostics.A_top_level_export_modifier_cannot_be_used_on_value_declarations_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled + ); } } } @@ -47959,65 +82999,97 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We can detect if augmentation was applied using following rules: // - augmentation for a global scope is always applied // - augmentation for some external module is applied if symbol for augmentation is merged (it was combined with target module). - const checkBody = isGlobalAugmentation || (getSymbolOfDeclaration(node).flags & SymbolFlags.Transient); + const checkBody = + isGlobalAugmentation || + getSymbolOfDeclaration(node).flags & + SymbolFlags.Transient; if (checkBody && node.body) { for (const statement of node.body.statements) { - checkModuleAugmentationElement(statement, isGlobalAugmentation); + checkModuleAugmentationElement( + statement, + isGlobalAugmentation + ); } } - } - else if (isGlobalSourceFile(node.parent)) { + } else if (isGlobalSourceFile(node.parent)) { if (isGlobalAugmentation) { - error(node.name, Diagnostics.Augmentations_for_the_global_scope_can_only_be_directly_nested_in_external_modules_or_ambient_module_declarations); - } - else if (isExternalModuleNameRelative(getTextOfIdentifierOrLiteral(node.name))) { - error(node.name, Diagnostics.Ambient_module_declaration_cannot_specify_relative_module_name); + error( + node.name, + Diagnostics.Augmentations_for_the_global_scope_can_only_be_directly_nested_in_external_modules_or_ambient_module_declarations + ); + } else if ( + isExternalModuleNameRelative( + getTextOfIdentifierOrLiteral(node.name) + ) + ) { + error( + node.name, + Diagnostics.Ambient_module_declaration_cannot_specify_relative_module_name + ); } - } - else { + } else { if (isGlobalAugmentation) { - error(node.name, Diagnostics.Augmentations_for_the_global_scope_can_only_be_directly_nested_in_external_modules_or_ambient_module_declarations); - } - else { + error( + node.name, + Diagnostics.Augmentations_for_the_global_scope_can_only_be_directly_nested_in_external_modules_or_ambient_module_declarations + ); + } else { // Node is not an augmentation and is not located on the script level. // This means that this is declaration of ambient module that is located in other module or namespace which is prohibited. - error(node.name, Diagnostics.Ambient_modules_cannot_be_nested_in_other_modules_or_namespaces); + error( + node.name, + Diagnostics.Ambient_modules_cannot_be_nested_in_other_modules_or_namespaces + ); } } } } } - function checkModuleAugmentationElement(node: Node, isGlobalAugmentation: boolean): void { + function checkModuleAugmentationElement( + node: Node, + isGlobalAugmentation: boolean + ): void { switch (node.kind) { case SyntaxKind.VariableStatement: // error each individual name in variable statement instead of marking the entire variable statement - for (const decl of (node as VariableStatement).declarationList.declarations) { + for (const decl of (node as VariableStatement).declarationList + .declarations) { checkModuleAugmentationElement(decl, isGlobalAugmentation); } break; case SyntaxKind.ExportAssignment: case SyntaxKind.ExportDeclaration: - grammarErrorOnFirstToken(node, Diagnostics.Exports_and_export_assignments_are_not_permitted_in_module_augmentations); + grammarErrorOnFirstToken( + node, + Diagnostics.Exports_and_export_assignments_are_not_permitted_in_module_augmentations + ); break; case SyntaxKind.ImportEqualsDeclaration: // import a = e.x; in module augmentation is ok, but not import a = require('fs) if (isInternalModuleImportEqualsDeclaration(node)) break; - // falls through + // falls through case SyntaxKind.ImportDeclaration: - grammarErrorOnFirstToken(node, Diagnostics.Imports_are_not_permitted_in_module_augmentations_Consider_moving_them_to_the_enclosing_external_module); + grammarErrorOnFirstToken( + node, + Diagnostics.Imports_are_not_permitted_in_module_augmentations_Consider_moving_them_to_the_enclosing_external_module + ); break; case SyntaxKind.BindingElement: case SyntaxKind.VariableDeclaration: - const name = (node as VariableDeclaration | BindingElement).name; + const name = (node as VariableDeclaration | BindingElement) + .name; if (isBindingPattern(name)) { for (const el of name.elements) { // mark individual names in binding pattern - checkModuleAugmentationElement(el, isGlobalAugmentation); + checkModuleAugmentationElement( + el, + isGlobalAugmentation + ); } break; } - // falls through + // falls through case SyntaxKind.ClassDeclaration: case SyntaxKind.EnumDeclaration: case SyntaxKind.FunctionDeclaration: @@ -48031,29 +83103,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getFirstNonModuleExportsIdentifier(node: EntityNameOrEntityNameExpression): Identifier { + function getFirstNonModuleExportsIdentifier( + node: EntityNameOrEntityNameExpression + ): Identifier { switch (node.kind) { case SyntaxKind.Identifier: return node; case SyntaxKind.QualifiedName: do { node = node.left; - } - while (node.kind !== SyntaxKind.Identifier); + } while (node.kind !== SyntaxKind.Identifier); return node; case SyntaxKind.PropertyAccessExpression: do { - if (isModuleExportsAccessExpression(node.expression) && !isPrivateIdentifier(node.name)) { + if ( + isModuleExportsAccessExpression(node.expression) && + !isPrivateIdentifier(node.name) + ) { return node.name; } node = node.expression; - } - while (node.kind !== SyntaxKind.Identifier); + } while (node.kind !== SyntaxKind.Identifier); return node; } } - function checkExternalImportOrExportDeclaration(node: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration): boolean { + function checkExternalImportOrExportDeclaration( + node: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration + ): boolean { const moduleName = getExternalModuleName(node); if (!moduleName || nodeIsMissing(moduleName)) { // Should be a parse error. @@ -48063,17 +83140,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { error(moduleName, Diagnostics.String_literal_expected); return false; } - const inAmbientExternalModule = node.parent.kind === SyntaxKind.ModuleBlock && isAmbientModule(node.parent.parent); - if (node.parent.kind !== SyntaxKind.SourceFile && !inAmbientExternalModule) { + const inAmbientExternalModule = + node.parent.kind === SyntaxKind.ModuleBlock && + isAmbientModule(node.parent.parent); + if ( + node.parent.kind !== SyntaxKind.SourceFile && + !inAmbientExternalModule + ) { error( moduleName, - node.kind === SyntaxKind.ExportDeclaration ? - Diagnostics.Export_declarations_are_not_permitted_in_a_namespace : - Diagnostics.Import_declarations_in_a_namespace_cannot_reference_a_module, + node.kind === SyntaxKind.ExportDeclaration + ? Diagnostics.Export_declarations_are_not_permitted_in_a_namespace + : Diagnostics.Import_declarations_in_a_namespace_cannot_reference_a_module ); return false; } - if (inAmbientExternalModule && isExternalModuleNameRelative(moduleName.text)) { + if ( + inAmbientExternalModule && + isExternalModuleNameRelative(moduleName.text) + ) { // we have already reported errors on top level imports/exports in external module augmentations in checkModuleDeclaration // no need to do this again. if (!isTopLevelInExternalModuleAugmentation(node)) { @@ -48081,12 +83166,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // An ExternalImportDeclaration in an AmbientExternalModuleDeclaration may reference // other external modules only through top - level external module names. // Relative external module names are not permitted. - error(node, Diagnostics.Import_or_export_declaration_in_an_ambient_module_declaration_cannot_reference_module_through_relative_module_name); + error( + node, + Diagnostics.Import_or_export_declaration_in_an_ambient_module_declaration_cannot_reference_module_through_relative_module_name + ); return false; } } if (!isImportEqualsDeclaration(node) && node.attributes) { - const diagnostic = node.attributes.token === SyntaxKind.WithKeyword ? Diagnostics.Import_attribute_values_must_be_string_literal_expressions : Diagnostics.Import_assertion_values_must_be_string_literal_expressions; + const diagnostic = + node.attributes.token === SyntaxKind.WithKeyword + ? Diagnostics.Import_attribute_values_must_be_string_literal_expressions + : Diagnostics.Import_assertion_values_must_be_string_literal_expressions; let hasError = false; for (const attr of node.attributes.elements) { if (!isStringLiteral(attr.value)) { @@ -48099,15 +83190,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; } - function checkModuleExportName(name: ModuleExportName | undefined, allowStringLiteral = true) { + function checkModuleExportName( + name: ModuleExportName | undefined, + allowStringLiteral = true + ) { if (name === undefined || name.kind !== SyntaxKind.StringLiteral) { return; } if (!allowStringLiteral) { grammarErrorOnNode(name, Diagnostics.Identifier_expected); - } - else if (moduleKind === ModuleKind.ES2015 || moduleKind === ModuleKind.ES2020) { - grammarErrorOnNode(name, Diagnostics.String_literal_import_and_export_names_are_not_supported_when_the_module_flag_is_set_to_es2015_or_es2020); + } else if ( + moduleKind === ModuleKind.ES2015 || + moduleKind === ModuleKind.ES2020 + ) { + grammarErrorOnNode( + name, + Diagnostics.String_literal_import_and_export_names_are_not_supported_when_the_module_flag_is_set_to_es2015_or_es2020 + ); } } @@ -48125,72 +83224,113 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { symbol = getMergedSymbol(symbol.exportSymbol || symbol); // A type-only import/export will already have a grammar error in a JS file, so no need to issue more errors within - if (isInJSFile(node) && !(target.flags & SymbolFlags.Value) && !isTypeOnlyImportOrExportDeclaration(node)) { - const errorNode = isImportOrExportSpecifier(node) ? node.propertyName || node.name : - isNamedDeclaration(node) ? node.name : - node; + if ( + isInJSFile(node) && + !(target.flags & SymbolFlags.Value) && + !isTypeOnlyImportOrExportDeclaration(node) + ) { + const errorNode = isImportOrExportSpecifier(node) + ? node.propertyName || node.name + : isNamedDeclaration(node) + ? node.name + : node; Debug.assert(node.kind !== SyntaxKind.NamespaceExport); if (node.kind === SyntaxKind.ExportSpecifier) { - const diag = error(errorNode, Diagnostics.Types_cannot_appear_in_export_declarations_in_JavaScript_files); - const alreadyExportedSymbol = getSourceFileOfNode(node).symbol?.exports?.get(moduleExportNameTextEscaped(node.propertyName || node.name)); + const diag = error( + errorNode, + Diagnostics.Types_cannot_appear_in_export_declarations_in_JavaScript_files + ); + const alreadyExportedSymbol = getSourceFileOfNode( + node + ).symbol?.exports?.get( + moduleExportNameTextEscaped( + node.propertyName || node.name + ) + ); if (alreadyExportedSymbol === target) { - const exportingDeclaration = alreadyExportedSymbol.declarations?.find(isJSDocNode); + const exportingDeclaration = + alreadyExportedSymbol.declarations?.find( + isJSDocNode + ); if (exportingDeclaration) { addRelatedInfo( diag, createDiagnosticForNode( exportingDeclaration, Diagnostics._0_is_automatically_exported_here, - unescapeLeadingUnderscores(alreadyExportedSymbol.escapedName), - ), + unescapeLeadingUnderscores( + alreadyExportedSymbol.escapedName + ) + ) ); } } - } - else { + } else { Debug.assert(node.kind !== SyntaxKind.VariableDeclaration); - const importDeclaration = findAncestor(node, or(isImportDeclaration, isImportEqualsDeclaration)); - const moduleSpecifier = (importDeclaration && tryGetModuleSpecifierFromDeclaration(importDeclaration)?.text) ?? "..."; - const importedIdentifier = unescapeLeadingUnderscores(isIdentifier(errorNode) ? errorNode.escapedText : symbol.escapedName); + const importDeclaration = findAncestor( + node, + or(isImportDeclaration, isImportEqualsDeclaration) + ); + const moduleSpecifier = + (importDeclaration && + tryGetModuleSpecifierFromDeclaration( + importDeclaration + )?.text) ?? + "..."; + const importedIdentifier = unescapeLeadingUnderscores( + isIdentifier(errorNode) + ? errorNode.escapedText + : symbol.escapedName + ); error( errorNode, Diagnostics._0_is_a_type_and_cannot_be_imported_in_JavaScript_files_Use_1_in_a_JSDoc_type_annotation, importedIdentifier, - `import("${moduleSpecifier}").${importedIdentifier}`, + `import("${moduleSpecifier}").${importedIdentifier}` ); } return; } const targetFlags = getSymbolFlags(target); - const excludedMeanings = (symbol.flags & (SymbolFlags.Value | SymbolFlags.ExportValue) ? SymbolFlags.Value : 0) | + const excludedMeanings = + (symbol.flags & (SymbolFlags.Value | SymbolFlags.ExportValue) + ? SymbolFlags.Value + : 0) | (symbol.flags & SymbolFlags.Type ? SymbolFlags.Type : 0) | - (symbol.flags & SymbolFlags.Namespace ? SymbolFlags.Namespace : 0); + (symbol.flags & SymbolFlags.Namespace + ? SymbolFlags.Namespace + : 0); if (targetFlags & excludedMeanings) { - const message = node.kind === SyntaxKind.ExportSpecifier ? - Diagnostics.Export_declaration_conflicts_with_exported_declaration_of_0 : - Diagnostics.Import_declaration_conflicts_with_local_declaration_of_0; + const message = + node.kind === SyntaxKind.ExportSpecifier + ? Diagnostics.Export_declaration_conflicts_with_exported_declaration_of_0 + : Diagnostics.Import_declaration_conflicts_with_local_declaration_of_0; error(node, message, symbolToString(symbol)); - } - else if (node.kind !== SyntaxKind.ExportSpecifier) { + } else if (node.kind !== SyntaxKind.ExportSpecifier) { // Look at 'compilerOptions.isolatedModules' and not 'getIsolatedModules(...)' (which considers 'verbatimModuleSyntax') // here because 'verbatimModuleSyntax' will already have an error for importing a type without 'import type'. - const appearsValueyToTranspiler = compilerOptions.isolatedModules && !findAncestor(node, isTypeOnlyImportOrExportDeclaration); - if (appearsValueyToTranspiler && symbol.flags & (SymbolFlags.Value | SymbolFlags.ExportValue)) { + const appearsValueyToTranspiler = + compilerOptions.isolatedModules && + !findAncestor(node, isTypeOnlyImportOrExportDeclaration); + if ( + appearsValueyToTranspiler && + symbol.flags & (SymbolFlags.Value | SymbolFlags.ExportValue) + ) { error( node, Diagnostics.Import_0_conflicts_with_local_value_so_must_be_declared_with_a_type_only_import_when_isolatedModules_is_enabled, symbolToString(symbol), - isolatedModulesLikeFlagName, + isolatedModulesLikeFlagName ); } } if ( - getIsolatedModules(compilerOptions) - && !isTypeOnlyImportOrExportDeclaration(node) - && !(node.flags & NodeFlags.Ambient) + getIsolatedModules(compilerOptions) && + !isTypeOnlyImportOrExportDeclaration(node) && + !(node.flags & NodeFlags.Ambient) ) { const typeOnlyAlias = getTypeOnlyAliasDeclaration(symbol); const isType = !(targetFlags & SymbolFlags.Value); @@ -48200,21 +83340,41 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ImportSpecifier: case SyntaxKind.ImportEqualsDeclaration: { if (compilerOptions.verbatimModuleSyntax) { - Debug.assertIsDefined(node.name, "An ImportClause with a symbol should have a name"); - const message = compilerOptions.verbatimModuleSyntax && isInternalModuleImportEqualsDeclaration(node) - ? Diagnostics.An_import_alias_cannot_resolve_to_a_type_or_type_only_declaration_when_verbatimModuleSyntax_is_enabled - : isType - ? Diagnostics._0_is_a_type_and_must_be_imported_using_a_type_only_import_when_verbatimModuleSyntax_is_enabled - : Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_imported_using_a_type_only_import_when_verbatimModuleSyntax_is_enabled; - const name = moduleExportNameTextUnescaped(node.kind === SyntaxKind.ImportSpecifier ? node.propertyName || node.name : node.name); + Debug.assertIsDefined( + node.name, + "An ImportClause with a symbol should have a name" + ); + const message = + compilerOptions.verbatimModuleSyntax && + isInternalModuleImportEqualsDeclaration( + node + ) + ? Diagnostics.An_import_alias_cannot_resolve_to_a_type_or_type_only_declaration_when_verbatimModuleSyntax_is_enabled + : isType + ? Diagnostics._0_is_a_type_and_must_be_imported_using_a_type_only_import_when_verbatimModuleSyntax_is_enabled + : Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_imported_using_a_type_only_import_when_verbatimModuleSyntax_is_enabled; + const name = moduleExportNameTextUnescaped( + node.kind === SyntaxKind.ImportSpecifier + ? node.propertyName || node.name + : node.name + ); addTypeOnlyDeclarationRelatedInfo( error(node, message, name), isType ? undefined : typeOnlyAlias, - name, + name ); } - if (isType && node.kind === SyntaxKind.ImportEqualsDeclaration && hasEffectiveModifier(node, ModifierFlags.Export)) { - error(node, Diagnostics.Cannot_use_export_import_on_a_type_or_type_only_namespace_when_0_is_enabled, isolatedModulesLikeFlagName); + if ( + isType && + node.kind === + SyntaxKind.ImportEqualsDeclaration && + hasEffectiveModifier(node, ModifierFlags.Export) + ) { + error( + node, + Diagnostics.Cannot_use_export_import_on_a_type_or_type_only_namespace_when_0_is_enabled, + isolatedModulesLikeFlagName + ); } break; } @@ -48222,12 +83382,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Don't allow re-exporting an export that will be elided when `--isolatedModules` is set. // The exception is that `import type { A } from './a'; export { A }` is allowed // because single-file analysis can determine that the export should be dropped. - if (compilerOptions.verbatimModuleSyntax || getSourceFileOfNode(typeOnlyAlias) !== getSourceFileOfNode(node)) { - const name = moduleExportNameTextUnescaped(node.propertyName || node.name); + if ( + compilerOptions.verbatimModuleSyntax || + getSourceFileOfNode(typeOnlyAlias) !== + getSourceFileOfNode(node) + ) { + const name = moduleExportNameTextUnescaped( + node.propertyName || node.name + ); const diagnostic = isType - ? error(node, Diagnostics.Re_exporting_a_type_when_0_is_enabled_requires_using_export_type, isolatedModulesLikeFlagName) - : error(node, Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_re_exported_using_a_type_only_re_export_when_1_is_enabled, name, isolatedModulesLikeFlagName); - addTypeOnlyDeclarationRelatedInfo(diagnostic, isType ? undefined : typeOnlyAlias, name); + ? error( + node, + Diagnostics.Re_exporting_a_type_when_0_is_enabled_requires_using_export_type, + isolatedModulesLikeFlagName + ) + : error( + node, + Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_re_exported_using_a_type_only_re_export_when_1_is_enabled, + name, + isolatedModulesLikeFlagName + ); + addTypeOnlyDeclarationRelatedInfo( + diagnostic, + isType ? undefined : typeOnlyAlias, + name + ); break; } } @@ -48238,21 +83417,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { compilerOptions.verbatimModuleSyntax && node.kind !== SyntaxKind.ImportEqualsDeclaration && !isInJSFile(node) && - host.getEmitModuleFormatOfFile(getSourceFileOfNode(node)) === ModuleKind.CommonJS + host.getEmitModuleFormatOfFile( + getSourceFileOfNode(node) + ) === ModuleKind.CommonJS ) { - error(node, Diagnostics.ESM_syntax_is_not_allowed_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled); - } - else if ( + error( + node, + Diagnostics.ESM_syntax_is_not_allowed_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled + ); + } else if ( moduleKind === ModuleKind.Preserve && node.kind !== SyntaxKind.ImportEqualsDeclaration && node.kind !== SyntaxKind.VariableDeclaration && - host.getEmitModuleFormatOfFile(getSourceFileOfNode(node)) === ModuleKind.CommonJS + host.getEmitModuleFormatOfFile( + getSourceFileOfNode(node) + ) === ModuleKind.CommonJS ) { // In `--module preserve`, ESM input syntax emits ESM output syntax, but there will be times // when we look at the `impliedNodeFormat` of this file and decide it's CommonJS (i.e., currently, // only if the file extension is .cjs/.cts). To avoid that inconsistency, we disallow ESM syntax // in files that are unambiguously CommonJS in this mode. - error(node, Diagnostics.ESM_syntax_is_not_allowed_in_a_CommonJS_module_when_module_is_set_to_preserve); + error( + node, + Diagnostics.ESM_syntax_is_not_allowed_in_a_CommonJS_module_when_module_is_set_to_preserve + ); } if ( @@ -48261,25 +83449,52 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { !(node.flags & NodeFlags.Ambient) && targetFlags & SymbolFlags.ConstEnum ) { - const constEnumDeclaration = target.valueDeclaration as EnumDeclaration; - const redirect = host.getRedirectFromOutput(getSourceFileOfNode(constEnumDeclaration).resolvedPath)?.resolvedRef; - if (constEnumDeclaration.flags & NodeFlags.Ambient && (!redirect || !shouldPreserveConstEnums(redirect.commandLine.options))) { - error(node, Diagnostics.Cannot_access_ambient_const_enums_when_0_is_enabled, isolatedModulesLikeFlagName); + const constEnumDeclaration = + target.valueDeclaration as EnumDeclaration; + const redirect = host.getRedirectFromOutput( + getSourceFileOfNode(constEnumDeclaration).resolvedPath + )?.resolvedRef; + if ( + constEnumDeclaration.flags & NodeFlags.Ambient && + (!redirect || + !shouldPreserveConstEnums( + redirect.commandLine.options + )) + ) { + error( + node, + Diagnostics.Cannot_access_ambient_const_enums_when_0_is_enabled, + isolatedModulesLikeFlagName + ); } } } if (isImportSpecifier(node)) { - const targetSymbol = resolveAliasWithDeprecationCheck(symbol, node); - if (isDeprecatedSymbol(targetSymbol) && targetSymbol.declarations) { - addDeprecatedSuggestion(node, targetSymbol.declarations, targetSymbol.escapedName as string); + const targetSymbol = resolveAliasWithDeprecationCheck( + symbol, + node + ); + if ( + isDeprecatedSymbol(targetSymbol) && + targetSymbol.declarations + ) { + addDeprecatedSuggestion( + node, + targetSymbol.declarations, + targetSymbol.escapedName as string + ); } } } } function resolveAliasWithDeprecationCheck(symbol: Symbol, location: Node) { - if (!(symbol.flags & SymbolFlags.Alias) || isDeprecatedSymbol(symbol) || !getDeclarationOfAliasSymbol(symbol)) { + if ( + !(symbol.flags & SymbolFlags.Alias) || + isDeprecatedSymbol(symbol) || + !getDeclarationOfAliasSymbol(symbol) + ) { return symbol; } @@ -48292,23 +83507,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (target === targetSymbol) break; if (target.declarations && length(target.declarations)) { if (isDeprecatedSymbol(target)) { - addDeprecatedSuggestion(location, target.declarations, target.escapedName as string); + addDeprecatedSuggestion( + location, + target.declarations, + target.escapedName as string + ); break; - } - else { + } else { if (symbol === targetSymbol) break; symbol = target; } } - } - else { + } else { break; } } return targetSymbol; } - function checkImportBinding(node: ImportEqualsDeclaration | ImportClause | NamespaceImport | ImportSpecifier) { + function checkImportBinding( + node: + | ImportEqualsDeclaration + | ImportClause + | NamespaceImport + | ImportSpecifier + ) { checkCollisionsForDeclarationName(node, node.name); checkAliasSymbol(node); if (node.kind === SyntaxKind.ImportSpecifier) { @@ -48316,24 +83539,41 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if ( moduleExportNameIsDefault(node.propertyName || node.name) && getESModuleInterop(compilerOptions) && - host.getEmitModuleFormatOfFile(getSourceFileOfNode(node)) < ModuleKind.System + host.getEmitModuleFormatOfFile(getSourceFileOfNode(node)) < + ModuleKind.System ) { - checkExternalEmitHelpers(node, ExternalEmitHelpers.ImportDefault); + checkExternalEmitHelpers( + node, + ExternalEmitHelpers.ImportDefault + ); } } } - function checkImportAttributes(declaration: ImportDeclaration | ExportDeclaration | JSDocImportTag) { + function checkImportAttributes( + declaration: ImportDeclaration | ExportDeclaration | JSDocImportTag + ) { const node = declaration.attributes; if (node) { - const importAttributesType = getGlobalImportAttributesType(/*reportErrors*/ true); + const importAttributesType = getGlobalImportAttributesType( + /*reportErrors*/ true + ); if (importAttributesType !== emptyObjectType) { - checkTypeAssignableTo(getTypeFromImportAttributes(node), getNullableType(importAttributesType, TypeFlags.Undefined), node); + checkTypeAssignableTo( + getTypeFromImportAttributes(node), + getNullableType(importAttributesType, TypeFlags.Undefined), + node + ); } - const validForTypeAttributes = isExclusivelyTypeOnlyImportOrExport(declaration); - const override = getResolutionModeOverride(node, validForTypeAttributes ? grammarErrorOnNode : undefined); - const isImportAttributes = declaration.attributes.token === SyntaxKind.WithKeyword; + const validForTypeAttributes = + isExclusivelyTypeOnlyImportOrExport(declaration); + const override = getResolutionModeOverride( + node, + validForTypeAttributes ? grammarErrorOnNode : undefined + ); + const isImportAttributes = + declaration.attributes.token === SyntaxKind.WithKeyword; if (validForTypeAttributes && override) { return; // Other grammar checks do not apply to type-only imports with resolution mode assertions } @@ -48343,30 +83583,54 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { node, isImportAttributes ? Diagnostics.Import_attributes_are_only_supported_when_the_module_option_is_set_to_esnext_node18_node20_nodenext_or_preserve - : Diagnostics.Import_assertions_are_only_supported_when_the_module_option_is_set_to_esnext_node18_node20_nodenext_or_preserve, + : Diagnostics.Import_assertions_are_only_supported_when_the_module_option_is_set_to_esnext_node18_node20_nodenext_or_preserve ); } - if (ModuleKind.Node20 <= moduleKind && moduleKind <= ModuleKind.NodeNext && !isImportAttributes) { - return grammarErrorOnFirstToken(node, Diagnostics.Import_assertions_have_been_replaced_by_import_attributes_Use_with_instead_of_assert); + if ( + ModuleKind.Node20 <= moduleKind && + moduleKind <= ModuleKind.NodeNext && + !isImportAttributes + ) { + return grammarErrorOnFirstToken( + node, + Diagnostics.Import_assertions_have_been_replaced_by_import_attributes_Use_with_instead_of_assert + ); } - if (declaration.moduleSpecifier && getEmitSyntaxForModuleSpecifierExpression(declaration.moduleSpecifier) === ModuleKind.CommonJS) { + if ( + declaration.moduleSpecifier && + getEmitSyntaxForModuleSpecifierExpression( + declaration.moduleSpecifier + ) === ModuleKind.CommonJS + ) { return grammarErrorOnNode( node, isImportAttributes ? Diagnostics.Import_attributes_are_not_allowed_on_statements_that_compile_to_CommonJS_require_calls - : Diagnostics.Import_assertions_are_not_allowed_on_statements_that_compile_to_CommonJS_require_calls, + : Diagnostics.Import_assertions_are_not_allowed_on_statements_that_compile_to_CommonJS_require_calls ); } - const isTypeOnly = isJSDocImportTag(declaration) || (isImportDeclaration(declaration) ? declaration.importClause?.isTypeOnly : declaration.isTypeOnly); + const isTypeOnly = + isJSDocImportTag(declaration) || + (isImportDeclaration(declaration) + ? declaration.importClause?.isTypeOnly + : declaration.isTypeOnly); if (isTypeOnly) { - return grammarErrorOnNode(node, isImportAttributes ? Diagnostics.Import_attributes_cannot_be_used_with_type_only_imports_or_exports : Diagnostics.Import_assertions_cannot_be_used_with_type_only_imports_or_exports); + return grammarErrorOnNode( + node, + isImportAttributes + ? Diagnostics.Import_attributes_cannot_be_used_with_type_only_imports_or_exports + : Diagnostics.Import_assertions_cannot_be_used_with_type_only_imports_or_exports + ); } if (override) { - return grammarErrorOnNode(node, Diagnostics.resolution_mode_can_only_be_set_for_type_only_imports); + return grammarErrorOnNode( + node, + Diagnostics.resolution_mode_can_only_be_set_for_type_only_imports + ); } } } @@ -48376,12 +83640,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkImportDeclaration(node: ImportDeclaration) { - 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)) { + 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 + ) + ) { // If we hit an import declaration in an illegal context, just bail out to avoid cascading errors. return; } if (!checkGrammarModifiers(node) && node.modifiers) { - grammarErrorOnFirstToken(node, Diagnostics.An_import_declaration_cannot_have_modifiers); + grammarErrorOnFirstToken( + node, + Diagnostics.An_import_declaration_cannot_have_modifiers + ); } if (checkExternalImportOrExportDeclaration(node)) { let resolvedModule; @@ -48391,27 +83665,55 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkImportBinding(importClause); } if (importClause.namedBindings) { - if (importClause.namedBindings.kind === SyntaxKind.NamespaceImport) { + if ( + importClause.namedBindings.kind === + SyntaxKind.NamespaceImport + ) { checkImportBinding(importClause.namedBindings); - if (host.getEmitModuleFormatOfFile(getSourceFileOfNode(node)) < ModuleKind.System && getESModuleInterop(compilerOptions)) { + if ( + host.getEmitModuleFormatOfFile( + getSourceFileOfNode(node) + ) < ModuleKind.System && + getESModuleInterop(compilerOptions) + ) { // import * as ns from "foo"; - checkExternalEmitHelpers(node, ExternalEmitHelpers.ImportStar); + checkExternalEmitHelpers( + node, + ExternalEmitHelpers.ImportStar + ); } - } - else { - resolvedModule = resolveExternalModuleName(node, node.moduleSpecifier); + } else { + resolvedModule = resolveExternalModuleName( + node, + node.moduleSpecifier + ); if (resolvedModule) { - forEach(importClause.namedBindings.elements, checkImportBinding); + forEach( + importClause.namedBindings.elements, + checkImportBinding + ); } } } - if (!importClause.isTypeOnly && ModuleKind.Node18 <= moduleKind && moduleKind <= ModuleKind.NodeNext && isOnlyImportableAsDefault(node.moduleSpecifier, resolvedModule) && !hasTypeJsonImportAttribute(node)) { + if ( + !importClause.isTypeOnly && + ModuleKind.Node18 <= moduleKind && + moduleKind <= ModuleKind.NodeNext && + isOnlyImportableAsDefault( + node.moduleSpecifier, + resolvedModule + ) && + !hasTypeJsonImportAttribute(node) + ) { // Import attributes/assertions are not allowed in --module node16, so don't suggest adding one - error(node.moduleSpecifier, Diagnostics.Importing_a_JSON_file_into_an_ECMAScript_module_requires_a_type_Colon_json_import_attribute_when_module_is_set_to_0, ModuleKind[moduleKind]); + error( + node.moduleSpecifier, + Diagnostics.Importing_a_JSON_file_into_an_ECMAScript_module_requires_a_type_Colon_json_import_attribute_when_module_is_set_to_0, + ModuleKind[moduleKind] + ); } - } - else if (noUncheckedSideEffectImports && !importClause) { + } else if (noUncheckedSideEffectImports && !importClause) { void resolveExternalModuleName(node, node.moduleSpecifier); } } @@ -48419,96 +83721,185 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function hasTypeJsonImportAttribute(node: ImportDeclaration) { - return !!node.attributes && node.attributes.elements.some(attr => getTextOfIdentifierOrLiteral(attr.name) === "type" && tryCast(attr.value, isStringLiteralLike)?.text === "json"); + return ( + !!node.attributes && + node.attributes.elements.some( + (attr) => + getTextOfIdentifierOrLiteral(attr.name) === "type" && + tryCast(attr.value, isStringLiteralLike)?.text === "json" + ) + ); } function checkImportEqualsDeclaration(node: ImportEqualsDeclaration) { - 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)) { + 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 + ) + ) { // If we hit an import declaration in an illegal context, just bail out to avoid cascading errors. return; } checkGrammarModifiers(node); - if (compilerOptions.erasableSyntaxOnly && !(node.flags & NodeFlags.Ambient)) { - error(node, Diagnostics.This_syntax_is_not_allowed_when_erasableSyntaxOnly_is_enabled); + if ( + compilerOptions.erasableSyntaxOnly && + !(node.flags & NodeFlags.Ambient) + ) { + error( + node, + Diagnostics.This_syntax_is_not_allowed_when_erasableSyntaxOnly_is_enabled + ); } - if (isInternalModuleImportEqualsDeclaration(node) || checkExternalImportOrExportDeclaration(node)) { + if ( + isInternalModuleImportEqualsDeclaration(node) || + checkExternalImportOrExportDeclaration(node) + ) { checkImportBinding(node); markLinkedReferences(node, ReferenceHint.ExportImportEquals); - if (node.moduleReference.kind !== SyntaxKind.ExternalModuleReference) { + if ( + node.moduleReference.kind !== SyntaxKind.ExternalModuleReference + ) { const target = resolveAlias(getSymbolOfDeclaration(node)); if (target !== unknownSymbol) { const targetFlags = getSymbolFlags(target); if (targetFlags & SymbolFlags.Value) { // Target is a value symbol, check that it is not hidden by a local declaration with the same name - const moduleName = getFirstIdentifier(node.moduleReference); - if (!(resolveEntityName(moduleName, SymbolFlags.Value | SymbolFlags.Namespace)!.flags & SymbolFlags.Namespace)) { - error(moduleName, Diagnostics.Module_0_is_hidden_by_a_local_declaration_with_the_same_name, declarationNameToString(moduleName)); + const moduleName = getFirstIdentifier( + node.moduleReference + ); + if ( + !( + resolveEntityName( + moduleName, + SymbolFlags.Value | SymbolFlags.Namespace + )!.flags & SymbolFlags.Namespace + ) + ) { + error( + moduleName, + Diagnostics.Module_0_is_hidden_by_a_local_declaration_with_the_same_name, + declarationNameToString(moduleName) + ); } } if (targetFlags & SymbolFlags.Type) { - checkTypeNameIsReserved(node.name, Diagnostics.Import_name_cannot_be_0); + checkTypeNameIsReserved( + node.name, + Diagnostics.Import_name_cannot_be_0 + ); } } if (node.isTypeOnly) { - grammarErrorOnNode(node, Diagnostics.An_import_alias_cannot_use_import_type); + grammarErrorOnNode( + node, + Diagnostics.An_import_alias_cannot_use_import_type + ); } - } - else { - if (ModuleKind.ES2015 <= moduleKind && moduleKind <= ModuleKind.ESNext && !node.isTypeOnly && !(node.flags & NodeFlags.Ambient)) { + } else { + if ( + ModuleKind.ES2015 <= moduleKind && + moduleKind <= ModuleKind.ESNext && + !node.isTypeOnly && + !(node.flags & NodeFlags.Ambient) + ) { // Import equals declaration cannot be emitted as ESM - 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); + 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 + ); } } } } function checkExportDeclaration(node: ExportDeclaration) { - 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)) { + 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 + ) + ) { // If we hit an export in an illegal context, just bail out to avoid cascading errors. return; } if (!checkGrammarModifiers(node) && hasSyntacticModifiers(node)) { - grammarErrorOnFirstToken(node, Diagnostics.An_export_declaration_cannot_have_modifiers); + grammarErrorOnFirstToken( + node, + Diagnostics.An_export_declaration_cannot_have_modifiers + ); } checkGrammarExportDeclaration(node); - if (!node.moduleSpecifier || checkExternalImportOrExportDeclaration(node)) { + if ( + !node.moduleSpecifier || + checkExternalImportOrExportDeclaration(node) + ) { if (node.exportClause && !isNamespaceExport(node.exportClause)) { // export { x, y } // export { x, y } from "foo" forEach(node.exportClause.elements, checkExportSpecifier); - const inAmbientExternalModule = node.parent.kind === SyntaxKind.ModuleBlock && isAmbientModule(node.parent.parent); - const inAmbientNamespaceDeclaration = !inAmbientExternalModule && node.parent.kind === SyntaxKind.ModuleBlock && - !node.moduleSpecifier && node.flags & NodeFlags.Ambient; - if (node.parent.kind !== SyntaxKind.SourceFile && !inAmbientExternalModule && !inAmbientNamespaceDeclaration) { - error(node, Diagnostics.Export_declarations_are_not_permitted_in_a_namespace); + const inAmbientExternalModule = + node.parent.kind === SyntaxKind.ModuleBlock && + isAmbientModule(node.parent.parent); + const inAmbientNamespaceDeclaration = + !inAmbientExternalModule && + node.parent.kind === SyntaxKind.ModuleBlock && + !node.moduleSpecifier && + node.flags & NodeFlags.Ambient; + if ( + node.parent.kind !== SyntaxKind.SourceFile && + !inAmbientExternalModule && + !inAmbientNamespaceDeclaration + ) { + error( + node, + Diagnostics.Export_declarations_are_not_permitted_in_a_namespace + ); } - } - else { + } else { // export * from "foo" // export * as ns from "foo"; - const moduleSymbol = resolveExternalModuleName(node, node.moduleSpecifier!); + const moduleSymbol = resolveExternalModuleName( + node, + node.moduleSpecifier! + ); if (moduleSymbol && hasExportAssignmentSymbol(moduleSymbol)) { - error(node.moduleSpecifier, Diagnostics.Module_0_uses_export_and_cannot_be_used_with_export_Asterisk, symbolToString(moduleSymbol)); - } - else if (node.exportClause) { + error( + node.moduleSpecifier, + Diagnostics.Module_0_uses_export_and_cannot_be_used_with_export_Asterisk, + symbolToString(moduleSymbol) + ); + } else if (node.exportClause) { checkAliasSymbol(node.exportClause); checkModuleExportName(node.exportClause.name); } - if (host.getEmitModuleFormatOfFile(getSourceFileOfNode(node)) < ModuleKind.System) { + if ( + host.getEmitModuleFormatOfFile(getSourceFileOfNode(node)) < + ModuleKind.System + ) { if (node.exportClause) { // export * as ns from "foo"; // 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. // We only use the helper here when in esModuleInterop if (getESModuleInterop(compilerOptions)) { - checkExternalEmitHelpers(node, ExternalEmitHelpers.ImportStar); + checkExternalEmitHelpers( + node, + ExternalEmitHelpers.ImportStar + ); } - } - else { + } else { // export * from "foo" - checkExternalEmitHelpers(node, ExternalEmitHelpers.ExportStar); + checkExternalEmitHelpers( + node, + ExternalEmitHelpers.ExportStar + ); } } } @@ -48517,14 +83908,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkGrammarExportDeclaration(node: ExportDeclaration): boolean { - if (node.isTypeOnly && node.exportClause?.kind === SyntaxKind.NamedExports) { + if ( + node.isTypeOnly && + node.exportClause?.kind === SyntaxKind.NamedExports + ) { return checkGrammarNamedImportsOrExports(node.exportClause); } return false; } - function checkGrammarModuleElementContext(node: Statement, errorMessage: DiagnosticMessage): boolean { - const isInAppropriateContext = node.parent.kind === SyntaxKind.SourceFile || node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.ModuleDeclaration; + function checkGrammarModuleElementContext( + node: Statement, + errorMessage: DiagnosticMessage + ): boolean { + const isInAppropriateContext = + node.parent.kind === SyntaxKind.SourceFile || + node.parent.kind === SyntaxKind.ModuleBlock || + node.parent.kind === SyntaxKind.ModuleDeclaration; if (!isInAppropriateContext) { grammarErrorOnFirstToken(node, errorMessage); } @@ -48533,11 +83933,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkExportSpecifier(node: ExportSpecifier) { checkAliasSymbol(node); - const hasModuleSpecifier = node.parent.parent.moduleSpecifier !== undefined; + const hasModuleSpecifier = + node.parent.parent.moduleSpecifier !== undefined; checkModuleExportName(node.propertyName, hasModuleSpecifier); checkModuleExportName(node.name); if (getEmitDeclarations(compilerOptions)) { - collectLinkedAliases(node.propertyName || node.name, /*setVisibility*/ true); + collectLinkedAliases( + node.propertyName || node.name, + /*setVisibility*/ true + ); } if (!hasModuleSpecifier) { const exportedName = node.propertyName || node.name; @@ -48545,21 +83949,44 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return; // Skip for invalid syntax like this: export { "x" } } // find immediate value referenced by exported name (SymbolFlags.Alias is set so we don't chase down aliases) - const symbol = resolveName(exportedName, exportedName.escapedText, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, /*nameNotFoundMessage*/ undefined, /*isUse*/ true); - if (symbol && (symbol === undefinedSymbol || symbol === globalThisSymbol || symbol.declarations && isGlobalSourceFile(getDeclarationContainer(symbol.declarations[0])))) { - error(exportedName, Diagnostics.Cannot_export_0_Only_local_declarations_can_be_exported_from_a_module, idText(exportedName)); - } - else { + const symbol = resolveName( + exportedName, + exportedName.escapedText, + SymbolFlags.Value | + SymbolFlags.Type | + SymbolFlags.Namespace | + SymbolFlags.Alias, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ true + ); + if ( + symbol && + (symbol === undefinedSymbol || + symbol === globalThisSymbol || + (symbol.declarations && + isGlobalSourceFile( + getDeclarationContainer(symbol.declarations[0]) + ))) + ) { + error( + exportedName, + Diagnostics.Cannot_export_0_Only_local_declarations_can_be_exported_from_a_module, + idText(exportedName) + ); + } else { markLinkedReferences(node, ReferenceHint.ExportSpecifier); } - } - else { + } else { if ( getESModuleInterop(compilerOptions) && - host.getEmitModuleFormatOfFile(getSourceFileOfNode(node)) < ModuleKind.System && + host.getEmitModuleFormatOfFile(getSourceFileOfNode(node)) < + ModuleKind.System && moduleExportNameIsDefault(node.propertyName || node.name) ) { - checkExternalEmitHelpers(node, ExternalEmitHelpers.ImportDefault); + checkExternalEmitHelpers( + node, + ExternalEmitHelpers.ImportDefault + ); } } } @@ -48573,124 +84000,191 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return; } - if (compilerOptions.erasableSyntaxOnly && node.isExportEquals && !(node.flags & NodeFlags.Ambient)) { - error(node, Diagnostics.This_syntax_is_not_allowed_when_erasableSyntaxOnly_is_enabled); + if ( + compilerOptions.erasableSyntaxOnly && + node.isExportEquals && + !(node.flags & NodeFlags.Ambient) + ) { + error( + node, + Diagnostics.This_syntax_is_not_allowed_when_erasableSyntaxOnly_is_enabled + ); } - const container = node.parent.kind === SyntaxKind.SourceFile ? node.parent : node.parent.parent as ModuleDeclaration; - if (container.kind === SyntaxKind.ModuleDeclaration && !isAmbientModule(container)) { + const container = + node.parent.kind === SyntaxKind.SourceFile + ? node.parent + : (node.parent.parent as ModuleDeclaration); + if ( + container.kind === SyntaxKind.ModuleDeclaration && + !isAmbientModule(container) + ) { if (node.isExportEquals) { - error(node, Diagnostics.An_export_assignment_cannot_be_used_in_a_namespace); - } - else { - error(node, Diagnostics.A_default_export_can_only_be_used_in_an_ECMAScript_style_module); + error( + node, + Diagnostics.An_export_assignment_cannot_be_used_in_a_namespace + ); + } else { + error( + node, + Diagnostics.A_default_export_can_only_be_used_in_an_ECMAScript_style_module + ); } return; } // Grammar checking if (!checkGrammarModifiers(node) && hasEffectiveModifiers(node)) { - grammarErrorOnFirstToken(node, Diagnostics.An_export_assignment_cannot_have_modifiers); + grammarErrorOnFirstToken( + node, + Diagnostics.An_export_assignment_cannot_have_modifiers + ); } const typeAnnotationNode = getEffectiveTypeAnnotationNode(node); if (typeAnnotationNode) { - checkTypeAssignableTo(checkExpressionCached(node.expression), getTypeFromTypeNode(typeAnnotationNode), node.expression); + checkTypeAssignableTo( + checkExpressionCached(node.expression), + getTypeFromTypeNode(typeAnnotationNode), + node.expression + ); } - const isIllegalExportDefaultInCJS = !node.isExportEquals && + const isIllegalExportDefaultInCJS = + !node.isExportEquals && !(node.flags & NodeFlags.Ambient) && compilerOptions.verbatimModuleSyntax && - host.getEmitModuleFormatOfFile(getSourceFileOfNode(node)) === ModuleKind.CommonJS; + host.getEmitModuleFormatOfFile(getSourceFileOfNode(node)) === + ModuleKind.CommonJS; if (node.expression.kind === SyntaxKind.Identifier) { const id = node.expression as Identifier; - const sym = getExportSymbolOfValueSymbolIfExported(resolveEntityName(id, SymbolFlags.All, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, node)); + const sym = getExportSymbolOfValueSymbolIfExported( + resolveEntityName( + id, + SymbolFlags.All, + /*ignoreErrors*/ true, + /*dontResolveAlias*/ true, + node + ) + ); if (sym) { markLinkedReferences(node, ReferenceHint.ExportAssignment); - const typeOnlyDeclaration = getTypeOnlyAliasDeclaration(sym, SymbolFlags.Value); + const typeOnlyDeclaration = getTypeOnlyAliasDeclaration( + sym, + SymbolFlags.Value + ); // If not a value, we're interpreting the identifier as a type export, along the lines of (`export { Id as default }`) if (getSymbolFlags(sym) & SymbolFlags.Value) { // However if it is a value, we need to check it's being used correctly checkExpressionCached(id); - if (!isIllegalExportDefaultInCJS && !(node.flags & NodeFlags.Ambient) && compilerOptions.verbatimModuleSyntax && typeOnlyDeclaration) { + if ( + !isIllegalExportDefaultInCJS && + !(node.flags & NodeFlags.Ambient) && + compilerOptions.verbatimModuleSyntax && + typeOnlyDeclaration + ) { error( id, node.isExportEquals ? Diagnostics.An_export_declaration_must_reference_a_real_value_when_verbatimModuleSyntax_is_enabled_but_0_resolves_to_a_type_only_declaration : Diagnostics.An_export_default_must_reference_a_real_value_when_verbatimModuleSyntax_is_enabled_but_0_resolves_to_a_type_only_declaration, - idText(id), + idText(id) ); } - } - else if (!isIllegalExportDefaultInCJS && !(node.flags & NodeFlags.Ambient) && compilerOptions.verbatimModuleSyntax) { + } else if ( + !isIllegalExportDefaultInCJS && + !(node.flags & NodeFlags.Ambient) && + compilerOptions.verbatimModuleSyntax + ) { error( id, node.isExportEquals ? Diagnostics.An_export_declaration_must_reference_a_value_when_verbatimModuleSyntax_is_enabled_but_0_only_refers_to_a_type : Diagnostics.An_export_default_must_reference_a_value_when_verbatimModuleSyntax_is_enabled_but_0_only_refers_to_a_type, - idText(id), + idText(id) ); } - if (!isIllegalExportDefaultInCJS && !(node.flags & NodeFlags.Ambient) && getIsolatedModules(compilerOptions) && !(sym.flags & SymbolFlags.Value)) { - const nonLocalMeanings = getSymbolFlags(sym, /*excludeTypeOnlyMeanings*/ false, /*excludeLocalMeanings*/ true); + if ( + !isIllegalExportDefaultInCJS && + !(node.flags & NodeFlags.Ambient) && + getIsolatedModules(compilerOptions) && + !(sym.flags & SymbolFlags.Value) + ) { + const nonLocalMeanings = getSymbolFlags( + sym, + /*excludeTypeOnlyMeanings*/ false, + /*excludeLocalMeanings*/ true + ); if ( - sym.flags & SymbolFlags.Alias - && nonLocalMeanings & SymbolFlags.Type - && !(nonLocalMeanings & SymbolFlags.Value) - && (!typeOnlyDeclaration || getSourceFileOfNode(typeOnlyDeclaration) !== getSourceFileOfNode(node)) + sym.flags & SymbolFlags.Alias && + nonLocalMeanings & SymbolFlags.Type && + !(nonLocalMeanings & SymbolFlags.Value) && + (!typeOnlyDeclaration || + getSourceFileOfNode(typeOnlyDeclaration) !== + getSourceFileOfNode(node)) ) { // import { SomeType } from "./someModule"; // export default SomeType; OR // export = SomeType; error( id, - node.isExportEquals ? - Diagnostics._0_resolves_to_a_type_and_must_be_marked_type_only_in_this_file_before_re_exporting_when_1_is_enabled_Consider_using_import_type_where_0_is_imported + node.isExportEquals + ? Diagnostics._0_resolves_to_a_type_and_must_be_marked_type_only_in_this_file_before_re_exporting_when_1_is_enabled_Consider_using_import_type_where_0_is_imported : Diagnostics._0_resolves_to_a_type_and_must_be_marked_type_only_in_this_file_before_re_exporting_when_1_is_enabled_Consider_using_export_type_0_as_default, idText(id), - isolatedModulesLikeFlagName, + isolatedModulesLikeFlagName ); - } - else if (typeOnlyDeclaration && getSourceFileOfNode(typeOnlyDeclaration) !== getSourceFileOfNode(node)) { + } else if ( + typeOnlyDeclaration && + getSourceFileOfNode(typeOnlyDeclaration) !== + getSourceFileOfNode(node) + ) { // import { SomeTypeOnlyValue } from "./someModule"; // export default SomeTypeOnlyValue; OR // export = SomeTypeOnlyValue; addTypeOnlyDeclarationRelatedInfo( error( id, - node.isExportEquals ? - Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_marked_type_only_in_this_file_before_re_exporting_when_1_is_enabled_Consider_using_import_type_where_0_is_imported + node.isExportEquals + ? Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_marked_type_only_in_this_file_before_re_exporting_when_1_is_enabled_Consider_using_import_type_where_0_is_imported : Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_marked_type_only_in_this_file_before_re_exporting_when_1_is_enabled_Consider_using_export_type_0_as_default, idText(id), - isolatedModulesLikeFlagName, + isolatedModulesLikeFlagName ), typeOnlyDeclaration, - idText(id), + idText(id) ); } } - } - else { + } else { checkExpressionCached(id); // doesn't resolve, check as expression to mark as error } if (getEmitDeclarations(compilerOptions)) { collectLinkedAliases(id, /*setVisibility*/ true); } - } - else { + } else { checkExpressionCached(node.expression); } if (isIllegalExportDefaultInCJS) { - error(node, Diagnostics.ESM_syntax_is_not_allowed_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled); + error( + node, + Diagnostics.ESM_syntax_is_not_allowed_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled + ); } checkExternalModuleExports(container); - if ((node.flags & NodeFlags.Ambient) && !isEntityNameExpression(node.expression)) { - grammarErrorOnNode(node.expression, Diagnostics.The_expression_of_an_export_assignment_must_be_an_identifier_or_qualified_name_in_an_ambient_context); + if ( + node.flags & NodeFlags.Ambient && + !isEntityNameExpression(node.expression) + ) { + grammarErrorOnNode( + node.expression, + Diagnostics.The_expression_of_an_export_assignment_must_be_an_identifier_or_qualified_name_in_an_ambient_context + ); } if (node.isExportEquals) { @@ -48698,15 +84192,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if ( moduleKind >= ModuleKind.ES2015 && moduleKind !== ModuleKind.Preserve && - ((node.flags & NodeFlags.Ambient && host.getImpliedNodeFormatForEmit(getSourceFileOfNode(node)) === ModuleKind.ESNext) || - (!(node.flags & NodeFlags.Ambient) && host.getImpliedNodeFormatForEmit(getSourceFileOfNode(node)) !== ModuleKind.CommonJS)) + ((node.flags & NodeFlags.Ambient && + host.getImpliedNodeFormatForEmit( + getSourceFileOfNode(node) + ) === ModuleKind.ESNext) || + (!(node.flags & NodeFlags.Ambient) && + host.getImpliedNodeFormatForEmit( + getSourceFileOfNode(node) + ) !== ModuleKind.CommonJS)) ) { // export assignment is not supported in es6 modules - grammarErrorOnNode(node, Diagnostics.Export_assignment_cannot_be_used_when_targeting_ECMAScript_modules_Consider_using_export_default_or_another_module_format_instead); - } - else if (moduleKind === ModuleKind.System && !(node.flags & NodeFlags.Ambient)) { + grammarErrorOnNode( + node, + Diagnostics.Export_assignment_cannot_be_used_when_targeting_ECMAScript_modules_Consider_using_export_default_or_another_module_format_instead + ); + } else if ( + moduleKind === ModuleKind.System && + !(node.flags & NodeFlags.Ambient) + ) { // system modules does not support export assignment - grammarErrorOnNode(node, Diagnostics.Export_assignment_is_not_supported_when_module_flag_is_system); + grammarErrorOnNode( + node, + Diagnostics.Export_assignment_is_not_supported_when_module_flag_is_system + ); } } } @@ -48719,11 +84227,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const moduleSymbol = getSymbolOfDeclaration(node); const links = getSymbolLinks(moduleSymbol); if (!links.exportsChecked) { - const exportEqualsSymbol = moduleSymbol.exports!.get("export=" as __String); + const exportEqualsSymbol = moduleSymbol.exports!.get( + "export=" as __String + ); if (exportEqualsSymbol && hasExportedMembers(moduleSymbol)) { - const declaration = getDeclarationOfAliasSymbol(exportEqualsSymbol) || exportEqualsSymbol.valueDeclaration; - if (declaration && !isTopLevelInExternalModuleAugmentation(declaration) && !isInJSFile(declaration)) { - error(declaration, Diagnostics.An_export_assignment_cannot_be_used_in_a_module_with_other_exported_elements); + const declaration = + getDeclarationOfAliasSymbol(exportEqualsSymbol) || + exportEqualsSymbol.valueDeclaration; + if ( + declaration && + !isTopLevelInExternalModuleAugmentation(declaration) && + !isInJSFile(declaration) + ) { + error( + declaration, + Diagnostics.An_export_assignment_cannot_be_used_in_a_module_with_other_exported_elements + ); } } // Checks for export * conflicts @@ -48738,8 +84257,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (flags & (SymbolFlags.Namespace | SymbolFlags.Enum)) { return; } - const exportedDeclarationsCount = countWhere(declarations, and(isNotOverloadAndNotAccessor, not(isInterfaceDeclaration))); - if (flags & SymbolFlags.TypeAlias && exportedDeclarationsCount <= 2) { + const exportedDeclarationsCount = countWhere( + declarations, + and( + isNotOverloadAndNotAccessor, + not(isInterfaceDeclaration) + ) + ); + if ( + flags & SymbolFlags.TypeAlias && + exportedDeclarationsCount <= 2 + ) { // it is legal to merge type alias with other values // so count should be either 1 (just type alias) or 2 (type alias + merged value) return; @@ -48748,7 +84276,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!isDuplicatedCommonJSExport(declarations)) { for (const declaration of declarations!) { if (isNotOverload(declaration)) { - diagnostics.add(createDiagnosticForNode(declaration, Diagnostics.Cannot_redeclare_exported_variable_0, unescapeLeadingUnderscores(id))); + diagnostics.add( + createDiagnosticForNode( + declaration, + Diagnostics.Cannot_redeclare_exported_variable_0, + unescapeLeadingUnderscores(id) + ) + ); } } } @@ -48759,10 +84293,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function isDuplicatedCommonJSExport(declarations: Declaration[] | undefined) { - return declarations - && declarations.length > 1 - && declarations.every(d => isInJSFile(d) && isAccessExpression(d) && (isExportsIdentifier(d.expression) || isModuleExportsAccessExpression(d.expression))); + function isDuplicatedCommonJSExport( + declarations: Declaration[] | undefined + ) { + return ( + declarations && + declarations.length > 1 && + declarations.every( + (d) => + isInJSFile(d) && + isAccessExpression(d) && + (isExportsIdentifier(d.expression) || + isModuleExportsAccessExpression(d.expression)) + ) + ); } function checkSourceElement(node: Node | undefined): void { @@ -48783,7 +84327,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (canHaveJSDoc(node)) { forEach(node.jsDoc, ({ comment, tags }) => { checkJSDocCommentWorker(comment); - forEach(tags, tag => { + forEach(tags, (tag) => { checkJSDocCommentWorker(tag.comment); if (isInJSFile(node)) { checkSourceElement(tag); @@ -48804,8 +84348,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { cancellationToken.throwIfCancellationRequested(); } } - if (kind >= SyntaxKind.FirstStatement && kind <= SyntaxKind.LastStatement && canHaveFlowNode(node) && node.flowNode && !isReachableFlowNode(node.flowNode)) { - errorOrSuggestion(compilerOptions.allowUnreachableCode === false, node, Diagnostics.Unreachable_code_detected); + if ( + kind >= SyntaxKind.FirstStatement && + kind <= SyntaxKind.LastStatement && + canHaveFlowNode(node) && + node.flowNode && + !isReachableFlowNode(node.flowNode) + ) { + errorOrSuggestion( + compilerOptions.allowUnreachableCode === false, + node, + Diagnostics.Unreachable_code_detected + ); } // If editing this, keep `isSourceElement` in utilities up to date. @@ -48826,11 +84380,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return checkSignatureDeclaration(node as SignatureDeclaration); case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: - return checkMethodDeclaration(node as MethodDeclaration | MethodSignature); + return checkMethodDeclaration( + node as MethodDeclaration | MethodSignature + ); case SyntaxKind.ClassStaticBlockDeclaration: - return checkClassStaticBlockDeclaration(node as ClassStaticBlockDeclaration); + return checkClassStaticBlockDeclaration( + node as ClassStaticBlockDeclaration + ); case SyntaxKind.Constructor: - return checkConstructorDeclaration(node as ConstructorDeclaration); + return checkConstructorDeclaration( + node as ConstructorDeclaration + ); case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: return checkAccessorDeclaration(node as AccessorDeclaration); @@ -48848,11 +84408,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return checkTupleType(node as TupleTypeNode); case SyntaxKind.UnionType: case SyntaxKind.IntersectionType: - return checkUnionOrIntersectionType(node as UnionOrIntersectionTypeNode); + return checkUnionOrIntersectionType( + node as UnionOrIntersectionTypeNode + ); case SyntaxKind.ParenthesizedType: case SyntaxKind.OptionalType: case SyntaxKind.RestType: - return checkSourceElement((node as ParenthesizedTypeNode | OptionalTypeNode | RestTypeNode).type); + return checkSourceElement( + ( + node as + | ParenthesizedTypeNode + | OptionalTypeNode + | RestTypeNode + ).type + ); case SyntaxKind.ThisType: return checkThisType(node as ThisTypeNode); case SyntaxKind.TypeOperator: @@ -48862,7 +84431,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.InferType: return checkInferType(node as InferTypeNode); case SyntaxKind.TemplateLiteralType: - return checkTemplateLiteralType(node as TemplateLiteralTypeNode); + return checkTemplateLiteralType( + node as TemplateLiteralTypeNode + ); case SyntaxKind.ImportType: return checkImportType(node as ImportTypeNode); case SyntaxKind.NamedTupleMember: @@ -48882,14 +84453,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.JSDocLink: case SyntaxKind.JSDocLinkCode: case SyntaxKind.JSDocLinkPlain: - return checkJSDocLinkLikeTag(node as JSDocLink | JSDocLinkCode | JSDocLinkPlain); + return checkJSDocLinkLikeTag( + node as JSDocLink | JSDocLinkCode | JSDocLinkPlain + ); case SyntaxKind.JSDocParameterTag: return checkJSDocParameterTag(node as JSDocParameterTag); case SyntaxKind.JSDocPropertyTag: return checkJSDocPropertyTag(node as JSDocPropertyTag); case SyntaxKind.JSDocFunctionType: checkJSDocFunctionType(node as JSDocFunctionType); - // falls through + // falls through case SyntaxKind.JSDocNonNullableType: case SyntaxKind.JSDocNullableType: case SyntaxKind.JSDocAllType: @@ -48906,7 +84479,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.JSDocPublicTag: case SyntaxKind.JSDocProtectedTag: case SyntaxKind.JSDocPrivateTag: - return checkJSDocAccessibilityModifiers(node as JSDocPublicTag | JSDocProtectedTag | JSDocPrivateTag); + return checkJSDocAccessibilityModifiers( + node as JSDocPublicTag | JSDocProtectedTag | JSDocPrivateTag + ); case SyntaxKind.JSDocSatisfiesTag: return checkJSDocSatisfiesTag(node as JSDocSatisfiesTag); case SyntaxKind.JSDocThisTag: @@ -48940,7 +84515,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return checkForOfStatement(node as ForOfStatement); case SyntaxKind.ContinueStatement: case SyntaxKind.BreakStatement: - return checkBreakOrContinueStatement(node as BreakOrContinueStatement); + return checkBreakOrContinueStatement( + node as BreakOrContinueStatement + ); case SyntaxKind.ReturnStatement: return checkReturnStatement(node as ReturnStatement); case SyntaxKind.WithStatement: @@ -48972,7 +84549,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ImportDeclaration: return checkImportDeclaration(node as ImportDeclaration); case SyntaxKind.ImportEqualsDeclaration: - return checkImportEqualsDeclaration(node as ImportEqualsDeclaration); + return checkImportEqualsDeclaration( + node as ImportEqualsDeclaration + ); case SyntaxKind.ExportDeclaration: return checkExportDeclaration(node as ExportDeclaration); case SyntaxKind.ExportAssignment: @@ -48986,9 +84565,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function checkJSDocCommentWorker(node: string | readonly JSDocComment[] | undefined) { + function checkJSDocCommentWorker( + node: string | readonly JSDocComment[] | undefined + ) { if (isArray(node)) { - forEach(node, tag => { + forEach(node, (tag) => { if (isJSDocLinkLike(tag)) { checkSourceElement(tag); } @@ -48999,7 +84580,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkJSDocTypeIsInJsFile(node: Node): void { if (!isInJSFile(node)) { if (isJSDocNonNullableType(node) || isJSDocNullableType(node)) { - const token = tokenToString(isJSDocNonNullableType(node) ? SyntaxKind.ExclamationToken : SyntaxKind.QuestionToken); + const token = tokenToString( + isJSDocNonNullableType(node) + ? SyntaxKind.ExclamationToken + : SyntaxKind.QuestionToken + ); const diagnostic = node.postfix ? Diagnostics._0_at_the_end_of_a_type_is_not_valid_TypeScript_syntax_Did_you_mean_to_write_1 : Diagnostics._0_at_the_start_of_a_type_is_not_valid_TypeScript_syntax_Did_you_mean_to_write_1; @@ -49010,13 +84595,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { diagnostic, token, typeToString( - isJSDocNullableType(node) && !(type === neverType || type === voidType) - ? getUnionType(append([type, undefinedType], node.postfix ? undefined : nullType)) : type, - ), + isJSDocNullableType(node) && + !(type === neverType || type === voidType) + ? getUnionType( + append( + [type, undefinedType], + node.postfix ? undefined : nullType + ) + ) + : type + ) + ); + } else { + grammarErrorOnNode( + node, + Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments ); - } - else { - grammarErrorOnNode(node, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments); } } } @@ -49029,18 +84623,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const { parent } = node; if (isParameter(parent) && isJSDocFunctionType(parent.parent)) { if (last(parent.parent.parameters) !== parent) { - error(node, Diagnostics.A_rest_parameter_must_be_last_in_a_parameter_list); + error( + node, + Diagnostics.A_rest_parameter_must_be_last_in_a_parameter_list + ); } return; } if (!isJSDocTypeExpression(parent)) { - error(node, Diagnostics.JSDoc_may_only_appear_in_the_last_parameter_of_a_signature); + error( + node, + Diagnostics.JSDoc_may_only_appear_in_the_last_parameter_of_a_signature + ); } const paramTag = node.parent.parent; if (!isJSDocParameterTag(paramTag)) { - error(node, Diagnostics.JSDoc_may_only_appear_in_the_last_parameter_of_a_signature); + error( + node, + Diagnostics.JSDoc_may_only_appear_in_the_last_parameter_of_a_signature + ); return; } @@ -49052,7 +84655,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const host = getHostSignatureFromJSDoc(paramTag); if (!host || last(host.parameters).symbol !== param) { - error(node, Diagnostics.A_rest_parameter_must_be_last_in_a_parameter_list); + error( + node, + Diagnostics.A_rest_parameter_must_be_last_in_a_parameter_list + ); } } @@ -49060,7 +84666,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const type = getTypeFromTypeNode(node.type); const { parent } = node; const paramTag = node.parent.parent; - if (isJSDocTypeExpression(node.parent) && isJSDocParameterTag(paramTag)) { + if ( + isJSDocTypeExpression(node.parent) && + isJSDocParameterTag(paramTag) + ) { // Else we will add a diagnostic, see `checkJSDocVariadicType`. const host = getHostSignatureFromJSDoc(paramTag); const isCallbackTag = isJSDocCallbackTag(paramTag.parent.parent); @@ -49073,12 +84682,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { Because `a` will just be of type `number | undefined`. A synthetic `...args` will also be added, which *will* get an array type. */ const lastParamDeclaration = isCallbackTag - ? lastOrUndefined((paramTag.parent.parent as unknown as JSDocCallbackTag).typeExpression.parameters) + ? lastOrUndefined( + ( + paramTag.parent + .parent as unknown as JSDocCallbackTag + ).typeExpression.parameters + ) : lastOrUndefined(host!.parameters); const symbol = getParameterSymbolFromJSDoc(paramTag); if ( !lastParamDeclaration || - symbol && lastParamDeclaration.symbol === symbol && isRestParameter(lastParamDeclaration) + (symbol && + lastParamDeclaration.symbol === symbol && + isRestParameter(lastParamDeclaration)) ) { return createArrayType(type); } @@ -49105,9 +84721,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!(links.flags & NodeCheckFlags.TypeChecked)) { links.deferredNodes ||= new Set(); links.deferredNodes.add(node); - } - else { - Debug.assert(!links.deferredNodes, "A type-checked file should have no deferred nodes."); + } else { + Debug.assert( + !links.deferredNodes, + "A type-checked file should have no deferred nodes." + ); } } @@ -49120,7 +84738,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkDeferredNode(node: Node) { - tracing?.push(tracing.Phase.Check, "checkDeferredNode", { kind: node.kind, pos: node.pos, end: node.end, path: (node as TracingNode).tracingPath }); + tracing?.push(tracing.Phase.Check, "checkDeferredNode", { + kind: node.kind, + pos: node.pos, + end: node.end, + path: (node as TracingNode).tracingPath, + }); const saveCurrentNode = currentNode; currentNode = node; instantiationCount = 0; @@ -49139,7 +84762,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ArrowFunction: case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: - checkFunctionExpressionOrObjectLiteralMethodDeferred(node as FunctionExpression); + checkFunctionExpressionOrObjectLiteralMethodDeferred( + node as FunctionExpression + ); break; case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: @@ -49152,7 +84777,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkTypeParameterDeferred(node as TypeParameterDeclaration); break; case SyntaxKind.JsxSelfClosingElement: - checkJsxSelfClosingElementDeferred(node as JsxSelfClosingElement); + checkJsxSelfClosingElementDeferred( + node as JsxSelfClosingElement + ); break; case SyntaxKind.JsxElement: checkJsxElementDeferred(node as JsxElement); @@ -49160,7 +84787,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.TypeAssertionExpression: case SyntaxKind.AsExpression: case SyntaxKind.ParenthesizedExpression: - checkAssertionDeferred(node as AssertionExpression | JSDocTypeAssertion); + checkAssertionDeferred( + node as AssertionExpression | JSDocTypeAssertion + ); break; case SyntaxKind.VoidExpression: checkExpression((node as VoidExpression).expression); @@ -49175,12 +84804,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { tracing?.pop(); } - function checkSourceFile(node: SourceFile, nodesToCheck: Node[] | undefined) { - tracing?.push(tracing.Phase.Check, nodesToCheck ? "checkSourceFileNodes" : "checkSourceFile", { path: node.path }, /*separateBeginAndEnd*/ true); + function checkSourceFile( + node: SourceFile, + nodesToCheck: Node[] | undefined + ) { + tracing?.push( + tracing.Phase.Check, + nodesToCheck ? "checkSourceFileNodes" : "checkSourceFile", + { path: node.path }, + /*separateBeginAndEnd*/ true + ); const beforeMark = nodesToCheck ? "beforeCheckNodes" : "beforeCheck"; const afterMark = nodesToCheck ? "afterCheckNodes" : "afterCheck"; performance.mark(beforeMark); - nodesToCheck ? checkSourceFileNodesWorker(node, nodesToCheck) : checkSourceFileWorker(node); + nodesToCheck + ? checkSourceFileNodesWorker(node, nodesToCheck) + : checkSourceFileWorker(node); performance.mark(afterMark); performance.measure("Check", beforeMark, afterMark); tracing?.pop(); @@ -49200,8 +84839,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getPotentiallyUnusedIdentifiers(sourceFile: SourceFile): readonly PotentiallyUnusedIdentifier[] { - return allPotentiallyUnusedIdentifiers.get(sourceFile.path) || emptyArray; + function getPotentiallyUnusedIdentifiers( + sourceFile: SourceFile + ): readonly PotentiallyUnusedIdentifier[] { + return ( + allPotentiallyUnusedIdentifiers.get(sourceFile.path) || emptyArray + ); } // Fully type check a source file and collect the relevant diagnostics. @@ -49223,10 +84866,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (links.flags & NodeCheckFlags.PartiallyTypeChecked) { potentialThisCollisions = links.potentialThisCollisions!; - potentialNewTargetCollisions = links.potentialNewTargetCollisions!; - potentialWeakMapSetCollisions = links.potentialWeakMapSetCollisions!; + potentialNewTargetCollisions = + links.potentialNewTargetCollisions!; + potentialWeakMapSetCollisions = + links.potentialWeakMapSetCollisions!; potentialReflectCollisions = links.potentialReflectCollisions!; - potentialUnusedRenamedBindingElementsInTypes = links.potentialUnusedRenamedBindingElementsInTypes!; + potentialUnusedRenamedBindingElementsInTypes = + links.potentialUnusedRenamedBindingElementsInTypes!; } forEach(node.statements, checkSourceElement); @@ -49240,12 +84886,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { addLazyDiagnostic(() => { // This relies on the results of other lazy diagnostics, so must be computed after them - if (!node.isDeclarationFile && (compilerOptions.noUnusedLocals || compilerOptions.noUnusedParameters)) { - checkUnusedIdentifiers(getPotentiallyUnusedIdentifiers(node), (containingNode, kind, diag) => { - if (!containsParseError(containingNode) && unusedIsError(kind, !!(containingNode.flags & NodeFlags.Ambient))) { - diagnostics.add(diag); + if ( + !node.isDeclarationFile && + (compilerOptions.noUnusedLocals || + compilerOptions.noUnusedParameters) + ) { + checkUnusedIdentifiers( + getPotentiallyUnusedIdentifiers(node), + (containingNode, kind, diag) => { + if ( + !containsParseError(containingNode) && + unusedIsError( + kind, + !!(containingNode.flags & NodeFlags.Ambient) + ) + ) { + diagnostics.add(diag); + } } - }); + ); } if (!node.isDeclarationFile) { checkPotentialUncheckedRenamedBindingElementsInTypes(); @@ -49257,17 +84916,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (potentialThisCollisions.length) { - forEach(potentialThisCollisions, checkIfThisIsCapturedInEnclosingScope); + forEach( + potentialThisCollisions, + checkIfThisIsCapturedInEnclosingScope + ); clear(potentialThisCollisions); } if (potentialNewTargetCollisions.length) { - forEach(potentialNewTargetCollisions, checkIfNewTargetIsCapturedInEnclosingScope); + forEach( + potentialNewTargetCollisions, + checkIfNewTargetIsCapturedInEnclosingScope + ); clear(potentialNewTargetCollisions); } if (potentialWeakMapSetCollisions.length) { - forEach(potentialWeakMapSetCollisions, checkWeakMapSetCollision); + forEach( + potentialWeakMapSetCollisions, + checkWeakMapSetCollision + ); clear(potentialWeakMapSetCollisions); } @@ -49280,7 +84948,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function checkSourceFileNodesWorker(file: SourceFile, nodes: readonly Node[]) { + function checkSourceFileNodesWorker( + file: SourceFile, + nodes: readonly Node[] + ) { const links = getNodeLinks(file); if (!(links.flags & NodeCheckFlags.TypeChecked)) { if (skipTypeChecking(file, compilerOptions, host)) { @@ -49300,13 +84971,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkDeferredNodes(file); - (links.potentialThisCollisions || (links.potentialThisCollisions = [])).push(...potentialThisCollisions); - (links.potentialNewTargetCollisions || (links.potentialNewTargetCollisions = [])).push(...potentialNewTargetCollisions); - (links.potentialWeakMapSetCollisions || (links.potentialWeakMapSetCollisions = [])).push(...potentialWeakMapSetCollisions); - (links.potentialReflectCollisions || (links.potentialReflectCollisions = [])).push(...potentialReflectCollisions); - (links.potentialUnusedRenamedBindingElementsInTypes || (links.potentialUnusedRenamedBindingElementsInTypes = [])).push( - ...potentialUnusedRenamedBindingElementsInTypes, - ); + ( + links.potentialThisCollisions || + (links.potentialThisCollisions = []) + ).push(...potentialThisCollisions); + ( + links.potentialNewTargetCollisions || + (links.potentialNewTargetCollisions = []) + ).push(...potentialNewTargetCollisions); + ( + links.potentialWeakMapSetCollisions || + (links.potentialWeakMapSetCollisions = []) + ).push(...potentialWeakMapSetCollisions); + ( + links.potentialReflectCollisions || + (links.potentialReflectCollisions = []) + ).push(...potentialReflectCollisions); + ( + links.potentialUnusedRenamedBindingElementsInTypes || + (links.potentialUnusedRenamedBindingElementsInTypes = []) + ).push(...potentialUnusedRenamedBindingElementsInTypes); links.flags |= NodeCheckFlags.PartiallyTypeChecked; for (const node of nodes) { @@ -49316,15 +85000,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getDiagnostics(sourceFile: SourceFile, ct: CancellationToken, nodesToCheck?: Node[]): Diagnostic[] { + function getDiagnostics( + sourceFile: SourceFile, + ct: CancellationToken, + nodesToCheck?: Node[] + ): Diagnostic[] { try { // Record the cancellation token so it can be checked later on during checkSourceElement. // Do this in a finally block so we can ensure that it gets reset back to nothing after // this call is done. cancellationToken = ct; return getDiagnosticsWorker(sourceFile, nodesToCheck); - } - finally { + } finally { cancellationToken = undefined; } } @@ -49337,7 +85024,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { deferredDiagnosticsCallbacks = []; } - function checkSourceFileWithEagerDiagnostics(sourceFile: SourceFile, nodesToCheck?: Node[]) { + function checkSourceFileWithEagerDiagnostics( + sourceFile: SourceFile, + nodesToCheck?: Node[] + ) { ensurePendingDiagnosticWorkComplete(); // then setup diagnostics for immediate invocation (as we are about to collect them, and // this avoids the overhead of longer-lived callbacks we don't need to allocate) @@ -49345,22 +85035,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // (as in those cases, all the diagnostics will still be computed as the appropriate place in the tree, // thus much more likely retaining the same union ordering as before we had lazy diagnostics) const oldAddLazyDiagnostics = addLazyDiagnostic; - addLazyDiagnostic = cb => cb(); + addLazyDiagnostic = (cb) => cb(); checkSourceFile(sourceFile, nodesToCheck); addLazyDiagnostic = oldAddLazyDiagnostics; } - function getDiagnosticsWorker(sourceFile: SourceFile, nodesToCheck: Node[] | undefined): Diagnostic[] { + function getDiagnosticsWorker( + sourceFile: SourceFile, + nodesToCheck: Node[] | undefined + ): Diagnostic[] { if (sourceFile) { ensurePendingDiagnosticWorkComplete(); // Some global diagnostics are deferred until they are needed and // may not be reported in the first call to getGlobalDiagnostics. // We should catch these changes and report them. - const previousGlobalDiagnostics = diagnostics.getGlobalDiagnostics(); - const previousGlobalDiagnosticsSize = previousGlobalDiagnostics.length; + const previousGlobalDiagnostics = + diagnostics.getGlobalDiagnostics(); + const previousGlobalDiagnosticsSize = + previousGlobalDiagnostics.length; checkSourceFileWithEagerDiagnostics(sourceFile, nodesToCheck); - const semanticDiagnostics = diagnostics.getDiagnostics(sourceFile.fileName); + const semanticDiagnostics = diagnostics.getDiagnostics( + sourceFile.fileName + ); if (nodesToCheck) { // No need to get global diagnostics. return semanticDiagnostics; @@ -49368,14 +85065,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const currentGlobalDiagnostics = diagnostics.getGlobalDiagnostics(); if (currentGlobalDiagnostics !== previousGlobalDiagnostics) { // If the arrays are not the same reference, new diagnostics were added. - const deferredGlobalDiagnostics = relativeComplement(previousGlobalDiagnostics, currentGlobalDiagnostics, compareDiagnostics); - return concatenate(deferredGlobalDiagnostics, semanticDiagnostics); - } - else if (previousGlobalDiagnosticsSize === 0 && currentGlobalDiagnostics.length > 0) { + const deferredGlobalDiagnostics = relativeComplement( + previousGlobalDiagnostics, + currentGlobalDiagnostics, + compareDiagnostics + ); + return concatenate( + deferredGlobalDiagnostics, + semanticDiagnostics + ); + } else if ( + previousGlobalDiagnosticsSize === 0 && + currentGlobalDiagnostics.length > 0 + ) { // If the arrays are the same reference, but the length has changed, a single // new diagnostic was added as DiagnosticCollection attempts to reuse the // same array. - return concatenate(currentGlobalDiagnostics, semanticDiagnostics); + return concatenate( + currentGlobalDiagnostics, + semanticDiagnostics + ); } return semanticDiagnostics; @@ -49383,7 +85092,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Global diagnostics are always added when a file is not provided to // getDiagnostics - forEach(host.getSourceFiles(), file => checkSourceFileWithEagerDiagnostics(file)); + forEach(host.getSourceFiles(), (file) => + checkSourceFileWithEagerDiagnostics(file) + ); return diagnostics.getDiagnostics(); } @@ -49410,24 +85121,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function populateSymbols() { while (location) { - if (canHaveLocals(location) && location.locals && !isGlobalSourceFile(location)) { + if ( + canHaveLocals(location) && + location.locals && + !isGlobalSourceFile(location) + ) { copySymbols(location.locals, meaning); } switch (location.kind) { case SyntaxKind.SourceFile: if (!isExternalModule(location as SourceFile)) break; - // falls through + // falls through case SyntaxKind.ModuleDeclaration: - copyLocallyVisibleExportSymbols(getSymbolOfDeclaration(location as ModuleDeclaration | SourceFile).exports!, meaning & SymbolFlags.ModuleMember); + copyLocallyVisibleExportSymbols( + getSymbolOfDeclaration( + location as ModuleDeclaration | SourceFile + ).exports!, + meaning & SymbolFlags.ModuleMember + ); break; case SyntaxKind.EnumDeclaration: - copySymbols(getSymbolOfDeclaration(location as EnumDeclaration).exports!, meaning & SymbolFlags.EnumMember); + copySymbols( + getSymbolOfDeclaration(location as EnumDeclaration) + .exports!, + meaning & SymbolFlags.EnumMember + ); break; case SyntaxKind.ClassExpression: const className = (location as ClassExpression).name; if (className) { - copySymbol((location as ClassExpression).symbol, meaning); + copySymbol( + (location as ClassExpression).symbol, + meaning + ); } // this fall-through is necessary because we would like to handle @@ -49440,13 +85167,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // (type parameters of classDeclaration/classExpression and interface are in member property of the symbol. // Note: that the memberFlags come from previous iteration. if (!isStaticSymbol) { - copySymbols(getMembersOfSymbol(getSymbolOfDeclaration(location as ClassDeclaration | InterfaceDeclaration)), meaning & SymbolFlags.Type); + copySymbols( + getMembersOfSymbol( + getSymbolOfDeclaration( + location as + | ClassDeclaration + | InterfaceDeclaration + ) + ), + meaning & SymbolFlags.Type + ); } break; case SyntaxKind.FunctionExpression: const funcName = (location as FunctionExpression).name; if (funcName) { - copySymbol((location as FunctionExpression).symbol, meaning); + copySymbol( + (location as FunctionExpression).symbol, + meaning + ); } break; } @@ -49483,17 +85222,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function copySymbols(source: SymbolTable, meaning: SymbolFlags): void { if (meaning) { - source.forEach(symbol => { + source.forEach((symbol) => { copySymbol(symbol, meaning); }); } } - function copyLocallyVisibleExportSymbols(source: SymbolTable, meaning: SymbolFlags): void { + function copyLocallyVisibleExportSymbols( + source: SymbolTable, + meaning: SymbolFlags + ): void { if (meaning) { - source.forEach(symbol => { + source.forEach((symbol) => { // Similar condition as in `resolveNameHelper` - if (!getDeclarationOfKind(symbol, SyntaxKind.ExportSpecifier) && !getDeclarationOfKind(symbol, SyntaxKind.NamespaceExport) && symbol.escapedName !== InternalSymbolName.Default) { + if ( + !getDeclarationOfKind( + symbol, + SyntaxKind.ExportSpecifier + ) && + !getDeclarationOfKind( + symbol, + SyntaxKind.NamespaceExport + ) && + symbol.escapedName !== InternalSymbolName.Default + ) { copySymbol(symbol, meaning); } }); @@ -49502,9 +85254,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isTypeDeclarationName(name: Node): boolean { - return name.kind === SyntaxKind.Identifier && + return ( + name.kind === SyntaxKind.Identifier && isTypeDeclaration(name.parent) && - getNameOfDeclaration(name.parent) === name; + getNameOfDeclaration(name.parent) === name + ); } // True if the given identifier is part of a type reference @@ -49524,11 +85278,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return node.parent.kind === SyntaxKind.ExpressionWithTypeArguments; } - function forEachEnclosingClass(node: Node, callback: (node: ClassLikeDeclaration) => T | undefined): T | undefined { + function forEachEnclosingClass( + node: Node, + callback: (node: ClassLikeDeclaration) => T | undefined + ): T | undefined { let result: T | undefined; let containingClass = getContainingClass(node); while (containingClass) { - if (result = callback(containingClass)) break; + if ((result = callback(containingClass))) break; containingClass = getContainingClass(containingClass); } @@ -49536,11 +85293,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isNodeUsedDuringClassInitialization(node: Node) { - return !!findAncestor(node, element => { - if (isConstructorDeclaration(element) && nodeIsPresent(element.body) || isPropertyDeclaration(element)) { + return !!findAncestor(node, (element) => { + if ( + (isConstructorDeclaration(element) && + nodeIsPresent(element.body)) || + isPropertyDeclaration(element) + ) { return true; - } - else if (isClassLike(element) || isFunctionLikeDeclaration(element)) { + } else if ( + isClassLike(element) || + isFunctionLikeDeclaration(element) + ) { return "quit"; } @@ -49548,21 +85311,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { }); } - function isNodeWithinClass(node: Node, classDeclaration: ClassLikeDeclaration) { - return !!forEachEnclosingClass(node, n => n === classDeclaration); + function isNodeWithinClass( + node: Node, + classDeclaration: ClassLikeDeclaration + ) { + return !!forEachEnclosingClass(node, (n) => n === classDeclaration); } - function getLeftSideOfImportEqualsOrExportAssignment(nodeOnRightSide: EntityName): ImportEqualsDeclaration | ExportAssignment | undefined { + function getLeftSideOfImportEqualsOrExportAssignment( + nodeOnRightSide: EntityName + ): ImportEqualsDeclaration | ExportAssignment | undefined { while (nodeOnRightSide.parent.kind === SyntaxKind.QualifiedName) { nodeOnRightSide = nodeOnRightSide.parent as QualifiedName; } - if (nodeOnRightSide.parent.kind === SyntaxKind.ImportEqualsDeclaration) { - return (nodeOnRightSide.parent as ImportEqualsDeclaration).moduleReference === nodeOnRightSide ? nodeOnRightSide.parent as ImportEqualsDeclaration : undefined; + if ( + nodeOnRightSide.parent.kind === SyntaxKind.ImportEqualsDeclaration + ) { + return (nodeOnRightSide.parent as ImportEqualsDeclaration) + .moduleReference === nodeOnRightSide + ? (nodeOnRightSide.parent as ImportEqualsDeclaration) + : undefined; } if (nodeOnRightSide.parent.kind === SyntaxKind.ExportAssignment) { - return (nodeOnRightSide.parent as ExportAssignment).expression === nodeOnRightSide as Node ? nodeOnRightSide.parent as ExportAssignment : undefined; + return (nodeOnRightSide.parent as ExportAssignment).expression === + (nodeOnRightSide as Node) + ? (nodeOnRightSide.parent as ExportAssignment) + : undefined; } return undefined; @@ -49572,30 +85348,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getLeftSideOfImportEqualsOrExportAssignment(node) !== undefined; } - function getSpecialPropertyAssignmentSymbolFromEntityName(entityName: EntityName | PropertyAccessExpression) { - const specialPropertyAssignmentKind = getAssignmentDeclarationKind(entityName.parent.parent as BinaryExpression); + function getSpecialPropertyAssignmentSymbolFromEntityName( + entityName: EntityName | PropertyAccessExpression + ) { + const specialPropertyAssignmentKind = getAssignmentDeclarationKind( + entityName.parent.parent as BinaryExpression + ); switch (specialPropertyAssignmentKind) { case AssignmentDeclarationKind.ExportsProperty: case AssignmentDeclarationKind.PrototypeProperty: return getSymbolOfNode(entityName.parent); case AssignmentDeclarationKind.Property: - if (isPropertyAccessExpression(entityName.parent) && getLeftmostAccessExpression(entityName.parent) === entityName) { + if ( + isPropertyAccessExpression(entityName.parent) && + getLeftmostAccessExpression(entityName.parent) === + entityName + ) { return undefined; } - // falls through + // falls through case AssignmentDeclarationKind.ThisProperty: case AssignmentDeclarationKind.ModuleExports: - return getSymbolOfDeclaration(entityName.parent.parent as BinaryExpression); + return getSymbolOfDeclaration( + entityName.parent.parent as BinaryExpression + ); } } - function isImportTypeQualifierPart(node: EntityName): ImportTypeNode | undefined { + function isImportTypeQualifierPart( + node: EntityName + ): ImportTypeNode | undefined { let parent = node.parent; while (isQualifiedName(parent)) { node = parent; parent = parent.parent; } - if (parent && parent.kind === SyntaxKind.ImportType && (parent as ImportTypeNode).qualifier === node) { + if ( + parent && + parent.kind === SyntaxKind.ImportType && + (parent as ImportTypeNode).qualifier === node + ) { return parent as ImportTypeNode; } return undefined; @@ -49603,19 +85395,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isThisPropertyAndThisTyped(node: PropertyAccessExpression) { if (node.expression.kind === SyntaxKind.ThisKeyword) { - const container = getThisContainer(node, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); + const container = getThisContainer( + node, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false + ); if (isFunctionLike(container)) { const containingLiteral = getContainingObjectLiteral(container); if (containingLiteral) { - const contextualType = getApparentTypeOfContextualType(containingLiteral, /*contextFlags*/ undefined); - const type = getThisTypeOfObjectLiteralFromContextualType(containingLiteral, contextualType); + const contextualType = getApparentTypeOfContextualType( + containingLiteral, + /*contextFlags*/ undefined + ); + const type = getThisTypeOfObjectLiteralFromContextualType( + containingLiteral, + contextualType + ); return type && !isTypeAny(type); } } } } - function getSymbolOfNameOrPropertyAccessExpression(name: EntityName | PrivateIdentifier | PropertyAccessExpression | JSDocMemberName): Symbol | undefined { + function getSymbolOfNameOrPropertyAccessExpression( + name: + | EntityName + | PrivateIdentifier + | PropertyAccessExpression + | JSDocMemberName + ): Symbol | undefined { if (isDeclarationName(name)) { return getSymbolOfNode(name.parent); } @@ -49626,26 +85434,51 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { name.parent === (name.parent.parent as BinaryExpression).left ) { // Check if this is a special property assignment - if (!isPrivateIdentifier(name) && !isJSDocMemberName(name) && !isThisPropertyAndThisTyped(name.parent as PropertyAccessExpression)) { - const specialPropertyAssignmentSymbol = getSpecialPropertyAssignmentSymbolFromEntityName(name); + if ( + !isPrivateIdentifier(name) && + !isJSDocMemberName(name) && + !isThisPropertyAndThisTyped( + name.parent as PropertyAccessExpression + ) + ) { + const specialPropertyAssignmentSymbol = + getSpecialPropertyAssignmentSymbolFromEntityName(name); if (specialPropertyAssignmentSymbol) { return specialPropertyAssignmentSymbol; } } } - if (name.parent.kind === SyntaxKind.ExportAssignment && isEntityNameExpression(name)) { + if ( + name.parent.kind === SyntaxKind.ExportAssignment && + isEntityNameExpression(name) + ) { // Even an entity name expression that doesn't resolve as an entityname may still typecheck as a property access expression - const success = resolveEntityName(name, /*all meanings*/ SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, /*ignoreErrors*/ true); + const success = resolveEntityName( + name, + /*all meanings*/ SymbolFlags.Value | + SymbolFlags.Type | + SymbolFlags.Namespace | + SymbolFlags.Alias, + /*ignoreErrors*/ true + ); if (success && success !== unknownSymbol) { return success; } - } - else if (isEntityName(name) && isInRightSideOfImportOrExportAssignment(name)) { + } else if ( + isEntityName(name) && + isInRightSideOfImportOrExportAssignment(name) + ) { // Since we already checked for ExportAssignment, this really could only be an Import - const importEqualsDeclaration = getAncestor(name, SyntaxKind.ImportEqualsDeclaration); + const importEqualsDeclaration = getAncestor( + name, + SyntaxKind.ImportEqualsDeclaration + ); Debug.assert(importEqualsDeclaration !== undefined); - return getSymbolOfPartOfRightHandSideOfImportEquals(name, /*dontResolveAlias*/ true); + return getSymbolOfPartOfRightHandSideOfImportEquals( + name, + /*dontResolveAlias*/ true + ); } if (isEntityName(name)) { @@ -49657,8 +85490,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - while (isRightSideOfQualifiedNameOrPropertyAccessOrJSDocMemberName(name)) { - name = name.parent as QualifiedName | PropertyAccessEntityNameExpression | JSDocMemberName; + while ( + isRightSideOfQualifiedNameOrPropertyAccessOrJSDocMemberName(name) + ) { + name = name.parent as + | QualifiedName + | PropertyAccessEntityNameExpression + | JSDocMemberName; } if (isInNameOfExpressionWithTypeArguments(name)) { @@ -49666,31 +85504,47 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (name.parent.kind === SyntaxKind.ExpressionWithTypeArguments) { // An 'ExpressionWithTypeArguments' may appear in type space (interface Foo extends Bar), // value space (return foo), or both(class Foo extends Bar); ensure the meaning matches. - meaning = isPartOfTypeNode(name) ? SymbolFlags.Type : SymbolFlags.Value; + meaning = isPartOfTypeNode(name) + ? SymbolFlags.Type + : SymbolFlags.Value; // In a class 'extends' clause we are also looking for a value. - if (isExpressionWithTypeArgumentsInClassExtendsClause(name.parent)) { + if ( + isExpressionWithTypeArgumentsInClassExtendsClause( + name.parent + ) + ) { meaning |= SymbolFlags.Value; } - } - else { + } else { meaning = SymbolFlags.Namespace; } meaning |= SymbolFlags.Alias; - const entityNameSymbol = isEntityNameExpression(name) ? resolveEntityName(name, meaning, /*ignoreErrors*/ true) : undefined; + const entityNameSymbol = isEntityNameExpression(name) + ? resolveEntityName(name, meaning, /*ignoreErrors*/ true) + : undefined; if (entityNameSymbol) { return entityNameSymbol; } } if (name.parent.kind === SyntaxKind.JSDocParameterTag) { - return getParameterSymbolFromJSDoc(name.parent as JSDocParameterTag); + return getParameterSymbolFromJSDoc( + name.parent as JSDocParameterTag + ); } - if (name.parent.kind === SyntaxKind.TypeParameter && name.parent.parent.kind === SyntaxKind.JSDocTemplateTag) { + if ( + name.parent.kind === SyntaxKind.TypeParameter && + name.parent.parent.kind === SyntaxKind.JSDocTemplateTag + ) { Debug.assert(!isInJSFile(name)); // Otherwise `isDeclarationName` would have been true. - const typeParameter = getTypeParameterFromJsDoc(name.parent as TypeParameterDeclaration & { parent: JSDocTemplateTag; }); + const typeParameter = getTypeParameterFromJsDoc( + name.parent as TypeParameterDeclaration & { + parent: JSDocTemplateTag; + } + ); return typeParameter && typeParameter.symbol; } @@ -49700,32 +85554,65 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - const isJSDoc = findAncestor(name, or(isJSDocLinkLike, isJSDocNameReference, isJSDocMemberName)); - const meaning = isJSDoc ? SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Value : SymbolFlags.Value; + const isJSDoc = findAncestor( + name, + or(isJSDocLinkLike, isJSDocNameReference, isJSDocMemberName) + ); + const meaning = isJSDoc + ? SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Value + : SymbolFlags.Value; if (name.kind === SyntaxKind.Identifier) { if (isJSXTagName(name) && isJsxIntrinsicTagName(name)) { - const symbol = getIntrinsicTagSymbol(name.parent as JsxOpeningLikeElement); + const symbol = getIntrinsicTagSymbol( + name.parent as JsxOpeningLikeElement + ); return symbol === unknownSymbol ? undefined : symbol; } - const result = resolveEntityName(name, meaning, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, getHostSignatureFromJSDoc(name)); + const result = resolveEntityName( + name, + meaning, + /*ignoreErrors*/ true, + /*dontResolveAlias*/ true, + getHostSignatureFromJSDoc(name) + ); if (!result && isJSDoc) { - const container = findAncestor(name, or(isClassLike, isInterfaceDeclaration)); + const container = findAncestor( + name, + or(isClassLike, isInterfaceDeclaration) + ); if (container) { - return resolveJSDocMemberName(name, /*ignoreErrors*/ true, getSymbolOfDeclaration(container)); + return resolveJSDocMemberName( + name, + /*ignoreErrors*/ true, + getSymbolOfDeclaration(container) + ); } } if (result && isJSDoc) { const container = getJSDocHost(name); - if (container && isEnumMember(container) && container === result.valueDeclaration) { - return resolveEntityName(name, meaning, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, getSourceFileOfNode(container)) || result; + if ( + container && + isEnumMember(container) && + container === result.valueDeclaration + ) { + return ( + resolveEntityName( + name, + meaning, + /*ignoreErrors*/ true, + /*dontResolveAlias*/ true, + getSourceFileOfNode(container) + ) || result + ); } } return result; - } - else if (isPrivateIdentifier(name)) { + } else if (isPrivateIdentifier(name)) { return getSymbolForPrivateIdentifierExpression(name); - } - else if (name.kind === SyntaxKind.PropertyAccessExpression || name.kind === SyntaxKind.QualifiedName) { + } else if ( + name.kind === SyntaxKind.PropertyAccessExpression || + name.kind === SyntaxKind.QualifiedName + ) { const links = getNodeLinks(name); if (links.resolvedSymbol) { return links.resolvedSymbol; @@ -49734,28 +85621,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (name.kind === SyntaxKind.PropertyAccessExpression) { checkPropertyAccessExpression(name, CheckMode.Normal); if (!links.resolvedSymbol) { - links.resolvedSymbol = getApplicableIndexSymbol(checkExpressionCached(name.expression), getLiteralTypeFromPropertyName(name.name)); + links.resolvedSymbol = getApplicableIndexSymbol( + checkExpressionCached(name.expression), + getLiteralTypeFromPropertyName(name.name) + ); } - } - else { + } else { checkQualifiedName(name, CheckMode.Normal); } if (!links.resolvedSymbol && isJSDoc && isQualifiedName(name)) { return resolveJSDocMemberName(name); } return links.resolvedSymbol; - } - else if (isJSDocMemberName(name)) { + } else if (isJSDocMemberName(name)) { return resolveJSDocMemberName(name); } - } - else if (isEntityName(name) && isTypeReferenceIdentifier(name)) { - const meaning = name.parent.kind === SyntaxKind.TypeReference ? SymbolFlags.Type : SymbolFlags.Namespace; - const symbol = resolveEntityName(name, meaning, /*ignoreErrors*/ true, /*dontResolveAlias*/ true); - return symbol && symbol !== unknownSymbol ? symbol : getUnresolvedSymbolForEntityName(name); + } else if (isEntityName(name) && isTypeReferenceIdentifier(name)) { + const meaning = + name.parent.kind === SyntaxKind.TypeReference + ? SymbolFlags.Type + : SymbolFlags.Namespace; + const symbol = resolveEntityName( + name, + meaning, + /*ignoreErrors*/ true, + /*dontResolveAlias*/ true + ); + return symbol && symbol !== unknownSymbol + ? symbol + : getUnresolvedSymbolForEntityName(name); } if (name.parent.kind === SyntaxKind.TypePredicate) { - return resolveEntityName(name as Identifier, /*meaning*/ SymbolFlags.FunctionScopedVariable, /*ignoreErrors*/ true); + return resolveEntityName( + name as Identifier, + /*meaning*/ SymbolFlags.FunctionScopedVariable, + /*ignoreErrors*/ true + ); } return undefined; } @@ -49763,24 +85664,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getApplicableIndexSymbol(type: Type, keyType: Type) { const infos = getApplicableIndexInfos(type, keyType); if (infos.length && (type as ObjectType).members) { - const symbol = getIndexSymbolFromSymbolTable(resolveStructuredTypeMembers(type as ObjectType).members); + const symbol = getIndexSymbolFromSymbolTable( + resolveStructuredTypeMembers(type as ObjectType).members + ); if (infos === getIndexInfosOfType(type)) { return symbol; - } - else if (symbol) { + } else if (symbol) { const symbolLinks = getSymbolLinks(symbol); - const declarationList = mapDefined(infos, i => i.declaration); + const declarationList = mapDefined(infos, (i) => i.declaration); const nodeListId = map(declarationList, getNodeId).join(","); if (!symbolLinks.filteredIndexSymbolCache) { symbolLinks.filteredIndexSymbolCache = new Map(); } if (symbolLinks.filteredIndexSymbolCache.has(nodeListId)) { - return symbolLinks.filteredIndexSymbolCache.get(nodeListId)!; - } - else { - const copy = createSymbol(SymbolFlags.Signature, InternalSymbolName.Index); - copy.declarations = mapDefined(infos, i => i.declaration); - copy.parent = type.aliasSymbol ? type.aliasSymbol : type.symbol ? type.symbol : getSymbolAtLocation(copy.declarations[0].parent); + return symbolLinks.filteredIndexSymbolCache.get( + nodeListId + )!; + } else { + const copy = createSymbol( + SymbolFlags.Signature, + InternalSymbolName.Index + ); + copy.declarations = mapDefined(infos, (i) => i.declaration); + copy.parent = type.aliasSymbol + ? type.aliasSymbol + : type.symbol + ? type.symbol + : getSymbolAtLocation(copy.declarations[0].parent); symbolLinks.filteredIndexSymbolCache.set(nodeListId, copy); return copy; } @@ -49796,30 +85706,63 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * * For unqualified names, a container K may be provided as a second argument. */ - function resolveJSDocMemberName(name: EntityName | JSDocMemberName, ignoreErrors?: boolean, container?: Symbol): Symbol | undefined { + function resolveJSDocMemberName( + name: EntityName | JSDocMemberName, + ignoreErrors?: boolean, + container?: Symbol + ): Symbol | undefined { if (isEntityName(name)) { // resolve static values first - const meaning = SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Value; - let symbol = resolveEntityName(name, meaning, ignoreErrors, /*dontResolveAlias*/ true, getHostSignatureFromJSDoc(name)); + const meaning = + SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Value; + let symbol = resolveEntityName( + name, + meaning, + ignoreErrors, + /*dontResolveAlias*/ true, + getHostSignatureFromJSDoc(name) + ); if (!symbol && isIdentifier(name) && container) { - symbol = getMergedSymbol(getSymbol(getExportsOfSymbol(container), name.escapedText, meaning)); + symbol = getMergedSymbol( + getSymbol( + getExportsOfSymbol(container), + name.escapedText, + meaning + ) + ); } if (symbol) { return symbol; } } - const left = isIdentifier(name) ? container : resolveJSDocMemberName(name.left, ignoreErrors, container); - const right = isIdentifier(name) ? name.escapedText : name.right.escapedText; + const left = isIdentifier(name) + ? container + : resolveJSDocMemberName(name.left, ignoreErrors, container); + const right = isIdentifier(name) + ? name.escapedText + : name.right.escapedText; if (left) { - const proto = left.flags & SymbolFlags.Value && getPropertyOfType(getTypeOfSymbol(left), "prototype" as __String); - const t = proto ? getTypeOfSymbol(proto) : getDeclaredTypeOfSymbol(left); + const proto = + left.flags & SymbolFlags.Value && + getPropertyOfType( + getTypeOfSymbol(left), + "prototype" as __String + ); + const t = proto + ? getTypeOfSymbol(proto) + : getDeclaredTypeOfSymbol(left); return getPropertyOfType(t, right); } } - function getSymbolAtLocation(node: Node, ignoreErrors?: boolean): Symbol | undefined { + function getSymbolAtLocation( + node: Node, + ignoreErrors?: boolean + ): Symbol | undefined { if (isSourceFile(node)) { - return isExternalModule(node) ? getMergedSymbol(node.symbol) : undefined; + return isExternalModule(node) + ? getMergedSymbol(node.symbol) + : undefined; } const { parent } = node; const grandParent = parent.parent; @@ -49832,32 +85775,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isDeclarationNameOrImportPropertyName(node)) { // This is a declaration, call getSymbolOfNode const parentSymbol = getSymbolOfDeclaration(parent as Declaration); - return isImportOrExportSpecifier(node.parent) && node.parent.propertyName === node + return isImportOrExportSpecifier(node.parent) && + node.parent.propertyName === node ? getImmediateAliasedSymbol(parentSymbol) : parentSymbol; - } - else if (isLiteralComputedPropertyDeclarationName(node)) { + } else if (isLiteralComputedPropertyDeclarationName(node)) { return getSymbolOfDeclaration(parent.parent as Declaration); } if (node.kind === SyntaxKind.Identifier) { if (isInRightSideOfImportOrExportAssignment(node as Identifier)) { - return getSymbolOfNameOrPropertyAccessExpression(node as Identifier); - } - else if ( + return getSymbolOfNameOrPropertyAccessExpression( + node as Identifier + ); + } else if ( parent.kind === SyntaxKind.BindingElement && grandParent.kind === SyntaxKind.ObjectBindingPattern && node === (parent as BindingElement).propertyName ) { const typeOfPattern = getTypeOfNode(grandParent); - const propertyDeclaration = getPropertyOfType(typeOfPattern, (node as Identifier).escapedText); + const propertyDeclaration = getPropertyOfType( + typeOfPattern, + (node as Identifier).escapedText + ); if (propertyDeclaration) { return propertyDeclaration; } - } - else if (isMetaProperty(parent) && parent.name === node) { - if (parent.keywordToken === SyntaxKind.NewKeyword && idText(node as Identifier) === "target") { + } else if (isMetaProperty(parent) && parent.name === node) { + if ( + parent.keywordToken === SyntaxKind.NewKeyword && + idText(node as Identifier) === "target" + ) { // `target` in `new.target` return checkNewTargetMetaProperty(parent).symbol; } @@ -49865,8 +85814,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // we have a fake expression type made for other reasons already, whose transient `meta` // member should more exactly be the kind of (declarationless) symbol we want. // (See #44364 and #45031 for relevant implementation PRs) - if (parent.keywordToken === SyntaxKind.ImportKeyword && idText(node as Identifier) === "meta") { - return getGlobalImportMetaExpressionType().members!.get("meta" as __String); + if ( + parent.keywordToken === SyntaxKind.ImportKeyword && + idText(node as Identifier) === "meta" + ) { + return getGlobalImportMetaExpressionType().members!.get( + "meta" as __String + ); } // no other meta properties are valid syntax, thus no others should have symbols return undefined; @@ -49879,12 +85833,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.PropertyAccessExpression: case SyntaxKind.QualifiedName: if (!isThisInTypeQuery(node)) { - return getSymbolOfNameOrPropertyAccessExpression(node as EntityName | PrivateIdentifier | PropertyAccessExpression); + return getSymbolOfNameOrPropertyAccessExpression( + node as + | EntityName + | PrivateIdentifier + | PropertyAccessExpression + ); } - // falls through + // falls through case SyntaxKind.ThisKeyword: - const container = getThisContainer(node, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); + const container = getThisContainer( + node, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false + ); if (isFunctionLike(container)) { const sig = getSignatureFromDeclaration(container); if (sig.thisParameter) { @@ -49894,10 +85857,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isInExpressionContext(node)) { return checkExpression(node as Expression).symbol; } - // falls through + // falls through case SyntaxKind.ThisType: - return getTypeFromThisTypeNode(node as ThisExpression | ThisTypeNode).symbol; + return getTypeFromThisTypeNode( + node as ThisExpression | ThisTypeNode + ).symbol; case SyntaxKind.SuperKeyword: return checkExpression(node as Expression).symbol; @@ -49905,8 +85870,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ConstructorKeyword: // constructor keyword for an overload, should take us to the definition if it exist const constructorDeclaration = node.parent; - if (constructorDeclaration && constructorDeclaration.kind === SyntaxKind.Constructor) { - return (constructorDeclaration.parent as ClassDeclaration).symbol; + if ( + constructorDeclaration && + constructorDeclaration.kind === SyntaxKind.Constructor + ) { + return (constructorDeclaration.parent as ClassDeclaration) + .symbol; } return undefined; @@ -49917,27 +85886,63 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // 3). Dynamic import call or require in javascript // 4). type A = import("./f/*gotToDefinitionHere*/oo") if ( - (isExternalModuleImportEqualsDeclaration(node.parent.parent) && getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node) || - ((node.parent.kind === SyntaxKind.ImportDeclaration || node.parent.kind === SyntaxKind.ExportDeclaration) && (node.parent as ImportDeclaration).moduleSpecifier === node) || - (isInJSFile(node) && isJSDocImportTag(node.parent) && node.parent.moduleSpecifier === node) || - ((isInJSFile(node) && isRequireCall(node.parent, /*requireStringLiteralLikeArgument*/ false)) || isImportCall(node.parent)) || - (isLiteralTypeNode(node.parent) && isLiteralImportTypeNode(node.parent.parent) && node.parent.parent.argument === node.parent) + (isExternalModuleImportEqualsDeclaration( + node.parent.parent + ) && + getExternalModuleImportEqualsDeclarationExpression( + node.parent.parent + ) === node) || + ((node.parent.kind === SyntaxKind.ImportDeclaration || + node.parent.kind === SyntaxKind.ExportDeclaration) && + (node.parent as ImportDeclaration).moduleSpecifier === + node) || + (isInJSFile(node) && + isJSDocImportTag(node.parent) && + node.parent.moduleSpecifier === node) || + (isInJSFile(node) && + isRequireCall( + node.parent, + /*requireStringLiteralLikeArgument*/ false + )) || + isImportCall(node.parent) || + (isLiteralTypeNode(node.parent) && + isLiteralImportTypeNode(node.parent.parent) && + node.parent.parent.argument === node.parent) ) { - return resolveExternalModuleName(node, node as LiteralExpression, ignoreErrors); + return resolveExternalModuleName( + node, + node as LiteralExpression, + ignoreErrors + ); } - if (isCallExpression(parent) && isBindableObjectDefinePropertyCall(parent) && parent.arguments[1] === node) { + if ( + isCallExpression(parent) && + isBindableObjectDefinePropertyCall(parent) && + parent.arguments[1] === node + ) { return getSymbolOfDeclaration(parent); } - // falls through + // falls through case SyntaxKind.NumericLiteral: // index access const objectType = isElementAccessExpression(parent) - ? parent.argumentExpression === node ? getTypeOfExpression(parent.expression) : undefined - : isLiteralTypeNode(parent) && isIndexedAccessTypeNode(grandParent) + ? parent.argumentExpression === node + ? getTypeOfExpression(parent.expression) + : undefined + : isLiteralTypeNode(parent) && + isIndexedAccessTypeNode(grandParent) ? getTypeFromTypeNode(grandParent.objectType) : undefined; - return objectType && getPropertyOfType(objectType, escapeLeadingUnderscores((node as StringLiteral | NumericLiteral).text)); + return ( + objectType && + getPropertyOfType( + objectType, + escapeLeadingUnderscores( + (node as StringLiteral | NumericLiteral).text + ) + ) + ); case SyntaxKind.DefaultKeyword: case SyntaxKind.FunctionKeyword: @@ -49945,22 +85950,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ClassKeyword: return getSymbolOfNode(node.parent); case SyntaxKind.ImportType: - return isLiteralImportTypeNode(node) ? getSymbolAtLocation(node.argument.literal, ignoreErrors) : undefined; + return isLiteralImportTypeNode(node) + ? getSymbolAtLocation(node.argument.literal, ignoreErrors) + : undefined; case SyntaxKind.ExportKeyword: - return isExportAssignment(node.parent) ? Debug.checkDefined(node.parent.symbol) : undefined; + return isExportAssignment(node.parent) + ? Debug.checkDefined(node.parent.symbol) + : undefined; case SyntaxKind.ImportKeyword: - if (isMetaProperty(node.parent) && node.parent.name.escapedText === "defer") { + if ( + isMetaProperty(node.parent) && + node.parent.name.escapedText === "defer" + ) { return undefined; } - // falls through + // falls through case SyntaxKind.NewKeyword: - return isMetaProperty(node.parent) ? checkMetaPropertyKeyword(node.parent).symbol : undefined; + return isMetaProperty(node.parent) + ? checkMetaPropertyKeyword(node.parent).symbol + : undefined; case SyntaxKind.InstanceOfKeyword: if (isBinaryExpression(node.parent)) { const type = getTypeOfExpression(node.parent.right); - const hasInstanceMethodType = getSymbolHasInstanceMethodOfObjectType(type); + const hasInstanceMethodType = + getSymbolHasInstanceMethodOfObjectType(type); return hasInstanceMethodType?.symbol ?? type.symbol; } return undefined; @@ -49968,44 +85983,84 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return checkExpression(node as Expression).symbol; case SyntaxKind.JsxNamespacedName: if (isJSXTagName(node) && isJsxIntrinsicTagName(node)) { - const symbol = getIntrinsicTagSymbol(node.parent as JsxOpeningLikeElement); + const symbol = getIntrinsicTagSymbol( + node.parent as JsxOpeningLikeElement + ); return symbol === unknownSymbol ? undefined : symbol; } - // falls through + // falls through default: return undefined; } } - function getIndexInfosAtLocation(node: Node): readonly IndexInfo[] | undefined { - if (isIdentifier(node) && isPropertyAccessExpression(node.parent) && node.parent.name === node) { + function getIndexInfosAtLocation( + node: Node + ): readonly IndexInfo[] | undefined { + if ( + isIdentifier(node) && + isPropertyAccessExpression(node.parent) && + node.parent.name === node + ) { const keyType = getLiteralTypeFromPropertyName(node); const objectType = getTypeOfExpression(node.parent.expression); - const objectTypes = objectType.flags & TypeFlags.Union ? (objectType as UnionType).types : [objectType]; - return flatMap(objectTypes, t => filter(getIndexInfosOfType(t), info => isApplicableIndexType(keyType, info.keyType))); + const objectTypes = + objectType.flags & TypeFlags.Union + ? (objectType as UnionType).types + : [objectType]; + return flatMap(objectTypes, (t) => + filter(getIndexInfosOfType(t), (info) => + isApplicableIndexType(keyType, info.keyType) + ) + ); } return undefined; } - function getShorthandAssignmentValueSymbol(location: Node | undefined): Symbol | undefined { - if (location && location.kind === SyntaxKind.ShorthandPropertyAssignment) { - return resolveEntityName((location as ShorthandPropertyAssignment).name, SymbolFlags.Value | SymbolFlags.Alias, /*ignoreErrors*/ true); + function getShorthandAssignmentValueSymbol( + location: Node | undefined + ): Symbol | undefined { + if ( + location && + location.kind === SyntaxKind.ShorthandPropertyAssignment + ) { + return resolveEntityName( + (location as ShorthandPropertyAssignment).name, + SymbolFlags.Value | SymbolFlags.Alias, + /*ignoreErrors*/ true + ); } return undefined; } /** Returns the target of an export specifier without following aliases */ - function getExportSpecifierLocalTargetSymbol(node: ExportSpecifier | Identifier): Symbol | undefined { + function getExportSpecifierLocalTargetSymbol( + node: ExportSpecifier | Identifier + ): Symbol | undefined { if (isExportSpecifier(node)) { const name = node.propertyName || node.name; - return node.parent.parent.moduleSpecifier ? - getExternalModuleMember(node.parent.parent, node) : - name.kind === SyntaxKind.StringLiteral ? undefined : // Skip for invalid syntax like this: export { "x" } - resolveEntityName(name, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, /*ignoreErrors*/ true); - } - else { - return resolveEntityName(node, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, /*ignoreErrors*/ true); + return node.parent.parent.moduleSpecifier + ? getExternalModuleMember(node.parent.parent, node) + : name.kind === SyntaxKind.StringLiteral + ? undefined // Skip for invalid syntax like this: export { "x" } + : resolveEntityName( + name, + SymbolFlags.Value | + SymbolFlags.Type | + SymbolFlags.Namespace | + SymbolFlags.Alias, + /*ignoreErrors*/ true + ); + } else { + return resolveEntityName( + node, + SymbolFlags.Value | + SymbolFlags.Type | + SymbolFlags.Namespace | + SymbolFlags.Alias, + /*ignoreErrors*/ true + ); } } @@ -50019,11 +86074,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return errorType; } - const classDecl = tryGetClassImplementingOrExtendingExpressionWithTypeArguments(node); - const classType = classDecl && getDeclaredTypeOfClassOrInterface(getSymbolOfDeclaration(classDecl.class)); + const classDecl = + tryGetClassImplementingOrExtendingExpressionWithTypeArguments(node); + const classType = + classDecl && + getDeclaredTypeOfClassOrInterface( + getSymbolOfDeclaration(classDecl.class) + ); if (isPartOfTypeNode(node)) { const typeFromTypeNode = getTypeFromTypeNode(node as TypeNode); - return classType ? getTypeWithThisArgument(typeFromTypeNode, classType.thisType) : typeFromTypeNode; + return classType + ? getTypeWithThisArgument(typeFromTypeNode, classType.thisType) + : typeFromTypeNode; } if (isExpressionNode(node)) { @@ -50034,7 +86096,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // A SyntaxKind.ExpressionWithTypeArguments is considered a type node, except when it occurs in the // extends clause of a class. We handle that case here. const baseType = firstOrUndefined(getBaseTypes(classType)); - return baseType ? getTypeWithThisArgument(baseType, classType.thisType) : errorType; + return baseType + ? getTypeWithThisArgument(baseType, classType.thisType) + : errorType; } if (isTypeDeclaration(node)) { @@ -50049,7 +86113,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (isBindingElement(node)) { - return getTypeForVariableLikeDeclaration(node, /*includeOptionality*/ true, CheckMode.Normal) || errorType; + return ( + getTypeForVariableLikeDeclaration( + node, + /*includeOptionality*/ true, + CheckMode.Normal + ) || errorType + ); } if (isDeclaration(node)) { @@ -50067,18 +86137,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (isBindingPattern(node)) { - return getTypeForVariableLikeDeclaration(node.parent, /*includeOptionality*/ true, CheckMode.Normal) || errorType; + return ( + getTypeForVariableLikeDeclaration( + node.parent, + /*includeOptionality*/ true, + CheckMode.Normal + ) || errorType + ); } if (isInRightSideOfImportOrExportAssignment(node as Identifier)) { const symbol = getSymbolAtLocation(node); if (symbol) { const declaredType = getDeclaredTypeOfSymbol(symbol); - return !isErrorType(declaredType) ? declaredType : getTypeOfSymbol(symbol); + return !isErrorType(declaredType) + ? declaredType + : getTypeOfSymbol(symbol); } } - if (isMetaProperty(node.parent) && node.parent.keywordToken === node.kind) { + if ( + isMetaProperty(node.parent) && + node.parent.keywordToken === node.kind + ) { return checkMetaPropertyKeyword(node.parent); } @@ -50095,35 +86176,67 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // } // [ a ] from // [a] = [ some array ...] - function getTypeOfAssignmentPattern(expr: AssignmentPattern): Type | undefined { - Debug.assert(expr.kind === SyntaxKind.ObjectLiteralExpression || expr.kind === SyntaxKind.ArrayLiteralExpression); + function getTypeOfAssignmentPattern( + expr: AssignmentPattern + ): Type | undefined { + Debug.assert( + expr.kind === SyntaxKind.ObjectLiteralExpression || + expr.kind === SyntaxKind.ArrayLiteralExpression + ); // If this is from "for of" // for ( { a } of elems) { // } if (expr.parent.kind === SyntaxKind.ForOfStatement) { - const iteratedType = checkRightHandSideOfForOf(expr.parent as ForOfStatement); - return checkDestructuringAssignment(expr, iteratedType || errorType); + const iteratedType = checkRightHandSideOfForOf( + expr.parent as ForOfStatement + ); + return checkDestructuringAssignment( + expr, + iteratedType || errorType + ); } // If this is from "for" initializer // for ({a } = elems[0];.....) { } if (expr.parent.kind === SyntaxKind.BinaryExpression) { - const iteratedType = getTypeOfExpression((expr.parent as BinaryExpression).right); - return checkDestructuringAssignment(expr, iteratedType || errorType); + const iteratedType = getTypeOfExpression( + (expr.parent as BinaryExpression).right + ); + return checkDestructuringAssignment( + expr, + iteratedType || errorType + ); } // If this is from nested object binding pattern // for ({ skills: { primary, secondary } } = multiRobot, i = 0; i < 1; i++) { if (expr.parent.kind === SyntaxKind.PropertyAssignment) { const node = cast(expr.parent.parent, isObjectLiteralExpression); - const typeOfParentObjectLiteral = getTypeOfAssignmentPattern(node) || errorType; + const typeOfParentObjectLiteral = + getTypeOfAssignmentPattern(node) || errorType; const propertyIndex = indexOfNode(node.properties, expr.parent); - return checkObjectLiteralDestructuringPropertyAssignment(node, typeOfParentObjectLiteral, propertyIndex); + return checkObjectLiteralDestructuringPropertyAssignment( + node, + typeOfParentObjectLiteral, + propertyIndex + ); } // Array literal assignment - array destructuring pattern const node = cast(expr.parent, isArrayLiteralExpression); // [{ property1: p1, property2 }] = elems; - const typeOfArrayLiteral = getTypeOfAssignmentPattern(node) || errorType; - const elementType = checkIteratedTypeOrElementType(IterationUse.Destructuring, typeOfArrayLiteral, undefinedType, expr.parent) || errorType; - return checkArrayLiteralDestructuringElementAssignment(node, typeOfArrayLiteral, node.elements.indexOf(expr), elementType); + const typeOfArrayLiteral = + getTypeOfAssignmentPattern(node) || errorType; + const elementType = + checkIteratedTypeOrElementType( + IterationUse.Destructuring, + typeOfArrayLiteral, + undefinedType, + expr.parent + ) || errorType; + return checkArrayLiteralDestructuringElementAssignment( + node, + typeOfArrayLiteral, + node.elements.indexOf(expr), + elementType + ); } // Gets the property symbol corresponding to the property in destructuring assignment @@ -50134,8 +86247,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // [a] = [ property1, property2 ] function getPropertySymbolOfDestructuringAssignment(location: Identifier) { // Get the type of the object or array literal and then look for property of given name in the type - const typeOfObjectLiteral = getTypeOfAssignmentPattern(cast(location.parent.parent, isAssignmentPattern)); - return typeOfObjectLiteral && getPropertyOfType(typeOfObjectLiteral, location.escapedText); + const typeOfObjectLiteral = getTypeOfAssignmentPattern( + cast(location.parent.parent, isAssignmentPattern) + ); + return ( + typeOfObjectLiteral && + getPropertyOfType(typeOfObjectLiteral, location.escapedText) + ); } function getRegularTypeOfExpression(expr: Expression): Type { @@ -50166,7 +86284,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getStringLiteralType(name.text); case SyntaxKind.ComputedPropertyName: const nameType = checkComputedPropertyName(name); - return isTypeAssignableToKind(nameType, TypeFlags.ESSymbolLike) ? nameType : stringType; + return isTypeAssignableToKind(nameType, TypeFlags.ESSymbolLike) + ? nameType + : stringType; default: return Debug.fail("Unsupported property name."); } @@ -50177,11 +86297,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getAugmentedPropertiesOfType(type: Type): Symbol[] { type = getApparentType(type); const propsByName = createSymbolTable(getPropertiesOfType(type)); - const functionType = getSignaturesOfType(type, SignatureKind.Call).length ? globalCallableFunctionType : - getSignaturesOfType(type, SignatureKind.Construct).length ? globalNewableFunctionType : - undefined; + const functionType = getSignaturesOfType(type, SignatureKind.Call) + .length + ? globalCallableFunctionType + : getSignaturesOfType(type, SignatureKind.Construct).length + ? globalNewableFunctionType + : undefined; if (functionType) { - forEach(getPropertiesOfType(functionType), p => { + forEach(getPropertiesOfType(functionType), (p) => { if (!propsByName.has(p.escapedName)) { propsByName.set(p.escapedName, p); } @@ -50191,21 +86314,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function typeHasCallOrConstructSignatures(type: Type): boolean { - return getSignaturesOfType(type, SignatureKind.Call).length !== 0 || getSignaturesOfType(type, SignatureKind.Construct).length !== 0; + return ( + getSignaturesOfType(type, SignatureKind.Call).length !== 0 || + getSignaturesOfType(type, SignatureKind.Construct).length !== 0 + ); } function getRootSymbols(symbol: Symbol): readonly Symbol[] { const roots = getImmediateRootSymbols(symbol); return roots ? flatMap(roots, getRootSymbols) : [symbol]; } - function getImmediateRootSymbols(symbol: Symbol): readonly Symbol[] | undefined { + function getImmediateRootSymbols( + symbol: Symbol + ): readonly Symbol[] | undefined { if (getCheckFlags(symbol) & CheckFlags.Synthetic) { - return mapDefined(getSymbolLinks(symbol).containingType!.types, type => getPropertyOfType(type, symbol.escapedName)); - } - else if (symbol.flags & SymbolFlags.Transient) { - const { links: { leftSpread, rightSpread, syntheticOrigin } } = symbol as TransientSymbol; - return leftSpread ? [leftSpread, rightSpread!] - : syntheticOrigin ? [syntheticOrigin] + return mapDefined( + getSymbolLinks(symbol).containingType!.types, + (type) => getPropertyOfType(type, symbol.escapedName) + ); + } else if (symbol.flags & SymbolFlags.Transient) { + const { + links: { leftSpread, rightSpread, syntheticOrigin }, + } = symbol as TransientSymbol; + return leftSpread + ? [leftSpread, rightSpread!] + : syntheticOrigin + ? [syntheticOrigin] : singleElementArray(tryGetTarget(symbol)); } return undefined; @@ -50213,7 +86347,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function tryGetTarget(symbol: Symbol): Symbol | undefined { let target: Symbol | undefined; let next: Symbol | undefined = symbol; - while (next = getSymbolLinks(next).target) { + while ((next = getSymbolLinks(next).target)) { target = next; } return target; @@ -50228,47 +86362,75 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!node) return false; const parent = node.parent; if (!parent) return false; - const isPropertyName = (isPropertyAccessExpression(parent) - || isPropertyAssignment(parent)) - && parent.name === node; - return !isPropertyName && getReferencedValueSymbol(node) === argumentsSymbol; + const isPropertyName = + (isPropertyAccessExpression(parent) || + isPropertyAssignment(parent)) && + parent.name === node; + return ( + !isPropertyName && + getReferencedValueSymbol(node) === argumentsSymbol + ); } function isNameOfModuleOrEnumDeclaration(node: Identifier) { - return isModuleOrEnumDeclaration(node.parent) && node === node.parent.name; + return ( + isModuleOrEnumDeclaration(node.parent) && node === node.parent.name + ); } // When resolved as an expression identifier, if the given node references an exported entity, return the declaration // node of the exported entity's container. Otherwise, return undefined. - function getReferencedExportContainer(nodeIn: Identifier, prefixLocals?: boolean): SourceFile | ModuleDeclaration | EnumDeclaration | undefined { + function getReferencedExportContainer( + nodeIn: Identifier, + prefixLocals?: boolean + ): SourceFile | ModuleDeclaration | EnumDeclaration | undefined { const node = getParseTreeNode(nodeIn, isIdentifier); if (node) { // When resolving the export container for the name of a module or enum // declaration, we need to start resolution at the declaration's container. // Otherwise, we could incorrectly resolve the export container as the // declaration if it contains an exported member with the same name. - let symbol = getReferencedValueSymbol(node, /*startInDeclarationContainer*/ isNameOfModuleOrEnumDeclaration(node)); + let symbol = getReferencedValueSymbol( + node, + /*startInDeclarationContainer*/ isNameOfModuleOrEnumDeclaration( + node + ) + ); if (symbol) { if (symbol.flags & SymbolFlags.ExportValue) { // If we reference an exported entity within the same module declaration, then whether // we prefix depends on the kind of entity. SymbolFlags.ExportHasLocal encompasses all the // kinds that we do NOT prefix. const exportSymbol = getMergedSymbol(symbol.exportSymbol!); - if (!prefixLocals && exportSymbol.flags & SymbolFlags.ExportHasLocal && !(exportSymbol.flags & SymbolFlags.Variable)) { + if ( + !prefixLocals && + exportSymbol.flags & SymbolFlags.ExportHasLocal && + !(exportSymbol.flags & SymbolFlags.Variable) + ) { return undefined; } symbol = exportSymbol; } const parentSymbol = getParentOfSymbol(symbol); if (parentSymbol) { - if (parentSymbol.flags & SymbolFlags.ValueModule && parentSymbol.valueDeclaration?.kind === SyntaxKind.SourceFile) { - const symbolFile = parentSymbol.valueDeclaration as SourceFile; + if ( + parentSymbol.flags & SymbolFlags.ValueModule && + parentSymbol.valueDeclaration?.kind === + SyntaxKind.SourceFile + ) { + const symbolFile = + parentSymbol.valueDeclaration as SourceFile; const referenceFile = getSourceFileOfNode(node); // If `node` accesses an export and that export isn't in the same file, then symbol is a namespace export, so return undefined. const symbolIsUmdExport = symbolFile !== referenceFile; return symbolIsUmdExport ? undefined : symbolFile; } - return findAncestor(node.parent, (n): n is ModuleDeclaration | EnumDeclaration => isModuleOrEnumDeclaration(n) && getSymbolOfDeclaration(n) === parentSymbol); + return findAncestor( + node.parent, + (n): n is ModuleDeclaration | EnumDeclaration => + isModuleOrEnumDeclaration(n) && + getSymbolOfDeclaration(n) === parentSymbol + ); } } } @@ -50276,7 +86438,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // When resolved as an expression identifier, if the given node references an import, return the declaration of // that import. Otherwise, return undefined. - function getReferencedImportDeclaration(nodeIn: Identifier): Declaration | undefined { + function getReferencedImportDeclaration( + nodeIn: Identifier + ): Declaration | undefined { const specifier = getIdentifierGeneratedImportReference(nodeIn); if (specifier) { return specifier; @@ -50287,7 +86451,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We should only get the declaration of an alias if there isn't a local value // declaration for the symbol - if (isNonLocalAlias(symbol, /*excludes*/ SymbolFlags.Value) && !getTypeOnlyAliasDeclaration(symbol, SymbolFlags.Value)) { + if ( + isNonLocalAlias(symbol, /*excludes*/ SymbolFlags.Value) && + !getTypeOnlyAliasDeclaration(symbol, SymbolFlags.Value) + ) { return getDeclarationOfAliasSymbol(symbol); } } @@ -50296,22 +86463,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isSymbolOfDestructuredElementOfCatchBinding(symbol: Symbol) { - return symbol.valueDeclaration - && isBindingElement(symbol.valueDeclaration) - && walkUpBindingElementsAndPatterns(symbol.valueDeclaration).parent.kind === SyntaxKind.CatchClause; + return ( + symbol.valueDeclaration && + isBindingElement(symbol.valueDeclaration) && + walkUpBindingElementsAndPatterns(symbol.valueDeclaration).parent + .kind === SyntaxKind.CatchClause + ); } function isSymbolOfDeclarationWithCollidingName(symbol: Symbol): boolean { - if (symbol.flags & SymbolFlags.BlockScoped && symbol.valueDeclaration && !isSourceFile(symbol.valueDeclaration)) { + if ( + symbol.flags & SymbolFlags.BlockScoped && + symbol.valueDeclaration && + !isSourceFile(symbol.valueDeclaration) + ) { const links = getSymbolLinks(symbol); if (links.isDeclarationWithCollidingName === undefined) { - const container = getEnclosingBlockScopeContainer(symbol.valueDeclaration); - if (isStatementWithLocals(container) || isSymbolOfDestructuredElementOfCatchBinding(symbol)) { - if (resolveName(container.parent, symbol.escapedName, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*isUse*/ false)) { + const container = getEnclosingBlockScopeContainer( + symbol.valueDeclaration + ); + if ( + isStatementWithLocals(container) || + isSymbolOfDestructuredElementOfCatchBinding(symbol) + ) { + if ( + resolveName( + container.parent, + symbol.escapedName, + SymbolFlags.Value, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ false + ) + ) { // redeclaration - always should be renamed links.isDeclarationWithCollidingName = true; - } - else if (hasNodeCheckFlag(symbol.valueDeclaration, NodeCheckFlags.CapturedBlockScopedBinding)) { + } else if ( + hasNodeCheckFlag( + symbol.valueDeclaration, + NodeCheckFlags.CapturedBlockScopedBinding + ) + ) { // binding is captured in the function // should be renamed if: // - binding is not top level - top level bindings never collide with anything @@ -50327,13 +86518,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // * variables from initializer are passed to rewritten loop body as parameters so they are not captured directly // * variables that are declared immediately in loop body will become top level variable after loop is rewritten and thus // they will not collide with anything - const isDeclaredInLoop = hasNodeCheckFlag(symbol.valueDeclaration, NodeCheckFlags.BlockScopedBindingInLoop); - const inLoopInitializer = isIterationStatement(container, /*lookInLabeledStatements*/ false); - const inLoopBodyBlock = container.kind === SyntaxKind.Block && isIterationStatement(container.parent, /*lookInLabeledStatements*/ false); + const isDeclaredInLoop = hasNodeCheckFlag( + symbol.valueDeclaration, + NodeCheckFlags.BlockScopedBindingInLoop + ); + const inLoopInitializer = isIterationStatement( + container, + /*lookInLabeledStatements*/ false + ); + const inLoopBodyBlock = + container.kind === SyntaxKind.Block && + isIterationStatement( + container.parent, + /*lookInLabeledStatements*/ false + ); - links.isDeclarationWithCollidingName = !isBlockScopedContainerTopLevel(container) && (!isDeclaredInLoop || (!inLoopInitializer && !inLoopBodyBlock)); - } - else { + links.isDeclarationWithCollidingName = + !isBlockScopedContainerTopLevel(container) && + (!isDeclaredInLoop || + (!inLoopInitializer && !inLoopBodyBlock)); + } else { links.isDeclarationWithCollidingName = false; } } @@ -50346,7 +86550,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // When resolved as an expression identifier, if the given node references a nested block scoped entity with // a name that either hides an existing name or might hide it when compiled downlevel, // return the declaration of that entity. Otherwise, return undefined. - function getReferencedDeclarationWithCollidingName(nodeIn: Identifier): Declaration | undefined { + function getReferencedDeclarationWithCollidingName( + nodeIn: Identifier + ): Declaration | undefined { if (!isGeneratedIdentifier(nodeIn)) { const node = getParseTreeNode(nodeIn, isIdentifier); if (node) { @@ -50378,39 +86584,72 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { Debug.assert(canCollectSymbolAliasAccessabilityData); switch (node.kind) { case SyntaxKind.ImportEqualsDeclaration: - return isAliasResolvedToValue(getSymbolOfDeclaration(node as ImportEqualsDeclaration)); + return isAliasResolvedToValue( + getSymbolOfDeclaration(node as ImportEqualsDeclaration) + ); case SyntaxKind.ImportClause: case SyntaxKind.NamespaceImport: case SyntaxKind.ImportSpecifier: case SyntaxKind.ExportSpecifier: - const symbol = getSymbolOfDeclaration(node as ImportClause | NamespaceImport | ImportSpecifier | ExportSpecifier); - return !!symbol && isAliasResolvedToValue(symbol, /*excludeTypeOnlyValues*/ true); + const symbol = getSymbolOfDeclaration( + node as + | ImportClause + | NamespaceImport + | ImportSpecifier + | ExportSpecifier + ); + return ( + !!symbol && + isAliasResolvedToValue( + symbol, + /*excludeTypeOnlyValues*/ true + ) + ); case SyntaxKind.ExportDeclaration: const exportClause = (node as ExportDeclaration).exportClause; - return !!exportClause && ( - isNamespaceExport(exportClause) || - some(exportClause.elements, isValueAliasDeclaration) + return ( + !!exportClause && + (isNamespaceExport(exportClause) || + some(exportClause.elements, isValueAliasDeclaration)) ); case SyntaxKind.ExportAssignment: - return (node as ExportAssignment).expression && (node as ExportAssignment).expression.kind === SyntaxKind.Identifier ? - isAliasResolvedToValue(getSymbolOfDeclaration(node as ExportAssignment), /*excludeTypeOnlyValues*/ true) : - true; + return (node as ExportAssignment).expression && + (node as ExportAssignment).expression.kind === + SyntaxKind.Identifier + ? isAliasResolvedToValue( + getSymbolOfDeclaration(node as ExportAssignment), + /*excludeTypeOnlyValues*/ true + ) + : true; } return false; } - function isTopLevelValueImportEqualsWithEntityName(nodeIn: ImportEqualsDeclaration): boolean { + function isTopLevelValueImportEqualsWithEntityName( + nodeIn: ImportEqualsDeclaration + ): boolean { const node = getParseTreeNode(nodeIn, isImportEqualsDeclaration); - if (node === undefined || node.parent.kind !== SyntaxKind.SourceFile || !isInternalModuleImportEqualsDeclaration(node)) { + if ( + node === undefined || + node.parent.kind !== SyntaxKind.SourceFile || + !isInternalModuleImportEqualsDeclaration(node) + ) { // parent is not source file or it is not reference to internal module return false; } const isValue = isAliasResolvedToValue(getSymbolOfDeclaration(node)); - return isValue && node.moduleReference && !nodeIsMissing(node.moduleReference); + return ( + isValue && + node.moduleReference && + !nodeIsMissing(node.moduleReference) + ); } - function isAliasResolvedToValue(symbol: Symbol | undefined, excludeTypeOnlyValues?: boolean): boolean { + function isAliasResolvedToValue( + symbol: Symbol | undefined, + excludeTypeOnlyValues?: boolean + ): boolean { if (!symbol) { return false; } @@ -50420,21 +86659,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If we don't, the merge may not have yet occured, and the flags check below will be missing flags that // are added as a result of the merge. void resolveExternalModuleSymbol(fileSymbol); - const target = getExportSymbolOfValueSymbolIfExported(resolveAlias(symbol)); + const target = getExportSymbolOfValueSymbolIfExported( + resolveAlias(symbol) + ); if (target === unknownSymbol) { - return !excludeTypeOnlyValues || !getTypeOnlyAliasDeclaration(symbol); + return ( + !excludeTypeOnlyValues || !getTypeOnlyAliasDeclaration(symbol) + ); } // const enums and modules that contain only const enums are not considered values from the emit perspective // unless 'preserveConstEnums' option is set to true - return !!(getSymbolFlags(symbol, excludeTypeOnlyValues, /*excludeLocalMeanings*/ true) & SymbolFlags.Value) && - (shouldPreserveConstEnums(compilerOptions) || !isConstEnumOrConstEnumOnlyModule(target)); + return ( + !!( + getSymbolFlags( + symbol, + excludeTypeOnlyValues, + /*excludeLocalMeanings*/ true + ) & SymbolFlags.Value + ) && + (shouldPreserveConstEnums(compilerOptions) || + !isConstEnumOrConstEnumOnlyModule(target)) + ); } function isConstEnumOrConstEnumOnlyModule(s: Symbol): boolean { return isConstEnumSymbol(s) || !!s.constEnumOnlyModule; } - function isReferencedAliasDeclaration(node: Node, checkChildren?: boolean): boolean { + function isReferencedAliasDeclaration( + node: Node, + checkChildren?: boolean + ): boolean { Debug.assert(canCollectSymbolAliasAccessabilityData); if (isAliasSymbolDeclaration(node)) { const symbol = getSymbolOfDeclaration(node as Declaration); @@ -50444,9 +86699,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const target = getSymbolLinks(symbol).aliasTarget; if ( - target && getEffectiveModifierFlags(node) & ModifierFlags.Export && + target && + getEffectiveModifierFlags(node) & ModifierFlags.Export && getSymbolFlags(target) & SymbolFlags.Value && - (shouldPreserveConstEnums(compilerOptions) || !isConstEnumOrConstEnumOnlyModule(target)) + (shouldPreserveConstEnums(compilerOptions) || + !isConstEnumOrConstEnumOnlyModule(target)) ) { // An `export import ... =` of a value symbol is always considered referenced return true; @@ -50454,7 +86711,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (checkChildren) { - return !!forEachChild(node, node => isReferencedAliasDeclaration(node, checkChildren)); + return !!forEachChild(node, (node) => + isReferencedAliasDeclaration(node, checkChildren) + ); } return false; } @@ -50470,18 +86729,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // function foo(a: any) { // This is implementation of the overloads // return a; // } - return signaturesOfSymbol.length > 1 || + return ( + signaturesOfSymbol.length > 1 || // If there is single signature for the symbol, it is overload if that signature isn't coming from the node // e.g.: function foo(a: string): string; // function foo(a: any) { // This is implementation of the overloads // return a; // } - (signaturesOfSymbol.length === 1 && signaturesOfSymbol[0].declaration !== node); + (signaturesOfSymbol.length === 1 && + signaturesOfSymbol[0].declaration !== node) + ); } return false; } - function declaredParameterTypeContainsUndefined(parameter: ParameterDeclaration | JSDocParameterTag) { + function declaredParameterTypeContainsUndefined( + parameter: ParameterDeclaration | JSDocParameterTag + ) { const typeNode = getNonlocalEffectiveTypeAnnotationNode(parameter); if (!typeNode) return false; const type = getTypeFromTypeNode(typeNode); @@ -50491,35 +86755,72 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return isErrorType(type) || containsUndefinedType(type); } - function requiresAddingImplicitUndefined(parameter: ParameterDeclaration | JSDocParameterTag, enclosingDeclaration: Node | undefined) { - return (isRequiredInitializedParameter(parameter, enclosingDeclaration) || isOptionalUninitializedParameterProperty(parameter)) && !declaredParameterTypeContainsUndefined(parameter); + function requiresAddingImplicitUndefined( + parameter: ParameterDeclaration | JSDocParameterTag, + enclosingDeclaration: Node | undefined + ) { + return ( + (isRequiredInitializedParameter(parameter, enclosingDeclaration) || + isOptionalUninitializedParameterProperty(parameter)) && + !declaredParameterTypeContainsUndefined(parameter) + ); } - function isRequiredInitializedParameter(parameter: ParameterDeclaration | JSDocParameterTag, enclosingDeclaration: Node | undefined): boolean { - if (!strictNullChecks || isOptionalParameter(parameter) || isJSDocParameterTag(parameter) || !parameter.initializer) { + function isRequiredInitializedParameter( + parameter: ParameterDeclaration | JSDocParameterTag, + enclosingDeclaration: Node | undefined + ): boolean { + if ( + !strictNullChecks || + isOptionalParameter(parameter) || + isJSDocParameterTag(parameter) || + !parameter.initializer + ) { return false; } - if (hasSyntacticModifier(parameter, ModifierFlags.ParameterPropertyModifier)) { - return !!enclosingDeclaration && isFunctionLikeDeclaration(enclosingDeclaration); + if ( + hasSyntacticModifier( + parameter, + ModifierFlags.ParameterPropertyModifier + ) + ) { + return ( + !!enclosingDeclaration && + isFunctionLikeDeclaration(enclosingDeclaration) + ); } return true; } - function isOptionalUninitializedParameterProperty(parameter: ParameterDeclaration | JSDocParameterTag) { - return strictNullChecks && + function isOptionalUninitializedParameterProperty( + parameter: ParameterDeclaration | JSDocParameterTag + ) { + return ( + strictNullChecks && isOptionalParameter(parameter) && (isJSDocParameterTag(parameter) || !parameter.initializer) && - hasSyntacticModifier(parameter, ModifierFlags.ParameterPropertyModifier); + hasSyntacticModifier( + parameter, + ModifierFlags.ParameterPropertyModifier + ) + ); } function isExpandoFunctionDeclaration(node: Declaration): boolean { - const declaration = getParseTreeNode(node, (n): n is FunctionDeclaration | VariableDeclaration => isFunctionDeclaration(n) || isVariableDeclaration(n)); + const declaration = getParseTreeNode( + node, + (n): n is FunctionDeclaration | VariableDeclaration => + isFunctionDeclaration(n) || isVariableDeclaration(n) + ); if (!declaration) { return false; } let symbol: Symbol | undefined; if (isVariableDeclaration(declaration)) { - if (declaration.type || (!isInJSFile(declaration) && !isVarConstLike(declaration))) { + if ( + declaration.type || + (!isInJSFile(declaration) && !isVarConstLike(declaration)) + ) { return false; } const initializer = getDeclaredExpandoInitializer(declaration); @@ -50527,14 +86828,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } symbol = getSymbolOfDeclaration(initializer); - } - else { + } else { symbol = getSymbolOfDeclaration(declaration); } - if (!symbol || !(symbol.flags & SymbolFlags.Function | SymbolFlags.Variable)) { + if ( + !symbol || + !((symbol.flags & SymbolFlags.Function) | SymbolFlags.Variable) + ) { return false; } - return !!forEachEntry(getExportsOfSymbol(symbol), p => p.flags & SymbolFlags.Value && isExpandoPropertyDeclaration(p.valueDeclaration)); + return !!forEachEntry( + getExportsOfSymbol(symbol), + (p) => + p.flags & SymbolFlags.Value && + isExpandoPropertyDeclaration(p.valueDeclaration) + ); } function getPropertiesOfContainerFunction(node: Declaration): Symbol[] { @@ -50543,7 +86851,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return emptyArray; } const symbol = getSymbolOfDeclaration(declaration); - return symbol && getPropertiesOfType(getTypeOfSymbol(symbol)) || emptyArray; + return ( + (symbol && getPropertiesOfType(getTypeOfSymbol(symbol))) || + emptyArray + ); } function getNodeCheckFlags(node: Node): NodeCheckFlags { @@ -50557,8 +86868,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return !!(getNodeCheckFlags(node) & flag); } - function calculateNodeCheckFlagWorker(node: Node, flag: LazyNodeCheckFlags) { - if (!compilerOptions.noCheck && canIncludeBindAndCheckDiagnostics(getSourceFileOfNode(node), compilerOptions)) { + function calculateNodeCheckFlagWorker( + node: Node, + flag: LazyNodeCheckFlags + ) { + if ( + !compilerOptions.noCheck && + canIncludeBindAndCheckDiagnostics( + getSourceFileOfNode(node), + compilerOptions + ) + ) { // Unless noCheck is passed, assume calculation of node check flags has been done eagerly. // This saves needing to mark up where in the eager traversal certain results are "done", // just to reconcile the eager and lazy results. This wouldn't be hard if an eager typecheck @@ -50598,10 +86918,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case NodeCheckFlags.CapturedBlockScopedBinding: return checkContainingBlockScopeBindingUses(node); default: - return Debug.assertNever(flag, `Unhandled node check flag calculation: ${Debug.formatNodeCheckFlags(flag)}`); + return Debug.assertNever( + flag, + `Unhandled node check flag calculation: ${Debug.formatNodeCheckFlags( + flag + )}` + ); } - function forEachNodeRecursively(root: Node, cb: (node: Node, parent: Node) => T | "skip" | undefined): T | undefined { + function forEachNodeRecursively( + root: Node, + cb: (node: Node, parent: Node) => T | "skip" | undefined + ): T | undefined { const rootResult = cb(root, root.parent); if (rootResult === "skip") return undefined; if (rootResult) return rootResult; @@ -50611,7 +86939,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkSuperExpressions(node: Node) { const links = getNodeLinks(node); if (links.calculatedFlags & flag) return "skip"; - links.calculatedFlags |= NodeCheckFlags.MethodWithSuperPropertyAccessInAsync | NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync | NodeCheckFlags.ContainsSuperPropertyInStaticInitializer; + links.calculatedFlags |= + NodeCheckFlags.MethodWithSuperPropertyAccessInAsync | + NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync | + NodeCheckFlags.ContainsSuperPropertyInStaticInitializer; checkSingleSuperExpression(node); return undefined; } @@ -50622,7 +86953,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkSingleSuperExpression(node: Node) { const nodeLinks = getNodeLinks(node); // This is called on sub-nodes of the original input, make sure we set `calculatedFlags` on the correct node - nodeLinks.calculatedFlags |= NodeCheckFlags.SuperInstance | NodeCheckFlags.SuperStatic; // Yes, we set this on non-applicable nodes, so we can entirely skip the traversal on future calls + nodeLinks.calculatedFlags |= + NodeCheckFlags.SuperInstance | NodeCheckFlags.SuperStatic; // Yes, we set this on non-applicable nodes, so we can entirely skip the traversal on future calls if (node.kind === SyntaxKind.SuperKeyword) { checkSuperExpression(node); } @@ -50631,7 +86963,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkIdentifiers(node: Node) { const links = getNodeLinks(node); if (links.calculatedFlags & flag) return "skip"; - links.calculatedFlags |= NodeCheckFlags.CaptureArguments | NodeCheckFlags.ContainsCapturedBlockScopeBinding | NodeCheckFlags.NeedsLoopOutParameter | NodeCheckFlags.ContainsConstructorReference; + links.calculatedFlags |= + NodeCheckFlags.CaptureArguments | + NodeCheckFlags.ContainsCapturedBlockScopeBinding | + NodeCheckFlags.NeedsLoopOutParameter | + NodeCheckFlags.ContainsConstructorReference; checkSingleIdentifier(node); return undefined; } @@ -50640,18 +86976,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { forEachNodeRecursively(node, checkIdentifiers); } - function isExpressionNodeOrShorthandPropertyAssignmentName(node: Identifier) { + function isExpressionNodeOrShorthandPropertyAssignmentName( + node: Identifier + ) { // TODO(jakebailey): Just use isExpressionNode once that considers these identifiers to be expressions. - return isExpressionNode(node) - || isShorthandPropertyAssignment(node.parent) && (node.parent.objectAssignmentInitializer ?? node.parent.name) === node; + return ( + isExpressionNode(node) || + (isShorthandPropertyAssignment(node.parent) && + (node.parent.objectAssignmentInitializer ?? + node.parent.name) === node) + ); } function checkSingleIdentifier(node: Node) { const nodeLinks = getNodeLinks(node); nodeLinks.calculatedFlags |= NodeCheckFlags.ConstructorReference; if (isIdentifier(node)) { - nodeLinks.calculatedFlags |= NodeCheckFlags.BlockScopedBindingInLoop | NodeCheckFlags.CapturedBlockScopedBinding; // Can't set on all arbitrary nodes (these nodes have this flag set by `checkSingleBlockScopeBinding` only) - if (isExpressionNodeOrShorthandPropertyAssignmentName(node) && !(isPropertyAccessExpression(node.parent) && node.parent.name === node)) { + nodeLinks.calculatedFlags |= + NodeCheckFlags.BlockScopedBindingInLoop | + NodeCheckFlags.CapturedBlockScopedBinding; // Can't set on all arbitrary nodes (these nodes have this flag set by `checkSingleBlockScopeBinding` only) + if ( + isExpressionNodeOrShorthandPropertyAssignmentName(node) && + !( + isPropertyAccessExpression(node.parent) && + node.parent.name === node + ) + ) { const s = getResolvedSymbol(node); if (s && s !== unknownSymbol) { checkIdentifierCalculateNodeCheckFlags(node, s); @@ -50663,13 +87013,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkBlockScopeBindings(node: Node) { const links = getNodeLinks(node); if (links.calculatedFlags & flag) return "skip"; - links.calculatedFlags |= NodeCheckFlags.LoopWithCapturedBlockScopedBinding | NodeCheckFlags.BlockScopedBindingInLoop | NodeCheckFlags.CapturedBlockScopedBinding; + links.calculatedFlags |= + NodeCheckFlags.LoopWithCapturedBlockScopedBinding | + NodeCheckFlags.BlockScopedBindingInLoop | + NodeCheckFlags.CapturedBlockScopedBinding; checkSingleBlockScopeBinding(node); return undefined; } function checkContainingBlockScopeBindingUses(node: Node) { - const scope = getEnclosingBlockScopeContainer(isDeclarationName(node) ? node.parent : node); + const scope = getEnclosingBlockScopeContainer( + isDeclarationName(node) ? node.parent : node + ); forEachNodeRecursively(scope, checkBlockScopeBindings); } @@ -50679,17 +87034,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkComputedPropertyName(node); } if (isPrivateIdentifier(node) && isClassElement(node.parent)) { - setNodeLinksForPrivateIdentifierScope(node.parent as PropertyDeclaration | PropertySignature | MethodDeclaration | MethodSignature | AccessorDeclaration); + setNodeLinksForPrivateIdentifierScope( + node.parent as + | PropertyDeclaration + | PropertySignature + | MethodDeclaration + | MethodSignature + | AccessorDeclaration + ); } } } function getEnumMemberValue(node: EnumMember): EvaluatorResult { computeEnumMemberValues(node.parent); - return getNodeLinks(node).enumMemberValue ?? evaluatorResult(/*value*/ undefined); + return ( + getNodeLinks(node).enumMemberValue ?? + evaluatorResult(/*value*/ undefined) + ); } - function canHaveConstantValue(node: Node): node is EnumMember | AccessExpression { + function canHaveConstantValue( + node: Node + ): node is EnumMember | AccessExpression { switch (node.kind) { case SyntaxKind.EnumMember: case SyntaxKind.PropertyAccessExpression: @@ -50699,7 +87066,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function getConstantValue(node: EnumMember | AccessExpression): string | number | undefined { + function getConstantValue( + node: EnumMember | AccessExpression + ): string | number | undefined { if (node.kind === SyntaxKind.EnumMember) { return getEnumMemberValue(node).value; } @@ -50707,8 +87076,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!getNodeLinks(node).resolvedSymbol) { void checkExpressionCached(node); // ensure cached resolved symbol is set } - const symbol = getNodeLinks(node).resolvedSymbol || (isEntityNameExpression(node) ? resolveEntityName(node, SymbolFlags.Value, /*ignoreErrors*/ true) : undefined); - if (symbol && (symbol.flags & SymbolFlags.EnumMember)) { + const symbol = + getNodeLinks(node).resolvedSymbol || + (isEntityNameExpression(node) + ? resolveEntityName( + node, + SymbolFlags.Value, + /*ignoreErrors*/ true + ) + : undefined); + if (symbol && symbol.flags & SymbolFlags.EnumMember) { // inline property\index accesses only for const enums const member = symbol.valueDeclaration as EnumMember; if (isEnumConst(member.parent)) { @@ -50720,10 +87097,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isFunctionType(type: Type): boolean { - return !!(type.flags & TypeFlags.Object) && getSignaturesOfType(type, SignatureKind.Call).length > 0; + return ( + !!(type.flags & TypeFlags.Object) && + getSignaturesOfType(type, SignatureKind.Call).length > 0 + ); } - function getTypeReferenceSerializationKind(typeNameIn: EntityName, location?: Node): TypeReferenceSerializationKind { + function getTypeReferenceSerializationKind( + typeNameIn: EntityName, + location?: Node + ): TypeReferenceSerializationKind { // ensure both `typeName` and `location` are parse tree nodes. const typeName = getParseTreeNode(typeNameIn, isEntityName); if (!typeName) return TypeReferenceSerializationKind.Unknown; @@ -50736,95 +87119,167 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Resolve the symbol as a value to ensure the type can be reached at runtime during emit. let isTypeOnly = false; if (isQualifiedName(typeName)) { - const rootValueSymbol = resolveEntityName(getFirstIdentifier(typeName), SymbolFlags.Value, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, location); - isTypeOnly = !!rootValueSymbol?.declarations?.every(isTypeOnlyImportOrExportDeclaration); + const rootValueSymbol = resolveEntityName( + getFirstIdentifier(typeName), + SymbolFlags.Value, + /*ignoreErrors*/ true, + /*dontResolveAlias*/ true, + location + ); + isTypeOnly = !!rootValueSymbol?.declarations?.every( + isTypeOnlyImportOrExportDeclaration + ); } - const valueSymbol = resolveEntityName(typeName, SymbolFlags.Value, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, location); - const resolvedValueSymbol = valueSymbol && valueSymbol.flags & SymbolFlags.Alias ? resolveAlias(valueSymbol) : valueSymbol; - isTypeOnly ||= !!(valueSymbol && getTypeOnlyAliasDeclaration(valueSymbol, SymbolFlags.Value)); + const valueSymbol = resolveEntityName( + typeName, + SymbolFlags.Value, + /*ignoreErrors*/ true, + /*dontResolveAlias*/ true, + location + ); + const resolvedValueSymbol = + valueSymbol && valueSymbol.flags & SymbolFlags.Alias + ? resolveAlias(valueSymbol) + : valueSymbol; + isTypeOnly ||= !!( + valueSymbol && + getTypeOnlyAliasDeclaration(valueSymbol, SymbolFlags.Value) + ); // Resolve the symbol as a type so that we can provide a more useful hint for the type serializer. - const typeSymbol = resolveEntityName(typeName, SymbolFlags.Type, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, location); - const resolvedTypeSymbol = typeSymbol && typeSymbol.flags & SymbolFlags.Alias ? resolveAlias(typeSymbol) : typeSymbol; + const typeSymbol = resolveEntityName( + typeName, + SymbolFlags.Type, + /*ignoreErrors*/ true, + /*dontResolveAlias*/ true, + location + ); + const resolvedTypeSymbol = + typeSymbol && typeSymbol.flags & SymbolFlags.Alias + ? resolveAlias(typeSymbol) + : typeSymbol; // In case the value symbol can't be resolved (e.g. because of missing declarations), use type symbol for reachability check. if (!valueSymbol) { - isTypeOnly ||= !!(typeSymbol && getTypeOnlyAliasDeclaration(typeSymbol, SymbolFlags.Type)); + isTypeOnly ||= !!( + typeSymbol && + getTypeOnlyAliasDeclaration(typeSymbol, SymbolFlags.Type) + ); } if (resolvedValueSymbol && resolvedValueSymbol === resolvedTypeSymbol) { - const globalPromiseSymbol = getGlobalPromiseConstructorSymbol(/*reportErrors*/ false); - if (globalPromiseSymbol && resolvedValueSymbol === globalPromiseSymbol) { + const globalPromiseSymbol = getGlobalPromiseConstructorSymbol( + /*reportErrors*/ false + ); + if ( + globalPromiseSymbol && + resolvedValueSymbol === globalPromiseSymbol + ) { return TypeReferenceSerializationKind.Promise; } const constructorType = getTypeOfSymbol(resolvedValueSymbol); if (constructorType && isConstructorType(constructorType)) { - return isTypeOnly ? TypeReferenceSerializationKind.TypeWithCallSignature : TypeReferenceSerializationKind.TypeWithConstructSignatureAndValue; + return isTypeOnly + ? TypeReferenceSerializationKind.TypeWithCallSignature + : TypeReferenceSerializationKind.TypeWithConstructSignatureAndValue; } } // We might not be able to resolve type symbol so use unknown type in that case (eg error case) if (!resolvedTypeSymbol) { - return isTypeOnly ? TypeReferenceSerializationKind.ObjectType : TypeReferenceSerializationKind.Unknown; + return isTypeOnly + ? TypeReferenceSerializationKind.ObjectType + : TypeReferenceSerializationKind.Unknown; } const type = getDeclaredTypeOfSymbol(resolvedTypeSymbol); if (isErrorType(type)) { - return isTypeOnly ? TypeReferenceSerializationKind.ObjectType : TypeReferenceSerializationKind.Unknown; - } - else if (type.flags & TypeFlags.AnyOrUnknown) { + return isTypeOnly + ? TypeReferenceSerializationKind.ObjectType + : TypeReferenceSerializationKind.Unknown; + } else if (type.flags & TypeFlags.AnyOrUnknown) { return TypeReferenceSerializationKind.ObjectType; - } - else if (isTypeAssignableToKind(type, TypeFlags.Void | TypeFlags.Nullable | TypeFlags.Never)) { + } else if ( + isTypeAssignableToKind( + type, + TypeFlags.Void | TypeFlags.Nullable | TypeFlags.Never + ) + ) { return TypeReferenceSerializationKind.VoidNullableOrNeverType; - } - else if (isTypeAssignableToKind(type, TypeFlags.BooleanLike)) { + } else if (isTypeAssignableToKind(type, TypeFlags.BooleanLike)) { return TypeReferenceSerializationKind.BooleanType; - } - else if (isTypeAssignableToKind(type, TypeFlags.NumberLike)) { + } else if (isTypeAssignableToKind(type, TypeFlags.NumberLike)) { return TypeReferenceSerializationKind.NumberLikeType; - } - else if (isTypeAssignableToKind(type, TypeFlags.BigIntLike)) { + } else if (isTypeAssignableToKind(type, TypeFlags.BigIntLike)) { return TypeReferenceSerializationKind.BigIntLikeType; - } - else if (isTypeAssignableToKind(type, TypeFlags.StringLike)) { + } else if (isTypeAssignableToKind(type, TypeFlags.StringLike)) { return TypeReferenceSerializationKind.StringLikeType; - } - else if (isTupleType(type)) { + } else if (isTupleType(type)) { return TypeReferenceSerializationKind.ArrayLikeType; - } - else if (isTypeAssignableToKind(type, TypeFlags.ESSymbolLike)) { + } else if (isTypeAssignableToKind(type, TypeFlags.ESSymbolLike)) { return TypeReferenceSerializationKind.ESSymbolType; - } - else if (isFunctionType(type)) { + } else if (isFunctionType(type)) { return TypeReferenceSerializationKind.TypeWithCallSignature; - } - else if (isArrayType(type)) { + } else if (isArrayType(type)) { return TypeReferenceSerializationKind.ArrayLikeType; - } - else { + } else { return TypeReferenceSerializationKind.ObjectType; } } - function createTypeOfDeclaration(declarationIn: HasInferredType, enclosingDeclaration: Node, flags: NodeBuilderFlags, internalFlags: InternalNodeBuilderFlags, tracker: SymbolTracker) { + function createTypeOfDeclaration( + declarationIn: HasInferredType, + enclosingDeclaration: Node, + flags: NodeBuilderFlags, + internalFlags: InternalNodeBuilderFlags, + tracker: SymbolTracker + ) { const declaration = getParseTreeNode(declarationIn, hasInferredType); if (!declaration) { - return factory.createToken(SyntaxKind.AnyKeyword) as KeywordTypeNode; + return factory.createToken( + SyntaxKind.AnyKeyword + ) as KeywordTypeNode; } // Get type of the symbol if this is the valid symbol otherwise get type at location const symbol = getSymbolOfDeclaration(declaration); - return nodeBuilder.serializeTypeForDeclaration(declaration, symbol, enclosingDeclaration, flags | NodeBuilderFlags.MultilineObjectLiterals, internalFlags, tracker); + return nodeBuilder.serializeTypeForDeclaration( + declaration, + symbol, + enclosingDeclaration, + flags | NodeBuilderFlags.MultilineObjectLiterals, + internalFlags, + tracker + ); } - function getAllAccessorDeclarationsForDeclaration(accessor: AccessorDeclaration): AllAccessorDeclarations { + function getAllAccessorDeclarationsForDeclaration( + accessor: AccessorDeclaration + ): AllAccessorDeclarations { accessor = getParseTreeNode(accessor, isGetOrSetAccessorDeclaration)!; // TODO: GH#18217 - const otherKind = accessor.kind === SyntaxKind.SetAccessor ? SyntaxKind.GetAccessor : SyntaxKind.SetAccessor; - const otherAccessor = getDeclarationOfKind(getSymbolOfDeclaration(accessor), otherKind); - const firstAccessor = otherAccessor && (otherAccessor.pos < accessor.pos) ? otherAccessor : accessor; - const secondAccessor = otherAccessor && (otherAccessor.pos < accessor.pos) ? accessor : otherAccessor; - const setAccessor = accessor.kind === SyntaxKind.SetAccessor ? accessor : otherAccessor as SetAccessorDeclaration; - const getAccessor = accessor.kind === SyntaxKind.GetAccessor ? accessor : otherAccessor as GetAccessorDeclaration; + const otherKind = + accessor.kind === SyntaxKind.SetAccessor + ? SyntaxKind.GetAccessor + : SyntaxKind.SetAccessor; + const otherAccessor = getDeclarationOfKind( + getSymbolOfDeclaration(accessor), + otherKind + ); + const firstAccessor = + otherAccessor && otherAccessor.pos < accessor.pos + ? otherAccessor + : accessor; + const secondAccessor = + otherAccessor && otherAccessor.pos < accessor.pos + ? accessor + : otherAccessor; + const setAccessor = + accessor.kind === SyntaxKind.SetAccessor + ? accessor + : (otherAccessor as SetAccessorDeclaration); + const getAccessor = + accessor.kind === SyntaxKind.GetAccessor + ? accessor + : (otherAccessor as GetAccessorDeclaration); return { firstAccessor, secondAccessor, @@ -50832,27 +87287,61 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { getAccessor, }; } - function createReturnTypeOfSignatureDeclaration(signatureDeclarationIn: SignatureDeclaration, enclosingDeclaration: Node, flags: NodeBuilderFlags, internalFlags: InternalNodeBuilderFlags, tracker: SymbolTracker) { - const signatureDeclaration = getParseTreeNode(signatureDeclarationIn, isFunctionLike); + function createReturnTypeOfSignatureDeclaration( + signatureDeclarationIn: SignatureDeclaration, + enclosingDeclaration: Node, + flags: NodeBuilderFlags, + internalFlags: InternalNodeBuilderFlags, + tracker: SymbolTracker + ) { + const signatureDeclaration = getParseTreeNode( + signatureDeclarationIn, + isFunctionLike + ); if (!signatureDeclaration) { - return factory.createToken(SyntaxKind.AnyKeyword) as KeywordTypeNode; + return factory.createToken( + SyntaxKind.AnyKeyword + ) as KeywordTypeNode; } - return nodeBuilder.serializeReturnTypeForSignature(signatureDeclaration, enclosingDeclaration, flags | NodeBuilderFlags.MultilineObjectLiterals, internalFlags, tracker); + return nodeBuilder.serializeReturnTypeForSignature( + signatureDeclaration, + enclosingDeclaration, + flags | NodeBuilderFlags.MultilineObjectLiterals, + internalFlags, + tracker + ); } - function createTypeOfExpression(exprIn: Expression, enclosingDeclaration: Node, flags: NodeBuilderFlags, internalFlags: InternalNodeBuilderFlags, tracker: SymbolTracker) { + function createTypeOfExpression( + exprIn: Expression, + enclosingDeclaration: Node, + flags: NodeBuilderFlags, + internalFlags: InternalNodeBuilderFlags, + tracker: SymbolTracker + ) { const expr = getParseTreeNode(exprIn, isExpression); if (!expr) { - return factory.createToken(SyntaxKind.AnyKeyword) as KeywordTypeNode; + return factory.createToken( + SyntaxKind.AnyKeyword + ) as KeywordTypeNode; } - return nodeBuilder.serializeTypeForExpression(expr, enclosingDeclaration, flags | NodeBuilderFlags.MultilineObjectLiterals, internalFlags, tracker); + return nodeBuilder.serializeTypeForExpression( + expr, + enclosingDeclaration, + flags | NodeBuilderFlags.MultilineObjectLiterals, + internalFlags, + tracker + ); } function hasGlobalName(name: string): boolean { return globals.has(escapeLeadingUnderscores(name)); } - function getReferencedValueSymbol(reference: Identifier, startInDeclarationContainer?: boolean): Symbol | undefined { + function getReferencedValueSymbol( + reference: Identifier, + startInDeclarationContainer?: boolean + ): Symbol | undefined { const resolvedSymbol = getNodeLinks(reference).resolvedSymbol; if (resolvedSymbol) { return resolvedSymbol; @@ -50868,7 +87357,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - return resolveName(location, reference.escapedText, SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias, /*nameNotFoundMessage*/ undefined, /*isUse*/ true); + return resolveName( + location, + reference.escapedText, + SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ true + ); } /** @@ -50878,7 +87373,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * This is because when caching the resolved symbol, we only consider value symbols, but here * we want to also get an alias symbol if one exists. */ - function getReferencedValueOrAliasSymbol(reference: Identifier): Symbol | undefined { + function getReferencedValueOrAliasSymbol( + reference: Identifier + ): Symbol | undefined { const resolvedSymbol = getNodeLinks(reference).resolvedSymbol; if (resolvedSymbol && resolvedSymbol !== unknownSymbol) { return resolvedSymbol; @@ -50890,17 +87387,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias, /*nameNotFoundMessage*/ undefined, /*isUse*/ true, - /*excludeGlobals*/ undefined, + /*excludeGlobals*/ undefined ); } - function getReferencedValueDeclaration(referenceIn: Identifier): Declaration | undefined { + function getReferencedValueDeclaration( + referenceIn: Identifier + ): Declaration | undefined { if (!isGeneratedIdentifier(referenceIn)) { const reference = getParseTreeNode(referenceIn, isIdentifier); if (reference) { const symbol = getReferencedValueSymbol(reference); if (symbol) { - return getExportSymbolOfValueSymbolIfExported(symbol).valueDeclaration; + return getExportSymbolOfValueSymbolIfExported(symbol) + .valueDeclaration; } } } @@ -50908,36 +87408,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - function getReferencedValueDeclarations(referenceIn: Identifier): Declaration[] | undefined { + function getReferencedValueDeclarations( + referenceIn: Identifier + ): Declaration[] | undefined { if (!isGeneratedIdentifier(referenceIn)) { const reference = getParseTreeNode(referenceIn, isIdentifier); if (reference) { const symbol = getReferencedValueSymbol(reference); if (symbol) { - return filter(getExportSymbolOfValueSymbolIfExported(symbol).declarations, declaration => { - switch (declaration.kind) { - case SyntaxKind.VariableDeclaration: - case SyntaxKind.Parameter: - case SyntaxKind.BindingElement: - case SyntaxKind.PropertyDeclaration: - case SyntaxKind.PropertyAssignment: - case SyntaxKind.ShorthandPropertyAssignment: - case SyntaxKind.EnumMember: - case SyntaxKind.ObjectLiteralExpression: - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.FunctionExpression: - case SyntaxKind.ArrowFunction: - case SyntaxKind.ClassDeclaration: - case SyntaxKind.ClassExpression: - case SyntaxKind.EnumDeclaration: - case SyntaxKind.MethodDeclaration: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - case SyntaxKind.ModuleDeclaration: - return true; + return filter( + getExportSymbolOfValueSymbolIfExported(symbol) + .declarations, + (declaration) => { + switch (declaration.kind) { + case SyntaxKind.VariableDeclaration: + case SyntaxKind.Parameter: + case SyntaxKind.BindingElement: + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertyAssignment: + case SyntaxKind.ShorthandPropertyAssignment: + case SyntaxKind.EnumMember: + case SyntaxKind.ObjectLiteralExpression: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.ModuleDeclaration: + return true; + } + return false; } - return false; - }); + ); } } } @@ -50945,34 +87451,79 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - function isLiteralConstDeclaration(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration): boolean { - if (isDeclarationReadonly(node) || isVariableDeclaration(node) && isVarConstLike(node)) { - return isFreshLiteralType(getTypeOfSymbol(getSymbolOfDeclaration(node))); + function isLiteralConstDeclaration( + node: + | VariableDeclaration + | PropertyDeclaration + | PropertySignature + | ParameterDeclaration + ): boolean { + if ( + isDeclarationReadonly(node) || + (isVariableDeclaration(node) && isVarConstLike(node)) + ) { + return isFreshLiteralType( + getTypeOfSymbol(getSymbolOfDeclaration(node)) + ); } return false; } - function literalTypeToNode(type: FreshableType, enclosing: Node, tracker: SymbolTracker): Expression { - const enumResult = type.flags & TypeFlags.EnumLike ? nodeBuilder.symbolToExpression(type.symbol, SymbolFlags.Value, enclosing, /*flags*/ undefined, /*internalFlags*/ undefined, tracker) - : type === trueType ? factory.createTrue() : type === falseType && factory.createFalse(); + function literalTypeToNode( + type: FreshableType, + enclosing: Node, + tracker: SymbolTracker + ): Expression { + const enumResult = + type.flags & TypeFlags.EnumLike + ? nodeBuilder.symbolToExpression( + type.symbol, + SymbolFlags.Value, + enclosing, + /*flags*/ undefined, + /*internalFlags*/ undefined, + tracker + ) + : type === trueType + ? factory.createTrue() + : type === falseType && factory.createFalse(); if (enumResult) return enumResult; const literalValue = (type as LiteralType).value; - return typeof literalValue === "object" ? factory.createBigIntLiteral(literalValue) : - typeof literalValue === "string" ? factory.createStringLiteral(literalValue) : - literalValue < 0 ? factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, factory.createNumericLiteral(-literalValue)) : - factory.createNumericLiteral(literalValue); - } - - function createLiteralConstValue(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration, tracker: SymbolTracker) { + return typeof literalValue === "object" + ? factory.createBigIntLiteral(literalValue) + : typeof literalValue === "string" + ? factory.createStringLiteral(literalValue) + : literalValue < 0 + ? factory.createPrefixUnaryExpression( + SyntaxKind.MinusToken, + factory.createNumericLiteral(-literalValue) + ) + : factory.createNumericLiteral(literalValue); + } + + function createLiteralConstValue( + node: + | VariableDeclaration + | PropertyDeclaration + | PropertySignature + | ParameterDeclaration, + tracker: SymbolTracker + ) { const type = getTypeOfSymbol(getSymbolOfDeclaration(node)); return literalTypeToNode(type as FreshableType, node, tracker); } function getJsxFactoryEntity(location: Node): EntityName | undefined { - return location ? (getJsxNamespace(location), (getSourceFileOfNode(location).localJsxFactory || _jsxFactoryEntity)) : _jsxFactoryEntity; + return location + ? (getJsxNamespace(location), + getSourceFileOfNode(location).localJsxFactory || + _jsxFactoryEntity) + : _jsxFactoryEntity; } - function getJsxFragmentFactoryEntity(location: Node): EntityName | undefined { + function getJsxFragmentFactoryEntity( + location: Node + ): EntityName | undefined { if (location) { const file = getSourceFileOfNode(location); if (file) { @@ -50980,16 +87531,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return file.localJsxFragmentFactory; } const jsxFragPragmas = file.pragmas.get("jsxfrag"); - const jsxFragPragma = isArray(jsxFragPragmas) ? jsxFragPragmas[0] : jsxFragPragmas; + const jsxFragPragma = isArray(jsxFragPragmas) + ? jsxFragPragmas[0] + : jsxFragPragmas; if (jsxFragPragma) { - file.localJsxFragmentFactory = parseIsolatedEntityName(jsxFragPragma.arguments.factory, languageVersion); + file.localJsxFragmentFactory = parseIsolatedEntityName( + jsxFragPragma.arguments.factory, + languageVersion + ); return file.localJsxFragmentFactory; } } } if (compilerOptions.jsxFragmentFactory) { - return parseIsolatedEntityName(compilerOptions.jsxFragmentFactory, languageVersion); + return parseIsolatedEntityName( + compilerOptions.jsxFragmentFactory, + languageVersion + ); } } @@ -50998,8 +87557,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (direct) { return direct; } - if (node.kind === SyntaxKind.Parameter && node.parent.kind === SyntaxKind.SetAccessor) { - const other = getAllAccessorDeclarationsForDeclaration(node.parent as SetAccessorDeclaration).getAccessor; + if ( + node.kind === SyntaxKind.Parameter && + node.parent.kind === SyntaxKind.SetAccessor + ) { + const other = getAllAccessorDeclarationsForDeclaration( + node.parent as SetAccessorDeclaration + ).getAccessor; if (other) { return getEffectiveReturnTypeNode(other); } @@ -51013,16 +87577,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { getReferencedImportDeclaration, getReferencedDeclarationWithCollidingName, isDeclarationWithCollidingName, - isValueAliasDeclaration: nodeIn => { + isValueAliasDeclaration: (nodeIn) => { const node = getParseTreeNode(nodeIn); // Synthesized nodes are always treated like values. - return node && canCollectSymbolAliasAccessabilityData ? isValueAliasDeclaration(node) : true; + return node && canCollectSymbolAliasAccessabilityData + ? isValueAliasDeclaration(node) + : true; }, hasGlobalName, isReferencedAliasDeclaration: (nodeIn, checkChildren?) => { const node = getParseTreeNode(nodeIn); // Synthesized nodes are always treated as referenced. - return node && canCollectSymbolAliasAccessabilityData ? isReferencedAliasDeclaration(node, checkChildren) : true; + return node && canCollectSymbolAliasAccessabilityData + ? isReferencedAliasDeclaration(node, checkChildren) + : true; }, hasNodeCheckFlag: (nodeIn, flag) => { const node = getParseTreeNode(nodeIn); @@ -51041,30 +87609,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { createLiteralConstValue, isSymbolAccessible, isEntityNameVisible, - getConstantValue: nodeIn => { + getConstantValue: (nodeIn) => { const node = getParseTreeNode(nodeIn, canHaveConstantValue); return node ? getConstantValue(node) : undefined; }, - getEnumMemberValue: nodeIn => { + getEnumMemberValue: (nodeIn) => { const node = getParseTreeNode(nodeIn, isEnumMember); return node ? getEnumMemberValue(node) : undefined; }, collectLinkedAliases, - markLinkedReferences: nodeIn => { + markLinkedReferences: (nodeIn) => { const node = getParseTreeNode(nodeIn); - return node && markLinkedReferences(node, ReferenceHint.Unspecified); + return ( + node && + markLinkedReferences(node, ReferenceHint.Unspecified) + ); }, getReferencedValueDeclaration, getReferencedValueDeclarations, getTypeReferenceSerializationKind, isOptionalParameter, isArgumentsLocalBinding, - getExternalModuleFileFromDeclaration: nodeIn => { - const node = getParseTreeNode(nodeIn, hasPossibleExternalModuleReference); + getExternalModuleFileFromDeclaration: (nodeIn) => { + const node = getParseTreeNode( + nodeIn, + hasPossibleExternalModuleReference + ); return node && getExternalModuleFileFromDeclaration(node); }, isLiteralConstDeclaration, - isLateBound: (nodeIn: Declaration): nodeIn is LateBoundDeclaration => { + isLateBound: ( + nodeIn: Declaration + ): nodeIn is LateBoundDeclaration => { const node = getParseTreeNode(nodeIn, isDeclaration); const symbol = node && getSymbolOfDeclaration(node); return !!(symbol && getCheckFlags(symbol) & CheckFlags.Late); @@ -51074,25 +87650,66 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { isBindingCapturedByNode: (node, decl) => { const parseNode = getParseTreeNode(node); const parseDecl = getParseTreeNode(decl); - return !!parseNode && !!parseDecl && (isVariableDeclaration(parseDecl) || isBindingElement(parseDecl)) && isBindingCapturedByNode(parseNode, parseDecl); + return ( + !!parseNode && + !!parseDecl && + (isVariableDeclaration(parseDecl) || + isBindingElement(parseDecl)) && + isBindingCapturedByNode(parseNode, parseDecl) + ); }, - getDeclarationStatementsForSourceFile: (node, flags, internalFlags, tracker) => { + getDeclarationStatementsForSourceFile: ( + node, + flags, + internalFlags, + tracker + ) => { const n = getParseTreeNode(node) as SourceFile; - Debug.assert(n && n.kind === SyntaxKind.SourceFile, "Non-sourcefile node passed into getDeclarationsForSourceFile"); + Debug.assert( + n && n.kind === SyntaxKind.SourceFile, + "Non-sourcefile node passed into getDeclarationsForSourceFile" + ); const sym = getSymbolOfDeclaration(node); if (!sym) { - return !node.locals ? [] : nodeBuilder.symbolTableToDeclarationStatements(node.locals, node, flags, internalFlags, tracker); + return !node.locals + ? [] + : nodeBuilder.symbolTableToDeclarationStatements( + node.locals, + node, + flags, + internalFlags, + tracker + ); } resolveExternalModuleSymbol(sym); // ensures cjs export assignment is setup - return !sym.exports ? [] : nodeBuilder.symbolTableToDeclarationStatements(sym.exports, node, flags, internalFlags, tracker); + return !sym.exports + ? [] + : nodeBuilder.symbolTableToDeclarationStatements( + sym.exports, + node, + flags, + internalFlags, + tracker + ); }, isImportRequiredByAugmentation, isDefinitelyReferenceToGlobalSymbolObject, - createLateBoundIndexSignatures: (cls, enclosing, flags, internalFlags, tracker) => { + createLateBoundIndexSignatures: ( + cls, + enclosing, + flags, + internalFlags, + tracker + ) => { const sym = cls.symbol; const staticInfos = getIndexInfosOfType(getTypeOfSymbol(sym)); const instanceIndexSymbol = getIndexSymbol(sym); - const instanceInfos = instanceIndexSymbol && getIndexInfosOfIndexSymbol(instanceIndexSymbol, arrayFrom(getMembersOfSymbol(sym).values())); + const instanceInfos = + instanceIndexSymbol && + getIndexInfosOfIndexSymbol( + instanceIndexSymbol, + arrayFrom(getMembersOfSymbol(sym).values()) + ); let result; for (const infoList of [staticInfos, instanceInfos]) { if (!length(infoList)) continue; @@ -51101,31 +87718,97 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (info.declaration) continue; if (info === anyBaseTypeIndexInfo) continue; // inherited, but looks like a late-bound signature because it has no declarations if (info.components) { - const allComponentComputedNamesSerializable = every(info.components, e => { - return !!(e.name && isComputedPropertyName(e.name) && isEntityNameExpression(e.name.expression) && enclosing && isEntityNameVisible(e.name.expression, enclosing, /*shouldComputeAliasToMakeVisible*/ false)?.accessibility === SymbolAccessibility.Accessible); - }); - if (allComponentComputedNamesSerializable) { - const newComponents = filter(info.components, e => { - // skip late bound props that contribute to the index signature - they'll be preserved via other means - return !hasLateBindableName(e); - }); - result.push(...map(newComponents, e => { - trackComputedName(e.name.expression as EntityNameExpression); - const mods = infoList === staticInfos ? [factory.createModifier(SyntaxKind.StaticKeyword)] as Modifier[] : undefined; - return factory.createPropertyDeclaration( - append(mods, info.isReadonly ? factory.createModifier(SyntaxKind.ReadonlyKeyword) : undefined), - e.name, - (isPropertySignature(e) || isPropertyDeclaration(e) || isMethodSignature(e) || isMethodDeclaration(e) || isGetAccessor(e) || isSetAccessor(e)) && e.questionToken ? factory.createToken(SyntaxKind.QuestionToken) : undefined, - nodeBuilder.typeToTypeNode(getTypeOfSymbol(e.symbol), enclosing, flags, internalFlags, tracker), - /*initializer*/ undefined, + const allComponentComputedNamesSerializable = every( + info.components, + (e) => { + return !!( + e.name && + isComputedPropertyName(e.name) && + isEntityNameExpression( + e.name.expression + ) && + enclosing && + isEntityNameVisible( + e.name.expression, + enclosing, + /*shouldComputeAliasToMakeVisible*/ false + )?.accessibility === + SymbolAccessibility.Accessible ); - })); + } + ); + if (allComponentComputedNamesSerializable) { + const newComponents = filter( + info.components, + (e) => { + // skip late bound props that contribute to the index signature - they'll be preserved via other means + return !hasLateBindableName(e); + } + ); + result.push( + ...map(newComponents, (e) => { + trackComputedName( + e.name + .expression as EntityNameExpression + ); + const mods = + infoList === staticInfos + ? ([ + factory.createModifier( + SyntaxKind.StaticKeyword + ), + ] as Modifier[]) + : undefined; + return factory.createPropertyDeclaration( + append( + mods, + info.isReadonly + ? factory.createModifier( + SyntaxKind.ReadonlyKeyword + ) + : undefined + ), + e.name, + (isPropertySignature(e) || + isPropertyDeclaration(e) || + isMethodSignature(e) || + isMethodDeclaration(e) || + isGetAccessor(e) || + isSetAccessor(e)) && + e.questionToken + ? factory.createToken( + SyntaxKind.QuestionToken + ) + : undefined, + nodeBuilder.typeToTypeNode( + getTypeOfSymbol(e.symbol), + enclosing, + flags, + internalFlags, + tracker + ), + /*initializer*/ undefined + ); + }) + ); continue; } } - const node = nodeBuilder.indexInfoToIndexSignatureDeclaration(info, enclosing, flags, internalFlags, tracker); + const node = + nodeBuilder.indexInfoToIndexSignatureDeclaration( + info, + enclosing, + flags, + internalFlags, + tracker + ); if (node && infoList === staticInfos) { - (((node as Mutable).modifiers ||= factory.createNodeArray()) as MutableNodeArray).unshift(factory.createModifier(SyntaxKind.StaticKeyword)); + ( + ((node as Mutable).modifiers ||= + factory.createNodeArray()) as MutableNodeArray + ).unshift( + factory.createModifier(SyntaxKind.StaticKeyword) + ); } if (node) { result.push(node); @@ -51134,18 +87817,41 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } return result; - function trackComputedName(accessExpression: EntityNameOrEntityNameExpression) { + function trackComputedName( + accessExpression: EntityNameOrEntityNameExpression + ) { if (!tracker.trackSymbol) return; // get symbol of the first identifier of the entityName - const firstIdentifier = getFirstIdentifier(accessExpression); - const name = resolveName(firstIdentifier, firstIdentifier.escapedText, SymbolFlags.Value | SymbolFlags.ExportValue, /*nameNotFoundMessage*/ undefined, /*isUse*/ true); + const firstIdentifier = + getFirstIdentifier(accessExpression); + const name = resolveName( + firstIdentifier, + firstIdentifier.escapedText, + SymbolFlags.Value | SymbolFlags.ExportValue, + /*nameNotFoundMessage*/ undefined, + /*isUse*/ true + ); if (name) { tracker.trackSymbol(name, enclosing, SymbolFlags.Value); } } }, - symbolToDeclarations: (symbol, meaning, flags, maximumLength, verbosityLevel, out) => { - return nodeBuilder.symbolToDeclarations(symbol, meaning, flags, maximumLength, verbosityLevel, out); + symbolToDeclarations: ( + symbol, + meaning, + flags, + maximumLength, + verbosityLevel, + out + ) => { + return nodeBuilder.symbolToDeclarations( + symbol, + meaning, + flags, + maximumLength, + verbosityLevel, + out + ); }, }; @@ -51173,9 +87879,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getExternalModuleFileFromDeclaration(declaration: AnyImportOrReExport | ModuleDeclaration | ImportTypeNode | ImportCall): SourceFile | undefined { - const specifier = declaration.kind === SyntaxKind.ModuleDeclaration ? tryCast(declaration.name, isStringLiteral) : getExternalModuleName(declaration); - const moduleSymbol = resolveExternalModuleNameWorker(specifier!, specifier!, /*moduleNotFoundError*/ undefined); // TODO: GH#18217 + function getExternalModuleFileFromDeclaration( + declaration: + | AnyImportOrReExport + | ModuleDeclaration + | ImportTypeNode + | ImportCall + ): SourceFile | undefined { + const specifier = + declaration.kind === SyntaxKind.ModuleDeclaration + ? tryCast(declaration.name, isStringLiteral) + : getExternalModuleName(declaration); + const moduleSymbol = resolveExternalModuleNameWorker( + specifier!, + specifier!, + /*moduleNotFoundError*/ undefined + ); // TODO: GH#18217 if (!moduleSymbol) { return undefined; } @@ -51191,17 +87910,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { amalgamatedDuplicates = new Map(); // Initialize global symbol table - let augmentations: (readonly (StringLiteral | Identifier)[])[] | undefined; + let augmentations: + | (readonly (StringLiteral | Identifier)[])[] + | undefined; for (const file of host.getSourceFiles()) { if (file.redirectInfo) { continue; } if (!isExternalOrCommonJsModule(file)) { // It is an error for a non-external-module (i.e. script) to declare its own `globalThis`. - const fileGlobalThisSymbol = file.locals!.get("globalThis" as __String); + const fileGlobalThisSymbol = file.locals!.get( + "globalThis" as __String + ); if (fileGlobalThisSymbol?.declarations) { for (const declaration of fileGlobalThisSymbol.declarations) { - diagnostics.add(createDiagnosticForNode(declaration, Diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0, "globalThis")); + diagnostics.add( + createDiagnosticForNode( + declaration, + Diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0, + "globalThis" + ) + ); } } mergeSymbolTable(globals, file.locals!); @@ -51209,11 +87938,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (file.jsGlobalAugmentations) { mergeSymbolTable(globals, file.jsGlobalAugmentations); } - if (file.patternAmbientModules && file.patternAmbientModules.length) { - patternAmbientModules = concatenate(patternAmbientModules, file.patternAmbientModules); + if ( + file.patternAmbientModules && + file.patternAmbientModules.length + ) { + patternAmbientModules = concatenate( + patternAmbientModules, + file.patternAmbientModules + ); } if (file.moduleAugmentations.length) { - (augmentations || (augmentations = [])).push(file.moduleAugmentations); + (augmentations || (augmentations = [])).push( + file.moduleAugmentations + ); } if (file.symbol && file.symbol.globalExports) { // Merge in UMD exports with first-in-wins semantics (see #9771) @@ -51237,7 +87974,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // this needs to be done after global symbol table is initialized to make sure that all ambient modules are indexed for (const list of augmentations) { for (const augmentation of list) { - if (!isGlobalScopeAugmentation(augmentation.parent as ModuleDeclaration)) continue; + if ( + !isGlobalScopeAugmentation( + augmentation.parent as ModuleDeclaration + ) + ) + continue; mergeModuleAugmentation(augmentation); } } @@ -51246,102 +87988,291 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { addUndefinedToGlobalsOrErrorOnRedeclaration(); getSymbolLinks(undefinedSymbol).type = undefinedWideningType; - getSymbolLinks(argumentsSymbol).type = getGlobalType("IArguments" as __String, /*arity*/ 0, /*reportErrors*/ true); + getSymbolLinks(argumentsSymbol).type = getGlobalType( + "IArguments" as __String, + /*arity*/ 0, + /*reportErrors*/ true + ); getSymbolLinks(unknownSymbol).type = errorType; - getSymbolLinks(globalThisSymbol).type = createObjectType(ObjectFlags.Anonymous, globalThisSymbol); + getSymbolLinks(globalThisSymbol).type = createObjectType( + ObjectFlags.Anonymous, + globalThisSymbol + ); // Initialize special types - globalArrayType = getGlobalType("Array" as __String, /*arity*/ 1, /*reportErrors*/ true); - globalObjectType = getGlobalType("Object" as __String, /*arity*/ 0, /*reportErrors*/ true); - globalFunctionType = getGlobalType("Function" as __String, /*arity*/ 0, /*reportErrors*/ true); - globalCallableFunctionType = strictBindCallApply && getGlobalType("CallableFunction" as __String, /*arity*/ 0, /*reportErrors*/ true) || globalFunctionType; - globalNewableFunctionType = strictBindCallApply && getGlobalType("NewableFunction" as __String, /*arity*/ 0, /*reportErrors*/ true) || globalFunctionType; - globalStringType = getGlobalType("String" as __String, /*arity*/ 0, /*reportErrors*/ true); - globalNumberType = getGlobalType("Number" as __String, /*arity*/ 0, /*reportErrors*/ true); - globalBooleanType = getGlobalType("Boolean" as __String, /*arity*/ 0, /*reportErrors*/ true); - globalRegExpType = getGlobalType("RegExp" as __String, /*arity*/ 0, /*reportErrors*/ true); + globalArrayType = getGlobalType( + "Array" as __String, + /*arity*/ 1, + /*reportErrors*/ true + ); + globalObjectType = getGlobalType( + "Object" as __String, + /*arity*/ 0, + /*reportErrors*/ true + ); + globalFunctionType = getGlobalType( + "Function" as __String, + /*arity*/ 0, + /*reportErrors*/ true + ); + globalCallableFunctionType = + (strictBindCallApply && + getGlobalType( + "CallableFunction" as __String, + /*arity*/ 0, + /*reportErrors*/ true + )) || + globalFunctionType; + globalNewableFunctionType = + (strictBindCallApply && + getGlobalType( + "NewableFunction" as __String, + /*arity*/ 0, + /*reportErrors*/ true + )) || + globalFunctionType; + globalStringType = getGlobalType( + "String" as __String, + /*arity*/ 0, + /*reportErrors*/ true + ); + globalNumberType = getGlobalType( + "Number" as __String, + /*arity*/ 0, + /*reportErrors*/ true + ); + globalBooleanType = getGlobalType( + "Boolean" as __String, + /*arity*/ 0, + /*reportErrors*/ true + ); + globalRegExpType = getGlobalType( + "RegExp" as __String, + /*arity*/ 0, + /*reportErrors*/ true + ); anyArrayType = createArrayType(anyType); autoArrayType = createArrayType(autoType); if (autoArrayType === emptyObjectType) { // autoArrayType is used as a marker, so even if global Array type is not defined, it needs to be a unique type - autoArrayType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray); + autoArrayType = createAnonymousType( + /*symbol*/ undefined, + emptySymbols, + emptyArray, + emptyArray, + emptyArray + ); } - globalReadonlyArrayType = getGlobalTypeOrUndefined("ReadonlyArray" as __String, /*arity*/ 1) as GenericType || globalArrayType; - anyReadonlyArrayType = globalReadonlyArrayType ? createTypeFromGenericGlobalType(globalReadonlyArrayType, [anyType]) : anyArrayType; - globalThisType = getGlobalTypeOrUndefined("ThisType" as __String, /*arity*/ 1) as GenericType; + globalReadonlyArrayType = + (getGlobalTypeOrUndefined( + "ReadonlyArray" as __String, + /*arity*/ 1 + ) as GenericType) || globalArrayType; + anyReadonlyArrayType = globalReadonlyArrayType + ? createTypeFromGenericGlobalType(globalReadonlyArrayType, [ + anyType, + ]) + : anyArrayType; + globalThisType = getGlobalTypeOrUndefined( + "ThisType" as __String, + /*arity*/ 1 + ) as GenericType; if (augmentations) { // merge _nonglobal_ module augmentations. // this needs to be done after global symbol table is initialized to make sure that all ambient modules are indexed for (const list of augmentations) { for (const augmentation of list) { - if (isGlobalScopeAugmentation(augmentation.parent as ModuleDeclaration)) continue; + if ( + isGlobalScopeAugmentation( + augmentation.parent as ModuleDeclaration + ) + ) + continue; mergeModuleAugmentation(augmentation); } } } - amalgamatedDuplicates.forEach(({ firstFile, secondFile, conflictingSymbols }) => { - // If not many things conflict, issue individual errors - if (conflictingSymbols.size < 8) { - conflictingSymbols.forEach(({ isBlockScoped, firstFileLocations, secondFileLocations }, symbolName) => { - const message = isBlockScoped ? Diagnostics.Cannot_redeclare_block_scoped_variable_0 : Diagnostics.Duplicate_identifier_0; - for (const node of firstFileLocations) { - addDuplicateDeclarationError(node, message, symbolName, secondFileLocations); - } - for (const node of secondFileLocations) { - addDuplicateDeclarationError(node, message, symbolName, firstFileLocations); - } - }); - } - else { - // Otherwise issue top-level error since the files appear very identical in terms of what they contain - const list = arrayFrom(conflictingSymbols.keys()).join(", "); - diagnostics.add(addRelatedInfo( - createDiagnosticForNode(firstFile, Diagnostics.Definitions_of_the_following_identifiers_conflict_with_those_in_another_file_Colon_0, list), - createDiagnosticForNode(secondFile, Diagnostics.Conflicts_are_in_this_file), - )); - diagnostics.add(addRelatedInfo( - createDiagnosticForNode(secondFile, Diagnostics.Definitions_of_the_following_identifiers_conflict_with_those_in_another_file_Colon_0, list), - createDiagnosticForNode(firstFile, Diagnostics.Conflicts_are_in_this_file), - )); + amalgamatedDuplicates.forEach( + ({ firstFile, secondFile, conflictingSymbols }) => { + // If not many things conflict, issue individual errors + if (conflictingSymbols.size < 8) { + conflictingSymbols.forEach( + ( + { + isBlockScoped, + firstFileLocations, + secondFileLocations, + }, + symbolName + ) => { + const message = isBlockScoped + ? Diagnostics.Cannot_redeclare_block_scoped_variable_0 + : Diagnostics.Duplicate_identifier_0; + for (const node of firstFileLocations) { + addDuplicateDeclarationError( + node, + message, + symbolName, + secondFileLocations + ); + } + for (const node of secondFileLocations) { + addDuplicateDeclarationError( + node, + message, + symbolName, + firstFileLocations + ); + } + } + ); + } else { + // Otherwise issue top-level error since the files appear very identical in terms of what they contain + const list = arrayFrom(conflictingSymbols.keys()).join( + ", " + ); + diagnostics.add( + addRelatedInfo( + createDiagnosticForNode( + firstFile, + Diagnostics.Definitions_of_the_following_identifiers_conflict_with_those_in_another_file_Colon_0, + list + ), + createDiagnosticForNode( + secondFile, + Diagnostics.Conflicts_are_in_this_file + ) + ) + ); + diagnostics.add( + addRelatedInfo( + createDiagnosticForNode( + secondFile, + Diagnostics.Definitions_of_the_following_identifiers_conflict_with_those_in_another_file_Colon_0, + list + ), + createDiagnosticForNode( + firstFile, + Diagnostics.Conflicts_are_in_this_file + ) + ) + ); + } } - }); + ); amalgamatedDuplicates = undefined; } - function checkExternalEmitHelpers(location: Node, helpers: ExternalEmitHelpers) { + function checkExternalEmitHelpers( + location: Node, + helpers: ExternalEmitHelpers + ) { if (compilerOptions.importHelpers) { const sourceFile = getSourceFileOfNode(location); - if (isEffectiveExternalModule(sourceFile, compilerOptions) && !(location.flags & NodeFlags.Ambient)) { - const helpersModule = resolveHelpersModule(sourceFile, location); + if ( + isEffectiveExternalModule(sourceFile, compilerOptions) && + !(location.flags & NodeFlags.Ambient) + ) { + const helpersModule = resolveHelpersModule( + sourceFile, + location + ); if (helpersModule !== unknownSymbol) { const links = getSymbolLinks(helpersModule); - links.requestedExternalEmitHelpers ??= 0 as ExternalEmitHelpers; - if ((links.requestedExternalEmitHelpers & helpers) !== helpers) { - const uncheckedHelpers = helpers & ~links.requestedExternalEmitHelpers; - for (let helper = ExternalEmitHelpers.FirstEmitHelper; helper <= ExternalEmitHelpers.LastEmitHelper; helper <<= 1) { + links.requestedExternalEmitHelpers ??= + 0 as ExternalEmitHelpers; + if ( + (links.requestedExternalEmitHelpers & helpers) !== + helpers + ) { + const uncheckedHelpers = + helpers & ~links.requestedExternalEmitHelpers; + for ( + let helper = ExternalEmitHelpers.FirstEmitHelper; + helper <= ExternalEmitHelpers.LastEmitHelper; + helper <<= 1 + ) { if (uncheckedHelpers & helper) { for (const name of getHelperNames(helper)) { - const symbol = resolveSymbol(getSymbol(getExportsOfModule(helpersModule), escapeLeadingUnderscores(name), SymbolFlags.Value)); + const symbol = resolveSymbol( + getSymbol( + getExportsOfModule(helpersModule), + escapeLeadingUnderscores(name), + SymbolFlags.Value + ) + ); if (!symbol) { - 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); - } - else if (helper & ExternalEmitHelpers.ClassPrivateFieldGet) { - if (!some(getSignaturesOfSymbol(symbol), signature => getParameterCount(signature) > 3)) { - 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); + 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 + ); + } else if ( + helper & + ExternalEmitHelpers.ClassPrivateFieldGet + ) { + if ( + !some( + getSignaturesOfSymbol(symbol), + (signature) => + getParameterCount( + signature + ) > 3 + ) + ) { + 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 + ); } - } - else if (helper & ExternalEmitHelpers.ClassPrivateFieldSet) { - if (!some(getSignaturesOfSymbol(symbol), signature => getParameterCount(signature) > 4)) { - 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); + } else if ( + helper & + ExternalEmitHelpers.ClassPrivateFieldSet + ) { + if ( + !some( + getSignaturesOfSymbol(symbol), + (signature) => + getParameterCount( + signature + ) > 4 + ) + ) { + 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 + ); } - } - else if (helper & ExternalEmitHelpers.SpreadArray) { - if (!some(getSignaturesOfSymbol(symbol), signature => getParameterCount(signature) > 2)) { - 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); + } else if ( + helper & ExternalEmitHelpers.SpreadArray + ) { + if ( + !some( + getSignaturesOfSymbol(symbol), + (signature) => + getParameterCount( + signature + ) > 2 + ) + ) { + 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 + ); } } } @@ -51363,7 +88294,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case ExternalEmitHelpers.Rest: return ["__rest"]; case ExternalEmitHelpers.Decorate: - return legacyDecorators ? ["__decorate"] : ["__esDecorate", "__runInitializers"]; + return legacyDecorators + ? ["__decorate"] + : ["__esDecorate", "__runInitializers"]; case ExternalEmitHelpers.Metadata: return ["__metadata"]; case ExternalEmitHelpers.Param: @@ -51416,25 +88349,48 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function resolveHelpersModule(file: SourceFile, errorNode: Node) { const links = getNodeLinks(file); if (!links.externalHelpersModule) { - links.externalHelpersModule = resolveExternalModule(getImportHelpersImportSpecifier(file), externalHelpersModuleNameText, Diagnostics.This_syntax_requires_an_imported_helper_but_module_0_cannot_be_found, errorNode) || unknownSymbol; + links.externalHelpersModule = + resolveExternalModule( + getImportHelpersImportSpecifier(file), + externalHelpersModuleNameText, + Diagnostics.This_syntax_requires_an_imported_helper_but_module_0_cannot_be_found, + errorNode + ) || unknownSymbol; } return links.externalHelpersModule; } // GRAMMAR CHECKING - function checkGrammarModifiers(node: HasModifiers | HasDecorators | HasIllegalModifiers | HasIllegalDecorators): boolean { - const quickResult = reportObviousDecoratorErrors(node) || reportObviousModifierErrors(node); + function checkGrammarModifiers( + node: + | HasModifiers + | HasDecorators + | HasIllegalModifiers + | HasIllegalDecorators + ): boolean { + const quickResult = + reportObviousDecoratorErrors(node) || + reportObviousModifierErrors(node); if (quickResult !== undefined) { return quickResult; } if (isParameter(node) && parameterIsThisKeyword(node)) { - return grammarErrorOnFirstToken(node, Diagnostics.Neither_decorators_nor_modifiers_may_be_applied_to_this_parameters); + return grammarErrorOnFirstToken( + node, + Diagnostics.Neither_decorators_nor_modifiers_may_be_applied_to_this_parameters + ); } - const blockScopeKind = isVariableStatement(node) ? node.declarationList.flags & NodeFlags.BlockScoped : NodeFlags.None; - let lastStatic: Node | undefined, lastDeclare: Node | undefined, lastAsync: Node | undefined, lastOverride: Node | undefined, firstDecorator: Decorator | undefined; + const blockScopeKind = isVariableStatement(node) + ? node.declarationList.flags & NodeFlags.BlockScoped + : NodeFlags.None; + let lastStatic: Node | undefined, + lastDeclare: Node | undefined, + lastAsync: Node | undefined, + lastOverride: Node | undefined, + firstDecorator: Decorator | undefined; let flags = ModifierFlags.None; let sawExportBeforeDecorators = false; // We parse decorators and modifiers in four contiguous chunks: @@ -51443,24 +88399,56 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let hasLeadingDecorators = false; for (const modifier of (node as HasModifiers).modifiers!) { if (isDecorator(modifier)) { - if (!nodeCanBeDecorated(legacyDecorators, node, node.parent, node.parent.parent)) { - if (node.kind === SyntaxKind.MethodDeclaration && !nodeIsPresent(node.body)) { - return grammarErrorOnFirstToken(node, Diagnostics.A_decorator_can_only_decorate_a_method_implementation_not_an_overload); - } - else { - return grammarErrorOnFirstToken(node, Diagnostics.Decorators_are_not_valid_here); + if ( + !nodeCanBeDecorated( + legacyDecorators, + node, + node.parent, + node.parent.parent + ) + ) { + if ( + node.kind === SyntaxKind.MethodDeclaration && + !nodeIsPresent(node.body) + ) { + return grammarErrorOnFirstToken( + node, + Diagnostics.A_decorator_can_only_decorate_a_method_implementation_not_an_overload + ); + } else { + return grammarErrorOnFirstToken( + node, + Diagnostics.Decorators_are_not_valid_here + ); } - } - else if (legacyDecorators && (node.kind === SyntaxKind.GetAccessor || node.kind === SyntaxKind.SetAccessor)) { - const accessors = getAllAccessorDeclarationsForDeclaration(node as AccessorDeclaration); - if (hasDecorators(accessors.firstAccessor) && node === accessors.secondAccessor) { - return grammarErrorOnFirstToken(node, Diagnostics.Decorators_cannot_be_applied_to_multiple_get_Slashset_accessors_of_the_same_name); + } else if ( + legacyDecorators && + (node.kind === SyntaxKind.GetAccessor || + node.kind === SyntaxKind.SetAccessor) + ) { + const accessors = getAllAccessorDeclarationsForDeclaration( + node as AccessorDeclaration + ); + if ( + hasDecorators(accessors.firstAccessor) && + node === accessors.secondAccessor + ) { + return grammarErrorOnFirstToken( + node, + Diagnostics.Decorators_cannot_be_applied_to_multiple_get_Slashset_accessors_of_the_same_name + ); } } // if we've seen any modifiers aside from `export`, `default`, or another decorator, then this is an invalid position - if (flags & ~(ModifierFlags.ExportDefault | ModifierFlags.Decorator)) { - return grammarErrorOnNode(modifier, Diagnostics.Decorators_are_not_valid_here); + if ( + flags & + ~(ModifierFlags.ExportDefault | ModifierFlags.Decorator) + ) { + return grammarErrorOnNode( + modifier, + Diagnostics.Decorators_are_not_valid_here + ); } // if we've already seen leading decorators and leading modifiers, then trailing decorators are an invalid position @@ -51469,8 +88457,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const sourceFile = getSourceFileOfNode(modifier); if (!hasParseDiagnostics(sourceFile)) { addRelatedInfo( - error(modifier, Diagnostics.Decorators_may_not_appear_after_export_or_export_default_if_they_also_appear_before_export), - createDiagnosticForNode(firstDecorator, Diagnostics.Decorator_used_before_export_here), + error( + modifier, + Diagnostics.Decorators_may_not_appear_after_export_or_export_default_if_they_also_appear_before_export + ), + createDiagnosticForNode( + firstDecorator, + Diagnostics.Decorator_used_before_export_here + ) ); return true; } @@ -51482,57 +88476,120 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // if we have not yet seen a modifier, then these are leading decorators if (!(flags & ModifierFlags.Modifier)) { hasLeadingDecorators = true; - } - else if (flags & ModifierFlags.Export) { + } else if (flags & ModifierFlags.Export) { sawExportBeforeDecorators = true; } firstDecorator ??= modifier; - } - else { + } else { if (modifier.kind !== SyntaxKind.ReadonlyKeyword) { - if (node.kind === SyntaxKind.PropertySignature || node.kind === SyntaxKind.MethodSignature) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_type_member, tokenToString(modifier.kind)); + if ( + node.kind === SyntaxKind.PropertySignature || + node.kind === SyntaxKind.MethodSignature + ) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_type_member, + tokenToString(modifier.kind) + ); } - if (node.kind === SyntaxKind.IndexSignature && (modifier.kind !== SyntaxKind.StaticKeyword || !isClassLike(node.parent))) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_an_index_signature, tokenToString(modifier.kind)); + if ( + node.kind === SyntaxKind.IndexSignature && + (modifier.kind !== SyntaxKind.StaticKeyword || + !isClassLike(node.parent)) + ) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_an_index_signature, + tokenToString(modifier.kind) + ); } } - if (modifier.kind !== SyntaxKind.InKeyword && modifier.kind !== SyntaxKind.OutKeyword && modifier.kind !== SyntaxKind.ConstKeyword) { + if ( + modifier.kind !== SyntaxKind.InKeyword && + modifier.kind !== SyntaxKind.OutKeyword && + modifier.kind !== SyntaxKind.ConstKeyword + ) { if (node.kind === SyntaxKind.TypeParameter) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_type_parameter, tokenToString(modifier.kind)); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_type_parameter, + tokenToString(modifier.kind) + ); } } switch (modifier.kind) { case SyntaxKind.ConstKeyword: { - if (node.kind !== SyntaxKind.EnumDeclaration && node.kind !== SyntaxKind.TypeParameter) { - return grammarErrorOnNode(node, Diagnostics.A_class_member_cannot_have_the_0_keyword, tokenToString(SyntaxKind.ConstKeyword)); + if ( + node.kind !== SyntaxKind.EnumDeclaration && + node.kind !== SyntaxKind.TypeParameter + ) { + return grammarErrorOnNode( + node, + Diagnostics.A_class_member_cannot_have_the_0_keyword, + tokenToString(SyntaxKind.ConstKeyword) + ); } - const parent = (isJSDocTemplateTag(node.parent) && getEffectiveJSDocHost(node.parent)) || node.parent; + const parent = + (isJSDocTemplateTag(node.parent) && + getEffectiveJSDocHost(node.parent)) || + node.parent; if ( - node.kind === SyntaxKind.TypeParameter && !(isFunctionLikeDeclaration(parent) || isClassLike(parent) || isFunctionTypeNode(parent) || - isConstructorTypeNode(parent) || isCallSignatureDeclaration(parent) || isConstructSignatureDeclaration(parent) || isMethodSignature(parent)) + node.kind === SyntaxKind.TypeParameter && + !( + isFunctionLikeDeclaration(parent) || + isClassLike(parent) || + isFunctionTypeNode(parent) || + isConstructorTypeNode(parent) || + isCallSignatureDeclaration(parent) || + isConstructSignatureDeclaration(parent) || + isMethodSignature(parent) + ) ) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_can_only_appear_on_a_type_parameter_of_a_function_method_or_class, tokenToString(modifier.kind)); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_can_only_appear_on_a_type_parameter_of_a_function_method_or_class, + tokenToString(modifier.kind) + ); } break; } case SyntaxKind.OverrideKeyword: // If node.kind === SyntaxKind.Parameter, checkParameter reports an error if it's not a parameter property. if (flags & ModifierFlags.Override) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "override"); - } - else if (flags & ModifierFlags.Ambient) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "override", "declare"); - } - else if (flags & ModifierFlags.Readonly) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "override", "readonly"); - } - else if (flags & ModifierFlags.Accessor) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "override", "accessor"); - } - else if (flags & ModifierFlags.Async) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "override", "async"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_already_seen, + "override" + ); + } else if (flags & ModifierFlags.Ambient) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "override", + "declare" + ); + } else if (flags & ModifierFlags.Readonly) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "override", + "readonly" + ); + } else if (flags & ModifierFlags.Accessor) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "override", + "accessor" + ); + } else if (flags & ModifierFlags.Async) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "override", + "async" + ); } flags |= ModifierFlags.Override; lastOverride = modifier; @@ -51541,67 +88598,143 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.PublicKeyword: case SyntaxKind.ProtectedKeyword: case SyntaxKind.PrivateKeyword: - const text = visibilityToString(modifierToFlag(modifier.kind)); + const text = visibilityToString( + modifierToFlag(modifier.kind) + ); if (flags & ModifierFlags.AccessibilityModifier) { - return grammarErrorOnNode(modifier, Diagnostics.Accessibility_modifier_already_seen); - } - else if (flags & ModifierFlags.Override) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "override"); - } - else if (flags & ModifierFlags.Static) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "static"); - } - else if (flags & ModifierFlags.Accessor) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "accessor"); - } - else if (flags & ModifierFlags.Readonly) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "readonly"); - } - else if (flags & ModifierFlags.Async) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "async"); - } - else if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element, text); - } - else if (flags & ModifierFlags.Abstract) { + return grammarErrorOnNode( + modifier, + Diagnostics.Accessibility_modifier_already_seen + ); + } else if (flags & ModifierFlags.Override) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + text, + "override" + ); + } else if (flags & ModifierFlags.Static) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + text, + "static" + ); + } else if (flags & ModifierFlags.Accessor) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + text, + "accessor" + ); + } else if (flags & ModifierFlags.Readonly) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + text, + "readonly" + ); + } else if (flags & ModifierFlags.Async) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + text, + "async" + ); + } else if ( + node.parent.kind === SyntaxKind.ModuleBlock || + node.parent.kind === SyntaxKind.SourceFile + ) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element, + text + ); + } else if (flags & ModifierFlags.Abstract) { if (modifier.kind === SyntaxKind.PrivateKeyword) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, text, "abstract"); - } - else { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "abstract"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + text, + "abstract" + ); + } else { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + text, + "abstract" + ); } - } - else if (isPrivateIdentifierClassElementDeclaration(node)) { - return grammarErrorOnNode(modifier, Diagnostics.An_accessibility_modifier_cannot_be_used_with_a_private_identifier); + } else if ( + isPrivateIdentifierClassElementDeclaration(node) + ) { + return grammarErrorOnNode( + modifier, + Diagnostics.An_accessibility_modifier_cannot_be_used_with_a_private_identifier + ); } flags |= modifierToFlag(modifier.kind); break; case SyntaxKind.StaticKeyword: if (flags & ModifierFlags.Static) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "static"); - } - else if (flags & ModifierFlags.Readonly) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "static", "readonly"); - } - else if (flags & ModifierFlags.Async) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "static", "async"); - } - else if (flags & ModifierFlags.Accessor) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "static", "accessor"); - } - else if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element, "static"); - } - else if (node.kind === SyntaxKind.Parameter) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "static"); - } - else if (flags & ModifierFlags.Abstract) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "static", "abstract"); - } - else if (flags & ModifierFlags.Override) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "static", "override"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_already_seen, + "static" + ); + } else if (flags & ModifierFlags.Readonly) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "static", + "readonly" + ); + } else if (flags & ModifierFlags.Async) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "static", + "async" + ); + } else if (flags & ModifierFlags.Accessor) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "static", + "accessor" + ); + } else if ( + node.parent.kind === SyntaxKind.ModuleBlock || + node.parent.kind === SyntaxKind.SourceFile + ) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element, + "static" + ); + } else if (node.kind === SyntaxKind.Parameter) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_parameter, + "static" + ); + } else if (flags & ModifierFlags.Abstract) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "static", + "abstract" + ); + } else if (flags & ModifierFlags.Override) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "static", + "override" + ); } flags |= ModifierFlags.Static; lastStatic = modifier; @@ -51609,16 +88742,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.AccessorKeyword: if (flags & ModifierFlags.Accessor) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "accessor"); - } - else if (flags & ModifierFlags.Readonly) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "accessor", "readonly"); - } - else if (flags & ModifierFlags.Ambient) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "accessor", "declare"); - } - else if (node.kind !== SyntaxKind.PropertyDeclaration) { - return grammarErrorOnNode(modifier, Diagnostics.accessor_modifier_can_only_appear_on_a_property_declaration); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_already_seen, + "accessor" + ); + } else if (flags & ModifierFlags.Readonly) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "accessor", + "readonly" + ); + } else if (flags & ModifierFlags.Ambient) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "accessor", + "declare" + ); + } else if ( + node.kind !== SyntaxKind.PropertyDeclaration + ) { + return grammarErrorOnNode( + modifier, + Diagnostics.accessor_modifier_can_only_appear_on_a_property_declaration + ); } flags |= ModifierFlags.Accessor; @@ -51626,14 +88775,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ReadonlyKeyword: if (flags & ModifierFlags.Readonly) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "readonly"); - } - else if (node.kind !== SyntaxKind.PropertyDeclaration && node.kind !== SyntaxKind.PropertySignature && node.kind !== SyntaxKind.IndexSignature && node.kind !== SyntaxKind.Parameter) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_already_seen, + "readonly" + ); + } else if ( + node.kind !== SyntaxKind.PropertyDeclaration && + node.kind !== SyntaxKind.PropertySignature && + node.kind !== SyntaxKind.IndexSignature && + node.kind !== SyntaxKind.Parameter + ) { // If node.kind === SyntaxKind.Parameter, checkParameter reports an error if it's not a parameter property. - return grammarErrorOnNode(modifier, Diagnostics.readonly_modifier_can_only_appear_on_a_property_declaration_or_index_signature); - } - else if (flags & ModifierFlags.Accessor) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "readonly", "accessor"); + return grammarErrorOnNode( + modifier, + Diagnostics.readonly_modifier_can_only_appear_on_a_property_declaration_or_index_signature + ); + } else if (flags & ModifierFlags.Accessor) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "readonly", + "accessor" + ); } flags |= ModifierFlags.Readonly; break; @@ -51647,86 +88811,179 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // ModuleDeclaration needs to be checked that it is uninstantiated later node.kind !== SyntaxKind.ModuleDeclaration && node.parent.kind === SyntaxKind.SourceFile && - host.getEmitModuleFormatOfFile(getSourceFileOfNode(node)) === ModuleKind.CommonJS + host.getEmitModuleFormatOfFile( + getSourceFileOfNode(node) + ) === ModuleKind.CommonJS ) { - return grammarErrorOnNode(modifier, Diagnostics.A_top_level_export_modifier_cannot_be_used_on_value_declarations_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled); + return grammarErrorOnNode( + modifier, + Diagnostics.A_top_level_export_modifier_cannot_be_used_on_value_declarations_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled + ); } if (flags & ModifierFlags.Export) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "export"); - } - else if (flags & ModifierFlags.Ambient) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "export", "declare"); - } - else if (flags & ModifierFlags.Abstract) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "export", "abstract"); - } - else if (flags & ModifierFlags.Async) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "export", "async"); - } - else if (isClassLike(node.parent)) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_class_elements_of_this_kind, "export"); - } - else if (node.kind === SyntaxKind.Parameter) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "export"); - } - else if (blockScopeKind === NodeFlags.Using) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_using_declaration, "export"); - } - else if (blockScopeKind === NodeFlags.AwaitUsing) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_an_await_using_declaration, "export"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_already_seen, + "export" + ); + } else if (flags & ModifierFlags.Ambient) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "export", + "declare" + ); + } else if (flags & ModifierFlags.Abstract) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "export", + "abstract" + ); + } else if (flags & ModifierFlags.Async) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "export", + "async" + ); + } else if (isClassLike(node.parent)) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_class_elements_of_this_kind, + "export" + ); + } else if (node.kind === SyntaxKind.Parameter) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_parameter, + "export" + ); + } else if (blockScopeKind === NodeFlags.Using) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_using_declaration, + "export" + ); + } else if (blockScopeKind === NodeFlags.AwaitUsing) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_an_await_using_declaration, + "export" + ); } flags |= ModifierFlags.Export; break; case SyntaxKind.DefaultKeyword: - const container = node.parent.kind === SyntaxKind.SourceFile ? node.parent : node.parent.parent; - if (container.kind === SyntaxKind.ModuleDeclaration && !isAmbientModule(container)) { - return grammarErrorOnNode(modifier, Diagnostics.A_default_export_can_only_be_used_in_an_ECMAScript_style_module); - } - else if (blockScopeKind === NodeFlags.Using) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_using_declaration, "default"); - } - else if (blockScopeKind === NodeFlags.AwaitUsing) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_an_await_using_declaration, "default"); - } - else if (!(flags & ModifierFlags.Export)) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "export", "default"); - } - else if (sawExportBeforeDecorators) { - return grammarErrorOnNode(firstDecorator!, Diagnostics.Decorators_are_not_valid_here); + const container = + node.parent.kind === SyntaxKind.SourceFile + ? node.parent + : node.parent.parent; + if ( + container.kind === SyntaxKind.ModuleDeclaration && + !isAmbientModule(container) + ) { + return grammarErrorOnNode( + modifier, + Diagnostics.A_default_export_can_only_be_used_in_an_ECMAScript_style_module + ); + } else if (blockScopeKind === NodeFlags.Using) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_using_declaration, + "default" + ); + } else if (blockScopeKind === NodeFlags.AwaitUsing) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_an_await_using_declaration, + "default" + ); + } else if (!(flags & ModifierFlags.Export)) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "export", + "default" + ); + } else if (sawExportBeforeDecorators) { + return grammarErrorOnNode( + firstDecorator!, + Diagnostics.Decorators_are_not_valid_here + ); } flags |= ModifierFlags.Default; break; case SyntaxKind.DeclareKeyword: if (flags & ModifierFlags.Ambient) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "declare"); - } - else if (flags & ModifierFlags.Async) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, "async"); - } - else if (flags & ModifierFlags.Override) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, "override"); - } - else if (isClassLike(node.parent) && !isPropertyDeclaration(node)) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_class_elements_of_this_kind, "declare"); - } - else if (node.kind === SyntaxKind.Parameter) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "declare"); - } - else if (blockScopeKind === NodeFlags.Using) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_using_declaration, "declare"); - } - else if (blockScopeKind === NodeFlags.AwaitUsing) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_an_await_using_declaration, "declare"); - } - else if ((node.parent.flags & NodeFlags.Ambient) && node.parent.kind === SyntaxKind.ModuleBlock) { - return grammarErrorOnNode(modifier, Diagnostics.A_declare_modifier_cannot_be_used_in_an_already_ambient_context); - } - else if (isPrivateIdentifierClassElementDeclaration(node)) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_a_private_identifier, "declare"); - } - else if (flags & ModifierFlags.Accessor) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "declare", "accessor"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_already_seen, + "declare" + ); + } else if (flags & ModifierFlags.Async) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, + "async" + ); + } else if (flags & ModifierFlags.Override) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, + "override" + ); + } else if ( + isClassLike(node.parent) && + !isPropertyDeclaration(node) + ) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_class_elements_of_this_kind, + "declare" + ); + } else if (node.kind === SyntaxKind.Parameter) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_parameter, + "declare" + ); + } else if (blockScopeKind === NodeFlags.Using) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_using_declaration, + "declare" + ); + } else if (blockScopeKind === NodeFlags.AwaitUsing) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_an_await_using_declaration, + "declare" + ); + } else if ( + node.parent.flags & NodeFlags.Ambient && + node.parent.kind === SyntaxKind.ModuleBlock + ) { + return grammarErrorOnNode( + modifier, + Diagnostics.A_declare_modifier_cannot_be_used_in_an_already_ambient_context + ); + } else if ( + isPrivateIdentifierClassElementDeclaration(node) + ) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_a_private_identifier, + "declare" + ); + } else if (flags & ModifierFlags.Accessor) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "declare", + "accessor" + ); } flags |= ModifierFlags.Ambient; lastDeclare = modifier; @@ -51734,7 +88991,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.AbstractKeyword: if (flags & ModifierFlags.Abstract) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "abstract"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_already_seen, + "abstract" + ); } if ( node.kind !== SyntaxKind.ClassDeclaration && @@ -51746,32 +89007,77 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { node.kind !== SyntaxKind.GetAccessor && node.kind !== SyntaxKind.SetAccessor ) { - return grammarErrorOnNode(modifier, Diagnostics.abstract_modifier_can_only_appear_on_a_class_method_or_property_declaration); + return grammarErrorOnNode( + modifier, + Diagnostics.abstract_modifier_can_only_appear_on_a_class_method_or_property_declaration + ); } - if (!(node.parent.kind === SyntaxKind.ClassDeclaration && hasSyntacticModifier(node.parent, ModifierFlags.Abstract))) { - const message = node.kind === SyntaxKind.PropertyDeclaration - ? Diagnostics.Abstract_properties_can_only_appear_within_an_abstract_class - : Diagnostics.Abstract_methods_can_only_appear_within_an_abstract_class; + if ( + !( + node.parent.kind === + SyntaxKind.ClassDeclaration && + hasSyntacticModifier( + node.parent, + ModifierFlags.Abstract + ) + ) + ) { + const message = + node.kind === SyntaxKind.PropertyDeclaration + ? Diagnostics.Abstract_properties_can_only_appear_within_an_abstract_class + : Diagnostics.Abstract_methods_can_only_appear_within_an_abstract_class; return grammarErrorOnNode(modifier, message); } if (flags & ModifierFlags.Static) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "static", "abstract"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "static", + "abstract" + ); } if (flags & ModifierFlags.Private) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "private", "abstract"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "private", + "abstract" + ); } if (flags & ModifierFlags.Async && lastAsync) { - return grammarErrorOnNode(lastAsync, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "async", "abstract"); + return grammarErrorOnNode( + lastAsync, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "async", + "abstract" + ); } if (flags & ModifierFlags.Override) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "abstract", "override"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "abstract", + "override" + ); } if (flags & ModifierFlags.Accessor) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "abstract", "accessor"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "abstract", + "accessor" + ); } } - if (isNamedDeclaration(node) && node.name.kind === SyntaxKind.PrivateIdentifier) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_a_private_identifier, "abstract"); + if ( + isNamedDeclaration(node) && + node.name.kind === SyntaxKind.PrivateIdentifier + ) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_a_private_identifier, + "abstract" + ); } flags |= ModifierFlags.Abstract; @@ -51779,16 +89085,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.AsyncKeyword: if (flags & ModifierFlags.Async) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "async"); - } - else if (flags & ModifierFlags.Ambient || node.parent.flags & NodeFlags.Ambient) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, "async"); - } - else if (node.kind === SyntaxKind.Parameter) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "async"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_already_seen, + "async" + ); + } else if ( + flags & ModifierFlags.Ambient || + node.parent.flags & NodeFlags.Ambient + ) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, + "async" + ); + } else if (node.kind === SyntaxKind.Parameter) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_parameter, + "async" + ); } if (flags & ModifierFlags.Abstract) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "async", "abstract"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "async", + "abstract" + ); } flags |= ModifierFlags.Async; lastAsync = modifier; @@ -51796,17 +89120,55 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.InKeyword: case SyntaxKind.OutKeyword: { - const inOutFlag = modifier.kind === SyntaxKind.InKeyword ? ModifierFlags.In : ModifierFlags.Out; - const inOutText = modifier.kind === SyntaxKind.InKeyword ? "in" : "out"; - const parent = isJSDocTemplateTag(node.parent) && (getEffectiveJSDocHost(node.parent) || find(getJSDocRoot(node.parent)?.tags, isJSDocTypedefTag)) || node.parent; - if (node.kind !== SyntaxKind.TypeParameter || parent && !(isInterfaceDeclaration(parent) || isClassLike(parent) || isTypeAliasDeclaration(parent) || isJSDocTypedefTag(parent))) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_can_only_appear_on_a_type_parameter_of_a_class_interface_or_type_alias, inOutText); + const inOutFlag = + modifier.kind === SyntaxKind.InKeyword + ? ModifierFlags.In + : ModifierFlags.Out; + const inOutText = + modifier.kind === SyntaxKind.InKeyword + ? "in" + : "out"; + const parent = + (isJSDocTemplateTag(node.parent) && + (getEffectiveJSDocHost(node.parent) || + find( + getJSDocRoot(node.parent)?.tags, + isJSDocTypedefTag + ))) || + node.parent; + if ( + node.kind !== SyntaxKind.TypeParameter || + (parent && + !( + isInterfaceDeclaration(parent) || + isClassLike(parent) || + isTypeAliasDeclaration(parent) || + isJSDocTypedefTag(parent) + )) + ) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_can_only_appear_on_a_type_parameter_of_a_class_interface_or_type_alias, + inOutText + ); } if (flags & inOutFlag) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, inOutText); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_already_seen, + inOutText + ); } - if (inOutFlag & ModifierFlags.In && flags & ModifierFlags.Out) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "in", "out"); + if ( + inOutFlag & ModifierFlags.In && + flags & ModifierFlags.Out + ) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "in", + "out" + ); } flags |= inOutFlag; break; @@ -51817,24 +89179,55 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (node.kind === SyntaxKind.Constructor) { if (flags & ModifierFlags.Static) { - return grammarErrorOnNode(lastStatic!, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "static"); + return grammarErrorOnNode( + lastStatic!, + Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, + "static" + ); } if (flags & ModifierFlags.Override) { - return grammarErrorOnNode(lastOverride!, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "override"); // TODO: GH#18217 + return grammarErrorOnNode( + lastOverride!, + Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, + "override" + ); // TODO: GH#18217 } if (flags & ModifierFlags.Async) { - return grammarErrorOnNode(lastAsync!, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "async"); + return grammarErrorOnNode( + lastAsync!, + Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, + "async" + ); } return false; - } - else if ((node.kind === SyntaxKind.ImportDeclaration || node.kind === SyntaxKind.ImportEqualsDeclaration) && flags & ModifierFlags.Ambient) { - return grammarErrorOnNode(lastDeclare!, Diagnostics.A_0_modifier_cannot_be_used_with_an_import_declaration, "declare"); - } - else if (node.kind === SyntaxKind.Parameter && (flags & ModifierFlags.ParameterPropertyModifier) && isBindingPattern(node.name)) { - return grammarErrorOnNode(node, Diagnostics.A_parameter_property_may_not_be_declared_using_a_binding_pattern); - } - else if (node.kind === SyntaxKind.Parameter && (flags & ModifierFlags.ParameterPropertyModifier) && node.dotDotDotToken) { - return grammarErrorOnNode(node, Diagnostics.A_parameter_property_cannot_be_declared_using_a_rest_parameter); + } else if ( + (node.kind === SyntaxKind.ImportDeclaration || + node.kind === SyntaxKind.ImportEqualsDeclaration) && + flags & ModifierFlags.Ambient + ) { + return grammarErrorOnNode( + lastDeclare!, + Diagnostics.A_0_modifier_cannot_be_used_with_an_import_declaration, + "declare" + ); + } else if ( + node.kind === SyntaxKind.Parameter && + flags & ModifierFlags.ParameterPropertyModifier && + isBindingPattern(node.name) + ) { + return grammarErrorOnNode( + node, + Diagnostics.A_parameter_property_may_not_be_declared_using_a_binding_pattern + ); + } else if ( + node.kind === SyntaxKind.Parameter && + flags & ModifierFlags.ParameterPropertyModifier && + node.dotDotDotToken + ) { + return grammarErrorOnNode( + node, + Diagnostics.A_parameter_property_cannot_be_declared_using_a_rest_parameter + ); } if (flags & ModifierFlags.Async) { return checkGrammarAsyncModifier(node, lastAsync!); @@ -51846,19 +89239,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * true | false: Early return this value from checkGrammarModifiers. * undefined: Need to do full checking on the modifiers. */ - function reportObviousModifierErrors(node: HasModifiers | HasIllegalModifiers): boolean | undefined { + function reportObviousModifierErrors( + node: HasModifiers | HasIllegalModifiers + ): boolean | undefined { if (!node.modifiers) return false; const modifier = findFirstIllegalModifier(node); - return modifier && grammarErrorOnFirstToken(modifier, Diagnostics.Modifiers_cannot_appear_here); + return ( + modifier && + grammarErrorOnFirstToken( + modifier, + Diagnostics.Modifiers_cannot_appear_here + ) + ); } - function findFirstModifierExcept(node: HasModifiers, allowedModifier: SyntaxKind): Modifier | undefined { + function findFirstModifierExcept( + node: HasModifiers, + allowedModifier: SyntaxKind + ): Modifier | undefined { const modifier = find(node.modifiers, isModifier); - return modifier && modifier.kind !== allowedModifier ? modifier : undefined; + return modifier && modifier.kind !== allowedModifier + ? modifier + : undefined; } - function findFirstIllegalModifier(node: HasModifiers | HasIllegalModifiers): Modifier | undefined { + function findFirstIllegalModifier( + node: HasModifiers | HasIllegalModifiers + ): Modifier | undefined { switch (node.kind) { case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: @@ -51885,41 +89293,79 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.MissingDeclaration: return find(node.modifiers, isModifier); default: - if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) { + if ( + node.parent.kind === SyntaxKind.ModuleBlock || + node.parent.kind === SyntaxKind.SourceFile + ) { return undefined; } switch (node.kind) { case SyntaxKind.FunctionDeclaration: - return findFirstModifierExcept(node, SyntaxKind.AsyncKeyword); + return findFirstModifierExcept( + node, + SyntaxKind.AsyncKeyword + ); case SyntaxKind.ClassDeclaration: case SyntaxKind.ConstructorType: - return findFirstModifierExcept(node, SyntaxKind.AbstractKeyword); + return findFirstModifierExcept( + node, + SyntaxKind.AbstractKeyword + ); case SyntaxKind.ClassExpression: case SyntaxKind.InterfaceDeclaration: case SyntaxKind.TypeAliasDeclaration: return find(node.modifiers, isModifier); case SyntaxKind.VariableStatement: - return node.declarationList.flags & NodeFlags.Using ? - findFirstModifierExcept(node, SyntaxKind.AwaitKeyword) : - find(node.modifiers, isModifier); + return node.declarationList.flags & NodeFlags.Using + ? findFirstModifierExcept( + node, + SyntaxKind.AwaitKeyword + ) + : find(node.modifiers, isModifier); case SyntaxKind.EnumDeclaration: - return findFirstModifierExcept(node, SyntaxKind.ConstKeyword); + return findFirstModifierExcept( + node, + SyntaxKind.ConstKeyword + ); default: Debug.assertNever(node); } } } - function reportObviousDecoratorErrors(node: HasModifiers | HasDecorators | HasIllegalModifiers | HasIllegalDecorators) { + function reportObviousDecoratorErrors( + node: + | HasModifiers + | HasDecorators + | HasIllegalModifiers + | HasIllegalDecorators + ) { const decorator = findFirstIllegalDecorator(node); - return decorator && grammarErrorOnFirstToken(decorator, Diagnostics.Decorators_are_not_valid_here); + return ( + decorator && + grammarErrorOnFirstToken( + decorator, + Diagnostics.Decorators_are_not_valid_here + ) + ); } - function findFirstIllegalDecorator(node: HasModifiers | HasDecorators | HasIllegalModifiers | HasIllegalDecorators): Decorator | undefined { - return canHaveIllegalDecorators(node) ? find(node.modifiers, isDecorator) : undefined; + function findFirstIllegalDecorator( + node: + | HasModifiers + | HasDecorators + | HasIllegalModifiers + | HasIllegalDecorators + ): Decorator | undefined { + return canHaveIllegalDecorators(node) + ? find(node.modifiers, isDecorator) + : undefined; } - function checkGrammarAsyncModifier(node: Node, asyncModifier: Node): boolean { + function checkGrammarAsyncModifier( + node: Node, + asyncModifier: Node + ): boolean { switch (node.kind) { case SyntaxKind.MethodDeclaration: case SyntaxKind.FunctionDeclaration: @@ -51928,80 +89374,155 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - return grammarErrorOnNode(asyncModifier, Diagnostics._0_modifier_cannot_be_used_here, "async"); + return grammarErrorOnNode( + asyncModifier, + Diagnostics._0_modifier_cannot_be_used_here, + "async" + ); } - function checkGrammarForDisallowedTrailingComma(list: NodeArray | undefined, diag = Diagnostics.Trailing_comma_not_allowed): boolean { + function checkGrammarForDisallowedTrailingComma( + list: NodeArray | undefined, + diag = Diagnostics.Trailing_comma_not_allowed + ): boolean { if (list && list.hasTrailingComma) { - return grammarErrorAtPos(list[0], list.end - ",".length, ",".length, diag); + return grammarErrorAtPos( + list[0], + list.end - ",".length, + ",".length, + diag + ); } return false; } - function checkGrammarTypeParameterList(typeParameters: NodeArray | undefined, file: SourceFile): boolean { + function checkGrammarTypeParameterList( + typeParameters: NodeArray | undefined, + file: SourceFile + ): boolean { if (typeParameters && typeParameters.length === 0) { const start = typeParameters.pos - "<".length; const end = skipTrivia(file.text, typeParameters.end) + ">".length; - return grammarErrorAtPos(file, start, end - start, Diagnostics.Type_parameter_list_cannot_be_empty); + return grammarErrorAtPos( + file, + start, + end - start, + Diagnostics.Type_parameter_list_cannot_be_empty + ); } return false; } - function checkGrammarParameterList(parameters: NodeArray) { + function checkGrammarParameterList( + parameters: NodeArray + ) { let seenOptionalParameter = false; const parameterCount = parameters.length; for (let i = 0; i < parameterCount; i++) { const parameter = parameters[i]; if (parameter.dotDotDotToken) { - if (i !== (parameterCount - 1)) { - return grammarErrorOnNode(parameter.dotDotDotToken, Diagnostics.A_rest_parameter_must_be_last_in_a_parameter_list); + if (i !== parameterCount - 1) { + return grammarErrorOnNode( + parameter.dotDotDotToken, + Diagnostics.A_rest_parameter_must_be_last_in_a_parameter_list + ); } - if (!(parameter.flags & NodeFlags.Ambient)) { // Allow `...foo,` in ambient declarations; see GH#23070 - checkGrammarForDisallowedTrailingComma(parameters, Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma); + if (!(parameter.flags & NodeFlags.Ambient)) { + // Allow `...foo,` in ambient declarations; see GH#23070 + checkGrammarForDisallowedTrailingComma( + parameters, + Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma + ); } if (parameter.questionToken) { - return grammarErrorOnNode(parameter.questionToken, Diagnostics.A_rest_parameter_cannot_be_optional); + return grammarErrorOnNode( + parameter.questionToken, + Diagnostics.A_rest_parameter_cannot_be_optional + ); } if (parameter.initializer) { - return grammarErrorOnNode(parameter.name, Diagnostics.A_rest_parameter_cannot_have_an_initializer); + return grammarErrorOnNode( + parameter.name, + Diagnostics.A_rest_parameter_cannot_have_an_initializer + ); } - } - else if (hasEffectiveQuestionToken(parameter)) { + } else if (hasEffectiveQuestionToken(parameter)) { seenOptionalParameter = true; if (parameter.questionToken && parameter.initializer) { - return grammarErrorOnNode(parameter.name, Diagnostics.Parameter_cannot_have_question_mark_and_initializer); + return grammarErrorOnNode( + parameter.name, + Diagnostics.Parameter_cannot_have_question_mark_and_initializer + ); } - } - else if (seenOptionalParameter && !parameter.initializer) { - return grammarErrorOnNode(parameter.name, Diagnostics.A_required_parameter_cannot_follow_an_optional_parameter); + } else if (seenOptionalParameter && !parameter.initializer) { + return grammarErrorOnNode( + parameter.name, + Diagnostics.A_required_parameter_cannot_follow_an_optional_parameter + ); } } } - function getNonSimpleParameters(parameters: readonly ParameterDeclaration[]): readonly ParameterDeclaration[] { - return filter(parameters, parameter => !!parameter.initializer || isBindingPattern(parameter.name) || isRestParameter(parameter)); + function getNonSimpleParameters( + parameters: readonly ParameterDeclaration[] + ): readonly ParameterDeclaration[] { + return filter( + parameters, + (parameter) => + !!parameter.initializer || + isBindingPattern(parameter.name) || + isRestParameter(parameter) + ); } - function checkGrammarForUseStrictSimpleParameterList(node: FunctionLikeDeclaration): boolean { + function checkGrammarForUseStrictSimpleParameterList( + node: FunctionLikeDeclaration + ): boolean { if (languageVersion >= ScriptTarget.ES2016) { - const useStrictDirective = node.body && isBlock(node.body) && findUseStrictPrologue(node.body.statements); + const useStrictDirective = + node.body && + isBlock(node.body) && + findUseStrictPrologue(node.body.statements); if (useStrictDirective) { - const nonSimpleParameters = getNonSimpleParameters(node.parameters); + const nonSimpleParameters = getNonSimpleParameters( + node.parameters + ); if (length(nonSimpleParameters)) { - forEach(nonSimpleParameters, parameter => { + forEach(nonSimpleParameters, (parameter) => { addRelatedInfo( - error(parameter, Diagnostics.This_parameter_is_not_allowed_with_use_strict_directive), - createDiagnosticForNode(useStrictDirective, Diagnostics.use_strict_directive_used_here), + error( + parameter, + Diagnostics.This_parameter_is_not_allowed_with_use_strict_directive + ), + createDiagnosticForNode( + useStrictDirective, + Diagnostics.use_strict_directive_used_here + ) ); }); - const diagnostics = nonSimpleParameters.map((parameter, index) => ( - index === 0 ? createDiagnosticForNode(parameter, Diagnostics.Non_simple_parameter_declared_here) : createDiagnosticForNode(parameter, Diagnostics.and_here) - )) as [DiagnosticWithLocation, ...DiagnosticWithLocation[]]; - addRelatedInfo(error(useStrictDirective, Diagnostics.use_strict_directive_cannot_be_used_with_non_simple_parameter_list), ...diagnostics); + const diagnostics = nonSimpleParameters.map( + (parameter, index) => + index === 0 + ? createDiagnosticForNode( + parameter, + Diagnostics.Non_simple_parameter_declared_here + ) + : createDiagnosticForNode( + parameter, + Diagnostics.and_here + ) + ) as [DiagnosticWithLocation, ...DiagnosticWithLocation[]]; + addRelatedInfo( + error( + useStrictDirective, + Diagnostics.use_strict_directive_cannot_be_used_with_non_simple_parameter_list + ), + ...diagnostics + ); return true; } } @@ -52009,20 +89530,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function checkGrammarFunctionLikeDeclaration(node: FunctionLikeDeclaration | MethodSignature): boolean { + function checkGrammarFunctionLikeDeclaration( + node: FunctionLikeDeclaration | MethodSignature + ): boolean { // Prevent cascading error by short-circuit const file = getSourceFileOfNode(node); - return checkGrammarModifiers(node) || + return ( + checkGrammarModifiers(node) || checkGrammarTypeParameterList(node.typeParameters, file) || checkGrammarParameterList(node.parameters) || checkGrammarArrowFunction(node, file) || - (isFunctionLikeDeclaration(node) && checkGrammarForUseStrictSimpleParameterList(node)); + (isFunctionLikeDeclaration(node) && + checkGrammarForUseStrictSimpleParameterList(node)) + ); } - function checkGrammarClassLikeDeclaration(node: ClassLikeDeclaration): boolean { + function checkGrammarClassLikeDeclaration( + node: ClassLikeDeclaration + ): boolean { const file = getSourceFileOfNode(node); - return checkGrammarClassDeclarationHeritageClauses(node) || - checkGrammarTypeParameterList(node.typeParameters, file); + return ( + checkGrammarClassDeclarationHeritageClauses(node) || + checkGrammarTypeParameterList(node.typeParameters, file) + ); } function checkGrammarArrowFunction(node: Node, file: SourceFile): boolean { @@ -52030,80 +89560,170 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - if (node.typeParameters && !(length(node.typeParameters) > 1 || node.typeParameters.hasTrailingComma || node.typeParameters[0].constraint)) { - if (file && fileExtensionIsOneOf(file.fileName, [Extension.Mts, Extension.Cts])) { - grammarErrorOnNode(node.typeParameters[0], Diagnostics.This_syntax_is_reserved_in_files_with_the_mts_or_cts_extension_Add_a_trailing_comma_or_explicit_constraint); + if ( + node.typeParameters && + !( + length(node.typeParameters) > 1 || + node.typeParameters.hasTrailingComma || + node.typeParameters[0].constraint + ) + ) { + if ( + file && + fileExtensionIsOneOf(file.fileName, [ + Extension.Mts, + Extension.Cts, + ]) + ) { + grammarErrorOnNode( + node.typeParameters[0], + Diagnostics.This_syntax_is_reserved_in_files_with_the_mts_or_cts_extension_Add_a_trailing_comma_or_explicit_constraint + ); } } const { equalsGreaterThanToken } = node; - const startLine = getLineAndCharacterOfPosition(file, equalsGreaterThanToken.pos).line; - const endLine = getLineAndCharacterOfPosition(file, equalsGreaterThanToken.end).line; - return startLine !== endLine && grammarErrorOnNode(equalsGreaterThanToken, Diagnostics.Line_terminator_not_permitted_before_arrow); + const startLine = getLineAndCharacterOfPosition( + file, + equalsGreaterThanToken.pos + ).line; + const endLine = getLineAndCharacterOfPosition( + file, + equalsGreaterThanToken.end + ).line; + return ( + startLine !== endLine && + grammarErrorOnNode( + equalsGreaterThanToken, + Diagnostics.Line_terminator_not_permitted_before_arrow + ) + ); } - function checkGrammarIndexSignatureParameters(node: SignatureDeclaration): boolean { + function checkGrammarIndexSignatureParameters( + node: SignatureDeclaration + ): boolean { const parameter = node.parameters[0]; if (node.parameters.length !== 1) { if (parameter) { - return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_must_have_exactly_one_parameter); - } - else { - return grammarErrorOnNode(node, Diagnostics.An_index_signature_must_have_exactly_one_parameter); + return grammarErrorOnNode( + parameter.name, + Diagnostics.An_index_signature_must_have_exactly_one_parameter + ); + } else { + return grammarErrorOnNode( + node, + Diagnostics.An_index_signature_must_have_exactly_one_parameter + ); } } - checkGrammarForDisallowedTrailingComma(node.parameters, Diagnostics.An_index_signature_cannot_have_a_trailing_comma); + checkGrammarForDisallowedTrailingComma( + node.parameters, + Diagnostics.An_index_signature_cannot_have_a_trailing_comma + ); if (parameter.dotDotDotToken) { - return grammarErrorOnNode(parameter.dotDotDotToken, Diagnostics.An_index_signature_cannot_have_a_rest_parameter); + return grammarErrorOnNode( + parameter.dotDotDotToken, + Diagnostics.An_index_signature_cannot_have_a_rest_parameter + ); } if (hasEffectiveModifiers(parameter)) { - return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_cannot_have_an_accessibility_modifier); + return grammarErrorOnNode( + parameter.name, + Diagnostics.An_index_signature_parameter_cannot_have_an_accessibility_modifier + ); } if (parameter.questionToken) { - return grammarErrorOnNode(parameter.questionToken, Diagnostics.An_index_signature_parameter_cannot_have_a_question_mark); + return grammarErrorOnNode( + parameter.questionToken, + Diagnostics.An_index_signature_parameter_cannot_have_a_question_mark + ); } if (parameter.initializer) { - return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_cannot_have_an_initializer); + return grammarErrorOnNode( + parameter.name, + Diagnostics.An_index_signature_parameter_cannot_have_an_initializer + ); } if (!parameter.type) { - return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_must_have_a_type_annotation); + return grammarErrorOnNode( + parameter.name, + Diagnostics.An_index_signature_parameter_must_have_a_type_annotation + ); } const type = getTypeFromTypeNode(parameter.type); - if (someType(type, t => !!(t.flags & TypeFlags.StringOrNumberLiteralOrUnique)) || isGenericType(type)) { - 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); + if ( + someType( + type, + (t) => !!(t.flags & TypeFlags.StringOrNumberLiteralOrUnique) + ) || + isGenericType(type) + ) { + 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 + ); } if (!everyType(type, isValidIndexKeyType)) { - return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_type_must_be_string_number_symbol_or_a_template_literal_type); + return grammarErrorOnNode( + parameter.name, + Diagnostics.An_index_signature_parameter_type_must_be_string_number_symbol_or_a_template_literal_type + ); } if (!node.type) { - return grammarErrorOnNode(node, Diagnostics.An_index_signature_must_have_a_type_annotation); + return grammarErrorOnNode( + node, + Diagnostics.An_index_signature_must_have_a_type_annotation + ); } return false; } function checkGrammarIndexSignature(node: IndexSignatureDeclaration) { // Prevent cascading error by short-circuit - return checkGrammarModifiers(node) || checkGrammarIndexSignatureParameters(node); + return ( + checkGrammarModifiers(node) || + checkGrammarIndexSignatureParameters(node) + ); } - function checkGrammarForAtLeastOneTypeArgument(node: Node, typeArguments: NodeArray | undefined): boolean { + function checkGrammarForAtLeastOneTypeArgument( + node: Node, + typeArguments: NodeArray | undefined + ): boolean { if (typeArguments && typeArguments.length === 0) { const sourceFile = getSourceFileOfNode(node); const start = typeArguments.pos - "<".length; - const end = skipTrivia(sourceFile.text, typeArguments.end) + ">".length; - return grammarErrorAtPos(sourceFile, start, end - start, Diagnostics.Type_argument_list_cannot_be_empty); + const end = + skipTrivia(sourceFile.text, typeArguments.end) + ">".length; + return grammarErrorAtPos( + sourceFile, + start, + end - start, + Diagnostics.Type_argument_list_cannot_be_empty + ); } return false; } - function checkGrammarTypeArguments(node: Node, typeArguments: NodeArray | undefined): boolean { - return checkGrammarForDisallowedTrailingComma(typeArguments) || - checkGrammarForAtLeastOneTypeArgument(node, typeArguments); + function checkGrammarTypeArguments( + node: Node, + typeArguments: NodeArray | undefined + ): boolean { + return ( + checkGrammarForDisallowedTrailingComma(typeArguments) || + checkGrammarForAtLeastOneTypeArgument(node, typeArguments) + ); } - function checkGrammarTaggedTemplateChain(node: TaggedTemplateExpression): boolean { + function checkGrammarTaggedTemplateChain( + node: TaggedTemplateExpression + ): boolean { if (node.questionDotToken || node.flags & NodeFlags.OptionalChain) { - return grammarErrorOnNode(node.template, Diagnostics.Tagged_template_expressions_are_not_permitted_in_an_optional_chain); + return grammarErrorOnNode( + node.template, + Diagnostics.Tagged_template_expressions_are_not_permitted_in_an_optional_chain + ); } return false; } @@ -52115,19 +89735,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (types && types.length === 0) { const listType = tokenToString(node.token); - return grammarErrorAtPos(node, types.pos, 0, Diagnostics._0_list_cannot_be_empty, listType); + return grammarErrorAtPos( + node, + types.pos, + 0, + Diagnostics._0_list_cannot_be_empty, + listType + ); } return some(types, checkGrammarExpressionWithTypeArguments); } - function checkGrammarExpressionWithTypeArguments(node: ExpressionWithTypeArguments | TypeQueryNode) { - if (isExpressionWithTypeArguments(node) && isImportKeyword(node.expression) && node.typeArguments) { - 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); + function checkGrammarExpressionWithTypeArguments( + node: ExpressionWithTypeArguments | TypeQueryNode + ) { + if ( + isExpressionWithTypeArguments(node) && + isImportKeyword(node.expression) && + node.typeArguments + ) { + 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 + ); } return checkGrammarTypeArguments(node, node.typeArguments); } - function checkGrammarClassDeclarationHeritageClauses(node: ClassLikeDeclaration) { + function checkGrammarClassDeclarationHeritageClauses( + node: ClassLikeDeclaration + ) { let seenExtendsClause = false; let seenImplementsClause = false; @@ -52135,23 +89772,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (const heritageClause of node.heritageClauses) { if (heritageClause.token === SyntaxKind.ExtendsKeyword) { if (seenExtendsClause) { - return grammarErrorOnFirstToken(heritageClause, Diagnostics.extends_clause_already_seen); + return grammarErrorOnFirstToken( + heritageClause, + Diagnostics.extends_clause_already_seen + ); } if (seenImplementsClause) { - return grammarErrorOnFirstToken(heritageClause, Diagnostics.extends_clause_must_precede_implements_clause); + return grammarErrorOnFirstToken( + heritageClause, + Diagnostics.extends_clause_must_precede_implements_clause + ); } if (heritageClause.types.length > 1) { - return grammarErrorOnFirstToken(heritageClause.types[1], Diagnostics.Classes_can_only_extend_a_single_class); + return grammarErrorOnFirstToken( + heritageClause.types[1], + Diagnostics.Classes_can_only_extend_a_single_class + ); } seenExtendsClause = true; - } - else { - Debug.assert(heritageClause.token === SyntaxKind.ImplementsKeyword); + } else { + Debug.assert( + heritageClause.token === SyntaxKind.ImplementsKeyword + ); if (seenImplementsClause) { - return grammarErrorOnFirstToken(heritageClause, Diagnostics.implements_clause_already_seen); + return grammarErrorOnFirstToken( + heritageClause, + Diagnostics.implements_clause_already_seen + ); } seenImplementsClause = true; @@ -52170,14 +89820,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (const heritageClause of node.heritageClauses) { if (heritageClause.token === SyntaxKind.ExtendsKeyword) { if (seenExtendsClause) { - return grammarErrorOnFirstToken(heritageClause, Diagnostics.extends_clause_already_seen); + return grammarErrorOnFirstToken( + heritageClause, + Diagnostics.extends_clause_already_seen + ); } seenExtendsClause = true; - } - else { - Debug.assert(heritageClause.token === SyntaxKind.ImplementsKeyword); - return grammarErrorOnFirstToken(heritageClause, Diagnostics.Interface_declaration_cannot_have_implements_clause); + } else { + Debug.assert( + heritageClause.token === SyntaxKind.ImplementsKeyword + ); + return grammarErrorOnFirstToken( + heritageClause, + Diagnostics.Interface_declaration_cannot_have_implements_clause + ); } // Grammar checking heritageClause inside class declaration @@ -52194,8 +89851,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const computedPropertyName = node as ComputedPropertyName; - if (computedPropertyName.expression.kind === SyntaxKind.BinaryExpression && (computedPropertyName.expression as BinaryExpression).operatorToken.kind === SyntaxKind.CommaToken) { - return grammarErrorOnNode(computedPropertyName.expression, Diagnostics.A_comma_expression_is_not_allowed_in_a_computed_property_name); + if ( + computedPropertyName.expression.kind === + SyntaxKind.BinaryExpression && + (computedPropertyName.expression as BinaryExpression).operatorToken + .kind === SyntaxKind.CommaToken + ) { + return grammarErrorOnNode( + computedPropertyName.expression, + Diagnostics.A_comma_expression_is_not_allowed_in_a_computed_property_name + ); } return false; } @@ -52205,26 +89870,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { Debug.assert( node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression || - node.kind === SyntaxKind.MethodDeclaration, + node.kind === SyntaxKind.MethodDeclaration ); if (node.flags & NodeFlags.Ambient) { - return grammarErrorOnNode(node.asteriskToken, Diagnostics.Generators_are_not_allowed_in_an_ambient_context); + return grammarErrorOnNode( + node.asteriskToken, + Diagnostics.Generators_are_not_allowed_in_an_ambient_context + ); } if (!node.body) { - return grammarErrorOnNode(node.asteriskToken, Diagnostics.An_overload_signature_cannot_be_declared_as_a_generator); + return grammarErrorOnNode( + node.asteriskToken, + Diagnostics.An_overload_signature_cannot_be_declared_as_a_generator + ); } } } - function checkGrammarForInvalidQuestionMark(questionToken: QuestionToken | undefined, message: DiagnosticMessage): boolean { + function checkGrammarForInvalidQuestionMark( + questionToken: QuestionToken | undefined, + message: DiagnosticMessage + ): boolean { return !!questionToken && grammarErrorOnNode(questionToken, message); } - function checkGrammarForInvalidExclamationToken(exclamationToken: ExclamationToken | undefined, message: DiagnosticMessage): boolean { - return !!exclamationToken && grammarErrorOnNode(exclamationToken, message); + function checkGrammarForInvalidExclamationToken( + exclamationToken: ExclamationToken | undefined, + message: DiagnosticMessage + ): boolean { + return ( + !!exclamationToken && grammarErrorOnNode(exclamationToken, message) + ); } - function checkGrammarObjectLiteralExpression(node: ObjectLiteralExpression, inDestructuring: boolean) { + function checkGrammarObjectLiteralExpression( + node: ObjectLiteralExpression, + inDestructuring: boolean + ) { const seen = new Map<__String, DeclarationMeaning>(); for (const prop of node.properties) { @@ -52232,8 +89914,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (inDestructuring) { // a rest property cannot be destructured any further const expression = skipParentheses(prop.expression); - if (isArrayLiteralExpression(expression) || isObjectLiteralExpression(expression)) { - return grammarErrorOnNode(prop.expression, Diagnostics.A_rest_element_cannot_contain_a_binding_pattern); + if ( + isArrayLiteralExpression(expression) || + isObjectLiteralExpression(expression) + ) { + return grammarErrorOnNode( + prop.expression, + Diagnostics.A_rest_element_cannot_contain_a_binding_pattern + ); } } continue; @@ -52244,28 +89932,49 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkGrammarComputedPropertyName(name); } - if (prop.kind === SyntaxKind.ShorthandPropertyAssignment && !inDestructuring && prop.objectAssignmentInitializer) { + if ( + prop.kind === SyntaxKind.ShorthandPropertyAssignment && + !inDestructuring && + prop.objectAssignmentInitializer + ) { // having objectAssignmentInitializer is only valid in ObjectAssignmentPattern // outside of destructuring it is a syntax error - 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); + 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 + ); } if (name.kind === SyntaxKind.PrivateIdentifier) { - grammarErrorOnNode(name, Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies); + grammarErrorOnNode( + name, + Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies + ); } // Modifiers are never allowed on properties except for 'async' on a method declaration if (canHaveModifiers(prop) && prop.modifiers) { for (const mod of prop.modifiers) { - if (isModifier(mod) && (mod.kind !== SyntaxKind.AsyncKeyword || prop.kind !== SyntaxKind.MethodDeclaration)) { - grammarErrorOnNode(mod, Diagnostics._0_modifier_cannot_be_used_here, getTextOfNode(mod)); + if ( + isModifier(mod) && + (mod.kind !== SyntaxKind.AsyncKeyword || + prop.kind !== SyntaxKind.MethodDeclaration) + ) { + grammarErrorOnNode( + mod, + Diagnostics._0_modifier_cannot_be_used_here, + getTextOfNode(mod) + ); } } - } - else if (canHaveIllegalModifiers(prop) && prop.modifiers) { + } else if (canHaveIllegalModifiers(prop) && prop.modifiers) { for (const mod of prop.modifiers) { if (isModifier(mod)) { - grammarErrorOnNode(mod, Diagnostics._0_modifier_cannot_be_used_here, getTextOfNode(mod)); + grammarErrorOnNode( + mod, + Diagnostics._0_modifier_cannot_be_used_here, + getTextOfNode(mod) + ); } } } @@ -52283,13 +89992,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ShorthandPropertyAssignment: case SyntaxKind.PropertyAssignment: // Grammar checking for computedPropertyName and shorthandPropertyAssignment - checkGrammarForInvalidExclamationToken(prop.exclamationToken, Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context); - checkGrammarForInvalidQuestionMark(prop.questionToken, Diagnostics.An_object_member_cannot_be_declared_optional); + checkGrammarForInvalidExclamationToken( + prop.exclamationToken, + Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context + ); + checkGrammarForInvalidQuestionMark( + prop.questionToken, + Diagnostics.An_object_member_cannot_be_declared_optional + ); if (name.kind === SyntaxKind.NumericLiteral) { checkGrammarNumericLiteral(name); } if (name.kind === SyntaxKind.BigIntLiteral) { - addErrorOrSuggestion(/*isError*/ true, createDiagnosticForNode(name, Diagnostics.A_bigint_literal_cannot_be_used_as_a_property_name)); + addErrorOrSuggestion( + /*isError*/ true, + createDiagnosticForNode( + name, + Diagnostics.A_bigint_literal_cannot_be_used_as_a_property_name + ) + ); } currentKind = DeclarationMeaning.PropertyAssignment; break; @@ -52303,11 +90024,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { currentKind = DeclarationMeaning.SetAccessor; break; default: - Debug.assertNever(prop, "Unexpected syntax kind:" + (prop as Node).kind); + Debug.assertNever( + prop, + "Unexpected syntax kind:" + (prop as Node).kind + ); } if (!inDestructuring) { - const effectiveName = getEffectivePropertyNameForPropertyNameNode(name); + const effectiveName = + getEffectivePropertyNameForPropertyNameNode(name); if (effectiveName === undefined) { continue; } @@ -52315,24 +90040,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const existingKind = seen.get(effectiveName); if (!existingKind) { seen.set(effectiveName, currentKind); - } - else { - if ((currentKind & DeclarationMeaning.Method) && (existingKind & DeclarationMeaning.Method)) { - grammarErrorOnNode(name, Diagnostics.Duplicate_identifier_0, getTextOfNode(name)); - } - else if ((currentKind & DeclarationMeaning.PropertyAssignment) && (existingKind & DeclarationMeaning.PropertyAssignment)) { - grammarErrorOnNode(name, Diagnostics.An_object_literal_cannot_have_multiple_properties_with_the_same_name, getTextOfNode(name)); - } - else if ((currentKind & DeclarationMeaning.GetOrSetAccessor) && (existingKind & DeclarationMeaning.GetOrSetAccessor)) { - if (existingKind !== DeclarationMeaning.GetOrSetAccessor && currentKind !== existingKind) { + } else { + if ( + currentKind & DeclarationMeaning.Method && + existingKind & DeclarationMeaning.Method + ) { + grammarErrorOnNode( + name, + Diagnostics.Duplicate_identifier_0, + getTextOfNode(name) + ); + } else if ( + currentKind & DeclarationMeaning.PropertyAssignment && + existingKind & DeclarationMeaning.PropertyAssignment + ) { + grammarErrorOnNode( + name, + Diagnostics.An_object_literal_cannot_have_multiple_properties_with_the_same_name, + getTextOfNode(name) + ); + } else if ( + currentKind & DeclarationMeaning.GetOrSetAccessor && + existingKind & DeclarationMeaning.GetOrSetAccessor + ) { + if ( + existingKind !== + DeclarationMeaning.GetOrSetAccessor && + currentKind !== existingKind + ) { seen.set(effectiveName, currentKind | existingKind); + } else { + return grammarErrorOnNode( + name, + Diagnostics.An_object_literal_cannot_have_multiple_get_Slashset_accessors_with_the_same_name + ); } - else { - return grammarErrorOnNode(name, Diagnostics.An_object_literal_cannot_have_multiple_get_Slashset_accessors_with_the_same_name); - } - } - else { - return grammarErrorOnNode(name, Diagnostics.An_object_literal_cannot_have_property_and_accessor_with_the_same_name); + } else { + return grammarErrorOnNode( + name, + Diagnostics.An_object_literal_cannot_have_property_and_accessor_with_the_same_name + ); } } } @@ -52353,57 +90100,103 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const escapedText = getEscapedTextOfJsxAttributeName(name); if (!seen.get(escapedText)) { seen.set(escapedText, true); - } - else { - return grammarErrorOnNode(name, Diagnostics.JSX_elements_cannot_have_multiple_attributes_with_the_same_name); + } else { + return grammarErrorOnNode( + name, + Diagnostics.JSX_elements_cannot_have_multiple_attributes_with_the_same_name + ); } - if (initializer && initializer.kind === SyntaxKind.JsxExpression && !initializer.expression) { - return grammarErrorOnNode(initializer, Diagnostics.JSX_attributes_must_only_be_assigned_a_non_empty_expression); + if ( + initializer && + initializer.kind === SyntaxKind.JsxExpression && + !initializer.expression + ) { + return grammarErrorOnNode( + initializer, + Diagnostics.JSX_attributes_must_only_be_assigned_a_non_empty_expression + ); } } } function checkGrammarJsxName(node: JsxTagNameExpression) { - if (isPropertyAccessExpression(node) && isJsxNamespacedName(node.expression)) { - return grammarErrorOnNode(node.expression, Diagnostics.JSX_property_access_expressions_cannot_include_JSX_namespace_names); + if ( + isPropertyAccessExpression(node) && + isJsxNamespacedName(node.expression) + ) { + return grammarErrorOnNode( + node.expression, + Diagnostics.JSX_property_access_expressions_cannot_include_JSX_namespace_names + ); } - if (isJsxNamespacedName(node) && getJSXTransformEnabled(compilerOptions) && !isIntrinsicJsxName(node.namespace.escapedText)) { - return grammarErrorOnNode(node, Diagnostics.React_components_cannot_include_JSX_namespace_names); + if ( + isJsxNamespacedName(node) && + getJSXTransformEnabled(compilerOptions) && + !isIntrinsicJsxName(node.namespace.escapedText) + ) { + return grammarErrorOnNode( + node, + Diagnostics.React_components_cannot_include_JSX_namespace_names + ); } } function checkGrammarJsxExpression(node: JsxExpression) { if (node.expression && isCommaSequence(node.expression)) { - return grammarErrorOnNode(node.expression, Diagnostics.JSX_expressions_may_not_use_the_comma_operator_Did_you_mean_to_write_an_array); + return grammarErrorOnNode( + node.expression, + Diagnostics.JSX_expressions_may_not_use_the_comma_operator_Did_you_mean_to_write_an_array + ); } } - function checkGrammarForInOrForOfStatement(forInOrOfStatement: ForInOrOfStatement): boolean { + function checkGrammarForInOrForOfStatement( + forInOrOfStatement: ForInOrOfStatement + ): boolean { if (checkGrammarStatementInAmbientContext(forInOrOfStatement)) { return true; } - if (forInOrOfStatement.kind === SyntaxKind.ForOfStatement && forInOrOfStatement.awaitModifier) { + if ( + forInOrOfStatement.kind === SyntaxKind.ForOfStatement && + forInOrOfStatement.awaitModifier + ) { if (!(forInOrOfStatement.flags & NodeFlags.AwaitContext)) { const sourceFile = getSourceFileOfNode(forInOrOfStatement); if (isInTopLevelContext(forInOrOfStatement)) { if (!hasParseDiagnostics(sourceFile)) { - if (!isEffectiveExternalModule(sourceFile, compilerOptions)) { - diagnostics.add(createDiagnosticForNode(forInOrOfStatement.awaitModifier, 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)); + if ( + !isEffectiveExternalModule( + sourceFile, + compilerOptions + ) + ) { + diagnostics.add( + createDiagnosticForNode( + forInOrOfStatement.awaitModifier, + 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 + ) + ); } switch (moduleKind) { case ModuleKind.Node16: case ModuleKind.Node18: case ModuleKind.Node20: case ModuleKind.NodeNext: - if (sourceFile.impliedNodeFormat === ModuleKind.CommonJS) { + if ( + sourceFile.impliedNodeFormat === + ModuleKind.CommonJS + ) { diagnostics.add( - createDiagnosticForNode(forInOrOfStatement.awaitModifier, Diagnostics.The_current_file_is_a_CommonJS_module_and_cannot_use_await_at_the_top_level), + createDiagnosticForNode( + forInOrOfStatement.awaitModifier, + Diagnostics.The_current_file_is_a_CommonJS_module_and_cannot_use_await_at_the_top_level + ) ); break; } - // fallthrough + // fallthrough case ModuleKind.ES2022: case ModuleKind.ESNext: case ModuleKind.Preserve: @@ -52411,23 +90204,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (languageVersion >= ScriptTarget.ES2017) { break; } - // fallthrough + // fallthrough default: diagnostics.add( - createDiagnosticForNode(forInOrOfStatement.awaitModifier, Diagnostics.Top_level_for_await_loops_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_node18_node20_nodenext_or_preserve_and_the_target_option_is_set_to_es2017_or_higher), + createDiagnosticForNode( + forInOrOfStatement.awaitModifier, + Diagnostics.Top_level_for_await_loops_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_node18_node20_nodenext_or_preserve_and_the_target_option_is_set_to_es2017_or_higher + ) ); break; } } - } - else { + } else { // use of 'for-await-of' in non-async function if (!hasParseDiagnostics(sourceFile)) { - const diagnostic = createDiagnosticForNode(forInOrOfStatement.awaitModifier, Diagnostics.for_await_loops_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules); + const diagnostic = createDiagnosticForNode( + forInOrOfStatement.awaitModifier, + Diagnostics.for_await_loops_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules + ); const func = getContainingFunction(forInOrOfStatement); if (func && func.kind !== SyntaxKind.Constructor) { - Debug.assert((getFunctionFlags(func) & FunctionFlags.Async) === 0, "Enclosing function should never be an async function."); - const relatedInfo = createDiagnosticForNode(func, Diagnostics.Did_you_mean_to_mark_this_function_as_async); + Debug.assert( + (getFunctionFlags(func) & + FunctionFlags.Async) === + 0, + "Enclosing function should never be an async function." + ); + const relatedInfo = createDiagnosticForNode( + func, + Diagnostics.Did_you_mean_to_mark_this_function_as_async + ); addRelatedInfo(diagnostic, relatedInfo); } diagnostics.add(diagnostic); @@ -52438,15 +90244,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if ( - isForOfStatement(forInOrOfStatement) && !(forInOrOfStatement.flags & NodeFlags.AwaitContext) && - isIdentifier(forInOrOfStatement.initializer) && forInOrOfStatement.initializer.escapedText === "async" + isForOfStatement(forInOrOfStatement) && + !(forInOrOfStatement.flags & NodeFlags.AwaitContext) && + isIdentifier(forInOrOfStatement.initializer) && + forInOrOfStatement.initializer.escapedText === "async" ) { - grammarErrorOnNode(forInOrOfStatement.initializer, Diagnostics.The_left_hand_side_of_a_for_of_statement_may_not_be_async); + grammarErrorOnNode( + forInOrOfStatement.initializer, + Diagnostics.The_left_hand_side_of_a_for_of_statement_may_not_be_async + ); return false; } - if (forInOrOfStatement.initializer.kind === SyntaxKind.VariableDeclarationList) { - const variableList = forInOrOfStatement.initializer as VariableDeclarationList; + if ( + forInOrOfStatement.initializer.kind === + SyntaxKind.VariableDeclarationList + ) { + const variableList = + forInOrOfStatement.initializer as VariableDeclarationList; if (!checkGrammarVariableDeclarationList(variableList)) { const declarations = variableList.declarations; @@ -52462,23 +90277,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (declarations.length > 1) { - const diagnostic = forInOrOfStatement.kind === SyntaxKind.ForInStatement - ? Diagnostics.Only_a_single_variable_declaration_is_allowed_in_a_for_in_statement - : Diagnostics.Only_a_single_variable_declaration_is_allowed_in_a_for_of_statement; - return grammarErrorOnFirstToken(variableList.declarations[1], diagnostic); + const diagnostic = + forInOrOfStatement.kind === SyntaxKind.ForInStatement + ? Diagnostics.Only_a_single_variable_declaration_is_allowed_in_a_for_in_statement + : Diagnostics.Only_a_single_variable_declaration_is_allowed_in_a_for_of_statement; + return grammarErrorOnFirstToken( + variableList.declarations[1], + diagnostic + ); } const firstDeclaration = declarations[0]; if (firstDeclaration.initializer) { - const diagnostic = forInOrOfStatement.kind === SyntaxKind.ForInStatement - ? Diagnostics.The_variable_declaration_of_a_for_in_statement_cannot_have_an_initializer - : Diagnostics.The_variable_declaration_of_a_for_of_statement_cannot_have_an_initializer; - return grammarErrorOnNode(firstDeclaration.name, diagnostic); + const diagnostic = + forInOrOfStatement.kind === SyntaxKind.ForInStatement + ? Diagnostics.The_variable_declaration_of_a_for_in_statement_cannot_have_an_initializer + : Diagnostics.The_variable_declaration_of_a_for_of_statement_cannot_have_an_initializer; + return grammarErrorOnNode( + firstDeclaration.name, + diagnostic + ); } if (firstDeclaration.type) { - const diagnostic = forInOrOfStatement.kind === SyntaxKind.ForInStatement - ? Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_use_a_type_annotation - : Diagnostics.The_left_hand_side_of_a_for_of_statement_cannot_use_a_type_annotation; + const diagnostic = + forInOrOfStatement.kind === SyntaxKind.ForInStatement + ? Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_use_a_type_annotation + : Diagnostics.The_left_hand_side_of_a_for_of_statement_cannot_use_a_type_annotation; return grammarErrorOnNode(firstDeclaration, diagnostic); } } @@ -52488,46 +90312,92 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkGrammarAccessor(accessor: AccessorDeclaration): boolean { - if (!(accessor.flags & NodeFlags.Ambient) && (accessor.parent.kind !== SyntaxKind.TypeLiteral) && (accessor.parent.kind !== SyntaxKind.InterfaceDeclaration)) { - if (languageVersion < ScriptTarget.ES2015 && isPrivateIdentifier(accessor.name)) { - return grammarErrorOnNode(accessor.name, Diagnostics.Private_identifiers_are_only_available_when_targeting_ECMAScript_2015_and_higher); + if ( + !(accessor.flags & NodeFlags.Ambient) && + accessor.parent.kind !== SyntaxKind.TypeLiteral && + accessor.parent.kind !== SyntaxKind.InterfaceDeclaration + ) { + if ( + languageVersion < ScriptTarget.ES2015 && + isPrivateIdentifier(accessor.name) + ) { + return grammarErrorOnNode( + accessor.name, + Diagnostics.Private_identifiers_are_only_available_when_targeting_ECMAScript_2015_and_higher + ); } - if (accessor.body === undefined && !hasSyntacticModifier(accessor, ModifierFlags.Abstract)) { - return grammarErrorAtPos(accessor, accessor.end - 1, ";".length, Diagnostics._0_expected, "{"); + if ( + accessor.body === undefined && + !hasSyntacticModifier(accessor, ModifierFlags.Abstract) + ) { + return grammarErrorAtPos( + accessor, + accessor.end - 1, + ";".length, + Diagnostics._0_expected, + "{" + ); } } if (accessor.body) { if (hasSyntacticModifier(accessor, ModifierFlags.Abstract)) { - return grammarErrorOnNode(accessor, Diagnostics.An_abstract_accessor_cannot_have_an_implementation); + return grammarErrorOnNode( + accessor, + Diagnostics.An_abstract_accessor_cannot_have_an_implementation + ); } - if (accessor.parent.kind === SyntaxKind.TypeLiteral || accessor.parent.kind === SyntaxKind.InterfaceDeclaration) { - return grammarErrorOnNode(accessor.body, Diagnostics.An_implementation_cannot_be_declared_in_ambient_contexts); + if ( + accessor.parent.kind === SyntaxKind.TypeLiteral || + accessor.parent.kind === SyntaxKind.InterfaceDeclaration + ) { + return grammarErrorOnNode( + accessor.body, + Diagnostics.An_implementation_cannot_be_declared_in_ambient_contexts + ); } } if (accessor.typeParameters) { - return grammarErrorOnNode(accessor.name, Diagnostics.An_accessor_cannot_have_type_parameters); + return grammarErrorOnNode( + accessor.name, + Diagnostics.An_accessor_cannot_have_type_parameters + ); } if (!doesAccessorHaveCorrectParameterCount(accessor)) { return grammarErrorOnNode( accessor.name, - accessor.kind === SyntaxKind.GetAccessor ? - Diagnostics.A_get_accessor_cannot_have_parameters : - Diagnostics.A_set_accessor_must_have_exactly_one_parameter, + accessor.kind === SyntaxKind.GetAccessor + ? Diagnostics.A_get_accessor_cannot_have_parameters + : Diagnostics.A_set_accessor_must_have_exactly_one_parameter ); } if (accessor.kind === SyntaxKind.SetAccessor) { if (accessor.type) { - return grammarErrorOnNode(accessor.name, Diagnostics.A_set_accessor_cannot_have_a_return_type_annotation); + return grammarErrorOnNode( + accessor.name, + Diagnostics.A_set_accessor_cannot_have_a_return_type_annotation + ); } - const parameter = Debug.checkDefined(getSetAccessorValueParameter(accessor), "Return value does not match parameter count assertion."); + const parameter = Debug.checkDefined( + getSetAccessorValueParameter(accessor), + "Return value does not match parameter count assertion." + ); if (parameter.dotDotDotToken) { - return grammarErrorOnNode(parameter.dotDotDotToken, Diagnostics.A_set_accessor_cannot_have_rest_parameter); + return grammarErrorOnNode( + parameter.dotDotDotToken, + Diagnostics.A_set_accessor_cannot_have_rest_parameter + ); } if (parameter.questionToken) { - return grammarErrorOnNode(parameter.questionToken, Diagnostics.A_set_accessor_cannot_have_an_optional_parameter); + return grammarErrorOnNode( + parameter.questionToken, + Diagnostics.A_set_accessor_cannot_have_an_optional_parameter + ); } if (parameter.initializer) { - return grammarErrorOnNode(accessor.name, Diagnostics.A_set_accessor_parameter_cannot_have_an_initializer); + return grammarErrorOnNode( + accessor.name, + Diagnostics.A_set_accessor_parameter_cannot_have_an_initializer + ); } } return false; @@ -52537,12 +90407,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * A get accessor has no parameters or a single `this` parameter. * A set accessor has one parameter or a `this` parameter and one more parameter. */ - function doesAccessorHaveCorrectParameterCount(accessor: AccessorDeclaration) { - return getAccessorThisParameter(accessor) || accessor.parameters.length === (accessor.kind === SyntaxKind.GetAccessor ? 0 : 1); + function doesAccessorHaveCorrectParameterCount( + accessor: AccessorDeclaration + ) { + return ( + getAccessorThisParameter(accessor) || + accessor.parameters.length === + (accessor.kind === SyntaxKind.GetAccessor ? 0 : 1) + ); } - function getAccessorThisParameter(accessor: AccessorDeclaration): ParameterDeclaration | undefined { - if (accessor.parameters.length === (accessor.kind === SyntaxKind.GetAccessor ? 1 : 2)) { + function getAccessorThisParameter( + accessor: AccessorDeclaration + ): ParameterDeclaration | undefined { + if ( + accessor.parameters.length === + (accessor.kind === SyntaxKind.GetAccessor ? 1 : 2) + ) { return getThisParameter(accessor); } } @@ -52550,7 +90431,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkGrammarTypeOperatorNode(node: TypeOperatorNode) { if (node.operator === SyntaxKind.UniqueKeyword) { if (node.type.kind !== SyntaxKind.SymbolKeyword) { - return grammarErrorOnNode(node.type, Diagnostics._0_expected, tokenToString(SyntaxKind.SymbolKeyword)); + return grammarErrorOnNode( + node.type, + Diagnostics._0_expected, + tokenToString(SyntaxKind.SymbolKeyword) + ); } let parent = walkUpParenthesizedTypes(node.parent); if (isInJSFile(parent) && isJSDocTypeExpression(parent)) { @@ -52563,13 +90448,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.VariableDeclaration: const decl = parent as VariableDeclaration; if (decl.name.kind !== SyntaxKind.Identifier) { - return grammarErrorOnNode(node, Diagnostics.unique_symbol_types_may_not_be_used_on_a_variable_declaration_with_a_binding_name); + return grammarErrorOnNode( + node, + Diagnostics.unique_symbol_types_may_not_be_used_on_a_variable_declaration_with_a_binding_name + ); } if (!isVariableDeclarationInVariableStatement(decl)) { - return grammarErrorOnNode(node, Diagnostics.unique_symbol_types_are_only_allowed_on_variables_in_a_variable_statement); + return grammarErrorOnNode( + node, + Diagnostics.unique_symbol_types_are_only_allowed_on_variables_in_a_variable_statement + ); } if (!(decl.parent.flags & NodeFlags.Const)) { - return grammarErrorOnNode((parent as VariableDeclaration).name, Diagnostics.A_variable_whose_type_is_a_unique_symbol_type_must_be_const); + return grammarErrorOnNode( + (parent as VariableDeclaration).name, + Diagnostics.A_variable_whose_type_is_a_unique_symbol_type_must_be_const + ); } break; @@ -52578,30 +90472,55 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { !isStatic(parent) || !hasEffectiveReadonlyModifier(parent) ) { - 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); + 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 + ); } break; case SyntaxKind.PropertySignature: if (!hasSyntacticModifier(parent, ModifierFlags.Readonly)) { - 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); + 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 + ); } break; default: - return grammarErrorOnNode(node, Diagnostics.unique_symbol_types_are_not_allowed_here); + return grammarErrorOnNode( + node, + Diagnostics.unique_symbol_types_are_not_allowed_here + ); } - } - else if (node.operator === SyntaxKind.ReadonlyKeyword) { - if (node.type.kind !== SyntaxKind.ArrayType && node.type.kind !== SyntaxKind.TupleType) { - return grammarErrorOnFirstToken(node, Diagnostics.readonly_type_modifier_is_only_permitted_on_array_and_tuple_literal_types, tokenToString(SyntaxKind.SymbolKeyword)); + } else if (node.operator === SyntaxKind.ReadonlyKeyword) { + if ( + node.type.kind !== SyntaxKind.ArrayType && + node.type.kind !== SyntaxKind.TupleType + ) { + return grammarErrorOnFirstToken( + node, + Diagnostics.readonly_type_modifier_is_only_permitted_on_array_and_tuple_literal_types, + tokenToString(SyntaxKind.SymbolKeyword) + ); } } } - function checkGrammarForInvalidDynamicName(node: DeclarationName, message: DiagnosticMessage) { + function checkGrammarForInvalidDynamicName( + node: DeclarationName, + message: DiagnosticMessage + ) { // Even non-bindable names are allowed as late-bound implied index signatures so long as the name is a simple `a.b.c` type name expression - if (isNonBindableDynamicName(node) && !isEntityNameExpression(isElementAccessExpression(node) ? skipParentheses(node.argumentExpression) : (node as ComputedPropertyName).expression)) { + if ( + isNonBindableDynamicName(node) && + !isEntityNameExpression( + isElementAccessExpression(node) + ? skipParentheses(node.argumentExpression) + : (node as ComputedPropertyName).expression + ) + ) { return grammarErrorOnNode(node, message); } } @@ -52614,17 +90533,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (node.kind === SyntaxKind.MethodDeclaration) { if (node.parent.kind === SyntaxKind.ObjectLiteralExpression) { // We only disallow modifier on a method declaration if it is a property of object-literal-expression - if (node.modifiers && !(node.modifiers.length === 1 && first(node.modifiers).kind === SyntaxKind.AsyncKeyword)) { - return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here); - } - else if (checkGrammarForInvalidQuestionMark(node.questionToken, Diagnostics.An_object_member_cannot_be_declared_optional)) { + if ( + node.modifiers && + !( + node.modifiers.length === 1 && + first(node.modifiers).kind === SyntaxKind.AsyncKeyword + ) + ) { + return grammarErrorOnFirstToken( + node, + Diagnostics.Modifiers_cannot_appear_here + ); + } else if ( + checkGrammarForInvalidQuestionMark( + node.questionToken, + Diagnostics.An_object_member_cannot_be_declared_optional + ) + ) { return true; - } - else if (checkGrammarForInvalidExclamationToken(node.exclamationToken, Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context)) { + } else if ( + checkGrammarForInvalidExclamationToken( + node.exclamationToken, + Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context + ) + ) { return true; - } - else if (node.body === undefined) { - return grammarErrorAtPos(node, node.end - 1, ";".length, Diagnostics._0_expected, "{"); + } else if (node.body === undefined) { + return grammarErrorAtPos( + node, + node.end - 1, + ";".length, + Diagnostics._0_expected, + "{" + ); } } if (checkGrammarForGenerator(node)) { @@ -52633,8 +90574,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (isClassLike(node.parent)) { - if (languageVersion < ScriptTarget.ES2015 && isPrivateIdentifier(node.name)) { - return grammarErrorOnNode(node.name, Diagnostics.Private_identifiers_are_only_available_when_targeting_ECMAScript_2015_and_higher); + if ( + languageVersion < ScriptTarget.ES2015 && + isPrivateIdentifier(node.name) + ) { + return grammarErrorOnNode( + node.name, + Diagnostics.Private_identifiers_are_only_available_when_targeting_ECMAScript_2015_and_higher + ); } // Technically, computed properties in ambient contexts is disallowed // for property declarations and accessors too, not just methods. @@ -52642,50 +90589,87 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // and accessors are not allowed in ambient contexts in general, // so this error only really matters for methods. if (node.flags & NodeFlags.Ambient) { - 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); - } - else if (node.kind === SyntaxKind.MethodDeclaration && !node.body) { - 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); + 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 + ); + } else if ( + node.kind === SyntaxKind.MethodDeclaration && + !node.body + ) { + 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 + ); } - } - else if (node.parent.kind === SyntaxKind.InterfaceDeclaration) { - 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); - } - else if (node.parent.kind === SyntaxKind.TypeLiteral) { - 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); + } else if (node.parent.kind === SyntaxKind.InterfaceDeclaration) { + 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 + ); + } else if (node.parent.kind === SyntaxKind.TypeLiteral) { + 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 + ); } } - function checkGrammarBreakOrContinueStatement(node: BreakOrContinueStatement): boolean { + function checkGrammarBreakOrContinueStatement( + node: BreakOrContinueStatement + ): boolean { let current: Node = node; while (current) { if (isFunctionLikeOrClassStaticBlockDeclaration(current)) { - return grammarErrorOnNode(node, Diagnostics.Jump_target_cannot_cross_function_boundary); + return grammarErrorOnNode( + node, + Diagnostics.Jump_target_cannot_cross_function_boundary + ); } switch (current.kind) { case SyntaxKind.LabeledStatement: - if (node.label && (current as LabeledStatement).label.escapedText === node.label.escapedText) { + if ( + node.label && + (current as LabeledStatement).label.escapedText === + node.label.escapedText + ) { // found matching label - verify that label usage is correct // continue can only target labels that are on iteration statements - const isMisplacedContinueLabel = node.kind === SyntaxKind.ContinueStatement - && !isIterationStatement((current as LabeledStatement).statement, /*lookInLabeledStatements*/ true); + const isMisplacedContinueLabel = + node.kind === SyntaxKind.ContinueStatement && + !isIterationStatement( + (current as LabeledStatement).statement, + /*lookInLabeledStatements*/ true + ); if (isMisplacedContinueLabel) { - return grammarErrorOnNode(node, Diagnostics.A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement); + return grammarErrorOnNode( + node, + Diagnostics.A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement + ); } return false; } break; case SyntaxKind.SwitchStatement: - if (node.kind === SyntaxKind.BreakStatement && !node.label) { + if ( + node.kind === SyntaxKind.BreakStatement && + !node.label + ) { // unlabeled break within switch statement - ok return false; } break; default: - if (isIterationStatement(current, /*lookInLabeledStatements*/ false) && !node.label) { + if ( + isIterationStatement( + current, + /*lookInLabeledStatements*/ false + ) && + !node.label + ) { // unlabeled break or continue within iteration statement - ok return false; } @@ -52696,16 +90680,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (node.label) { - const message = node.kind === SyntaxKind.BreakStatement - ? Diagnostics.A_break_statement_can_only_jump_to_a_label_of_an_enclosing_statement - : Diagnostics.A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement; + const message = + node.kind === SyntaxKind.BreakStatement + ? Diagnostics.A_break_statement_can_only_jump_to_a_label_of_an_enclosing_statement + : Diagnostics.A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement; return grammarErrorOnNode(node, message); - } - else { - const message = node.kind === SyntaxKind.BreakStatement - ? Diagnostics.A_break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement - : Diagnostics.A_continue_statement_can_only_be_used_within_an_enclosing_iteration_statement; + } else { + const message = + node.kind === SyntaxKind.BreakStatement + ? Diagnostics.A_break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement + : Diagnostics.A_continue_statement_can_only_be_used_within_an_enclosing_iteration_statement; return grammarErrorOnNode(node, message); } } @@ -52714,59 +90699,97 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (node.dotDotDotToken) { const elements = node.parent.elements; if (node !== last(elements)) { - return grammarErrorOnNode(node, Diagnostics.A_rest_element_must_be_last_in_a_destructuring_pattern); + return grammarErrorOnNode( + node, + Diagnostics.A_rest_element_must_be_last_in_a_destructuring_pattern + ); } - checkGrammarForDisallowedTrailingComma(elements, Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma); + checkGrammarForDisallowedTrailingComma( + elements, + Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma + ); if (node.propertyName) { - return grammarErrorOnNode(node.name, Diagnostics.A_rest_element_cannot_have_a_property_name); + return grammarErrorOnNode( + node.name, + Diagnostics.A_rest_element_cannot_have_a_property_name + ); } } if (node.dotDotDotToken && node.initializer) { // Error on equals token which immediately precedes the initializer - return grammarErrorAtPos(node, node.initializer.pos - 1, 1, Diagnostics.A_rest_element_cannot_have_an_initializer); + return grammarErrorAtPos( + node, + node.initializer.pos - 1, + 1, + Diagnostics.A_rest_element_cannot_have_an_initializer + ); } } function isStringOrNumberLiteralExpression(expr: Expression) { - return isStringOrNumericLiteralLike(expr) || - expr.kind === SyntaxKind.PrefixUnaryExpression && (expr as PrefixUnaryExpression).operator === SyntaxKind.MinusToken && - (expr as PrefixUnaryExpression).operand.kind === SyntaxKind.NumericLiteral; + return ( + isStringOrNumericLiteralLike(expr) || + (expr.kind === SyntaxKind.PrefixUnaryExpression && + (expr as PrefixUnaryExpression).operator === + SyntaxKind.MinusToken && + (expr as PrefixUnaryExpression).operand.kind === + SyntaxKind.NumericLiteral) + ); } function isBigIntLiteralExpression(expr: Expression) { - return expr.kind === SyntaxKind.BigIntLiteral || - expr.kind === SyntaxKind.PrefixUnaryExpression && (expr as PrefixUnaryExpression).operator === SyntaxKind.MinusToken && - (expr as PrefixUnaryExpression).operand.kind === SyntaxKind.BigIntLiteral; + return ( + expr.kind === SyntaxKind.BigIntLiteral || + (expr.kind === SyntaxKind.PrefixUnaryExpression && + (expr as PrefixUnaryExpression).operator === + SyntaxKind.MinusToken && + (expr as PrefixUnaryExpression).operand.kind === + SyntaxKind.BigIntLiteral) + ); } function isSimpleLiteralEnumReference(expr: Expression) { if ( - (isPropertyAccessExpression(expr) || (isElementAccessExpression(expr) && isStringOrNumberLiteralExpression(expr.argumentExpression))) && + (isPropertyAccessExpression(expr) || + (isElementAccessExpression(expr) && + isStringOrNumberLiteralExpression( + expr.argumentExpression + ))) && isEntityNameExpression(expr.expression) ) { return !!(checkExpressionCached(expr).flags & TypeFlags.EnumLike); } } - function checkAmbientInitializer(node: VariableDeclaration | PropertyDeclaration | PropertySignature) { + function checkAmbientInitializer( + node: VariableDeclaration | PropertyDeclaration | PropertySignature + ) { const initializer = node.initializer; if (initializer) { const isInvalidInitializer = !( isStringOrNumberLiteralExpression(initializer) || isSimpleLiteralEnumReference(initializer) || - initializer.kind === SyntaxKind.TrueKeyword || initializer.kind === SyntaxKind.FalseKeyword || + initializer.kind === SyntaxKind.TrueKeyword || + initializer.kind === SyntaxKind.FalseKeyword || isBigIntLiteralExpression(initializer) ); - const isConstOrReadonly = isDeclarationReadonly(node) || isVariableDeclaration(node) && (isVarConstLike(node)); + const isConstOrReadonly = + isDeclarationReadonly(node) || + (isVariableDeclaration(node) && isVarConstLike(node)); if (isConstOrReadonly && !node.type) { if (isInvalidInitializer) { - return grammarErrorOnNode(initializer, Diagnostics.A_const_initializer_in_an_ambient_context_must_be_a_string_or_numeric_literal_or_literal_enum_reference); + return grammarErrorOnNode( + initializer, + Diagnostics.A_const_initializer_in_an_ambient_context_must_be_a_string_or_numeric_literal_or_literal_enum_reference + ); } - } - else { - return grammarErrorOnNode(initializer, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts); + } else { + return grammarErrorOnNode( + initializer, + Diagnostics.Initializers_are_not_allowed_in_ambient_contexts + ); } } } @@ -52777,32 +90800,66 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isBindingPattern(node.name)) { switch (blockScopeKind) { case NodeFlags.AwaitUsing: - return grammarErrorOnNode(node, Diagnostics._0_declarations_may_not_have_binding_patterns, "await using"); + return grammarErrorOnNode( + node, + Diagnostics._0_declarations_may_not_have_binding_patterns, + "await using" + ); case NodeFlags.Using: - return grammarErrorOnNode(node, Diagnostics._0_declarations_may_not_have_binding_patterns, "using"); + return grammarErrorOnNode( + node, + Diagnostics._0_declarations_may_not_have_binding_patterns, + "using" + ); } } - if (node.parent.parent.kind !== SyntaxKind.ForInStatement && node.parent.parent.kind !== SyntaxKind.ForOfStatement) { + if ( + node.parent.parent.kind !== SyntaxKind.ForInStatement && + node.parent.parent.kind !== SyntaxKind.ForOfStatement + ) { if (nodeFlags & NodeFlags.Ambient) { checkAmbientInitializer(node); - } - else if (!node.initializer) { - if (isBindingPattern(node.name) && !isBindingPattern(node.parent)) { - return grammarErrorOnNode(node, Diagnostics.A_destructuring_declaration_must_have_an_initializer); + } else if (!node.initializer) { + if ( + isBindingPattern(node.name) && + !isBindingPattern(node.parent) + ) { + return grammarErrorOnNode( + node, + Diagnostics.A_destructuring_declaration_must_have_an_initializer + ); } switch (blockScopeKind) { case NodeFlags.AwaitUsing: - return grammarErrorOnNode(node, Diagnostics._0_declarations_must_be_initialized, "await using"); + return grammarErrorOnNode( + node, + Diagnostics._0_declarations_must_be_initialized, + "await using" + ); case NodeFlags.Using: - return grammarErrorOnNode(node, Diagnostics._0_declarations_must_be_initialized, "using"); + return grammarErrorOnNode( + node, + Diagnostics._0_declarations_must_be_initialized, + "using" + ); case NodeFlags.Const: - return grammarErrorOnNode(node, Diagnostics._0_declarations_must_be_initialized, "const"); + return grammarErrorOnNode( + node, + Diagnostics._0_declarations_must_be_initialized, + "const" + ); } } } - if (node.exclamationToken && (node.parent.parent.kind !== SyntaxKind.VariableStatement || !node.type || node.initializer || nodeFlags & NodeFlags.Ambient)) { + if ( + node.exclamationToken && + (node.parent.parent.kind !== SyntaxKind.VariableStatement || + !node.type || + node.initializer || + nodeFlags & NodeFlags.Ambient) + ) { const message = node.initializer ? Diagnostics.Declarations_with_initializers_cannot_also_have_definite_assignment_assertions : !node.type @@ -52812,8 +90869,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if ( - host.getEmitModuleFormatOfFile(getSourceFileOfNode(node)) < ModuleKind.System && - !(node.parent.parent.flags & NodeFlags.Ambient) && hasSyntacticModifier(node.parent.parent, ModifierFlags.Export) + host.getEmitModuleFormatOfFile(getSourceFileOfNode(node)) < + ModuleKind.System && + !(node.parent.parent.flags & NodeFlags.Ambient) && + hasSyntacticModifier(node.parent.parent, ModifierFlags.Export) ) { checkESModuleMarker(node.name); } @@ -52825,16 +90884,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // It is a SyntaxError if a VariableDeclaration or VariableDeclarationNoIn occurs within strict code // and its Identifier is eval or arguments - return !!blockScopeKind && checkGrammarNameInLetOrConstDeclarations(node.name); + return ( + !!blockScopeKind && + checkGrammarNameInLetOrConstDeclarations(node.name) + ); } function checkESModuleMarker(name: Identifier | BindingPattern): boolean { if (name.kind === SyntaxKind.Identifier) { if (idText(name) === "__esModule") { - return grammarErrorOnNodeSkippedOn("noEmit", name, Diagnostics.Identifier_expected_esModule_is_reserved_as_an_exported_marker_when_transforming_ECMAScript_modules); + return grammarErrorOnNodeSkippedOn( + "noEmit", + name, + Diagnostics.Identifier_expected_esModule_is_reserved_as_an_exported_marker_when_transforming_ECMAScript_modules + ); } - } - else { + } else { const elements = name.elements; for (const element of elements) { if (!isOmittedExpression(element)) { @@ -52845,13 +90910,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function checkGrammarNameInLetOrConstDeclarations(name: Identifier | BindingPattern): boolean { + function checkGrammarNameInLetOrConstDeclarations( + name: Identifier | BindingPattern + ): boolean { if (name.kind === SyntaxKind.Identifier) { if (name.escapedText === "let") { - return grammarErrorOnNode(name, Diagnostics.let_is_not_allowed_to_be_used_as_a_name_in_let_or_const_declarations); + return grammarErrorOnNode( + name, + Diagnostics.let_is_not_allowed_to_be_used_as_a_name_in_let_or_const_declarations + ); } - } - else { + } else { const elements = name.elements; for (const element of elements) { if (!isOmittedExpression(element)) { @@ -52862,33 +90931,45 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function checkGrammarVariableDeclarationList(declarationList: VariableDeclarationList): boolean { + function checkGrammarVariableDeclarationList( + declarationList: VariableDeclarationList + ): boolean { const declarations = declarationList.declarations; - if (checkGrammarForDisallowedTrailingComma(declarationList.declarations)) { + if ( + checkGrammarForDisallowedTrailingComma(declarationList.declarations) + ) { return true; } if (!declarationList.declarations.length) { - return grammarErrorAtPos(declarationList, declarations.pos, declarations.end - declarations.pos, Diagnostics.Variable_declaration_list_cannot_be_empty); + return grammarErrorAtPos( + declarationList, + declarations.pos, + declarations.end - declarations.pos, + Diagnostics.Variable_declaration_list_cannot_be_empty + ); } const blockScopeFlags = declarationList.flags & NodeFlags.BlockScoped; - if (blockScopeFlags === NodeFlags.Using || blockScopeFlags === NodeFlags.AwaitUsing) { + if ( + blockScopeFlags === NodeFlags.Using || + blockScopeFlags === NodeFlags.AwaitUsing + ) { if (isForInStatement(declarationList.parent)) { return grammarErrorOnNode( declarationList, - blockScopeFlags === NodeFlags.Using ? - Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_a_using_declaration : - Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_an_await_using_declaration, + blockScopeFlags === NodeFlags.Using + ? Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_a_using_declaration + : Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_an_await_using_declaration ); } if (declarationList.flags & NodeFlags.Ambient) { return grammarErrorOnNode( declarationList, - blockScopeFlags === NodeFlags.Using ? - Diagnostics.using_declarations_are_not_allowed_in_ambient_contexts : - Diagnostics.await_using_declarations_are_not_allowed_in_ambient_contexts, + blockScopeFlags === NodeFlags.Using + ? Diagnostics.using_declarations_are_not_allowed_in_ambient_contexts + : Diagnostics.await_using_declarations_are_not_allowed_in_ambient_contexts ); } @@ -52917,16 +90998,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; } - function checkGrammarForDisallowedBlockScopedVariableStatement(node: VariableStatement) { + function checkGrammarForDisallowedBlockScopedVariableStatement( + node: VariableStatement + ) { if (!allowBlockDeclarations(node.parent)) { - const blockScopeKind = getCombinedNodeFlagsCached(node.declarationList) & NodeFlags.BlockScoped; + const blockScopeKind = + getCombinedNodeFlagsCached(node.declarationList) & + NodeFlags.BlockScoped; if (blockScopeKind) { - const keyword = blockScopeKind === NodeFlags.Let ? "let" : - blockScopeKind === NodeFlags.Const ? "const" : - blockScopeKind === NodeFlags.Using ? "using" : - blockScopeKind === NodeFlags.AwaitUsing ? "await using" : - Debug.fail("Unknown BlockScope flag"); - error(node, Diagnostics._0_declarations_can_only_be_declared_inside_a_block, keyword); + const keyword = + blockScopeKind === NodeFlags.Let + ? "let" + : blockScopeKind === NodeFlags.Const + ? "const" + : blockScopeKind === NodeFlags.Using + ? "using" + : blockScopeKind === NodeFlags.AwaitUsing + ? "await using" + : Debug.fail("Unknown BlockScope flag"); + error( + node, + Diagnostics._0_declarations_can_only_be_declared_inside_a_block, + keyword + ); } } } @@ -52936,22 +91030,47 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { switch (node.keywordToken) { case SyntaxKind.NewKeyword: if (escapedText !== "target") { - return grammarErrorOnNode(node.name, Diagnostics._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, unescapeLeadingUnderscores(node.name.escapedText), tokenToString(node.keywordToken), "target"); + return grammarErrorOnNode( + node.name, + Diagnostics._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, + unescapeLeadingUnderscores(node.name.escapedText), + tokenToString(node.keywordToken), + "target" + ); } break; case SyntaxKind.ImportKeyword: if (escapedText !== "meta") { - const isCallee = isCallExpression(node.parent) && node.parent.expression === node; + const isCallee = + isCallExpression(node.parent) && + node.parent.expression === node; if (escapedText === "defer") { if (!isCallee) { - return grammarErrorAtPos(node, node.end, 0, Diagnostics._0_expected, "("); + return grammarErrorAtPos( + node, + node.end, + 0, + Diagnostics._0_expected, + "(" + ); } - } - else { + } else { if (isCallee) { - return grammarErrorOnNode(node.name, Diagnostics._0_is_not_a_valid_meta_property_for_keyword_import_Did_you_mean_meta_or_defer, unescapeLeadingUnderscores(node.name.escapedText)); + return grammarErrorOnNode( + node.name, + Diagnostics._0_is_not_a_valid_meta_property_for_keyword_import_Did_you_mean_meta_or_defer, + unescapeLeadingUnderscores( + node.name.escapedText + ) + ); } - return grammarErrorOnNode(node.name, Diagnostics._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, unescapeLeadingUnderscores(node.name.escapedText), tokenToString(node.keywordToken), "meta"); + return grammarErrorOnNode( + node.name, + Diagnostics._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, + unescapeLeadingUnderscores(node.name.escapedText), + tokenToString(node.keywordToken), + "meta" + ); } } break; @@ -52962,26 +91081,57 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return sourceFile.parseDiagnostics.length > 0; } - function grammarErrorOnFirstToken(node: Node, message: DiagnosticMessage, ...args: DiagnosticArguments): boolean { + function grammarErrorOnFirstToken( + node: Node, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ): boolean { const sourceFile = getSourceFileOfNode(node); if (!hasParseDiagnostics(sourceFile)) { const span = getSpanOfTokenAtPosition(sourceFile, node.pos); - diagnostics.add(createFileDiagnostic(sourceFile, span.start, span.length, message, ...args)); + diagnostics.add( + createFileDiagnostic( + sourceFile, + span.start, + span.length, + message, + ...args + ) + ); return true; } return false; } - function grammarErrorAtPos(nodeForSourceFile: Node, start: number, length: number, message: DiagnosticMessage, ...args: DiagnosticArguments): boolean { + function grammarErrorAtPos( + nodeForSourceFile: Node, + start: number, + length: number, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ): boolean { const sourceFile = getSourceFileOfNode(nodeForSourceFile); if (!hasParseDiagnostics(sourceFile)) { - diagnostics.add(createFileDiagnostic(sourceFile, start, length, message, ...args)); + diagnostics.add( + createFileDiagnostic( + sourceFile, + start, + length, + message, + ...args + ) + ); return true; } return false; } - function grammarErrorOnNodeSkippedOn(key: keyof CompilerOptions, node: Node, message: DiagnosticMessage, ...args: DiagnosticArguments): boolean { + function grammarErrorOnNodeSkippedOn( + key: keyof CompilerOptions, + node: Node, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ): boolean { const sourceFile = getSourceFileOfNode(node); if (!hasParseDiagnostics(sourceFile)) { errorSkippedOn(key, node, message, ...args); @@ -52990,7 +91140,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function grammarErrorOnNode(node: Node, message: DiagnosticMessage, ...args: DiagnosticArguments): boolean { + function grammarErrorOnNode( + node: Node, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ): boolean { const sourceFile = getSourceFileOfNode(node); if (!hasParseDiagnostics(sourceFile)) { error(node, message, ...args); @@ -52999,62 +91153,133 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function checkGrammarConstructorTypeParameters(node: ConstructorDeclaration) { - const jsdocTypeParameters = isInJSFile(node) ? getJSDocTypeParameterDeclarations(node) : undefined; - const range = node.typeParameters || jsdocTypeParameters && firstOrUndefined(jsdocTypeParameters); + function checkGrammarConstructorTypeParameters( + node: ConstructorDeclaration + ) { + const jsdocTypeParameters = isInJSFile(node) + ? getJSDocTypeParameterDeclarations(node) + : undefined; + const range = + node.typeParameters || + (jsdocTypeParameters && firstOrUndefined(jsdocTypeParameters)); if (range) { - const pos = range.pos === range.end ? range.pos : skipTrivia(getSourceFileOfNode(node).text, range.pos); - return grammarErrorAtPos(node, pos, range.end - pos, Diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration); + const pos = + range.pos === range.end + ? range.pos + : skipTrivia(getSourceFileOfNode(node).text, range.pos); + return grammarErrorAtPos( + node, + pos, + range.end - pos, + Diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration + ); } } - function checkGrammarConstructorTypeAnnotation(node: ConstructorDeclaration) { + function checkGrammarConstructorTypeAnnotation( + node: ConstructorDeclaration + ) { const type = node.type || getEffectiveReturnTypeNode(node); if (type) { - return grammarErrorOnNode(type, Diagnostics.Type_annotation_cannot_appear_on_a_constructor_declaration); + return grammarErrorOnNode( + type, + Diagnostics.Type_annotation_cannot_appear_on_a_constructor_declaration + ); } } - function checkGrammarProperty(node: PropertyDeclaration | PropertySignature) { - if (isComputedPropertyName(node.name) && isBinaryExpression(node.name.expression) && node.name.expression.operatorToken.kind === SyntaxKind.InKeyword) { - return grammarErrorOnNode(node.parent.members[0], Diagnostics.A_mapped_type_may_not_declare_properties_or_methods); + function checkGrammarProperty( + node: PropertyDeclaration | PropertySignature + ) { + if ( + isComputedPropertyName(node.name) && + isBinaryExpression(node.name.expression) && + node.name.expression.operatorToken.kind === SyntaxKind.InKeyword + ) { + return grammarErrorOnNode( + node.parent.members[0], + Diagnostics.A_mapped_type_may_not_declare_properties_or_methods + ); } if (isClassLike(node.parent)) { - if (isStringLiteral(node.name) && node.name.text === "constructor") { - return grammarErrorOnNode(node.name, Diagnostics.Classes_may_not_have_a_field_named_constructor); + if ( + isStringLiteral(node.name) && + node.name.text === "constructor" + ) { + return grammarErrorOnNode( + node.name, + Diagnostics.Classes_may_not_have_a_field_named_constructor + ); } - 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)) { + 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 + ) + ) { return true; } - if (languageVersion < ScriptTarget.ES2015 && isPrivateIdentifier(node.name)) { - return grammarErrorOnNode(node.name, Diagnostics.Private_identifiers_are_only_available_when_targeting_ECMAScript_2015_and_higher); + if ( + languageVersion < ScriptTarget.ES2015 && + isPrivateIdentifier(node.name) + ) { + return grammarErrorOnNode( + node.name, + Diagnostics.Private_identifiers_are_only_available_when_targeting_ECMAScript_2015_and_higher + ); } - if (languageVersion < ScriptTarget.ES2015 && isAutoAccessorPropertyDeclaration(node)) { - return grammarErrorOnNode(node.name, Diagnostics.Properties_with_the_accessor_modifier_are_only_available_when_targeting_ECMAScript_2015_and_higher); + if ( + languageVersion < ScriptTarget.ES2015 && + isAutoAccessorPropertyDeclaration(node) + ) { + return grammarErrorOnNode( + node.name, + Diagnostics.Properties_with_the_accessor_modifier_are_only_available_when_targeting_ECMAScript_2015_and_higher + ); } - if (isAutoAccessorPropertyDeclaration(node) && checkGrammarForInvalidQuestionMark(node.questionToken, Diagnostics.An_accessor_property_cannot_be_declared_optional)) { + if ( + isAutoAccessorPropertyDeclaration(node) && + checkGrammarForInvalidQuestionMark( + node.questionToken, + Diagnostics.An_accessor_property_cannot_be_declared_optional + ) + ) { return true; } - } - else if (node.parent.kind === SyntaxKind.InterfaceDeclaration) { - 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)) { + } else if (node.parent.kind === SyntaxKind.InterfaceDeclaration) { + 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 + ) + ) { return true; } // Interfaces cannot contain property declarations Debug.assertNode(node, isPropertySignature); if (node.initializer) { - return grammarErrorOnNode(node.initializer, Diagnostics.An_interface_property_cannot_have_an_initializer); + return grammarErrorOnNode( + node.initializer, + Diagnostics.An_interface_property_cannot_have_an_initializer + ); } - } - else if (isTypeLiteralNode(node.parent)) { - 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)) { + } else if (isTypeLiteralNode(node.parent)) { + 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 + ) + ) { return true; } // Type literals cannot contain property declarations Debug.assertNode(node, isPropertySignature); if (node.initializer) { - return grammarErrorOnNode(node.initializer, Diagnostics.A_type_literal_property_cannot_have_an_initializer); + return grammarErrorOnNode( + node.initializer, + Diagnostics.A_type_literal_property_cannot_have_an_initializer + ); } } @@ -53063,8 +91288,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if ( - isPropertyDeclaration(node) && node.exclamationToken && (!isClassLike(node.parent) || !node.type || node.initializer || - node.flags & NodeFlags.Ambient || isStatic(node) || hasAbstractModifier(node)) + isPropertyDeclaration(node) && + node.exclamationToken && + (!isClassLike(node.parent) || + !node.type || + node.initializer || + node.flags & NodeFlags.Ambient || + isStatic(node) || + hasAbstractModifier(node)) ) { const message = node.initializer ? Diagnostics.Declarations_with_initializers_cannot_also_have_definite_assignment_assertions @@ -53075,7 +91306,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function checkGrammarTopLevelElementForRequiredDeclareModifier(node: Node): boolean { + function checkGrammarTopLevelElementForRequiredDeclareModifier( + node: Node + ): boolean { // A declare modifier is required for any top level .d.ts declaration except export=, export default, export as namespace // interfaces and imports categories: // @@ -53096,18 +91329,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { node.kind === SyntaxKind.ExportDeclaration || node.kind === SyntaxKind.ExportAssignment || node.kind === SyntaxKind.NamespaceExportDeclaration || - hasSyntacticModifier(node, ModifierFlags.Ambient | ModifierFlags.Export | ModifierFlags.Default) + hasSyntacticModifier( + node, + ModifierFlags.Ambient | + ModifierFlags.Export | + ModifierFlags.Default + ) ) { return false; } - return grammarErrorOnFirstToken(node, Diagnostics.Top_level_declarations_in_d_ts_files_must_start_with_either_a_declare_or_export_modifier); + return grammarErrorOnFirstToken( + node, + Diagnostics.Top_level_declarations_in_d_ts_files_must_start_with_either_a_declare_or_export_modifier + ); } - function checkGrammarTopLevelElementsForRequiredDeclareModifier(file: SourceFile): boolean { + function checkGrammarTopLevelElementsForRequiredDeclareModifier( + file: SourceFile + ): boolean { for (const decl of file.statements) { - if (isDeclaration(decl) || decl.kind === SyntaxKind.VariableStatement) { - if (checkGrammarTopLevelElementForRequiredDeclareModifier(decl)) { + if ( + isDeclaration(decl) || + decl.kind === SyntaxKind.VariableStatement + ) { + if ( + checkGrammarTopLevelElementForRequiredDeclareModifier(decl) + ) { return true; } } @@ -53116,15 +91364,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkGrammarSourceFile(node: SourceFile): boolean { - return !!(node.flags & NodeFlags.Ambient) && checkGrammarTopLevelElementsForRequiredDeclareModifier(node); + return ( + !!(node.flags & NodeFlags.Ambient) && + checkGrammarTopLevelElementsForRequiredDeclareModifier(node) + ); } function checkGrammarStatementInAmbientContext(node: Node): boolean { if (node.flags & NodeFlags.Ambient) { // Find containing block which is either Block, ModuleBlock, SourceFile const links = getNodeLinks(node); - if (!links.hasReportedStatementInAmbientContext && (isFunctionLike(node.parent) || isAccessor(node.parent))) { - return getNodeLinks(node).hasReportedStatementInAmbientContext = grammarErrorOnFirstToken(node, Diagnostics.An_implementation_cannot_be_declared_in_ambient_contexts); + if ( + !links.hasReportedStatementInAmbientContext && + (isFunctionLike(node.parent) || isAccessor(node.parent)) + ) { + return (getNodeLinks( + node + ).hasReportedStatementInAmbientContext = + grammarErrorOnFirstToken( + node, + Diagnostics.An_implementation_cannot_be_declared_in_ambient_contexts + )); } // We are either parented by another statement, or some sort of block. @@ -53132,14 +91392,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // to prevent noisiness. So use a bit on the block to indicate if // this has already been reported, and don't report if it has. // - if (node.parent.kind === SyntaxKind.Block || node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) { + if ( + node.parent.kind === SyntaxKind.Block || + node.parent.kind === SyntaxKind.ModuleBlock || + node.parent.kind === SyntaxKind.SourceFile + ) { const links = getNodeLinks(node.parent); // Check if the containing block ever report this error if (!links.hasReportedStatementInAmbientContext) { - return links.hasReportedStatementInAmbientContext = grammarErrorOnFirstToken(node, Diagnostics.Statements_are_not_allowed_in_ambient_contexts); + return (links.hasReportedStatementInAmbientContext = + grammarErrorOnFirstToken( + node, + Diagnostics.Statements_are_not_allowed_in_ambient_contexts + )); } - } - else { + } else { // We must be parented by a statement. If so, there's no need // to report the error as our parent will have already done it. // Debug.assert(isStatement(node.parent)); @@ -53171,15 +91438,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return; } - 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)); + 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 + ) + ); } function checkGrammarBigIntLiteral(node: BigIntLiteral): boolean { - const literalType = isLiteralTypeNode(node.parent) || - isPrefixUnaryExpression(node.parent) && isLiteralTypeNode(node.parent.parent); + const literalType = + isLiteralTypeNode(node.parent) || + (isPrefixUnaryExpression(node.parent) && + isLiteralTypeNode(node.parent.parent)); if (!literalType) { if (languageVersion < ScriptTarget.ES2020) { - if (grammarErrorOnNode(node, Diagnostics.BigInt_literals_are_not_available_when_targeting_lower_than_ES2020)) { + if ( + grammarErrorOnNode( + node, + Diagnostics.BigInt_literals_are_not_available_when_targeting_lower_than_ES2020 + ) + ) { return true; } } @@ -53187,11 +91467,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function grammarErrorAfterFirstToken(node: Node, message: DiagnosticMessage, ...args: DiagnosticArguments): boolean { + function grammarErrorAfterFirstToken( + node: Node, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ): boolean { const sourceFile = getSourceFileOfNode(node); if (!hasParseDiagnostics(sourceFile)) { const span = getSpanOfTokenAtPosition(sourceFile, node.pos); - diagnostics.add(createFileDiagnostic(sourceFile, textSpanEnd(span), /*length*/ 0, message, ...args)); + diagnostics.add( + createFileDiagnostic( + sourceFile, + textSpanEnd(span), + /*length*/ 0, + message, + ...args + ) + ); return true; } return false; @@ -53213,92 +91505,159 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkGrammarImportClause(node: ImportClause): boolean { if (node.phaseModifier === SyntaxKind.TypeKeyword) { if (node.name && node.namedBindings) { - return grammarErrorOnNode(node, Diagnostics.A_type_only_import_can_specify_a_default_import_or_named_bindings_but_not_both); + return grammarErrorOnNode( + node, + Diagnostics.A_type_only_import_can_specify_a_default_import_or_named_bindings_but_not_both + ); } if (node.namedBindings?.kind === SyntaxKind.NamedImports) { return checkGrammarNamedImportsOrExports(node.namedBindings); } - } - else if (node.phaseModifier === SyntaxKind.DeferKeyword) { + } else if (node.phaseModifier === SyntaxKind.DeferKeyword) { if (node.name) { - return grammarErrorOnNode(node, Diagnostics.Default_imports_are_not_allowed_in_a_deferred_import); + return grammarErrorOnNode( + node, + Diagnostics.Default_imports_are_not_allowed_in_a_deferred_import + ); } if (node.namedBindings?.kind === SyntaxKind.NamedImports) { - return grammarErrorOnNode(node, Diagnostics.Named_imports_are_not_allowed_in_a_deferred_import); + return grammarErrorOnNode( + node, + Diagnostics.Named_imports_are_not_allowed_in_a_deferred_import + ); } - if (moduleKind !== ModuleKind.ESNext && moduleKind !== ModuleKind.Preserve) { - return grammarErrorOnNode(node, Diagnostics.Deferred_imports_are_only_supported_when_the_module_flag_is_set_to_esnext_or_preserve); + if ( + moduleKind !== ModuleKind.ESNext && + moduleKind !== ModuleKind.Preserve + ) { + return grammarErrorOnNode( + node, + Diagnostics.Deferred_imports_are_only_supported_when_the_module_flag_is_set_to_esnext_or_preserve + ); } } return false; } - function checkGrammarNamedImportsOrExports(namedBindings: NamedImportsOrExports): boolean { - return !!forEach(namedBindings.elements, specifier => { - if (specifier.isTypeOnly) { - return grammarErrorOnFirstToken( - specifier, - specifier.kind === SyntaxKind.ImportSpecifier - ? Diagnostics.The_type_modifier_cannot_be_used_on_a_named_import_when_import_type_is_used_on_its_import_statement - : Diagnostics.The_type_modifier_cannot_be_used_on_a_named_export_when_export_type_is_used_on_its_export_statement, - ); + function checkGrammarNamedImportsOrExports( + namedBindings: NamedImportsOrExports + ): boolean { + return !!forEach( + namedBindings.elements, + (specifier) => { + if (specifier.isTypeOnly) { + return grammarErrorOnFirstToken( + specifier, + specifier.kind === SyntaxKind.ImportSpecifier + ? Diagnostics.The_type_modifier_cannot_be_used_on_a_named_import_when_import_type_is_used_on_its_import_statement + : Diagnostics.The_type_modifier_cannot_be_used_on_a_named_export_when_export_type_is_used_on_its_export_statement + ); + } } - }); + ); } function checkGrammarImportCallExpression(node: ImportCall): boolean { - if (compilerOptions.verbatimModuleSyntax && moduleKind === ModuleKind.CommonJS) { - return grammarErrorOnNode(node, Diagnostics.ESM_syntax_is_not_allowed_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled); + if ( + compilerOptions.verbatimModuleSyntax && + moduleKind === ModuleKind.CommonJS + ) { + return grammarErrorOnNode( + node, + Diagnostics.ESM_syntax_is_not_allowed_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled + ); } if (node.expression.kind === SyntaxKind.MetaProperty) { - if (moduleKind !== ModuleKind.ESNext && moduleKind !== ModuleKind.Preserve) { - return grammarErrorOnNode(node, Diagnostics.Deferred_imports_are_only_supported_when_the_module_flag_is_set_to_esnext_or_preserve); + if ( + moduleKind !== ModuleKind.ESNext && + moduleKind !== ModuleKind.Preserve + ) { + return grammarErrorOnNode( + node, + Diagnostics.Deferred_imports_are_only_supported_when_the_module_flag_is_set_to_esnext_or_preserve + ); } - } - else if (moduleKind === ModuleKind.ES2015) { - return grammarErrorOnNode(node, Diagnostics.Dynamic_imports_are_only_supported_when_the_module_flag_is_set_to_es2020_es2022_esnext_commonjs_amd_system_umd_node16_node18_node20_or_nodenext); + } else if (moduleKind === ModuleKind.ES2015) { + return grammarErrorOnNode( + node, + Diagnostics.Dynamic_imports_are_only_supported_when_the_module_flag_is_set_to_es2020_es2022_esnext_commonjs_amd_system_umd_node16_node18_node20_or_nodenext + ); } if (node.typeArguments) { - 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); + 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 + ); } const nodeArguments = node.arguments; - if (!(ModuleKind.Node16 <= moduleKind && moduleKind <= ModuleKind.NodeNext) && moduleKind !== ModuleKind.ESNext && moduleKind !== ModuleKind.Preserve) { + if ( + !( + ModuleKind.Node16 <= moduleKind && + moduleKind <= ModuleKind.NodeNext + ) && + moduleKind !== ModuleKind.ESNext && + moduleKind !== ModuleKind.Preserve + ) { // We are allowed trailing comma after proposal-import-assertions. checkGrammarForDisallowedTrailingComma(nodeArguments); if (nodeArguments.length > 1) { const importAttributesArgument = nodeArguments[1]; - return grammarErrorOnNode(importAttributesArgument, Diagnostics.Dynamic_imports_only_support_a_second_argument_when_the_module_option_is_set_to_esnext_node16_node18_node20_nodenext_or_preserve); + return grammarErrorOnNode( + importAttributesArgument, + Diagnostics.Dynamic_imports_only_support_a_second_argument_when_the_module_option_is_set_to_esnext_node16_node18_node20_nodenext_or_preserve + ); } } if (nodeArguments.length === 0 || nodeArguments.length > 2) { - return grammarErrorOnNode(node, Diagnostics.Dynamic_imports_can_only_accept_a_module_specifier_and_an_optional_set_of_attributes_as_arguments); + return grammarErrorOnNode( + node, + Diagnostics.Dynamic_imports_can_only_accept_a_module_specifier_and_an_optional_set_of_attributes_as_arguments + ); } // see: parseArgumentOrArrayLiteralElement...we use this function which parse arguments of callExpression to parse specifier for dynamic import. // parseArgumentOrArrayLiteralElement allows spread element to be in an argument list which is not allowed as specifier in dynamic import. const spreadElement = find(nodeArguments, isSpreadElement); if (spreadElement) { - return grammarErrorOnNode(spreadElement, Diagnostics.Argument_of_dynamic_import_cannot_be_spread_element); + return grammarErrorOnNode( + spreadElement, + Diagnostics.Argument_of_dynamic_import_cannot_be_spread_element + ); } return false; } - function findMatchingTypeReferenceOrTypeAliasReference(source: Type, unionTarget: UnionOrIntersectionType) { + function findMatchingTypeReferenceOrTypeAliasReference( + source: Type, + unionTarget: UnionOrIntersectionType + ) { const sourceObjectFlags = getObjectFlags(source); - if (sourceObjectFlags & (ObjectFlags.Reference | ObjectFlags.Anonymous) && unionTarget.flags & TypeFlags.Union) { - return find(unionTarget.types, target => { + if ( + sourceObjectFlags & + (ObjectFlags.Reference | ObjectFlags.Anonymous) && + unionTarget.flags & TypeFlags.Union + ) { + return find(unionTarget.types, (target) => { if (target.flags & TypeFlags.Object) { - const overlapObjFlags = sourceObjectFlags & getObjectFlags(target); + const overlapObjFlags = + sourceObjectFlags & getObjectFlags(target); if (overlapObjFlags & ObjectFlags.Reference) { - return (source as TypeReference).target === (target as TypeReference).target; + return ( + (source as TypeReference).target === + (target as TypeReference).target + ); } if (overlapObjFlags & ObjectFlags.Anonymous) { - return !!(source as AnonymousType).aliasSymbol && (source as AnonymousType).aliasSymbol === (target as AnonymousType).aliasSymbol; + return ( + !!(source as AnonymousType).aliasSymbol && + (source as AnonymousType).aliasSymbol === + (target as AnonymousType).aliasSymbol + ); } } return false; @@ -53306,37 +91665,75 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function findBestTypeForObjectLiteral(source: Type, unionTarget: UnionOrIntersectionType) { - if (getObjectFlags(source) & ObjectFlags.ObjectLiteral && someType(unionTarget, isArrayLikeType)) { - return find(unionTarget.types, t => !isArrayLikeType(t)); + function findBestTypeForObjectLiteral( + source: Type, + unionTarget: UnionOrIntersectionType + ) { + if ( + getObjectFlags(source) & ObjectFlags.ObjectLiteral && + someType(unionTarget, isArrayLikeType) + ) { + return find(unionTarget.types, (t) => !isArrayLikeType(t)); } } - function findBestTypeForInvokable(source: Type, unionTarget: UnionOrIntersectionType) { + function findBestTypeForInvokable( + source: Type, + unionTarget: UnionOrIntersectionType + ) { let signatureKind = SignatureKind.Call; - const hasSignatures = getSignaturesOfType(source, signatureKind).length > 0 || - (signatureKind = SignatureKind.Construct, getSignaturesOfType(source, signatureKind).length > 0); + const hasSignatures = + getSignaturesOfType(source, signatureKind).length > 0 || + ((signatureKind = SignatureKind.Construct), + getSignaturesOfType(source, signatureKind).length > 0); if (hasSignatures) { - return find(unionTarget.types, t => getSignaturesOfType(t, signatureKind).length > 0); + return find( + unionTarget.types, + (t) => getSignaturesOfType(t, signatureKind).length > 0 + ); } } - function findMostOverlappyType(source: Type, unionTarget: UnionOrIntersectionType) { + function findMostOverlappyType( + source: Type, + unionTarget: UnionOrIntersectionType + ) { let bestMatch: Type | undefined; - if (!(source.flags & (TypeFlags.Primitive | TypeFlags.InstantiablePrimitive))) { + if ( + !( + source.flags & + (TypeFlags.Primitive | TypeFlags.InstantiablePrimitive) + ) + ) { let matchingCount = 0; for (const target of unionTarget.types) { - if (!(target.flags & (TypeFlags.Primitive | TypeFlags.InstantiablePrimitive))) { - const overlap = getIntersectionType([getIndexType(source), getIndexType(target)]); + if ( + !( + target.flags & + (TypeFlags.Primitive | TypeFlags.InstantiablePrimitive) + ) + ) { + const overlap = getIntersectionType([ + getIndexType(source), + getIndexType(target), + ]); if (overlap.flags & TypeFlags.Index) { // perfect overlap of keys return target; - } - else if (isUnitType(overlap) || overlap.flags & TypeFlags.Union) { + } else if ( + isUnitType(overlap) || + overlap.flags & TypeFlags.Union + ) { // We only want to account for literal types otherwise. // If we have a union of index types, it seems likely that we // needed to elaborate between two generic mapped types anyway. - const len = overlap.flags & TypeFlags.Union ? countWhere((overlap as UnionType).types, isUnitType) : 1; + const len = + overlap.flags & TypeFlags.Union + ? countWhere( + (overlap as UnionType).types, + isUnitType + ) + : 1; if (len >= matchingCount) { bestMatch = target; matchingCount = len; @@ -53350,7 +91747,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function filterPrimitivesIfContainsNonPrimitive(type: UnionType) { if (maybeTypeOfKind(type, TypeFlags.NonPrimitive)) { - const result = filterType(type, t => !(t.flags & TypeFlags.Primitive)); + const result = filterType( + type, + (t) => !(t.flags & TypeFlags.Primitive) + ); if (!(result.flags & TypeFlags.Never)) { return result; } @@ -53359,17 +91759,41 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Keep this up-to-date with the same logic within `getApparentTypeOfContextualType`, since they should behave similarly - function findMatchingDiscriminantType(source: Type, target: Type, isRelatedTo: (source: Type, target: Type) => Ternary) { - if (target.flags & TypeFlags.Union && source.flags & (TypeFlags.Intersection | TypeFlags.Object)) { - const match = getMatchingUnionConstituentForType(target as UnionType, source); + function findMatchingDiscriminantType( + source: Type, + target: Type, + isRelatedTo: (source: Type, target: Type) => Ternary + ) { + if ( + target.flags & TypeFlags.Union && + source.flags & (TypeFlags.Intersection | TypeFlags.Object) + ) { + const match = getMatchingUnionConstituentForType( + target as UnionType, + source + ); if (match) { return match; } const sourceProperties = getPropertiesOfType(source); if (sourceProperties) { - const sourcePropertiesFiltered = findDiscriminantProperties(sourceProperties, target); + const sourcePropertiesFiltered = findDiscriminantProperties( + sourceProperties, + target + ); if (sourcePropertiesFiltered) { - const discriminated = discriminateTypeByDiscriminableItems(target as UnionType, map(sourcePropertiesFiltered, p => ([() => getTypeOfSymbol(p), p.escapedName] as [() => Type, __String])), isRelatedTo); + const discriminated = discriminateTypeByDiscriminableItems( + target as UnionType, + map( + sourcePropertiesFiltered, + (p) => + [() => getTypeOfSymbol(p), p.escapedName] as [ + () => Type, + __String + ] + ), + isRelatedTo + ); if (discriminated !== target) { return discriminated; } @@ -53381,8 +91805,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getEffectivePropertyNameForPropertyNameNode(node: PropertyName) { const name = getPropertyNameForPropertyNameNode(node); - return name ? name : - isComputedPropertyName(node) ? tryGetNameFromType(getTypeOfExpression(node.expression)) : undefined; + return name + ? name + : isComputedPropertyName(node) + ? tryGetNameFromType(getTypeOfExpression(node.expression)) + : undefined; } function getCombinedModifierFlagsCached(node: Declaration) { @@ -53406,27 +91833,47 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return lastGetCombinedNodeFlagsResult; } - function isVarConstLike(node: VariableDeclaration | VariableDeclarationList) { - const blockScopeKind = getCombinedNodeFlagsCached(node) & NodeFlags.BlockScoped; - return blockScopeKind === NodeFlags.Const || + function isVarConstLike( + node: VariableDeclaration | VariableDeclarationList + ) { + const blockScopeKind = + getCombinedNodeFlagsCached(node) & NodeFlags.BlockScoped; + return ( + blockScopeKind === NodeFlags.Const || blockScopeKind === NodeFlags.Using || - blockScopeKind === NodeFlags.AwaitUsing; + blockScopeKind === NodeFlags.AwaitUsing + ); } - function getJSXRuntimeImportSpecifier(file: SourceFile | undefined, specifierText: string) { + function getJSXRuntimeImportSpecifier( + file: SourceFile | undefined, + specifierText: string + ) { // Synthesized JSX import is either first or after tslib const jsxImportIndex = compilerOptions.importHelpers ? 1 : 0; const specifier = file?.imports[jsxImportIndex]; if (specifier) { - Debug.assert(nodeIsSynthesized(specifier) && specifier.text === specifierText, `Expected sourceFile.imports[${jsxImportIndex}] to be the synthesized JSX runtime import`); + Debug.assert( + nodeIsSynthesized(specifier) && + specifier.text === specifierText, + `Expected sourceFile.imports[${jsxImportIndex}] to be the synthesized JSX runtime import` + ); } return specifier; } function getImportHelpersImportSpecifier(file: SourceFile) { - Debug.assert(compilerOptions.importHelpers, "Expected importHelpers to be enabled"); + Debug.assert( + compilerOptions.importHelpers, + "Expected importHelpers to be enabled" + ); const specifier = file.imports[0]; - Debug.assert(specifier && nodeIsSynthesized(specifier) && specifier.text === "tslib", `Expected sourceFile.imports[0] to be the synthesized tslib import`); + Debug.assert( + specifier && + nodeIsSynthesized(specifier) && + specifier.text === "tslib", + `Expected sourceFile.imports[0] to be the synthesized tslib import` + ); return specifier; } } @@ -53437,8 +91884,11 @@ function isNotAccessor(declaration: Declaration): boolean { } function isNotOverload(declaration: Declaration): boolean { - return (declaration.kind !== SyntaxKind.FunctionDeclaration && declaration.kind !== SyntaxKind.MethodDeclaration) || - !!(declaration as FunctionDeclaration).body; + return ( + (declaration.kind !== SyntaxKind.FunctionDeclaration && + declaration.kind !== SyntaxKind.MethodDeclaration) || + !!(declaration as FunctionDeclaration).body + ); } /** Like 'isDeclarationName', but returns true for LHS of `import { x as y }` or `export { x as y }`. */ @@ -53456,20 +91906,26 @@ namespace JsxNames { export const JSX = "JSX" as __String; export const IntrinsicElements = "IntrinsicElements" as __String; export const ElementClass = "ElementClass" as __String; - export const ElementAttributesPropertyNameContainer = "ElementAttributesProperty" as __String; // TODO: Deprecate and remove support - export const ElementChildrenAttributeNameContainer = "ElementChildrenAttribute" as __String; + export const ElementAttributesPropertyNameContainer = + "ElementAttributesProperty" as __String; // TODO: Deprecate and remove support + export const ElementChildrenAttributeNameContainer = + "ElementChildrenAttribute" as __String; export const Element = "Element" as __String; export const ElementType = "ElementType" as __String; export const IntrinsicAttributes = "IntrinsicAttributes" as __String; - export const IntrinsicClassAttributes = "IntrinsicClassAttributes" as __String; - export const LibraryManagedAttributes = "LibraryManagedAttributes" as __String; + export const IntrinsicClassAttributes = + "IntrinsicClassAttributes" as __String; + export const LibraryManagedAttributes = + "LibraryManagedAttributes" as __String; } namespace ReactNames { export const Fragment = "Fragment" as __String; } -function getIterationTypesKeyFromIterationTypeKind(typeKind: IterationTypeKind) { +function getIterationTypesKeyFromIterationTypeKind( + typeKind: IterationTypeKind +) { switch (typeKind) { case IterationTypeKind.Yield: return "yieldType"; @@ -53489,22 +91945,35 @@ function signatureHasLiteralTypes(s: Signature) { return !!(s.flags & SignatureFlags.HasLiteralTypes); } -function createBasicNodeBuilderModuleSpecifierResolutionHost(host: TypeCheckerHost): ModuleSpecifierResolutionHost { +function createBasicNodeBuilderModuleSpecifierResolutionHost( + host: TypeCheckerHost +): ModuleSpecifierResolutionHost { return { - getCommonSourceDirectory: !!(host as Program).getCommonSourceDirectory ? () => (host as Program).getCommonSourceDirectory() : () => "", + getCommonSourceDirectory: !!(host as Program).getCommonSourceDirectory + ? () => (host as Program).getCommonSourceDirectory() + : () => "", getCurrentDirectory: () => host.getCurrentDirectory(), getSymlinkCache: maybeBind(host, host.getSymlinkCache), getPackageJsonInfoCache: () => host.getPackageJsonInfoCache?.(), useCaseSensitiveFileNames: () => host.useCaseSensitiveFileNames(), redirectTargetsMap: host.redirectTargetsMap, - getRedirectFromSourceFile: fileName => host.getRedirectFromSourceFile(fileName), - isSourceOfProjectReferenceRedirect: fileName => host.isSourceOfProjectReferenceRedirect(fileName), - fileExists: fileName => host.fileExists(fileName), + getRedirectFromSourceFile: (fileName) => + host.getRedirectFromSourceFile(fileName), + isSourceOfProjectReferenceRedirect: (fileName) => + host.isSourceOfProjectReferenceRedirect(fileName), + fileExists: (fileName) => host.fileExists(fileName), getFileIncludeReasons: () => host.getFileIncludeReasons(), - readFile: host.readFile ? (fileName => host.readFile!(fileName)) : undefined, - getDefaultResolutionModeForFile: file => host.getDefaultResolutionModeForFile(file), - getModeForResolutionAtIndex: (file, index) => host.getModeForResolutionAtIndex(file, index), - getGlobalTypingsCacheLocation: maybeBind(host, host.getGlobalTypingsCacheLocation), + readFile: host.readFile + ? (fileName) => host.readFile!(fileName) + : undefined, + getDefaultResolutionModeForFile: (file) => + host.getDefaultResolutionModeForFile(file), + getModeForResolutionAtIndex: (file, index) => + host.getModeForResolutionAtIndex(file, index), + getGlobalTypingsCacheLocation: maybeBind( + host, + host.getGlobalTypingsCacheLocation + ), }; } @@ -53559,14 +92028,26 @@ interface NodeBuilderContext extends SyntacticTypeNodeBuilderContext { } class SymbolTrackerImpl implements SymbolTracker { - moduleResolverHost: ModuleSpecifierResolutionHost & { getCommonSourceDirectory(): string; } | undefined = undefined; + moduleResolverHost: + | (ModuleSpecifierResolutionHost & { + getCommonSourceDirectory(): string; + }) + | undefined = undefined; context: NodeBuilderContext; readonly inner: SymbolTracker | undefined = undefined; readonly canTrackSymbol: boolean; disableTrackSymbol = false; - constructor(context: NodeBuilderContext, tracker: SymbolTracker | undefined, moduleResolverHost: ModuleSpecifierResolutionHost & { getCommonSourceDirectory(): string; } | undefined) { + constructor( + context: NodeBuilderContext, + tracker: SymbolTracker | undefined, + moduleResolverHost: + | (ModuleSpecifierResolutionHost & { + getCommonSourceDirectory(): string; + }) + | undefined + ) { while (tracker instanceof SymbolTrackerImpl) { tracker = tracker.inner; } @@ -53577,14 +92058,23 @@ class SymbolTrackerImpl implements SymbolTracker { this.canTrackSymbol = !!this.inner?.trackSymbol; } - trackSymbol(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags): boolean { + trackSymbol( + symbol: Symbol, + enclosingDeclaration: Node | undefined, + meaning: SymbolFlags + ): boolean { if (this.inner?.trackSymbol && !this.disableTrackSymbol) { if (this.inner.trackSymbol(symbol, enclosingDeclaration, meaning)) { this.onDiagnosticReported(); return true; } // Skip recording type parameters as they dont contribute to late painted statements - if (!(symbol.flags & SymbolFlags.TypeParameter)) (this.context.trackedSymbols ??= []).push([symbol, enclosingDeclaration, meaning]); + if (!(symbol.flags & SymbolFlags.TypeParameter)) + (this.context.trackedSymbols ??= []).push([ + symbol, + enclosingDeclaration, + meaning, + ]); } return false; } @@ -53631,10 +92121,18 @@ class SymbolTrackerImpl implements SymbolTracker { } } - reportNonlocalAugmentation(containingFile: SourceFile, parentSymbol: Symbol, augmentingSymbol: Symbol): void { + reportNonlocalAugmentation( + containingFile: SourceFile, + parentSymbol: Symbol, + augmentingSymbol: Symbol + ): void { if (this.inner?.reportNonlocalAugmentation) { this.onDiagnosticReported(); - this.inner.reportNonlocalAugmentation(containingFile, parentSymbol, augmentingSymbol); + this.inner.reportNonlocalAugmentation( + containingFile, + parentSymbol, + augmentingSymbol + ); } } @@ -53650,7 +92148,10 @@ class SymbolTrackerImpl implements SymbolTracker { } reportInferenceFallback(node: Node): void { - if (this.inner?.reportInferenceFallback && !this.context.suppressReportInferenceFallback) { + if ( + this.inner?.reportInferenceFallback && + !this.context.suppressReportInferenceFallback + ) { this.onDiagnosticReported(); this.inner.reportInferenceFallback(node); } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 91ecc9f7f0b5e..267a8c1291a7a 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -8511,5 +8511,9 @@ "'{0}' is not a valid meta-property for keyword 'import'. Did you mean 'meta' or 'defer'?": { "category": "Error", "code": 18061 + }, + "Enum member keys should not use computed strings like ['A']. Use a string literal instead for clarity and compatibility.": { + "category": "Suggestion", + "code": 18062 } } diff --git a/tests/baselines/reference/enumComputedStringSuggestion.js b/tests/baselines/reference/enumComputedStringSuggestion.js new file mode 100644 index 0000000000000..f29ddfc54a00c --- /dev/null +++ b/tests/baselines/reference/enumComputedStringSuggestion.js @@ -0,0 +1,13 @@ +//// [tests/cases/compiler/enumComputedStringSuggestion.ts] //// + +//// [enumComputedStringSuggestion.ts] +enum Test { + ["Hello"] = 1, +} + + +//// [enumComputedStringSuggestion.js] +var Test; +(function (Test) { + Test[Test["Hello"] = 1] = "Hello"; +})(Test || (Test = {})); diff --git a/tests/baselines/reference/enumComputedStringSuggestion.symbols b/tests/baselines/reference/enumComputedStringSuggestion.symbols new file mode 100644 index 0000000000000..40fd54c094ad7 --- /dev/null +++ b/tests/baselines/reference/enumComputedStringSuggestion.symbols @@ -0,0 +1,11 @@ +//// [tests/cases/compiler/enumComputedStringSuggestion.ts] //// + +=== enumComputedStringSuggestion.ts === +enum Test { +>Test : Symbol(Test, Decl(enumComputedStringSuggestion.ts, 0, 0)) + + ["Hello"] = 1, +>["Hello"] : Symbol(Test["Hello"], Decl(enumComputedStringSuggestion.ts, 0, 11)) +>"Hello" : Symbol(Test["Hello"], Decl(enumComputedStringSuggestion.ts, 0, 11)) +} + diff --git a/tests/baselines/reference/enumComputedStringSuggestion.types b/tests/baselines/reference/enumComputedStringSuggestion.types new file mode 100644 index 0000000000000..89ab93732e08d --- /dev/null +++ b/tests/baselines/reference/enumComputedStringSuggestion.types @@ -0,0 +1,16 @@ +//// [tests/cases/compiler/enumComputedStringSuggestion.ts] //// + +=== enumComputedStringSuggestion.ts === +enum Test { +>Test : Test +> : ^^^^ + + ["Hello"] = 1, +>["Hello"] : Test.Hello +> : ^^^^^^^^^^ +>"Hello" : "Hello" +> : ^^^^^^^ +>1 : 1 +> : ^ +} + diff --git a/tests/cases/compiler/enumComputedStringSuggestion.ts b/tests/cases/compiler/enumComputedStringSuggestion.ts new file mode 100644 index 0000000000000..f4a895d1cbd24 --- /dev/null +++ b/tests/cases/compiler/enumComputedStringSuggestion.ts @@ -0,0 +1,3 @@ +enum Test { + ["Hello"] = 1, +}