mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-15 03:23:08 -06:00
Cache accessibe symbol chains and serialized type parameter name generation (#43973)
* Cache accessibe symbol chains, type parameter name generation * Move signature declaration helper length approximation to start of function * Add node result caching internal to `typeToTypeNodeHelper` * Suggestion from PR
This commit is contained in:
parent
0454ae4720
commit
f7a97b7759
@ -3935,12 +3935,12 @@ namespace ts {
|
||||
return typeCopy;
|
||||
}
|
||||
|
||||
function forEachSymbolTableInScope<T>(enclosingDeclaration: Node | undefined, callback: (symbolTable: SymbolTable, ignoreQualification?: boolean, isLocalNameLookup?: boolean) => T): T {
|
||||
function forEachSymbolTableInScope<T>(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) {
|
||||
// Locals of a source file are not in scope (because they get merged into the global symbol table)
|
||||
if (location.locals && !isGlobalSourceFile(location)) {
|
||||
if (result = callback(location.locals, /*ignoreQualification*/ undefined, /*isLocalNameLookup*/ true)) {
|
||||
if (result = callback(location.locals, /*ignoreQualification*/ undefined, /*isLocalNameLookup*/ true, location)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -3955,7 +3955,7 @@ namespace ts {
|
||||
// `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)) {
|
||||
if (result = callback(sym?.exports || emptySymbols, /*ignoreQualification*/ undefined, /*isLocalNameLookup*/ true, location)) {
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
@ -3976,7 +3976,7 @@ namespace ts {
|
||||
(table || (table = createSymbolTable())).set(key, memberSymbol);
|
||||
}
|
||||
});
|
||||
if (table && (result = callback(table))) {
|
||||
if (table && (result = callback(table, /*ignoreQualification*/ undefined, /*isLocalNameLookup*/ false, location))) {
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
@ -3995,13 +3995,23 @@ namespace ts {
|
||||
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)}|${meaning}`;
|
||||
if (cache.has(key)) {
|
||||
return cache.get(key);
|
||||
}
|
||||
|
||||
const id = getSymbolId(symbol);
|
||||
let visitedSymbolTables = visitedSymbolTablesMap.get(id);
|
||||
if (!visitedSymbolTables) {
|
||||
visitedSymbolTablesMap.set(id, visitedSymbolTables = []);
|
||||
}
|
||||
return 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)
|
||||
@ -4479,7 +4489,7 @@ namespace ts {
|
||||
enclosingDeclaration,
|
||||
flags: flags || NodeBuilderFlags.None,
|
||||
// If no full tracker is provided, fake up a dummy one with a basic limited-functionality moduleResolverHost
|
||||
tracker: tracker && tracker.trackSymbol ? tracker : { trackSymbol: noop, moduleResolverHost: flags! & NodeBuilderFlags.DoNotIncludeSymbolChain ? {
|
||||
tracker: tracker && tracker.trackSymbol ? tracker : { trackSymbol: () => false, moduleResolverHost: flags! & NodeBuilderFlags.DoNotIncludeSymbolChain ? {
|
||||
getCommonSourceDirectory: !!(host as Program).getCommonSourceDirectory ? () => (host as Program).getCommonSourceDirectory() : () => "",
|
||||
getSourceFiles: () => host.getSourceFiles(),
|
||||
getCurrentDirectory: () => host.getCurrentDirectory(),
|
||||
@ -4492,11 +4502,13 @@ namespace ts {
|
||||
getFileIncludeReasons: () => host.getFileIncludeReasons(),
|
||||
} : undefined },
|
||||
encounteredError: false,
|
||||
reportedDiagnostic: false,
|
||||
visitedTypes: undefined,
|
||||
symbolDepth: undefined,
|
||||
inferTypeParameters: undefined,
|
||||
approximateLength: 0
|
||||
};
|
||||
context.tracker = wrapSymbolTrackerToReportForContext(context, context.tracker);
|
||||
const resultingNode = cb(context);
|
||||
if (context.truncating && context.flags & NodeBuilderFlags.NoTruncation) {
|
||||
context.tracker?.reportTruncationError?.();
|
||||
@ -4504,6 +4516,36 @@ namespace ts {
|
||||
return context.encounteredError ? undefined : resultingNode;
|
||||
}
|
||||
|
||||
function wrapSymbolTrackerToReportForContext(context: NodeBuilderContext, tracker: SymbolTracker): SymbolTracker {
|
||||
const oldTrackSymbol = tracker.trackSymbol;
|
||||
return {
|
||||
...tracker,
|
||||
reportCyclicStructureError: wrapReportedDiagnostic(tracker.reportCyclicStructureError),
|
||||
reportInaccessibleThisError: wrapReportedDiagnostic(tracker.reportInaccessibleThisError),
|
||||
reportInaccessibleUniqueSymbolError: wrapReportedDiagnostic(tracker.reportInaccessibleUniqueSymbolError),
|
||||
reportLikelyUnsafeImportRequiredError: wrapReportedDiagnostic(tracker.reportLikelyUnsafeImportRequiredError),
|
||||
reportNonlocalAugmentation: wrapReportedDiagnostic(tracker.reportNonlocalAugmentation),
|
||||
reportPrivateInBaseOfClassExpression: wrapReportedDiagnostic(tracker.reportPrivateInBaseOfClassExpression),
|
||||
trackSymbol: oldTrackSymbol && ((...args) => {
|
||||
const result = oldTrackSymbol(...args);
|
||||
if (result) {
|
||||
context.reportedDiagnostic = true;
|
||||
}
|
||||
return result;
|
||||
}),
|
||||
};
|
||||
|
||||
function wrapReportedDiagnostic<T extends (...args: any[]) => any>(method: T | undefined): T | undefined {
|
||||
if (!method) {
|
||||
return method;
|
||||
}
|
||||
return (((...args) => {
|
||||
context.reportedDiagnostic = true;
|
||||
return method(...args);
|
||||
}) as T);
|
||||
}
|
||||
}
|
||||
|
||||
function checkTruncationLength(context: NodeBuilderContext): boolean {
|
||||
if (context.truncating) return context.truncating;
|
||||
return context.truncating = context.approximateLength > ((context.flags & NodeBuilderFlags.NoTruncation) ? noTruncationMaximumTruncationLength : defaultMaximumTruncationLength);
|
||||
@ -4830,7 +4872,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function visitAndTransformType<T>(type: Type, transform: (type: Type) => T) {
|
||||
function visitAndTransformType<T extends TypeNode>(type: Type, transform: (type: Type) => T) {
|
||||
const typeId = type.id;
|
||||
const isConstructorObject = getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & SymbolFlags.Class;
|
||||
const id = getObjectFlags(type) & ObjectFlags.Reference && (<TypeReference>type).node ? "N" + getNodeId((<TypeReference>type).node!) :
|
||||
@ -4845,6 +4887,20 @@ namespace ts {
|
||||
context.symbolDepth = new Map();
|
||||
}
|
||||
|
||||
const links = context.enclosingDeclaration && getNodeLinks(context.enclosingDeclaration);
|
||||
const key = `${getTypeId(type)}|${context.flags}`;
|
||||
if (links) {
|
||||
links.serializedTypes ||= new Map();
|
||||
}
|
||||
const cachedResult = links?.serializedTypes?.get(key);
|
||||
if (cachedResult) {
|
||||
if (cachedResult.truncating) {
|
||||
context.truncating = true;
|
||||
}
|
||||
context.approximateLength += cachedResult.addedLength;
|
||||
return deepCloneOrReuseNode(cachedResult) as TypeNode as T;
|
||||
}
|
||||
|
||||
let depth: number | undefined;
|
||||
if (id) {
|
||||
depth = context.symbolDepth!.get(id) || 0;
|
||||
@ -4854,12 +4910,28 @@ namespace ts {
|
||||
context.symbolDepth!.set(id, depth + 1);
|
||||
}
|
||||
context.visitedTypes.add(typeId);
|
||||
const startLength = context.approximateLength;
|
||||
const result = transform(type);
|
||||
const addedLength = context.approximateLength - startLength;
|
||||
if (!context.reportedDiagnostic && !context.encounteredError) {
|
||||
if (context.truncating) {
|
||||
(result as any).truncating = true;
|
||||
}
|
||||
(result as any).addedLength = addedLength;
|
||||
links?.serializedTypes?.set(key, result as TypeNode as TypeNode & {truncating?: boolean, addedLength: number});
|
||||
}
|
||||
context.visitedTypes.delete(typeId);
|
||||
if (id) {
|
||||
context.symbolDepth!.set(id, depth!);
|
||||
}
|
||||
return result;
|
||||
|
||||
function deepCloneOrReuseNode(node: Node): Node {
|
||||
if (!nodeIsSynthesized(node) && getParseTreeNode(node) === node) {
|
||||
return node;
|
||||
}
|
||||
return setTextRange(factory.cloneNode(visitEachChild(node, deepCloneOrReuseNode, nullTransformationContext)), node);
|
||||
}
|
||||
}
|
||||
|
||||
function createTypeNodeFromObjectType(type: ObjectType): TypeNode {
|
||||
@ -5346,6 +5418,7 @@ namespace ts {
|
||||
function signatureToSignatureDeclarationHelper(signature: Signature, kind: SignatureDeclaration["kind"], context: NodeBuilderContext, options?: SignatureToSignatureDeclarationOptions): SignatureDeclaration {
|
||||
const suppressAny = context.flags & NodeBuilderFlags.SuppressAnyReturnType;
|
||||
if (suppressAny) context.flags &= ~NodeBuilderFlags.SuppressAnyReturnType; // suppress only toplevel `any`s
|
||||
context.approximateLength += 3; // Usually a signature contributes a few more characters than this, but 3 is the minimum
|
||||
let typeParameters: TypeParameterDeclaration[] | undefined;
|
||||
let typeArguments: TypeNode[] | undefined;
|
||||
if (context.flags & NodeBuilderFlags.WriteTypeArgumentsOfSignature && signature.target && signature.mapper && signature.target.typeParameters) {
|
||||
@ -5389,7 +5462,6 @@ namespace ts {
|
||||
const flags = modifiersToFlags(modifiers);
|
||||
modifiers = factory.createModifiersFromModifierFlags(flags | ModifierFlags.Abstract);
|
||||
}
|
||||
context.approximateLength += 3; // Usually a signature contributes a few more characters than this, but 3 is the minimum
|
||||
|
||||
const node =
|
||||
kind === SyntaxKind.CallSignature ? factory.createCallSignature(typeParameters, parameters, returnTypeNode) :
|
||||
@ -5816,7 +5888,7 @@ namespace ts {
|
||||
}
|
||||
if (context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams) {
|
||||
const rawtext = result.escapedText as string;
|
||||
let i = 0;
|
||||
let i = context.typeParameterNamesByTextNextNameCount?.get(rawtext) || 0;
|
||||
let text = rawtext;
|
||||
while (context.typeParameterNamesByText?.has(text) || typeParameterShadowsNameInScope(text as __String, context, type)) {
|
||||
i++;
|
||||
@ -5825,8 +5897,11 @@ namespace ts {
|
||||
if (text !== rawtext) {
|
||||
result = factory.createIdentifier(text, result.typeArguments);
|
||||
}
|
||||
(context.typeParameterNames || (context.typeParameterNames = new Map())).set(getTypeId(type), result);
|
||||
(context.typeParameterNamesByText || (context.typeParameterNamesByText = new Set())).add(result.escapedText as string);
|
||||
// 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
|
||||
(context.typeParameterNamesByTextNextNameCount ||= new Map()).set(rawtext, i);
|
||||
(context.typeParameterNames ||= new Map()).set(getTypeId(type), result);
|
||||
(context.typeParameterNamesByText ||= new Set()).add(rawtext);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -5987,6 +6062,7 @@ namespace ts {
|
||||
if (initial.typeParameterSymbolList) {
|
||||
initial.typeParameterSymbolList = new Set(initial.typeParameterSymbolList);
|
||||
}
|
||||
initial.tracker = wrapSymbolTrackerToReportForContext(initial, initial.tracker);
|
||||
return initial;
|
||||
}
|
||||
|
||||
@ -6278,11 +6354,13 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
else if (oldcontext.tracker && oldcontext.tracker.trackSymbol) {
|
||||
oldcontext.tracker.trackSymbol(sym, decl, meaning);
|
||||
return oldcontext.tracker.trackSymbol(sym, decl, meaning);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
},
|
||||
};
|
||||
context.tracker = wrapSymbolTrackerToReportForContext(context, context.tracker);
|
||||
forEachEntry(symbolTable, (symbol, name) => {
|
||||
const baseName = unescapeLeadingUnderscores(name);
|
||||
void getInternalSymbolName(symbol, baseName); // Called to cache values into `usedSymbolNames` and `remappedSymbolNames`
|
||||
@ -6502,6 +6580,9 @@ namespace ts {
|
||||
const oldContext = context;
|
||||
context = cloneNodeBuilderContext(context);
|
||||
const result = serializeSymbolWorker(symbol, isPrivate, propertyAsAlias);
|
||||
if (context.reportedDiagnostic) {
|
||||
oldcontext.reportedDiagnostic = context.reportedDiagnostic; // hoist diagnostic result into outer context
|
||||
}
|
||||
context = oldContext;
|
||||
return result;
|
||||
}
|
||||
@ -7275,7 +7356,7 @@ namespace ts {
|
||||
// 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 oldTrack = context.tracker.trackSymbol;
|
||||
context.tracker.trackSymbol = noop;
|
||||
context.tracker.trackSymbol = () => false;
|
||||
if (isExportAssignmentCompatibleSymbolName) {
|
||||
results.push(factory.createExportAssignment(
|
||||
/*decorators*/ undefined,
|
||||
@ -7731,6 +7812,7 @@ namespace ts {
|
||||
|
||||
// State
|
||||
encounteredError: boolean;
|
||||
reportedDiagnostic: boolean;
|
||||
visitedTypes: Set<number> | undefined;
|
||||
symbolDepth: ESMap<string, number> | undefined;
|
||||
inferTypeParameters: TypeParameter[] | undefined;
|
||||
@ -7739,6 +7821,7 @@ namespace ts {
|
||||
typeParameterSymbolList?: Set<number>;
|
||||
typeParameterNames?: ESMap<TypeId, Identifier>;
|
||||
typeParameterNamesByText?: Set<string>;
|
||||
typeParameterNamesByTextNextNameCount?: ESMap<string, number>;
|
||||
usedSymbolNames?: Set<string>;
|
||||
remappedSymbolNames?: ESMap<SymbolId, string>;
|
||||
reverseMappedStack?: ReverseMappedSymbol[];
|
||||
|
||||
@ -145,8 +145,10 @@ namespace ts {
|
||||
symbolAccessibilityResult.errorSymbolName,
|
||||
symbolAccessibilityResult.errorModuleName));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function trackExternalModuleSymbolOfImportTypeNode(symbol: Symbol) {
|
||||
@ -156,9 +158,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
function trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) {
|
||||
if (symbol.flags & SymbolFlags.TypeParameter) return;
|
||||
handleSymbolAccessibilityError(resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning, /*shouldComputeAliasesToMakeVisible*/ true));
|
||||
if (symbol.flags & SymbolFlags.TypeParameter) return false;
|
||||
const issuedDiagnostic = handleSymbolAccessibilityError(resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning, /*shouldComputeAliasesToMakeVisible*/ true));
|
||||
recordTypeReferenceDirectivesIfNecessary(resolver.getTypeReferenceDirectivesForSymbol(symbol, meaning));
|
||||
return issuedDiagnostic;
|
||||
}
|
||||
|
||||
function reportPrivateInBaseOfClassExpression(propertyName: string) {
|
||||
|
||||
@ -4831,6 +4831,7 @@ namespace ts {
|
||||
typeOnlyDeclaration?: TypeOnlyCompatibleAliasDeclaration | false; // First resolved alias declaration that makes the symbol only usable in type constructs
|
||||
isConstructorDeclaredProperty?: boolean; // Property declared through 'this.x = ...' assignment in constructor
|
||||
tupleLabelDeclaration?: NamedTupleMember | ParameterDeclaration; // Declaration associated with the tuple's label
|
||||
accessibleChainCache?: ESMap<string, Symbol[] | undefined>;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@ -4986,6 +4987,7 @@ namespace ts {
|
||||
isExhaustive?: boolean; // Is node an exhaustive switch statement
|
||||
skipDirectInference?: true; // Flag set by the API `getContextualType` call on a node when `Completions` is passed to force the checker to skip making inferences to a node's type
|
||||
declarationRequiresScopeChange?: boolean; // Set by `useOuterVariableScopeInParameter` in checker when downlevel emit would change the name resolution scope inside of a parameter.
|
||||
serializedTypes?: ESMap<string, TypeNode & {truncating?: boolean, addedLength: number}>; // Collection of types serialized at this location
|
||||
}
|
||||
|
||||
export const enum TypeFlags {
|
||||
@ -8118,7 +8120,7 @@ namespace ts {
|
||||
// Called when the symbol writer encounters a symbol to write. Currently only used by the
|
||||
// declaration emitter to help determine if it should patch up the final declaration file
|
||||
// with import statements it previously saw (but chose not to emit).
|
||||
trackSymbol?(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags): void;
|
||||
trackSymbol?(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags): boolean;
|
||||
reportInaccessibleThisError?(): void;
|
||||
reportPrivateInBaseOfClassExpression?(propertyName: string): void;
|
||||
reportInaccessibleUniqueSymbolError?(): void;
|
||||
|
||||
@ -83,7 +83,7 @@ namespace ts {
|
||||
increaseIndent: noop,
|
||||
decreaseIndent: noop,
|
||||
clear: () => str = "",
|
||||
trackSymbol: noop,
|
||||
trackSymbol: () => false,
|
||||
reportInaccessibleThisError: noop,
|
||||
reportInaccessibleUniqueSymbolError: noop,
|
||||
reportPrivateInBaseOfClassExpression: noop,
|
||||
@ -4029,7 +4029,7 @@ namespace ts {
|
||||
reportInaccessibleThisError: noop,
|
||||
reportPrivateInBaseOfClassExpression: noop,
|
||||
reportInaccessibleUniqueSymbolError: noop,
|
||||
trackSymbol: noop,
|
||||
trackSymbol: () => false,
|
||||
writeKeyword: write,
|
||||
writeOperator: write,
|
||||
writeParameter: write,
|
||||
|
||||
@ -254,7 +254,11 @@ namespace compiler {
|
||||
if (compilerOptions.skipDefaultLibCheck === undefined) compilerOptions.skipDefaultLibCheck = true;
|
||||
if (compilerOptions.noErrorTruncation === undefined) compilerOptions.noErrorTruncation = true;
|
||||
|
||||
const preProgram = ts.length(rootFiles) < 100 ? ts.createProgram(rootFiles || [], { ...compilerOptions, configFile: compilerOptions.configFile, traceResolution: false }, host) : undefined;
|
||||
// pre-emit/post-emit error comparison requires declaration emit twice, which can be slow. If it's unlikely to flag any error consistency issues
|
||||
// and if the test is running `skipLibCheck` - an indicator that we want the tets to run quickly - skip the before/after error comparison, too
|
||||
const skipErrorComparison = ts.length(rootFiles) >= 100 || (!!compilerOptions.skipLibCheck && !!compilerOptions.declaration);
|
||||
|
||||
const preProgram = !skipErrorComparison ? ts.createProgram(rootFiles || [], { ...compilerOptions, configFile: compilerOptions.configFile, traceResolution: false }, host) : undefined;
|
||||
const preErrors = preProgram && ts.getPreEmitDiagnostics(preProgram);
|
||||
|
||||
const program = ts.createProgram(rootFiles || [], compilerOptions, host);
|
||||
|
||||
@ -18,7 +18,7 @@ namespace ts.codefix {
|
||||
|
||||
export function getNoopSymbolTrackerWithResolver(context: TypeConstructionContext): SymbolTracker {
|
||||
return {
|
||||
trackSymbol: noop,
|
||||
trackSymbol: () => false,
|
||||
moduleResolverHost: getModuleSpecifierResolverHost(context.program, context.host),
|
||||
};
|
||||
}
|
||||
|
||||
@ -2093,7 +2093,7 @@ namespace ts {
|
||||
increaseIndent: () => { indent++; },
|
||||
decreaseIndent: () => { indent--; },
|
||||
clear: resetWriter,
|
||||
trackSymbol: noop,
|
||||
trackSymbol: () => false,
|
||||
reportInaccessibleThisError: noop,
|
||||
reportInaccessibleUniqueSymbolError: noop,
|
||||
reportPrivateInBaseOfClassExpression: noop,
|
||||
@ -2619,6 +2619,7 @@ namespace ts {
|
||||
const res = checker.typeToTypeNode(type, enclosingScope, NodeBuilderFlags.NoTruncation, {
|
||||
trackSymbol: (symbol, declaration, meaning) => {
|
||||
typeIsAccessible = typeIsAccessible && checker.isSymbolAccessible(symbol, declaration, meaning, /*shouldComputeAliasToMarkVisible*/ false).accessibility === SymbolAccessibility.Accessible;
|
||||
return !typeIsAccessible;
|
||||
},
|
||||
reportInaccessibleThisError: notAccessible,
|
||||
reportPrivateInBaseOfClassExpression: notAccessible,
|
||||
|
||||
@ -0,0 +1,42 @@
|
||||
tests/cases/compiler/Api.ts(6,5): error TS7056: The inferred type of this node exceeds the maximum length the compiler will serialize. An explicit type annotation is needed.
|
||||
tests/cases/compiler/Api.ts(7,5): error TS7056: The inferred type of this node exceeds the maximum length the compiler will serialize. An explicit type annotation is needed.
|
||||
tests/cases/compiler/Api.ts(8,5): error TS7056: The inferred type of this node exceeds the maximum length the compiler will serialize. An explicit type annotation is needed.
|
||||
|
||||
|
||||
==== tests/cases/compiler/http-client.ts (0 errors) ====
|
||||
type TPromise<ResolveType, RejectType = any> = Omit<Promise<ResolveType>, "then" | "catch"> & {
|
||||
then<TResult1 = ResolveType, TResult2 = never>(
|
||||
onfulfilled?: ((value: ResolveType) => TResult1 | PromiseLike<TResult1>) | undefined | null,
|
||||
onrejected?: ((reason: RejectType) => TResult2 | PromiseLike<TResult2>) | undefined | null,
|
||||
): TPromise<TResult1 | TResult2, RejectType>;
|
||||
catch<TResult = never>(
|
||||
onrejected?: ((reason: RejectType) => TResult | PromiseLike<TResult>) | undefined | null,
|
||||
): TPromise<ResolveType | TResult, RejectType>;
|
||||
};
|
||||
|
||||
export interface HttpResponse<D extends unknown, E extends unknown = unknown> extends Response {
|
||||
data: D;
|
||||
error: E;
|
||||
}
|
||||
|
||||
export class HttpClient<SecurityDataType = unknown> {
|
||||
public request = <T = any, E = any>(): TPromise<HttpResponse<T, E>> => {
|
||||
return '' as any;
|
||||
};
|
||||
}
|
||||
==== tests/cases/compiler/Api.ts (3 errors) ====
|
||||
import { HttpClient } from "./http-client";
|
||||
|
||||
export class Api<SecurityDataType = unknown> {
|
||||
constructor(private http: HttpClient<SecurityDataType>) { }
|
||||
|
||||
abc1 = () => this.http.request();
|
||||
~~~~
|
||||
!!! error TS7056: The inferred type of this node exceeds the maximum length the compiler will serialize. An explicit type annotation is needed.
|
||||
abc2 = () => this.http.request();
|
||||
~~~~
|
||||
!!! error TS7056: The inferred type of this node exceeds the maximum length the compiler will serialize. An explicit type annotation is needed.
|
||||
abc3 = () => this.http.request();
|
||||
~~~~
|
||||
!!! error TS7056: The inferred type of this node exceeds the maximum length the compiler will serialize. An explicit type annotation is needed.
|
||||
}
|
||||
@ -0,0 +1,77 @@
|
||||
//// [tests/cases/compiler/declarationEmitPrivatePromiseLikeInterface.ts] ////
|
||||
|
||||
//// [http-client.ts]
|
||||
type TPromise<ResolveType, RejectType = any> = Omit<Promise<ResolveType>, "then" | "catch"> & {
|
||||
then<TResult1 = ResolveType, TResult2 = never>(
|
||||
onfulfilled?: ((value: ResolveType) => TResult1 | PromiseLike<TResult1>) | undefined | null,
|
||||
onrejected?: ((reason: RejectType) => TResult2 | PromiseLike<TResult2>) | undefined | null,
|
||||
): TPromise<TResult1 | TResult2, RejectType>;
|
||||
catch<TResult = never>(
|
||||
onrejected?: ((reason: RejectType) => TResult | PromiseLike<TResult>) | undefined | null,
|
||||
): TPromise<ResolveType | TResult, RejectType>;
|
||||
};
|
||||
|
||||
export interface HttpResponse<D extends unknown, E extends unknown = unknown> extends Response {
|
||||
data: D;
|
||||
error: E;
|
||||
}
|
||||
|
||||
export class HttpClient<SecurityDataType = unknown> {
|
||||
public request = <T = any, E = any>(): TPromise<HttpResponse<T, E>> => {
|
||||
return '' as any;
|
||||
};
|
||||
}
|
||||
//// [Api.ts]
|
||||
import { HttpClient } from "./http-client";
|
||||
|
||||
export class Api<SecurityDataType = unknown> {
|
||||
constructor(private http: HttpClient<SecurityDataType>) { }
|
||||
|
||||
abc1 = () => this.http.request();
|
||||
abc2 = () => this.http.request();
|
||||
abc3 = () => this.http.request();
|
||||
}
|
||||
|
||||
//// [http-client.js]
|
||||
"use strict";
|
||||
exports.__esModule = true;
|
||||
exports.HttpClient = void 0;
|
||||
var HttpClient = /** @class */ (function () {
|
||||
function HttpClient() {
|
||||
this.request = function () {
|
||||
return '';
|
||||
};
|
||||
}
|
||||
return HttpClient;
|
||||
}());
|
||||
exports.HttpClient = HttpClient;
|
||||
//// [Api.js]
|
||||
"use strict";
|
||||
exports.__esModule = true;
|
||||
exports.Api = void 0;
|
||||
var Api = /** @class */ (function () {
|
||||
function Api(http) {
|
||||
var _this = this;
|
||||
this.http = http;
|
||||
this.abc1 = function () { return _this.http.request(); };
|
||||
this.abc2 = function () { return _this.http.request(); };
|
||||
this.abc3 = function () { return _this.http.request(); };
|
||||
}
|
||||
return Api;
|
||||
}());
|
||||
exports.Api = Api;
|
||||
|
||||
|
||||
//// [http-client.d.ts]
|
||||
declare type TPromise<ResolveType, RejectType = any> = Omit<Promise<ResolveType>, "then" | "catch"> & {
|
||||
then<TResult1 = ResolveType, TResult2 = never>(onfulfilled?: ((value: ResolveType) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: RejectType) => TResult2 | PromiseLike<TResult2>) | undefined | null): TPromise<TResult1 | TResult2, RejectType>;
|
||||
catch<TResult = never>(onrejected?: ((reason: RejectType) => TResult | PromiseLike<TResult>) | undefined | null): TPromise<ResolveType | TResult, RejectType>;
|
||||
};
|
||||
export interface HttpResponse<D extends unknown, E extends unknown = unknown> extends Response {
|
||||
data: D;
|
||||
error: E;
|
||||
}
|
||||
export declare class HttpClient<SecurityDataType = unknown> {
|
||||
request: <T = any, E = any>() => TPromise<HttpResponse<T, E>, any>;
|
||||
}
|
||||
export {};
|
||||
@ -155,7 +155,7 @@ let p2 = p1.deeper({ two: '2' })
|
||||
>p1.deeper({ two: '2' }) : { result: { one: string; } & { two: string; }; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => any; }; }; }; }; }; }; }; }; }; }; }
|
||||
>p1.deeper : <U extends Object>(child: U) => { result: { one: string; } & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U & U & U & U & U & U & U & U; deeper: any; }; }; }; }; }; }; }; }; }; }; }
|
||||
>p1 : { result: { one: string; }; deeper: <U extends Object>(child: U) => { result: { one: string; } & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => any; }; }; }; }; }; }; }; }; }; }; }
|
||||
>deeper : <U extends Object>(child: U) => { result: { one: string; } & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U & U & U & U & U & U & U & U; deeper: any; }; }; }; }; }; }; }; }; }; }; }
|
||||
>deeper : <U extends Object>(child: U) => { result: { one: string; } & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & U & U & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => any; }; }; }; }; }; }; }; }; }; }
|
||||
>{ two: '2' } : { two: string; }
|
||||
>two : string
|
||||
>'2' : "2"
|
||||
@ -181,7 +181,7 @@ let p3 = p2.deeper({ three: '3' })
|
||||
>p2.deeper({ three: '3' }) : { result: { one: string; } & { two: string; } & { three: string; }; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & { three: string; } & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & { three: string; } & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & { three: string; } & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & { three: string; } & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & { three: string; } & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & { three: string; } & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & { three: string; } & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & { three: string; } & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & { three: string; } & U & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & { three: string; } & U & U & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => any; }; }; }; }; }; }; }; }; }; }; }
|
||||
>p2.deeper : <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U & U & U & U & U & U & U; deeper: any; }; }; }; }; }; }; }; }; }; }; }
|
||||
>p2 : { result: { one: string; } & { two: string; }; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => any; }; }; }; }; }; }; }; }; }; }; }
|
||||
>deeper : <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U & U & U & U & U & U & U; deeper: any; }; }; }; }; }; }; }; }; }; }; }
|
||||
>deeper : <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => { result: { one: string; } & { two: string; } & U & U & U & U & U & U & U & U & U & U; deeper: <U extends Object>(child: U) => any; }; }; }; }; }; }; }; }; }; }
|
||||
>{ three: '3' } : { three: string; }
|
||||
>three : string
|
||||
>'3' : "3"
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
// @declaration: true
|
||||
// @skipLibCheck: true
|
||||
// @noTypesAndSymbols: true
|
||||
// @filename: http-client.ts
|
||||
type TPromise<ResolveType, RejectType = any> = Omit<Promise<ResolveType>, "then" | "catch"> & {
|
||||
then<TResult1 = ResolveType, TResult2 = never>(
|
||||
onfulfilled?: ((value: ResolveType) => TResult1 | PromiseLike<TResult1>) | undefined | null,
|
||||
onrejected?: ((reason: RejectType) => TResult2 | PromiseLike<TResult2>) | undefined | null,
|
||||
): TPromise<TResult1 | TResult2, RejectType>;
|
||||
catch<TResult = never>(
|
||||
onrejected?: ((reason: RejectType) => TResult | PromiseLike<TResult>) | undefined | null,
|
||||
): TPromise<ResolveType | TResult, RejectType>;
|
||||
};
|
||||
|
||||
export interface HttpResponse<D extends unknown, E extends unknown = unknown> extends Response {
|
||||
data: D;
|
||||
error: E;
|
||||
}
|
||||
|
||||
export class HttpClient<SecurityDataType = unknown> {
|
||||
public request = <T = any, E = any>(): TPromise<HttpResponse<T, E>> => {
|
||||
return '' as any;
|
||||
};
|
||||
}
|
||||
// @filename: Api.ts
|
||||
import { HttpClient } from "./http-client";
|
||||
|
||||
export class Api<SecurityDataType = unknown> {
|
||||
constructor(private http: HttpClient<SecurityDataType>) { }
|
||||
|
||||
abc1 = () => this.http.request();
|
||||
abc2 = () => this.http.request();
|
||||
abc3 = () => this.http.request();
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user