Skip to content

Added typeToTypeNode with truncation #59332

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Aug 30, 2024
30 changes: 25 additions & 5 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
addRange,
addRelatedInfo,
addSyntheticLeadingComment,
addSyntheticTrailingComment,
AliasDeclarationNode,
AllAccessorDeclarations,
AmbientModuleDeclaration,
Expand Down Expand Up @@ -7054,6 +7055,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {

function createTypeNodesFromResolvedType(resolvedType: ResolvedType): TypeElement[] | undefined {
if (checkTruncationLength(context)) {
if (context.flags & NodeBuilderFlags.NoTruncation) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a test that shows what this looks like?

Copy link
Member Author

@armanio123 armanio123 Aug 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that you mentioned, there's no test for this scenario. I removed this check, and nothing regressed. I'm not sure how to test it but if it's utterly necessary I can address that another PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

@armanio123 armanio123 Aug 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After deeper analysis, the file hugeDeclarationOutputGetsTruncatedWithError.types access this code.

Check line 18, for the last property zz. It changes from "zz": { ...; } to zz: { };. This is a "type" tests, during emit the "elided" comment gets added: zz: { /*elided*/ };

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we add elided in type tests?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was working on it. Added.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to confirm, you're saying that in *.types files we will write "zz": { ...; } but in emit we will write zz: { /*elided*/ };? The thing I was interested in is whether or not we should do the latter for both, but maybe that's not what you were describing?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I mean, before this change files in *.types files and during emit we write "zz": { ...; }.

After this change, *.types files and emit write "zz": { }, and .d.ts files "zz": { /*elided*/ } respectively.

See the test codeFixClassImplementInterfaceNoTruncationProperties.ts for the emit example. hugeDeclarationOutputGetsTruncatedWithError.types shows the *.types change.

return [addSyntheticTrailingComment(factory.createNotEmittedTypeElement(), SyntaxKind.MultiLineCommentTrivia, "elided")];
}
return [factory.createPropertySignature(/*modifiers*/ undefined, "...", /*questionToken*/ undefined, /*type*/ undefined)];
}
const typeElements: TypeElement[] = [];
Expand Down Expand Up @@ -7085,7 +7089,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
}
if (checkTruncationLength(context) && (i + 2 < properties.length - 1)) {
typeElements.push(factory.createPropertySignature(/*modifiers*/ undefined, `... ${properties.length - i} more ...`, /*questionToken*/ undefined, /*type*/ undefined));
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));
}
addPropertyToElementList(properties[properties.length - 1], context, typeElements);
break;
}
Expand All @@ -7100,7 +7110,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (!(context.flags & NodeBuilderFlags.NoTruncation)) {
return factory.createTypeReferenceNode(factory.createIdentifier("..."), /*typeArguments*/ undefined);
}
return factory.createKeywordTypeNode(SyntaxKind.AnyKeyword);
return addSyntheticLeadingComment(factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), SyntaxKind.MultiLineCommentTrivia, "elided");
}

function shouldUsePlaceholderForProperty(propertySymbol: Symbol, context: NodeBuilderContext) {
Expand Down Expand Up @@ -7260,12 +7270,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (some(types)) {
if (checkTruncationLength(context)) {
if (!isBareList) {
return [factory.createTypeReferenceNode("...", /*typeArguments*/ undefined)];
return [
context.flags & NodeBuilderFlags.NoTruncation
? addSyntheticLeadingComment(factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), SyntaxKind.MultiLineCommentTrivia, "elided")
: factory.createTypeReferenceNode("...", /*typeArguments*/ undefined),
];
}
else if (types.length > 2) {
return [
typeToTypeNodeHelper(types[0], context),
factory.createTypeReferenceNode(`... ${types.length - 2} more ...`, /*typeArguments*/ undefined),
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),
];
}
Expand All @@ -7278,7 +7294,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
for (const type of types) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Am I confused or is this truncating things more when the flag is enabled?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not more per se, but it is replacing the previous values with an any

We kinda have 3 states: when NoTruncation is disabled, we truncate up to defaultMaximumTruncationLength, if NoTruncation is enabled it truncates up to noTruncationMaximumTruncationLength, anything after that is an any.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A ... ${types.length - i} more elided ... comment would be more in-line with the non-grammatical node this replaces when NoTruncation is set.

Copy link
Member Author

@armanio123 armanio123 Aug 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we decide to remove all of the types and just have an any it will not make sense to have this message as the code will look like:

 foo(bar: /*... 516 more elided ...*/ any): /*elided*/ any {
        throw new Error("Method not implemented.");
    }
    get bar(): /*... 516 more elided ...*/ any {
        throw new Error("Method not implemented.");
    }
    set bar(value: /*... 516 more elided ...*/ any) {
        throw new Error("Method not implemented.");
    }
    baz<V extends /*... 516 more elided ...*/ any>(value: V): V {
        throw new Error("Method not implemented.");
    }

We can instead count all of the types that were elided and put that like the example below buy I honestly prefer just having /*elided*/ for something short and descriptive enough IMO.

 foo(bar: /*... 800 elided ...*/ any): /*... 800 elided ...*/ any {
       throw new Error("Method not implemented.");
 }

i++;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, this is discarding all the parts we already actually got to before hitting the truncation limit - shouldn't this all be something more like

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

merged into the line below? This way we still get something like

A | B | C | /* ... 6 more elided ... */ any | undefined

out? (Part of the reason elision is a bit special here is because it endeavors to retain the last element, since elision only really makes sense in the middle.)
As written, this is just going to output

/* elided */ any

for the whole union, even if there's enough allotted space for a lot of the union.

Copy link
Member Author

@armanio123 armanio123 Aug 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Including part of types then truncating with an any seems to me like it would be incorrect and unnecessary, even for the last type. Instead, I would argue that if we are truncating and putting any anyway, we might as well remove the whole thing and replace it for an any.

Arguably, adding the types might serve as documentation, but it will be incorrect as we're not including all of the types, just some of them.

Copy link
Member

@weswigham weswigham Aug 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary for the type arithmetic? Yes. A | B | any is just any. Unnecessary for the human that has to go and fill in the blank after the quickfix runs? Probably not! The more context we retain, the easier it is for the human that has to go and fix this fix's output with what's supposed to go there!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed as requested but I have some concerns.

I understand your point about retaining context, however, I respectfully disagree because the amount of code generated might become too large to be useful. I fear even the comment might go unnoticed. If this happens, including partial types and then truncating with any can lead to confusion and inaccuracies.

I feel is more efficient to replace the entire section with any to maintain clarity and correctness. This way, we avoid the risk of misinterpretation and ensure the code remains manageable.

i.e take a look at the test codeFixClassImplementInterfaceNoTruncation.ts in the latest change, finding where the parameter type ends is already complicated. A user noticing the comment, or the introduction of any seems likely to be missed.

if (checkTruncationLength(context) && (i + 2 < types.length - 1)) {
result.push(factory.createTypeReferenceNode(`... ${types.length - i} more ...`, /*typeArguments*/ undefined));
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),
);
const typeNode = typeToTypeNodeHelper(types[types.length - 1], context);
if (typeNode) {
result.push(typeNode);
Expand Down
1 change: 1 addition & 0 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1880,6 +1880,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri

// Transformation nodes
case SyntaxKind.NotEmittedStatement:
case SyntaxKind.NotEmittedTypeElement:
return;
}
if (isExpression(node)) {
Expand Down
7 changes: 7 additions & 0 deletions src/compiler/factory/nodeFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ import {
NonNullExpression,
NoSubstitutionTemplateLiteral,
NotEmittedStatement,
NotEmittedTypeElement,
NullLiteral,
nullNodeConverters,
nullParenthesizerRules,
Expand Down Expand Up @@ -1007,6 +1008,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
createSyntheticExpression,
createSyntaxList,
createNotEmittedStatement,
createNotEmittedTypeElement,
createPartiallyEmittedExpression,
updatePartiallyEmittedExpression,
createCommaListExpression,
Expand Down Expand Up @@ -6263,6 +6265,11 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
: node;
}

// @api
function createNotEmittedTypeElement() {
return createBaseNode<NotEmittedTypeElement>(SyntaxKind.NotEmittedTypeElement);
}

function flattenCommaElements(node: Expression): Expression | readonly Expression[] {
if (nodeIsSynthesized(node) && !isParseTreeNode(node) && !node.original && !node.emitNode && !node.id) {
if (isCommaListExpression(node)) {
Expand Down
6 changes: 6 additions & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,7 @@ export const enum SyntaxKind {

// Transformation nodes
NotEmittedStatement,
NotEmittedTypeElement,
PartiallyEmittedExpression,
CommaListExpression,
SyntheticReferenceExpression,
Expand Down Expand Up @@ -3310,6 +3311,10 @@ export interface NotEmittedStatement extends Statement {
readonly kind: SyntaxKind.NotEmittedStatement;
}

export interface NotEmittedTypeElement extends TypeElement {
readonly kind: SyntaxKind.NotEmittedTypeElement;
}

/**
* A list of comma-separated expressions. This node is only created by transformations.
*/
Expand Down Expand Up @@ -9144,6 +9149,7 @@ export interface NodeFactory {
//

createNotEmittedStatement(original: Node): NotEmittedStatement;
createNotEmittedTypeElement(): NotEmittedTypeElement;
createPartiallyEmittedExpression(expression: Expression, original?: Node): PartiallyEmittedExpression;
updatePartiallyEmittedExpression(node: PartiallyEmittedExpression, expression: Expression): PartiallyEmittedExpression;
/** @internal */ createSyntheticReferenceExpression(expression: Expression, thisArg: Expression): SyntheticReferenceExpression;
Expand Down
3 changes: 2 additions & 1 deletion src/compiler/utilitiesPublic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1767,7 +1767,8 @@ export function isTypeElement(node: Node): node is TypeElement {
|| kind === SyntaxKind.MethodSignature
|| kind === SyntaxKind.IndexSignature
|| kind === SyntaxKind.GetAccessor
|| kind === SyntaxKind.SetAccessor;
|| kind === SyntaxKind.SetAccessor
|| kind === SyntaxKind.NotEmittedTypeElement;
}

export function isClassOrTypeElement(node: Node): node is ClassElement | TypeElement {
Expand Down
6 changes: 3 additions & 3 deletions src/services/codefixes/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,12 +217,12 @@ export function addNewNodeForMemberSymbol(
const optional = !!(symbol.flags & SymbolFlags.Optional);
const ambient = !!(enclosingDeclaration.flags & NodeFlags.Ambient) || isAmbient;
const quotePreference = getQuotePreference(sourceFile, preferences);
const flags = NodeBuilderFlags.NoTruncation
| (quotePreference === QuotePreference.Single ? NodeBuilderFlags.UseSingleQuotesForStringLiteralType : NodeBuilderFlags.None);

switch (kind) {
case SyntaxKind.PropertySignature:
case SyntaxKind.PropertyDeclaration:
let flags = NodeBuilderFlags.NoTruncation;
flags |= quotePreference === QuotePreference.Single ? NodeBuilderFlags.UseSingleQuotesForStringLiteralType : 0;
let typeNode = checker.typeToTypeNode(type, enclosingDeclaration, flags, InternalNodeBuilderFlags.AllowUnresolvedNames, getNoopSymbolTrackerWithResolver(context));
if (importAdder) {
const importableReference = tryGetAutoImportableReferenceFromTypeNode(typeNode, scriptTarget);
Expand All @@ -242,7 +242,7 @@ export function addNewNodeForMemberSymbol(
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor: {
Debug.assertIsDefined(declarations);
let typeNode = checker.typeToTypeNode(type, enclosingDeclaration, /*flags*/ undefined, /*internalFlags*/ undefined, getNoopSymbolTrackerWithResolver(context));
let typeNode = checker.typeToTypeNode(type, enclosingDeclaration, flags, /*internalFlags*/ undefined, getNoopSymbolTrackerWithResolver(context));
const allAccessors = getAllAccessorDeclarations(declarations, declaration as AccessorDeclaration);
const orderedAccessors = allAccessors.secondAccessor
? [allAccessors.firstAccessor, allAccessors.secondAccessor]
Expand Down
13 changes: 9 additions & 4 deletions tests/baselines/reference/api/typescript.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3983,10 +3983,11 @@ declare namespace ts {
JSDocImportTag = 351,
SyntaxList = 352,
NotEmittedStatement = 353,
PartiallyEmittedExpression = 354,
CommaListExpression = 355,
SyntheticReferenceExpression = 356,
Count = 357,
NotEmittedTypeElement = 354,
PartiallyEmittedExpression = 355,
CommaListExpression = 356,
SyntheticReferenceExpression = 357,
Count = 358,
FirstAssignment = 64,
LastAssignment = 79,
FirstCompoundAssignment = 65,
Expand Down Expand Up @@ -5212,6 +5213,9 @@ declare namespace ts {
interface NotEmittedStatement extends Statement {
readonly kind: SyntaxKind.NotEmittedStatement;
}
interface NotEmittedTypeElement extends TypeElement {
readonly kind: SyntaxKind.NotEmittedTypeElement;
}
/**
* A list of comma-separated expressions. This node is only created by transformations.
*/
Expand Down Expand Up @@ -7792,6 +7796,7 @@ declare namespace ts {
createSourceFile(statements: readonly Statement[], endOfFileToken: EndOfFileToken, flags: NodeFlags): SourceFile;
updateSourceFile(node: SourceFile, statements: readonly Statement[], isDeclarationFile?: boolean, referencedFiles?: readonly FileReference[], typeReferences?: readonly FileReference[], hasNoDefaultLib?: boolean, libReferences?: readonly FileReference[]): SourceFile;
createNotEmittedStatement(original: Node): NotEmittedStatement;
createNotEmittedTypeElement(): NotEmittedTypeElement;
createPartiallyEmittedExpression(expression: Expression, original?: Node): PartiallyEmittedExpression;
updatePartiallyEmittedExpression(node: PartiallyEmittedExpression, expression: Expression): PartiallyEmittedExpression;
createCommaListExpression(elements: readonly Expression[]): CommaListExpression;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,6 @@ var C = /** @class */ (function () {
declare class C {
static D: {
new (): {};
D: any;
D: /*elided*/ any;
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ function f(k) {
//// [mod1.d.ts]
export var K: {
new (): {
values(): any;
values(): /*elided*/ any;
};
};
//// [main.d.ts]
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/declFileTypeofFunction.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,6 @@ declare function b1(): typeof b1;
declare function foo(): typeof foo;
declare var foo1: typeof foo;
declare var foo2: typeof foo;
declare var foo3: () => any;
declare var x: () => any;
declare var foo3: () => /*elided*/ any;
declare var x: () => /*elided*/ any;
declare function foo5(x: number): (x: number) => number;
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ function f() {

//// [declarationEmitInferredTypeAlias4.d.ts]
declare function f<A>(): A[] | {
x: A[] | any;
x: A[] | /*elided*/ any;
};
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ void p3.result.three;
//// [declarationsWithRecursiveInternalTypesProduceUniqueTypeParams.d.ts]
export type Key<U> = keyof U;
export type Value<K extends Key<U>, U> = U[K];
export declare const updateIfChanged: <T>(t: T) => (<K extends keyof T>(key: K) => (<K_1 extends keyof Value<K, T>>(key: K_1) => (<K_2 extends keyof Value<K_1, Value<K, T>>>(key: K_2) => (<K_3 extends keyof Value<K_2, Value<K_1, Value<K, T>>>>(key: K_3) => (<K_4 extends keyof Value<K_3, Value<K_2, Value<K_1, Value<K, T>>>>>(key: K_4) => (<K_5 extends keyof Value<K_4, Value<K_3, Value<K_2, Value<K_1, Value<K, T>>>>>>(key: K_5) => (<K_6 extends keyof Value<K_5, Value<K_4, Value<K_3, Value<K_2, Value<K_1, Value<K, T>>>>>>>(key: K_6) => (<K_7 extends keyof Value<K_6, Value<K_5, Value<K_4, Value<K_3, Value<K_2, Value<K_1, Value<K, T>>>>>>>>(key: K_7) => (<K_8 extends keyof Value<K_7, Value<K_6, Value<K_5, Value<K_4, Value<K_3, Value<K_2, Value<K_1, Value<K, T>>>>>>>>>(key: K_8) => (<K_9 extends keyof Value<K_8, Value<K_7, Value<K_6, Value<K_5, Value<K_4, Value<K_3, Value<K_2, Value<K_1, Value<K, T>>>>>>>>>>(key: K_9) => (<K_10 extends keyof Value<K_9, Value<K_8, Value<K_7, Value<K_6, Value<K_5, Value<K_4, Value<K_3, Value<K_2, Value<K_1, Value<K, T>>>>>>>>>>>(key: K_10) => any & {
export declare const updateIfChanged: <T>(t: T) => (<K extends keyof T>(key: K) => (<K_1 extends keyof Value<K, T>>(key: K_1) => (<K_2 extends keyof Value<K_1, Value<K, T>>>(key: K_2) => (<K_3 extends keyof Value<K_2, Value<K_1, Value<K, T>>>>(key: K_3) => (<K_4 extends keyof Value<K_3, Value<K_2, Value<K_1, Value<K, T>>>>>(key: K_4) => (<K_5 extends keyof Value<K_4, Value<K_3, Value<K_2, Value<K_1, Value<K, T>>>>>>(key: K_5) => (<K_6 extends keyof Value<K_5, Value<K_4, Value<K_3, Value<K_2, Value<K_1, Value<K, T>>>>>>>(key: K_6) => (<K_7 extends keyof Value<K_6, Value<K_5, Value<K_4, Value<K_3, Value<K_2, Value<K_1, Value<K, T>>>>>>>>(key: K_7) => (<K_8 extends keyof Value<K_7, Value<K_6, Value<K_5, Value<K_4, Value<K_3, Value<K_2, Value<K_1, Value<K, T>>>>>>>>>(key: K_8) => (<K_9 extends keyof Value<K_8, Value<K_7, Value<K_6, Value<K_5, Value<K_4, Value<K_3, Value<K_2, Value<K_1, Value<K, T>>>>>>>>>>(key: K_9) => (<K_10 extends keyof Value<K_9, Value<K_8, Value<K_7, Value<K_6, Value<K_5, Value<K_4, Value<K_3, Value<K_2, Value<K_1, Value<K, T>>>>>>>>>>>(key: K_10) => /*elided*/ any & {
map: (updater: (u: Value<K_10, Value<K_9, Value<K_8, Value<K_7, Value<K_6, Value<K_5, Value<K_4, Value<K_3, Value<K_2, Value<K_1, Value<K, T>>>>>>>>>>>) => Value<K_10, Value<K_9, Value<K_8, Value<K_7, Value<K_6, Value<K_5, Value<K_4, Value<K_3, Value<K_2, Value<K_1, Value<K, T>>>>>>>>>>>) => T;
set: (newU: Value<K_10, Value<K_9, Value<K_8, Value<K_7, Value<K_6, Value<K_5, Value<K_4, Value<K_3, Value<K_2, Value<K_1, Value<K, T>>>>>>>>>>>) => T;
}) & {
Expand Down Expand Up @@ -155,7 +155,7 @@ export declare const testRecFun: <T extends Object>(parent: T) => {
result: T & U & U_1 & U_2 & U_3 & U_4 & U_5 & U_6 & U_7 & U_8;
deeper: <U_9 extends Object>(child: U_9) => {
result: T & U & U_1 & U_2 & U_3 & U_4 & U_5 & U_6 & U_7 & U_8 & U_9;
deeper: <U_10 extends Object>(child: U_10) => any;
deeper: <U_10 extends Object>(child: U_10) => /*elided*/ any;
};
};
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,12 @@ export declare var simpleExample: {
};
export declare var circularReference: {
new (): {
tags(c: any): any;
tags(c: /*elided*/ any): /*elided*/ any;
};
getTags(c: {
tags(c: any): any;
tags(c: /*elided*/ any): /*elided*/ any;
}): {
tags(c: any): any;
tags(c: /*elided*/ any): /*elided*/ any;
};
};
export declare class FooItem {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ var x = function somefn() { return somefn; };


//// [functionExpressionReturningItself.d.ts]
declare var x: () => any;
declare var x: () => /*elided*/ any;
Loading