diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b9c3d4c16ce..b3dfbb94616 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4093,7 +4093,7 @@ namespace ts { context.enclosingDeclaration = saveEnclosingDeclaration; const optionalToken = propertySymbol.flags & SymbolFlags.Optional ? createToken(SyntaxKind.QuestionToken) : undefined; if (propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(propertyType).length && !isReadonlySymbol(propertySymbol)) { - const signatures = getSignaturesOfType(propertyType, SignatureKind.Call); + const signatures = getSignaturesOfType(filterType(propertyType, t => !(t.flags & TypeFlags.Undefined)), SignatureKind.Call); for (const signature of signatures) { const methodDeclaration = signatureToSignatureDeclarationHelper(signature, SyntaxKind.MethodSignature, context); methodDeclaration.name = propertyName; diff --git a/tests/baselines/reference/declarationEmitOptionalMethod.js b/tests/baselines/reference/declarationEmitOptionalMethod.js new file mode 100644 index 00000000000..0b622ff550a --- /dev/null +++ b/tests/baselines/reference/declarationEmitOptionalMethod.js @@ -0,0 +1,23 @@ +//// [declarationEmitOptionalMethod.ts] +export const Foo = (opts: { + a?(): void, + b?: () => void, +}): { + c?(): void, + d?: () => void, +} => ({ }); + +//// [declarationEmitOptionalMethod.js] +"use strict"; +exports.__esModule = true; +exports.Foo = function (opts) { return ({}); }; + + +//// [declarationEmitOptionalMethod.d.ts] +export declare const Foo: (opts: { + a?(): void; + b?: (() => void) | undefined; +}) => { + c?(): void; + d?: (() => void) | undefined; +}; diff --git a/tests/baselines/reference/declarationEmitOptionalMethod.symbols b/tests/baselines/reference/declarationEmitOptionalMethod.symbols new file mode 100644 index 00000000000..fe5799f1672 --- /dev/null +++ b/tests/baselines/reference/declarationEmitOptionalMethod.symbols @@ -0,0 +1,19 @@ +=== tests/cases/compiler/declarationEmitOptionalMethod.ts === +export const Foo = (opts: { +>Foo : Symbol(Foo, Decl(declarationEmitOptionalMethod.ts, 0, 12)) +>opts : Symbol(opts, Decl(declarationEmitOptionalMethod.ts, 0, 20)) + + a?(): void, +>a : Symbol(a, Decl(declarationEmitOptionalMethod.ts, 0, 27)) + + b?: () => void, +>b : Symbol(b, Decl(declarationEmitOptionalMethod.ts, 1, 15)) + +}): { + c?(): void, +>c : Symbol(c, Decl(declarationEmitOptionalMethod.ts, 3, 5)) + + d?: () => void, +>d : Symbol(d, Decl(declarationEmitOptionalMethod.ts, 4, 15)) + +} => ({ }); diff --git a/tests/baselines/reference/declarationEmitOptionalMethod.types b/tests/baselines/reference/declarationEmitOptionalMethod.types new file mode 100644 index 00000000000..2da39f70022 --- /dev/null +++ b/tests/baselines/reference/declarationEmitOptionalMethod.types @@ -0,0 +1,23 @@ +=== tests/cases/compiler/declarationEmitOptionalMethod.ts === +export const Foo = (opts: { +>Foo : (opts: { a?(): void; b?: (() => void) | undefined; }) => { c?(): void; d?: (() => void) | undefined; } +>(opts: { a?(): void, b?: () => void,}): { c?(): void, d?: () => void,} => ({ }) : (opts: { a?(): void; b?: (() => void) | undefined; }) => { c?(): void; d?: (() => void) | undefined; } +>opts : { a?(): void; b?: (() => void) | undefined; } + + a?(): void, +>a : (() => void) | undefined + + b?: () => void, +>b : (() => void) | undefined + +}): { + c?(): void, +>c : (() => void) | undefined + + d?: () => void, +>d : (() => void) | undefined + +} => ({ }); +>({ }) : {} +>{ } : {} + diff --git a/tests/baselines/reference/definiteAssignmentAssertionsWithObjectShortHand.js b/tests/baselines/reference/definiteAssignmentAssertionsWithObjectShortHand.js index c3bfe922374..d640ca11683 100644 --- a/tests/baselines/reference/definiteAssignmentAssertionsWithObjectShortHand.js +++ b/tests/baselines/reference/definiteAssignmentAssertionsWithObjectShortHand.js @@ -20,4 +20,6 @@ declare const a: string | undefined; declare const foo: { a: string; }; -declare const bar: {}; +declare const bar: { + a?(): void; +}; diff --git a/tests/baselines/reference/definiteAssignmentAssertionsWithObjectShortHand.types b/tests/baselines/reference/definiteAssignmentAssertionsWithObjectShortHand.types index 73c3edfdaa5..48fcebd5222 100644 --- a/tests/baselines/reference/definiteAssignmentAssertionsWithObjectShortHand.types +++ b/tests/baselines/reference/definiteAssignmentAssertionsWithObjectShortHand.types @@ -9,8 +9,8 @@ const foo = { a! } >a : string const bar = { ->bar : {} ->{ a ? () { }} : {} +>bar : { a?(): void; } +>{ a ? () { }} : { a?(): void; } a ? () { } >a : (() => void) | undefined diff --git a/tests/baselines/reference/strictTypeofUnionNarrowing.types b/tests/baselines/reference/strictTypeofUnionNarrowing.types index bfaabcb3946..8cd547bd16b 100644 --- a/tests/baselines/reference/strictTypeofUnionNarrowing.types +++ b/tests/baselines/reference/strictTypeofUnionNarrowing.types @@ -52,15 +52,15 @@ function stringify3(anything: unknown | undefined): string { // should simplify } function stringify4(anything: { toString?(): string } | undefined): string { ->stringify4 : (anything: {} | undefined) => string ->anything : {} | undefined +>stringify4 : (anything: { toString?(): string; } | undefined) => string +>anything : { toString?(): string; } | undefined >toString : (() => string) | undefined return typeof anything === "string" ? anything.toUpperCase() : ""; >typeof anything === "string" ? anything.toUpperCase() : "" : string >typeof anything === "string" : boolean >typeof anything : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" ->anything : {} | undefined +>anything : { toString?(): string; } | undefined >"string" : "string" >anything.toUpperCase() : string >anything.toUpperCase : () => string diff --git a/tests/baselines/reference/typeFromContextualThisType.types b/tests/baselines/reference/typeFromContextualThisType.types index fc6e3961800..035ab3eb3b0 100644 --- a/tests/baselines/reference/typeFromContextualThisType.types +++ b/tests/baselines/reference/typeFromContextualThisType.types @@ -1,7 +1,7 @@ === tests/cases/conformance/salsa/bug25926.js === /** @type {{ a(): void; b?(n: number): number; }} */ const o1 = { ->o1 : { a(): void; } +>o1 : { a(): void; b?(n: number): number; } >{ a() { this.b = n => n; }} : { a(): void; } a() { @@ -10,7 +10,7 @@ const o1 = { this.b = n => n; >this.b = n => n : (n: number) => number >this.b : ((n: number) => number) | undefined ->this : { a(): void; } +>this : { a(): void; b?(n: number): number; } >b : ((n: number) => number) | undefined >n => n : (n: number) => number >n : number @@ -20,7 +20,7 @@ const o1 = { /** @type {{ d(): void; e?(n: number): number; f?(n: number): number; g?: number }} */ const o2 = { ->o2 : { d(): void; g?: number | undefined; } +>o2 : { d(): void; e?(n: number): number; f?(n: number): number; g?: number | undefined; } >{ d() { this.e = this.f = m => this.g || m; }} : { d(): void; } d() { @@ -29,17 +29,17 @@ const o2 = { this.e = this.f = m => this.g || m; >this.e = this.f = m => this.g || m : (m: number) => number >this.e : ((n: number) => number) | undefined ->this : { d(): void; g?: number | undefined; } +>this : { d(): void; e?(n: number): number; f?(n: number): number; g?: number | undefined; } >e : ((n: number) => number) | undefined >this.f = m => this.g || m : (m: number) => number >this.f : ((n: number) => number) | undefined ->this : { d(): void; g?: number | undefined; } +>this : { d(): void; e?(n: number): number; f?(n: number): number; g?: number | undefined; } >f : ((n: number) => number) | undefined >m => this.g || m : (m: number) => number >m : number >this.g || m : number >this.g : number | undefined ->this : { d(): void; g?: number | undefined; } +>this : { d(): void; e?(n: number): number; f?(n: number): number; g?: number | undefined; } >g : number | undefined >m : number } diff --git a/tests/cases/compiler/declarationEmitOptionalMethod.ts b/tests/cases/compiler/declarationEmitOptionalMethod.ts new file mode 100644 index 00000000000..708a6852e4b --- /dev/null +++ b/tests/cases/compiler/declarationEmitOptionalMethod.ts @@ -0,0 +1,9 @@ +// @declaration: true +// @strictNullChecks: true +export const Foo = (opts: { + a?(): void, + b?: () => void, +}): { + c?(): void, + d?: () => void, +} => ({ }); \ No newline at end of file