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:
Wesley Wigham 2021-05-12 12:11:20 -07:00 committed by GitHub
parent 0454ae4720
commit f7a97b7759
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 271 additions and 25 deletions

View File

@ -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[];

View File

@ -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) {

View File

@ -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;

View File

@ -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,

View File

@ -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);

View File

@ -18,7 +18,7 @@ namespace ts.codefix {
export function getNoopSymbolTrackerWithResolver(context: TypeConstructionContext): SymbolTracker {
return {
trackSymbol: noop,
trackSymbol: () => false,
moduleResolverHost: getModuleSpecifierResolverHost(context.program, context.host),
};
}

View File

@ -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,

View File

@ -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.
}

View File

@ -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 {};

View File

@ -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"

View File

@ -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();
}