From cd7636d8ddb74a42d1dbea0a41dd4ec4ba06cbae Mon Sep 17 00:00:00 2001 From: Titian Cernicova-Dragomir Date: Thu, 7 Mar 2024 14:30:35 +0000 Subject: [PATCH] Preserve types from initializers that contain function expressions and arrow functions. --- src/compiler/checker.ts | 41 ++++++++++-- src/compiler/transformers/declarations.ts | 19 +++++- .../transformers/declarations/diagnostics.ts | 2 + src/compiler/types.ts | 2 +- tests/baselines/reference/commentsFunction.js | 6 +- tests/baselines/reference/correlatedUnions.js | 2 +- .../reference/declFileTypeofFunction.js | 4 +- ...declarationEmitShadowingInferNotRenamed.js | 2 +- .../functionExpressionReturningItself.js | 2 +- .../reference/keyofAndIndexedAccess.js | 8 ++- ...GenericInstantiationPreservesInlineForm.js | 4 +- ...amingDestructuredPropertyInFunctionType.js | 4 +- ...im-declarations-functions(strict=false).js | 62 ++++++++++--------- ...tim-declarations-functions(strict=true).js | 52 +++++++++------- 14 files changed, 136 insertions(+), 74 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a3dfbe44a6b54..cf099c8daf724 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6329,8 +6329,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const firstIdentifier = getFirstIdentifier(entityName); const symbol = resolveName(enclosingDeclaration, firstIdentifier.escapedText, meaning, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false); - if (symbol && symbol.flags & SymbolFlags.TypeParameter && meaning & SymbolFlags.Type) { - return { accessibility: SymbolAccessibility.Accessible }; + if (symbol) { + if (symbol.flags & SymbolFlags.TypeParameter && meaning & SymbolFlags.Type) { + return { accessibility: SymbolAccessibility.Accessible }; + } + + // Parameters or binding elements from parameters are always visible in their enclosing function declarations + if (symbol.flags & SymbolFlags.FunctionScopedVariable && meaning & SymbolFlags.Value) { + let declaration: Node | undefined = symbol.valueDeclaration; + while (declaration) { + if (declaration.kind === SyntaxKind.Parameter) break; + if (declaration.kind === SyntaxKind.BindingElement) { + declaration = declaration.parent.parent; + } + break; + } + if (declaration?.kind === SyntaxKind.Parameter) { + return { accessibility: SymbolAccessibility.Accessible }; + } + } } if (!symbol && isThisIdentifier(firstIdentifier) && isSymbolAccessible(getSymbolOfDeclaration(getThisContainer(firstIdentifier, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false)), firstIdentifier, meaning, /*shouldComputeAliasesToMakeVisible*/ false).accessibility === SymbolAccessibility.Accessible) { return { accessibility: SymbolAccessibility.Accessible }; @@ -48160,13 +48177,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { hasSyntacticModifier(parameter, ModifierFlags.ParameterPropertyModifier); } - function isExpandoFunctionDeclaration(node: Declaration): boolean { - const declaration = getParseTreeNode(node, isFunctionDeclaration); + function isExpandoFunctionDeclaration(node: FunctionDeclaration | VariableDeclaration): boolean { + const declaration = getParseTreeNode(node, isDeclaration); if (!declaration) { return false; } - const symbol = getSymbolOfDeclaration(declaration); - if (!symbol || !(symbol.flags & SymbolFlags.Function)) { + let symbol: Symbol; + if (isVariableDeclaration(declaration)) { + if (declaration.type || !isVarConstLike(declaration)) { + return false; + } + if (!(declaration.initializer && isFunctionExpressionOrArrowFunction(declaration.initializer))) { + return false; + } + symbol = getSymbolOfDeclaration(declaration.initializer); + } + else { + symbol = getSymbolOfDeclaration(declaration); + } + if (!symbol || !(symbol.flags & SymbolFlags.Function | SymbolFlags.Variable)) { return false; } return !!forEachEntry(getExportsOfSymbol(symbol), p => p.flags & SymbolFlags.Value && isExpandoPropertyDeclaration(p.valueDeclaration)); diff --git a/src/compiler/transformers/declarations.ts b/src/compiler/transformers/declarations.ts index 9ba6e19ec4dc6..148007b60e3d1 100644 --- a/src/compiler/transformers/declarations.ts +++ b/src/compiler/transformers/declarations.ts @@ -6,6 +6,7 @@ import { append, ArrayBindingElement, arrayFrom, + ArrowFunction, AsExpression, BindingElement, BindingName, @@ -51,6 +52,7 @@ import { flatten, forEach, FunctionDeclaration, + FunctionExpression, FunctionTypeNode, GeneratedIdentifierFlags, GetAccessorDeclaration, @@ -864,6 +866,9 @@ export function transformDeclarations(context: TransformationContext) { } function typeFromExpression(node: Expression, requiresUndefined?: boolean): TypeNode | undefined { switch (node.kind) { + case SyntaxKind.ArrowFunction: + case SyntaxKind.FunctionExpression: + return typeFromFunctionLikeExpression(node as ArrowFunction | FunctionExpression); case SyntaxKind.TypeAssertionExpression: case SyntaxKind.AsExpression: const asExpression = node as AsExpression | TypeAssertion; @@ -877,7 +882,19 @@ export function transformDeclarations(context: TransformationContext) { } return undefined; } + function typeFromFunctionLikeExpression(fnNode: FunctionExpression | ArrowFunction) { + const oldEnclosingDeclaration = enclosingDeclaration; + enclosingDeclaration = fnNode; + const returnType = fnNode.type ? visitTypeNode(fnNode.type) : inferReturnTypeOfSignatureSignature(fnNode); + const fnTypeNode = factory.createFunctionTypeNode( + visitNodes(fnNode.typeParameters, visitDeclarationSubtree, isTypeParameterDeclaration), + fnNode.parameters.map(p => ensureParameter(p)), + returnType, + ); + enclosingDeclaration = oldEnclosingDeclaration; + return fnTypeNode; + } function typeFromAccessor(node: AccessorDeclaration) { const accessorDeclarations = resolver.getAllAccessorDeclarations(node); const accessorType = getTypeAnnotationFromAllAccessorDeclarations(node, accessorDeclarations); @@ -892,7 +909,7 @@ export function transformDeclarations(context: TransformationContext) { return visitNode(declaredType, visitDeclarationSubtree, isTypeNode)!; } let resultType; - if (node.initializer) { + if (node.initializer && !resolver.isExpandoFunctionDeclaration(node)) { resultType = typeFromExpression(node.initializer); } return resultType ?? inferVariableLikeType(node); diff --git a/src/compiler/transformers/declarations/diagnostics.ts b/src/compiler/transformers/declarations/diagnostics.ts index ef9935c7342ed..08dd85e4a4888 100644 --- a/src/compiler/transformers/declarations/diagnostics.ts +++ b/src/compiler/transformers/declarations/diagnostics.ts @@ -459,6 +459,8 @@ export function createGetSymbolAccessibilityDiagnosticForNode(node: DeclarationD Diagnostics.Parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1; } + case SyntaxKind.ArrowFunction: + case SyntaxKind.FunctionExpression: case SyntaxKind.FunctionDeclaration: case SyntaxKind.FunctionType: return symbolAccessibilityResult.errorModuleName ? diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 3d7b3580bccfb..bf3a313a5c182 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5604,7 +5604,7 @@ export interface EmitResolver { collectLinkedAliases(node: Identifier, setVisibility?: boolean): Node[] | undefined; isImplementationOfOverload(node: SignatureDeclaration): boolean | undefined; requiresAddingImplicitUndefined(node: ParameterDeclaration): boolean; - isExpandoFunctionDeclaration(node: FunctionDeclaration): boolean; + isExpandoFunctionDeclaration(node: VariableDeclaration | FunctionDeclaration): boolean; getPropertiesOfContainerFunction(node: Declaration): Symbol[]; createTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression | ElementAccessExpression | BinaryExpression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean): TypeNode | undefined; createReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker): TypeNode | undefined; diff --git a/tests/baselines/reference/commentsFunction.js b/tests/baselines/reference/commentsFunction.js index 852490d0d8330..bc1e901995cd9 100644 --- a/tests/baselines/reference/commentsFunction.js +++ b/tests/baselines/reference/commentsFunction.js @@ -111,9 +111,9 @@ b: number): void; /** fooFunc * comment */ -declare var fooFunc: (b: string) => string; -declare var lambdaFoo: (a: number, b: number) => number; -declare var lambddaNoVarComment: (a: number, b: number) => number; +declare var fooFunc: (/** fooFunctionValue param */ b: string) => string; +declare var lambdaFoo: (/**param a*/ a: number, /**param b*/ b: number) => number; +declare var lambddaNoVarComment: (/**param a*/ a: number, /**param b*/ b: number) => number; declare function blah(a: string): void; declare function blah2(a: string): void; declare function blah3(a: string): void; diff --git a/tests/baselines/reference/correlatedUnions.js b/tests/baselines/reference/correlatedUnions.js index 05e77d8b4d3e1..c758bd3145a6d 100644 --- a/tests/baselines/reference/correlatedUnions.js +++ b/tests/baselines/reference/correlatedUnions.js @@ -602,7 +602,7 @@ type SameKeys = { }; }; type MappedFromOriginal = SameKeys; -declare const getStringAndNumberFromOriginalAndMapped: (original: Original, mappedFromOriginal: MappedFromOriginal, key: K, nestedKey: N) => [Original[K][N], MappedFromOriginal[K][N]]; +declare const getStringAndNumberFromOriginalAndMapped: >(original: Original, mappedFromOriginal: MappedFromOriginal, key: K, nestedKey: N) => [Original[K][N], MappedFromOriginal[K][N]]; interface Config { string: string; number: number; diff --git a/tests/baselines/reference/declFileTypeofFunction.js b/tests/baselines/reference/declFileTypeofFunction.js index a1d770ca5ac70..eb36d70575a4a 100644 --- a/tests/baselines/reference/declFileTypeofFunction.js +++ b/tests/baselines/reference/declFileTypeofFunction.js @@ -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: () => () => any; +declare var x: () => () => any; declare function foo5(x: number): (x: number) => number; diff --git a/tests/baselines/reference/declarationEmitShadowingInferNotRenamed.js b/tests/baselines/reference/declarationEmitShadowingInferNotRenamed.js index 2112c95e5d806..07a7d4d542f25 100644 --- a/tests/baselines/reference/declarationEmitShadowingInferNotRenamed.js +++ b/tests/baselines/reference/declarationEmitShadowingInferNotRenamed.js @@ -38,5 +38,5 @@ type Client = string; type UpdatedClient = C & { foo: number; }; -export declare const createClient: Client> | (new (...args: any[]) => Client)>(clientDef: D) => D extends new (...args: any[]) => infer C ? UpdatedClient : { [K in keyof D]: D[K] extends new (...args: any[]) => infer C_1 ? UpdatedClient : never; }; +export declare const createClient: Client) | Record Client>>(clientDef: D) => D extends new (...args: any[]) => infer C ? UpdatedClient : { [K in keyof D]: D[K] extends new (...args: any[]) => infer C_1 ? UpdatedClient : never; }; export {}; diff --git a/tests/baselines/reference/functionExpressionReturningItself.js b/tests/baselines/reference/functionExpressionReturningItself.js index e12a26909b987..244cbda2b81a9 100644 --- a/tests/baselines/reference/functionExpressionReturningItself.js +++ b/tests/baselines/reference/functionExpressionReturningItself.js @@ -8,4 +8,4 @@ var x = function somefn() { return somefn; }; //// [functionExpressionReturningItself.d.ts] -declare var x: () => any; +declare var x: () => () => any; diff --git a/tests/baselines/reference/keyofAndIndexedAccess.js b/tests/baselines/reference/keyofAndIndexedAccess.js index ea10cf32f5e50..7548184d7994d 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess.js +++ b/tests/baselines/reference/keyofAndIndexedAccess.js @@ -1431,7 +1431,11 @@ type DictDict = { }; declare function ff1(dd: DictDict, k1: V, k2: T): number; declare function ff2(dd: DictDict, k1: V, k2: T): number; -declare const cf1: (t: T, k: K) => void; -declare const cf2: (t: T, k: K) => void; +declare const cf2: (t: T, k: K) => void; diff --git a/tests/baselines/reference/mappedTypeGenericInstantiationPreservesInlineForm.js b/tests/baselines/reference/mappedTypeGenericInstantiationPreservesInlineForm.js index 8c3efbcca6d84..712b5232084ed 100644 --- a/tests/baselines/reference/mappedTypeGenericInstantiationPreservesInlineForm.js +++ b/tests/baselines/reference/mappedTypeGenericInstantiationPreservesInlineForm.js @@ -15,7 +15,9 @@ export function test2>(schema: { //// [mappedTypeGenericInstantiationPreservesInlineForm.d.ts] -export declare const test1: >(schema: { [K in keyof Required]: T[K]; }) => void; +export declare const test1: >(schema: { + [K in keyof Required]: T[K]; +}) => void; export declare function test2>(schema: { [K in keyof Required]: T[K]; }): void; diff --git a/tests/baselines/reference/renamingDestructuredPropertyInFunctionType.js b/tests/baselines/reference/renamingDestructuredPropertyInFunctionType.js index af19e36e72147..9c8cccf1093f4 100644 --- a/tests/baselines/reference/renamingDestructuredPropertyInFunctionType.js +++ b/tests/baselines/reference/renamingDestructuredPropertyInFunctionType.js @@ -171,8 +171,8 @@ interface I { declare function f1({ a: string }: O): void; declare const f2: ({ a: string }: O) => void; declare const f3: ({ a: string, b, c }: O) => void; -declare const f4: ({ a: string }: O) => string; -declare const f5: ({ a: string, b, c }: O) => string; +declare const f4: ({ a: string }: O) => typeof string; +declare const f5: ({ a: string, b, c }: O) => typeof string; declare const obj1: { method({ a: string }: O): void; }; diff --git a/tests/baselines/reference/verbatim-declarations-functions(strict=false).js b/tests/baselines/reference/verbatim-declarations-functions(strict=false).js index 87933c4c6678a..e6f9e5e06981d 100644 --- a/tests/baselines/reference/verbatim-declarations-functions(strict=false).js +++ b/tests/baselines/reference/verbatim-declarations-functions(strict=false).js @@ -188,45 +188,45 @@ exports.createClient = createClient; type P = { name: string; }; -export declare let vLet: (p: P, p2: P) => P; -export declare const vConst: (p: P, p2: P) => P; -export declare function fn(p?: (p: P, p2: P) => P): void; +export declare let vLet: (/* param */ p: P, p2: typeof p) => P; +export declare const vConst: (/* param */ p: P, p2: typeof p) => P; +export declare function fn(p?: (/* param */ p: P, p2: typeof p) => P): void; export declare function fnTypeFromBinding({ foo }: { foo: number; -}, p?: (p: P, p2: P, p3: typeof foo) => P): void; +}, p?: (/* param */ p: P, p2: typeof p, p3: typeof foo) => P): void; /** p wil be resolved by the checker (requires | undefined) */ -export declare function fnWithRequiredDefaultParam(p: (p: P, p2: P) => P, req: number): void; +export declare function fnWithRequiredDefaultParam(p: (/* param */ p: P, p2: typeof p) => P, req: number): void; /** p wil be resolved by the checker (requires | undefined) */ -export declare const exprWithRequiredDefaultParam: (p: (p: P, p2: P) => P, req: number) => void; +export declare const exprWithRequiredDefaultParam: (p: (/* param */ p: P, p2: typeof p) => P, req: number) => void; export declare class C { - ctorField: (p: P, p2: P) => P; - field: (p: P, p2: P) => P; - readonly roFiled: (p: P, p2: P) => P; - method(p?: (p: P, p2: P) => P): void; + ctorField: (/* param */ p: P, p2: typeof p) => P; + field: (/* param */ p: P, p2: typeof p) => P; + readonly roFiled: (/* param */ p: P, p2: typeof p) => P; + method(p?: (/* param */ p: P, p2: typeof p) => P): void; /** p wil be resolved by the checker (requires | undefined) */ - methodWithRequiredDefault(p: (p: P, p2: P) => P, req: number): void; + methodWithRequiredDefault(p: (/* param */ p: P, p2: typeof p) => P, req: number): void; thisType: () => this; - constructor(ctorField?: (p: P, p2: P) => P); + constructor(ctorField?: (/* param */ p: P, p2: typeof p) => P); } -declare const _default: (p: P, p2: P) => P; +declare const _default: (/* param */ p: P, p2: typeof p) => P; export default _default; //// [functionExpressionPlacement.d.ts] type P = { name: string; }; -export declare let vLet: (p: P, p2: P) => P; -export declare const vConst: (p: P, p2: P) => P; -export declare function fn(p?: (p: P, p2: P) => P): void; +export declare let vLet: (/* param */ p: P, p2: typeof p) => P; +export declare const vConst: (/* param */ p: P, p2: typeof p) => P; +export declare function fn(p?: (/* param */ p: P, p2: typeof p) => P): void; /** p wil be resolved by the checker (requires | undefined) */ -export declare function fnWithRequiredDefaultParam(p: (p: P, p2: P) => P, req: number): void; +export declare function fnWithRequiredDefaultParam(p: (/* param */ p: P, p2: typeof p) => P, req: number): void; export declare class C { - ctorField: (p: P, p2: P) => P; - field: (p: P, p2: P) => P; - readonly roFiled: (p: P, p2: P) => P; - method(p?: (p: P, p2: P) => P): void; + ctorField: (/* param */ p: P, p2: typeof p) => P; + field: (/* param */ p: P, p2: typeof p) => P; + readonly roFiled: (/* param */ p: P, p2: typeof p) => P; + method(p?: (/* param */ p: P, p2: typeof p) => P): void; /** p wil be resolved by the checker (requires | undefined) */ - methodWithRequiredDefault(p: (p: P, p2: P) => P, req: number): void; - constructor(ctorField?: (p: P, p2: P) => P); + methodWithRequiredDefault(p: (/* param */ p: P, p2: typeof p) => P, req: number): void; + constructor(ctorField?: (/* param */ p: P, p2: typeof p) => P); } export default function (/* param */ p: P, p2: typeof p): P; export {}; @@ -234,12 +234,16 @@ export {}; type P = { name: string; }; -export declare let fromAnnotation: (p: P) => string; +export declare let fromAnnotation: (p: P) => typeof p[keyof typeof p]; export declare let fromInference: (p: P) => string; export {}; //// [genericFunctions.d.ts] -export declare let g1: (p: T) => void; -export declare let g2: () => G2; -export declare const createClient: (clientDef: D) => D extends new (...args: any[]) => infer D_1 ? D_1 extends { - d: infer D_2; -} ? D_2 : never : never; +type G1 = { + name: string; +}; +export declare let g1: (/* param */ p: T) => void; +export declare let g2: () => G2; +export declare const createClient: (clientDef: D) => D extends new (...args: any[]) => infer D ? (D extends { + d: infer D; +} ? D : never) : never; +export {}; diff --git a/tests/baselines/reference/verbatim-declarations-functions(strict=true).js b/tests/baselines/reference/verbatim-declarations-functions(strict=true).js index 4ce35e732fb95..b6e3c10e8b299 100644 --- a/tests/baselines/reference/verbatim-declarations-functions(strict=true).js +++ b/tests/baselines/reference/verbatim-declarations-functions(strict=true).js @@ -188,45 +188,45 @@ exports.createClient = createClient; type P = { name: string; }; -export declare let vLet: (p: P, p2: P) => P; -export declare const vConst: (p: P, p2: P) => P; -export declare function fn(p?: (p: P, p2: P) => P): void; +export declare let vLet: (/* param */ p: P, p2: typeof p) => P; +export declare const vConst: (/* param */ p: P, p2: typeof p) => P; +export declare function fn(p?: (/* param */ p: P, p2: typeof p) => P): void; export declare function fnTypeFromBinding({ foo }: { foo: number; -}, p?: (p: P, p2: P, p3: typeof foo) => P): void; +}, p?: (/* param */ p: P, p2: typeof p, p3: typeof foo) => P): void; /** p wil be resolved by the checker (requires | undefined) */ export declare function fnWithRequiredDefaultParam(p: ((p: P, p2: P) => P) | undefined, req: number): void; /** p wil be resolved by the checker (requires | undefined) */ export declare const exprWithRequiredDefaultParam: (p: ((p: P, p2: P) => P) | undefined, req: number) => void; export declare class C { - ctorField: (p: P, p2: P) => P; - field: (p: P, p2: P) => P; - readonly roFiled: (p: P, p2: P) => P; - method(p?: (p: P, p2: P) => P): void; + ctorField: (/* param */ p: P, p2: typeof p) => P; + field: (/* param */ p: P, p2: typeof p) => P; + readonly roFiled: (/* param */ p: P, p2: typeof p) => P; + method(p?: (/* param */ p: P, p2: typeof p) => P): void; /** p wil be resolved by the checker (requires | undefined) */ methodWithRequiredDefault(p: ((p: P, p2: P) => P) | undefined, req: number): void; thisType: () => this; - constructor(ctorField?: (p: P, p2: P) => P); + constructor(ctorField?: (/* param */ p: P, p2: typeof p) => P); } -declare const _default: (p: P, p2: P) => P; +declare const _default: (/* param */ p: P, p2: typeof p) => P; export default _default; //// [functionExpressionPlacement.d.ts] type P = { name: string; }; -export declare let vLet: (p: P, p2: P) => P; -export declare const vConst: (p: P, p2: P) => P; -export declare function fn(p?: (p: P, p2: P) => P): void; +export declare let vLet: (/* param */ p: P, p2: typeof p) => P; +export declare const vConst: (/* param */ p: P, p2: typeof p) => P; +export declare function fn(p?: (/* param */ p: P, p2: typeof p) => P): void; /** p wil be resolved by the checker (requires | undefined) */ export declare function fnWithRequiredDefaultParam(p: ((p: P, p2: P) => P) | undefined, req: number): void; export declare class C { - ctorField: (p: P, p2: P) => P; - field: (p: P, p2: P) => P; - readonly roFiled: (p: P, p2: P) => P; - method(p?: (p: P, p2: P) => P): void; + ctorField: (/* param */ p: P, p2: typeof p) => P; + field: (/* param */ p: P, p2: typeof p) => P; + readonly roFiled: (/* param */ p: P, p2: typeof p) => P; + method(p?: (/* param */ p: P, p2: typeof p) => P): void; /** p wil be resolved by the checker (requires | undefined) */ methodWithRequiredDefault(p: ((p: P, p2: P) => P) | undefined, req: number): void; - constructor(ctorField?: (p: P, p2: P) => P); + constructor(ctorField?: (/* param */ p: P, p2: typeof p) => P); } export default function (/* param */ p: P, p2: typeof p): P; export {}; @@ -234,12 +234,16 @@ export {}; type P = { name: string; }; -export declare let fromAnnotation: (p: P) => string; +export declare let fromAnnotation: (p: P) => typeof p[keyof typeof p]; export declare let fromInference: (p: P) => string; export {}; //// [genericFunctions.d.ts] -export declare let g1: (p: T) => void; -export declare let g2: () => G2; -export declare const createClient: (clientDef: D) => D extends new (...args: any[]) => infer D_1 ? D_1 extends { - d: infer D_2; -} ? D_2 : never : never; +type G1 = { + name: string; +}; +export declare let g1: (/* param */ p: T) => void; +export declare let g2: () => G2; +export declare const createClient: (clientDef: D) => D extends new (...args: any[]) => infer D ? (D extends { + d: infer D; +} ? D : never) : never; +export {};