diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index 8aec6df21d7af..ba8575b4b74c9 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -21442,6 +21442,25 @@ func (c *Checker) isReadonlyArraySymbol(symbol *ast.Symbol) bool { // parameters and may differ in return types. When signatures differ in return types, the resulting return // type is the union of the constituent return types. func (c *Checker) getUnionSignatures(signatureLists [][]*Signature) []*Signature { + if core.Some(signatureLists, func(signatures []*Signature) bool { return len(signatures) > 1 }) { + signatureLists = core.Map(signatureLists, func(signatures []*Signature) []*Signature { + return core.FlatMap(signatures, func(signature *Signature) []*Signature { + minArgumentCount := c.getMinArgumentCount(signature) + parameterCount := c.getParameterCount(signature) + if len(signature.typeParameters) != 0 || c.hasEffectiveRestParameter(signature) || minArgumentCount == parameterCount { + return []*Signature{signature} + } + result := make([]*Signature, 0, parameterCount-minArgumentCount+1) + for arity := minArgumentCount; arity < parameterCount; arity++ { + variant := c.cloneSignature(signature) + variant.parameters = variant.parameters[:arity] + variant.minArgumentCount = int32(arity) + result = append(result, variant) + } + return append(result, signature) + }) + }) + } var result []*Signature var indexWithLengthOverOne int var countLengthOverOne int diff --git a/tsc/testdata/baselines/reference/compiler/unionOverloadSignatureOrder.errors.txt b/tsc/testdata/baselines/reference/compiler/unionOverloadSignatureOrder.errors.txt new file mode 100644 index 0000000000000..29a0457f9ed5d --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/unionOverloadSignatureOrder.errors.txt @@ -0,0 +1,83 @@ +unionOverloadSignatureOrder.ts(55,19): error TS2769: No overload matches this call. + The last overload gave the following error. + Argument of type '"other"' is not assignable to parameter of type '"num" | "str"'. + + +==== unionOverloadSignatureOrder.ts (1 errors) ==== + namespace Unprimed { + interface Alpha { + foo(n: "str", opt?: boolean): string; + } + + interface Beta { + foo(n: "str", opt?: true): string; + foo(n: string): number | string; + } + + declare let alphaBeta: Alpha | Beta; + declare let betaAlpha: Beta | Alpha; + + const alphaBetaResult: string = alphaBeta.foo("str"); + const betaAlphaResult: string = betaAlpha.foo("str"); + } + + namespace Primed { + interface Alpha { + foo(n: "str", opt?: boolean): string; + } + + type B = Beta["foo"]; + + interface Beta { + foo(n: "str", opt?: true): string; + foo(n: string): number | string; + } + + declare let alphaBeta: Alpha | Beta; + declare let betaAlpha: Beta | Alpha; + + const alphaBetaResult: string = alphaBeta.foo("str"); + const betaAlphaResult: string = betaAlpha.foo("str"); + } + + namespace MultipleOverloads { + interface Alpha { + foo(type: "num", opts?: unknown): number; + foo(type: "str", opts?: unknown): string; + foo(type: string, opts?: unknown): number | string; + } + + interface Beta { + foo(type: "num", opts?: { a?: string }): number; + foo(type: "str", opts?: { b?: string }): string; + foo(type: "num" | "str", opts?: unknown): number | string; + } + + declare let beta: Beta; + beta.foo("str"); + + declare let alphaBeta: Alpha | Beta; + const result: string = alphaBeta.foo("str"); + alphaBeta.foo("other"); + ~~~~~~~ +!!! error TS2769: No overload matches this call. +!!! error TS2769: The last overload gave the following error. +!!! error TS2769: Argument of type '"other"' is not assignable to parameter of type '"num" | "str"'. +!!! related TS2771 unionOverloadSignatureOrder.ts:47:9: The last overload is declared here. + alphaBeta.foo("str", false); + } + + namespace ReversedDeclarations { + interface Beta { + foo(n: "str", opt?: true): string; + foo(n: string): number | string; + } + + interface Alpha { + foo(n: "str", opt?: boolean): string; + } + + declare let alphaBeta: Alpha | Beta; + const result: string = alphaBeta.foo("str"); + } + \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/compiler/unionOverloadSignatureOrder.js b/tsc/testdata/baselines/reference/compiler/unionOverloadSignatureOrder.js new file mode 100644 index 0000000000000..007c5be42f05f --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/unionOverloadSignatureOrder.js @@ -0,0 +1,99 @@ +//// [tests/cases/compiler/unionOverloadSignatureOrder.ts] //// + +//// [unionOverloadSignatureOrder.ts] +namespace Unprimed { + interface Alpha { + foo(n: "str", opt?: boolean): string; + } + + interface Beta { + foo(n: "str", opt?: true): string; + foo(n: string): number | string; + } + + declare let alphaBeta: Alpha | Beta; + declare let betaAlpha: Beta | Alpha; + + const alphaBetaResult: string = alphaBeta.foo("str"); + const betaAlphaResult: string = betaAlpha.foo("str"); +} + +namespace Primed { + interface Alpha { + foo(n: "str", opt?: boolean): string; + } + + type B = Beta["foo"]; + + interface Beta { + foo(n: "str", opt?: true): string; + foo(n: string): number | string; + } + + declare let alphaBeta: Alpha | Beta; + declare let betaAlpha: Beta | Alpha; + + const alphaBetaResult: string = alphaBeta.foo("str"); + const betaAlphaResult: string = betaAlpha.foo("str"); +} + +namespace MultipleOverloads { + interface Alpha { + foo(type: "num", opts?: unknown): number; + foo(type: "str", opts?: unknown): string; + foo(type: string, opts?: unknown): number | string; + } + + interface Beta { + foo(type: "num", opts?: { a?: string }): number; + foo(type: "str", opts?: { b?: string }): string; + foo(type: "num" | "str", opts?: unknown): number | string; + } + + declare let beta: Beta; + beta.foo("str"); + + declare let alphaBeta: Alpha | Beta; + const result: string = alphaBeta.foo("str"); + alphaBeta.foo("other"); + alphaBeta.foo("str", false); +} + +namespace ReversedDeclarations { + interface Beta { + foo(n: "str", opt?: true): string; + foo(n: string): number | string; + } + + interface Alpha { + foo(n: "str", opt?: boolean): string; + } + + declare let alphaBeta: Alpha | Beta; + const result: string = alphaBeta.foo("str"); +} + + +//// [unionOverloadSignatureOrder.js] +"use strict"; +var Unprimed; +(function (Unprimed) { + const alphaBetaResult = alphaBeta.foo("str"); + const betaAlphaResult = betaAlpha.foo("str"); +})(Unprimed || (Unprimed = {})); +var Primed; +(function (Primed) { + const alphaBetaResult = alphaBeta.foo("str"); + const betaAlphaResult = betaAlpha.foo("str"); +})(Primed || (Primed = {})); +var MultipleOverloads; +(function (MultipleOverloads) { + beta.foo("str"); + const result = alphaBeta.foo("str"); + alphaBeta.foo("other"); + alphaBeta.foo("str", false); +})(MultipleOverloads || (MultipleOverloads = {})); +var ReversedDeclarations; +(function (ReversedDeclarations) { + const result = alphaBeta.foo("str"); +})(ReversedDeclarations || (ReversedDeclarations = {})); diff --git a/tsc/testdata/baselines/reference/compiler/unionOverloadSignatureOrder.symbols b/tsc/testdata/baselines/reference/compiler/unionOverloadSignatureOrder.symbols new file mode 100644 index 0000000000000..855d3c0ae34a1 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/unionOverloadSignatureOrder.symbols @@ -0,0 +1,214 @@ +//// [tests/cases/compiler/unionOverloadSignatureOrder.ts] //// + +=== unionOverloadSignatureOrder.ts === +namespace Unprimed { +>Unprimed : Symbol(Unprimed, Decl(unionOverloadSignatureOrder.ts, 0, 0)) + + interface Alpha { +>Alpha : Symbol(Alpha, Decl(unionOverloadSignatureOrder.ts, 0, 20)) + + foo(n: "str", opt?: boolean): string; +>foo : Symbol(Alpha.foo, Decl(unionOverloadSignatureOrder.ts, 1, 21)) +>n : Symbol(n, Decl(unionOverloadSignatureOrder.ts, 2, 12)) +>opt : Symbol(opt, Decl(unionOverloadSignatureOrder.ts, 2, 21)) + } + + interface Beta { +>Beta : Symbol(Beta, Decl(unionOverloadSignatureOrder.ts, 3, 5)) + + foo(n: "str", opt?: true): string; +>foo : Symbol(Beta.foo, Decl(unionOverloadSignatureOrder.ts, 5, 20), Decl(unionOverloadSignatureOrder.ts, 6, 42)) +>n : Symbol(n, Decl(unionOverloadSignatureOrder.ts, 6, 12)) +>opt : Symbol(opt, Decl(unionOverloadSignatureOrder.ts, 6, 21)) + + foo(n: string): number | string; +>foo : Symbol(Beta.foo, Decl(unionOverloadSignatureOrder.ts, 5, 20), Decl(unionOverloadSignatureOrder.ts, 6, 42)) +>n : Symbol(n, Decl(unionOverloadSignatureOrder.ts, 7, 12)) + } + + declare let alphaBeta: Alpha | Beta; +>alphaBeta : Symbol(alphaBeta, Decl(unionOverloadSignatureOrder.ts, 10, 15)) +>Alpha : Symbol(Alpha, Decl(unionOverloadSignatureOrder.ts, 0, 20)) +>Beta : Symbol(Beta, Decl(unionOverloadSignatureOrder.ts, 3, 5)) + + declare let betaAlpha: Beta | Alpha; +>betaAlpha : Symbol(betaAlpha, Decl(unionOverloadSignatureOrder.ts, 11, 15)) +>Beta : Symbol(Beta, Decl(unionOverloadSignatureOrder.ts, 3, 5)) +>Alpha : Symbol(Alpha, Decl(unionOverloadSignatureOrder.ts, 0, 20)) + + const alphaBetaResult: string = alphaBeta.foo("str"); +>alphaBetaResult : Symbol(alphaBetaResult, Decl(unionOverloadSignatureOrder.ts, 13, 9)) +>alphaBeta.foo : Symbol(foo, Decl(unionOverloadSignatureOrder.ts, 1, 21), Decl(unionOverloadSignatureOrder.ts, 5, 20), Decl(unionOverloadSignatureOrder.ts, 6, 42)) +>alphaBeta : Symbol(alphaBeta, Decl(unionOverloadSignatureOrder.ts, 10, 15)) +>foo : Symbol(foo, Decl(unionOverloadSignatureOrder.ts, 1, 21), Decl(unionOverloadSignatureOrder.ts, 5, 20), Decl(unionOverloadSignatureOrder.ts, 6, 42)) + + const betaAlphaResult: string = betaAlpha.foo("str"); +>betaAlphaResult : Symbol(betaAlphaResult, Decl(unionOverloadSignatureOrder.ts, 14, 9)) +>betaAlpha.foo : Symbol(foo, Decl(unionOverloadSignatureOrder.ts, 1, 21), Decl(unionOverloadSignatureOrder.ts, 5, 20), Decl(unionOverloadSignatureOrder.ts, 6, 42)) +>betaAlpha : Symbol(betaAlpha, Decl(unionOverloadSignatureOrder.ts, 11, 15)) +>foo : Symbol(foo, Decl(unionOverloadSignatureOrder.ts, 1, 21), Decl(unionOverloadSignatureOrder.ts, 5, 20), Decl(unionOverloadSignatureOrder.ts, 6, 42)) +} + +namespace Primed { +>Primed : Symbol(Primed, Decl(unionOverloadSignatureOrder.ts, 15, 1)) + + interface Alpha { +>Alpha : Symbol(Alpha, Decl(unionOverloadSignatureOrder.ts, 17, 18)) + + foo(n: "str", opt?: boolean): string; +>foo : Symbol(Alpha.foo, Decl(unionOverloadSignatureOrder.ts, 18, 21)) +>n : Symbol(n, Decl(unionOverloadSignatureOrder.ts, 19, 12)) +>opt : Symbol(opt, Decl(unionOverloadSignatureOrder.ts, 19, 21)) + } + + type B = Beta["foo"]; +>B : Symbol(B, Decl(unionOverloadSignatureOrder.ts, 20, 5)) +>Beta : Symbol(Beta, Decl(unionOverloadSignatureOrder.ts, 22, 25)) + + interface Beta { +>Beta : Symbol(Beta, Decl(unionOverloadSignatureOrder.ts, 22, 25)) + + foo(n: "str", opt?: true): string; +>foo : Symbol(Beta.foo, Decl(unionOverloadSignatureOrder.ts, 24, 20), Decl(unionOverloadSignatureOrder.ts, 25, 42)) +>n : Symbol(n, Decl(unionOverloadSignatureOrder.ts, 25, 12)) +>opt : Symbol(opt, Decl(unionOverloadSignatureOrder.ts, 25, 21)) + + foo(n: string): number | string; +>foo : Symbol(Beta.foo, Decl(unionOverloadSignatureOrder.ts, 24, 20), Decl(unionOverloadSignatureOrder.ts, 25, 42)) +>n : Symbol(n, Decl(unionOverloadSignatureOrder.ts, 26, 12)) + } + + declare let alphaBeta: Alpha | Beta; +>alphaBeta : Symbol(alphaBeta, Decl(unionOverloadSignatureOrder.ts, 29, 15)) +>Alpha : Symbol(Alpha, Decl(unionOverloadSignatureOrder.ts, 17, 18)) +>Beta : Symbol(Beta, Decl(unionOverloadSignatureOrder.ts, 22, 25)) + + declare let betaAlpha: Beta | Alpha; +>betaAlpha : Symbol(betaAlpha, Decl(unionOverloadSignatureOrder.ts, 30, 15)) +>Beta : Symbol(Beta, Decl(unionOverloadSignatureOrder.ts, 22, 25)) +>Alpha : Symbol(Alpha, Decl(unionOverloadSignatureOrder.ts, 17, 18)) + + const alphaBetaResult: string = alphaBeta.foo("str"); +>alphaBetaResult : Symbol(alphaBetaResult, Decl(unionOverloadSignatureOrder.ts, 32, 9)) +>alphaBeta.foo : Symbol(foo, Decl(unionOverloadSignatureOrder.ts, 18, 21), Decl(unionOverloadSignatureOrder.ts, 24, 20), Decl(unionOverloadSignatureOrder.ts, 25, 42)) +>alphaBeta : Symbol(alphaBeta, Decl(unionOverloadSignatureOrder.ts, 29, 15)) +>foo : Symbol(foo, Decl(unionOverloadSignatureOrder.ts, 18, 21), Decl(unionOverloadSignatureOrder.ts, 24, 20), Decl(unionOverloadSignatureOrder.ts, 25, 42)) + + const betaAlphaResult: string = betaAlpha.foo("str"); +>betaAlphaResult : Symbol(betaAlphaResult, Decl(unionOverloadSignatureOrder.ts, 33, 9)) +>betaAlpha.foo : Symbol(foo, Decl(unionOverloadSignatureOrder.ts, 18, 21), Decl(unionOverloadSignatureOrder.ts, 24, 20), Decl(unionOverloadSignatureOrder.ts, 25, 42)) +>betaAlpha : Symbol(betaAlpha, Decl(unionOverloadSignatureOrder.ts, 30, 15)) +>foo : Symbol(foo, Decl(unionOverloadSignatureOrder.ts, 18, 21), Decl(unionOverloadSignatureOrder.ts, 24, 20), Decl(unionOverloadSignatureOrder.ts, 25, 42)) +} + +namespace MultipleOverloads { +>MultipleOverloads : Symbol(MultipleOverloads, Decl(unionOverloadSignatureOrder.ts, 34, 1)) + + interface Alpha { +>Alpha : Symbol(Alpha, Decl(unionOverloadSignatureOrder.ts, 36, 29)) + + foo(type: "num", opts?: unknown): number; +>foo : Symbol(Alpha.foo, Decl(unionOverloadSignatureOrder.ts, 37, 21), Decl(unionOverloadSignatureOrder.ts, 38, 49), Decl(unionOverloadSignatureOrder.ts, 39, 49)) +>type : Symbol(type, Decl(unionOverloadSignatureOrder.ts, 38, 12)) +>opts : Symbol(opts, Decl(unionOverloadSignatureOrder.ts, 38, 24)) + + foo(type: "str", opts?: unknown): string; +>foo : Symbol(Alpha.foo, Decl(unionOverloadSignatureOrder.ts, 37, 21), Decl(unionOverloadSignatureOrder.ts, 38, 49), Decl(unionOverloadSignatureOrder.ts, 39, 49)) +>type : Symbol(type, Decl(unionOverloadSignatureOrder.ts, 39, 12)) +>opts : Symbol(opts, Decl(unionOverloadSignatureOrder.ts, 39, 24)) + + foo(type: string, opts?: unknown): number | string; +>foo : Symbol(Alpha.foo, Decl(unionOverloadSignatureOrder.ts, 37, 21), Decl(unionOverloadSignatureOrder.ts, 38, 49), Decl(unionOverloadSignatureOrder.ts, 39, 49)) +>type : Symbol(type, Decl(unionOverloadSignatureOrder.ts, 40, 12)) +>opts : Symbol(opts, Decl(unionOverloadSignatureOrder.ts, 40, 25)) + } + + interface Beta { +>Beta : Symbol(Beta, Decl(unionOverloadSignatureOrder.ts, 41, 5)) + + foo(type: "num", opts?: { a?: string }): number; +>foo : Symbol(Beta.foo, Decl(unionOverloadSignatureOrder.ts, 43, 20), Decl(unionOverloadSignatureOrder.ts, 44, 56), Decl(unionOverloadSignatureOrder.ts, 45, 56)) +>type : Symbol(type, Decl(unionOverloadSignatureOrder.ts, 44, 12)) +>opts : Symbol(opts, Decl(unionOverloadSignatureOrder.ts, 44, 24)) +>a : Symbol(a, Decl(unionOverloadSignatureOrder.ts, 44, 33)) + + foo(type: "str", opts?: { b?: string }): string; +>foo : Symbol(Beta.foo, Decl(unionOverloadSignatureOrder.ts, 43, 20), Decl(unionOverloadSignatureOrder.ts, 44, 56), Decl(unionOverloadSignatureOrder.ts, 45, 56)) +>type : Symbol(type, Decl(unionOverloadSignatureOrder.ts, 45, 12)) +>opts : Symbol(opts, Decl(unionOverloadSignatureOrder.ts, 45, 24)) +>b : Symbol(b, Decl(unionOverloadSignatureOrder.ts, 45, 33)) + + foo(type: "num" | "str", opts?: unknown): number | string; +>foo : Symbol(Beta.foo, Decl(unionOverloadSignatureOrder.ts, 43, 20), Decl(unionOverloadSignatureOrder.ts, 44, 56), Decl(unionOverloadSignatureOrder.ts, 45, 56)) +>type : Symbol(type, Decl(unionOverloadSignatureOrder.ts, 46, 12)) +>opts : Symbol(opts, Decl(unionOverloadSignatureOrder.ts, 46, 32)) + } + + declare let beta: Beta; +>beta : Symbol(beta, Decl(unionOverloadSignatureOrder.ts, 49, 15)) +>Beta : Symbol(Beta, Decl(unionOverloadSignatureOrder.ts, 41, 5)) + + beta.foo("str"); +>beta.foo : Symbol(Beta.foo, Decl(unionOverloadSignatureOrder.ts, 43, 20), Decl(unionOverloadSignatureOrder.ts, 44, 56), Decl(unionOverloadSignatureOrder.ts, 45, 56)) +>beta : Symbol(beta, Decl(unionOverloadSignatureOrder.ts, 49, 15)) +>foo : Symbol(Beta.foo, Decl(unionOverloadSignatureOrder.ts, 43, 20), Decl(unionOverloadSignatureOrder.ts, 44, 56), Decl(unionOverloadSignatureOrder.ts, 45, 56)) + + declare let alphaBeta: Alpha | Beta; +>alphaBeta : Symbol(alphaBeta, Decl(unionOverloadSignatureOrder.ts, 52, 15)) +>Alpha : Symbol(Alpha, Decl(unionOverloadSignatureOrder.ts, 36, 29)) +>Beta : Symbol(Beta, Decl(unionOverloadSignatureOrder.ts, 41, 5)) + + const result: string = alphaBeta.foo("str"); +>result : Symbol(result, Decl(unionOverloadSignatureOrder.ts, 53, 9)) +>alphaBeta.foo : Symbol(foo, Decl(unionOverloadSignatureOrder.ts, 37, 21), Decl(unionOverloadSignatureOrder.ts, 38, 49), Decl(unionOverloadSignatureOrder.ts, 39, 49), Decl(unionOverloadSignatureOrder.ts, 43, 20), Decl(unionOverloadSignatureOrder.ts, 44, 56) ... and 1 more) +>alphaBeta : Symbol(alphaBeta, Decl(unionOverloadSignatureOrder.ts, 52, 15)) +>foo : Symbol(foo, Decl(unionOverloadSignatureOrder.ts, 37, 21), Decl(unionOverloadSignatureOrder.ts, 38, 49), Decl(unionOverloadSignatureOrder.ts, 39, 49), Decl(unionOverloadSignatureOrder.ts, 43, 20), Decl(unionOverloadSignatureOrder.ts, 44, 56) ... and 1 more) + + alphaBeta.foo("other"); +>alphaBeta.foo : Symbol(foo, Decl(unionOverloadSignatureOrder.ts, 37, 21), Decl(unionOverloadSignatureOrder.ts, 38, 49), Decl(unionOverloadSignatureOrder.ts, 39, 49), Decl(unionOverloadSignatureOrder.ts, 43, 20), Decl(unionOverloadSignatureOrder.ts, 44, 56) ... and 1 more) +>alphaBeta : Symbol(alphaBeta, Decl(unionOverloadSignatureOrder.ts, 52, 15)) +>foo : Symbol(foo, Decl(unionOverloadSignatureOrder.ts, 37, 21), Decl(unionOverloadSignatureOrder.ts, 38, 49), Decl(unionOverloadSignatureOrder.ts, 39, 49), Decl(unionOverloadSignatureOrder.ts, 43, 20), Decl(unionOverloadSignatureOrder.ts, 44, 56) ... and 1 more) + + alphaBeta.foo("str", false); +>alphaBeta.foo : Symbol(foo, Decl(unionOverloadSignatureOrder.ts, 37, 21), Decl(unionOverloadSignatureOrder.ts, 38, 49), Decl(unionOverloadSignatureOrder.ts, 39, 49), Decl(unionOverloadSignatureOrder.ts, 43, 20), Decl(unionOverloadSignatureOrder.ts, 44, 56) ... and 1 more) +>alphaBeta : Symbol(alphaBeta, Decl(unionOverloadSignatureOrder.ts, 52, 15)) +>foo : Symbol(foo, Decl(unionOverloadSignatureOrder.ts, 37, 21), Decl(unionOverloadSignatureOrder.ts, 38, 49), Decl(unionOverloadSignatureOrder.ts, 39, 49), Decl(unionOverloadSignatureOrder.ts, 43, 20), Decl(unionOverloadSignatureOrder.ts, 44, 56) ... and 1 more) +} + +namespace ReversedDeclarations { +>ReversedDeclarations : Symbol(ReversedDeclarations, Decl(unionOverloadSignatureOrder.ts, 56, 1)) + + interface Beta { +>Beta : Symbol(Beta, Decl(unionOverloadSignatureOrder.ts, 58, 32)) + + foo(n: "str", opt?: true): string; +>foo : Symbol(Beta.foo, Decl(unionOverloadSignatureOrder.ts, 59, 20), Decl(unionOverloadSignatureOrder.ts, 60, 42)) +>n : Symbol(n, Decl(unionOverloadSignatureOrder.ts, 60, 12)) +>opt : Symbol(opt, Decl(unionOverloadSignatureOrder.ts, 60, 21)) + + foo(n: string): number | string; +>foo : Symbol(Beta.foo, Decl(unionOverloadSignatureOrder.ts, 59, 20), Decl(unionOverloadSignatureOrder.ts, 60, 42)) +>n : Symbol(n, Decl(unionOverloadSignatureOrder.ts, 61, 12)) + } + + interface Alpha { +>Alpha : Symbol(Alpha, Decl(unionOverloadSignatureOrder.ts, 62, 5)) + + foo(n: "str", opt?: boolean): string; +>foo : Symbol(Alpha.foo, Decl(unionOverloadSignatureOrder.ts, 64, 21)) +>n : Symbol(n, Decl(unionOverloadSignatureOrder.ts, 65, 12)) +>opt : Symbol(opt, Decl(unionOverloadSignatureOrder.ts, 65, 21)) + } + + declare let alphaBeta: Alpha | Beta; +>alphaBeta : Symbol(alphaBeta, Decl(unionOverloadSignatureOrder.ts, 68, 15)) +>Alpha : Symbol(Alpha, Decl(unionOverloadSignatureOrder.ts, 62, 5)) +>Beta : Symbol(Beta, Decl(unionOverloadSignatureOrder.ts, 58, 32)) + + const result: string = alphaBeta.foo("str"); +>result : Symbol(result, Decl(unionOverloadSignatureOrder.ts, 69, 9)) +>alphaBeta.foo : Symbol(foo, Decl(unionOverloadSignatureOrder.ts, 64, 21), Decl(unionOverloadSignatureOrder.ts, 59, 20), Decl(unionOverloadSignatureOrder.ts, 60, 42)) +>alphaBeta : Symbol(alphaBeta, Decl(unionOverloadSignatureOrder.ts, 68, 15)) +>foo : Symbol(foo, Decl(unionOverloadSignatureOrder.ts, 64, 21), Decl(unionOverloadSignatureOrder.ts, 59, 20), Decl(unionOverloadSignatureOrder.ts, 60, 42)) +} + diff --git a/tsc/testdata/baselines/reference/compiler/unionOverloadSignatureOrder.types b/tsc/testdata/baselines/reference/compiler/unionOverloadSignatureOrder.types new file mode 100644 index 0000000000000..1a33ac16347cb --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/unionOverloadSignatureOrder.types @@ -0,0 +1,206 @@ +//// [tests/cases/compiler/unionOverloadSignatureOrder.ts] //// + +=== unionOverloadSignatureOrder.ts === +namespace Unprimed { +>Unprimed : typeof Unprimed + + interface Alpha { + foo(n: "str", opt?: boolean): string; +>foo : (n: "str", opt?: boolean) => string +>n : "str" +>opt : boolean | undefined + } + + interface Beta { + foo(n: "str", opt?: true): string; +>foo : { (n: "str", opt?: true): string; (n: string): number | string; } +>n : "str" +>opt : true | undefined +>true : true + + foo(n: string): number | string; +>foo : { (n: "str", opt?: true): string; (n: string): number | string; } +>n : string + } + + declare let alphaBeta: Alpha | Beta; +>alphaBeta : Alpha | Beta + + declare let betaAlpha: Beta | Alpha; +>betaAlpha : Alpha | Beta + + const alphaBetaResult: string = alphaBeta.foo("str"); +>alphaBetaResult : string +>alphaBeta.foo("str") : string +>alphaBeta.foo : ((n: "str", opt?: boolean) => string) | { (n: "str", opt?: true): string; (n: string): number | string; } +>alphaBeta : Alpha | Beta +>foo : ((n: "str", opt?: boolean) => string) | { (n: "str", opt?: true): string; (n: string): number | string; } +>"str" : "str" + + const betaAlphaResult: string = betaAlpha.foo("str"); +>betaAlphaResult : string +>betaAlpha.foo("str") : string +>betaAlpha.foo : ((n: "str", opt?: boolean) => string) | { (n: "str", opt?: true): string; (n: string): number | string; } +>betaAlpha : Alpha | Beta +>foo : ((n: "str", opt?: boolean) => string) | { (n: "str", opt?: true): string; (n: string): number | string; } +>"str" : "str" +} + +namespace Primed { +>Primed : typeof Primed + + interface Alpha { + foo(n: "str", opt?: boolean): string; +>foo : (n: "str", opt?: boolean) => string +>n : "str" +>opt : boolean | undefined + } + + type B = Beta["foo"]; +>B : { (n: "str", opt?: true): string; (n: string): number | string; } + + interface Beta { + foo(n: "str", opt?: true): string; +>foo : { (n: "str", opt?: true): string; (n: string): number | string; } +>n : "str" +>opt : true | undefined +>true : true + + foo(n: string): number | string; +>foo : { (n: "str", opt?: true): string; (n: string): number | string; } +>n : string + } + + declare let alphaBeta: Alpha | Beta; +>alphaBeta : Alpha | Beta + + declare let betaAlpha: Beta | Alpha; +>betaAlpha : Alpha | Beta + + const alphaBetaResult: string = alphaBeta.foo("str"); +>alphaBetaResult : string +>alphaBeta.foo("str") : string +>alphaBeta.foo : ((n: "str", opt?: boolean) => string) | { (n: "str", opt?: true): string; (n: string): number | string; } +>alphaBeta : Alpha | Beta +>foo : ((n: "str", opt?: boolean) => string) | { (n: "str", opt?: true): string; (n: string): number | string; } +>"str" : "str" + + const betaAlphaResult: string = betaAlpha.foo("str"); +>betaAlphaResult : string +>betaAlpha.foo("str") : string +>betaAlpha.foo : ((n: "str", opt?: boolean) => string) | { (n: "str", opt?: true): string; (n: string): number | string; } +>betaAlpha : Alpha | Beta +>foo : ((n: "str", opt?: boolean) => string) | { (n: "str", opt?: true): string; (n: string): number | string; } +>"str" : "str" +} + +namespace MultipleOverloads { +>MultipleOverloads : typeof MultipleOverloads + + interface Alpha { + foo(type: "num", opts?: unknown): number; +>foo : { (type: "num", opts?: unknown): number; (type: "str", opts?: unknown): string; (type: string, opts?: unknown): number | string; } +>type : "num" +>opts : unknown + + foo(type: "str", opts?: unknown): string; +>foo : { (type: "num", opts?: unknown): number; (type: "str", opts?: unknown): string; (type: string, opts?: unknown): number | string; } +>type : "str" +>opts : unknown + + foo(type: string, opts?: unknown): number | string; +>foo : { (type: "num", opts?: unknown): number; (type: "str", opts?: unknown): string; (type: string, opts?: unknown): number | string; } +>type : string +>opts : unknown + } + + interface Beta { + foo(type: "num", opts?: { a?: string }): number; +>foo : { (type: "num", opts?: { a?: string; }): number; (type: "str", opts?: { b?: string; }): string; (type: "num" | "str", opts?: unknown): number | string; } +>type : "num" +>opts : { a?: string; } | undefined +>a : string | undefined + + foo(type: "str", opts?: { b?: string }): string; +>foo : { (type: "num", opts?: { a?: string; }): number; (type: "str", opts?: { b?: string; }): string; (type: "num" | "str", opts?: unknown): number | string; } +>type : "str" +>opts : { b?: string; } | undefined +>b : string | undefined + + foo(type: "num" | "str", opts?: unknown): number | string; +>foo : { (type: "num", opts?: { a?: string; }): number; (type: "str", opts?: { b?: string; }): string; (type: "num" | "str", opts?: unknown): number | string; } +>type : "num" | "str" +>opts : unknown + } + + declare let beta: Beta; +>beta : Beta + + beta.foo("str"); +>beta.foo("str") : string +>beta.foo : { (type: "num", opts?: { a?: string; }): number; (type: "str", opts?: { b?: string; }): string; (type: "num" | "str", opts?: unknown): number | string; } +>beta : Beta +>foo : { (type: "num", opts?: { a?: string; }): number; (type: "str", opts?: { b?: string; }): string; (type: "num" | "str", opts?: unknown): number | string; } +>"str" : "str" + + declare let alphaBeta: Alpha | Beta; +>alphaBeta : Alpha | Beta + + const result: string = alphaBeta.foo("str"); +>result : string +>alphaBeta.foo("str") : string +>alphaBeta.foo : { (type: "num", opts?: unknown): number; (type: "str", opts?: unknown): string; (type: string, opts?: unknown): number | string; } | { (type: "num", opts?: { a?: string; }): number; (type: "str", opts?: { b?: string; }): string; (type: "num" | "str", opts?: unknown): number | string; } +>alphaBeta : Alpha | Beta +>foo : { (type: "num", opts?: unknown): number; (type: "str", opts?: unknown): string; (type: string, opts?: unknown): number | string; } | { (type: "num", opts?: { a?: string; }): number; (type: "str", opts?: { b?: string; }): string; (type: "num" | "str", opts?: unknown): number | string; } +>"str" : "str" + + alphaBeta.foo("other"); +>alphaBeta.foo("other") : never +>alphaBeta.foo : { (type: "num", opts?: unknown): number; (type: "str", opts?: unknown): string; (type: string, opts?: unknown): number | string; } | { (type: "num", opts?: { a?: string; }): number; (type: "str", opts?: { b?: string; }): string; (type: "num" | "str", opts?: unknown): number | string; } +>alphaBeta : Alpha | Beta +>foo : { (type: "num", opts?: unknown): number; (type: "str", opts?: unknown): string; (type: string, opts?: unknown): number | string; } | { (type: "num", opts?: { a?: string; }): number; (type: "str", opts?: { b?: string; }): string; (type: "num" | "str", opts?: unknown): number | string; } +>"other" : "other" + + alphaBeta.foo("str", false); +>alphaBeta.foo("str", false) : string +>alphaBeta.foo : { (type: "num", opts?: unknown): number; (type: "str", opts?: unknown): string; (type: string, opts?: unknown): number | string; } | { (type: "num", opts?: { a?: string; }): number; (type: "str", opts?: { b?: string; }): string; (type: "num" | "str", opts?: unknown): number | string; } +>alphaBeta : Alpha | Beta +>foo : { (type: "num", opts?: unknown): number; (type: "str", opts?: unknown): string; (type: string, opts?: unknown): number | string; } | { (type: "num", opts?: { a?: string; }): number; (type: "str", opts?: { b?: string; }): string; (type: "num" | "str", opts?: unknown): number | string; } +>"str" : "str" +>false : false +} + +namespace ReversedDeclarations { +>ReversedDeclarations : typeof ReversedDeclarations + + interface Beta { + foo(n: "str", opt?: true): string; +>foo : { (n: "str", opt?: true): string; (n: string): number | string; } +>n : "str" +>opt : true | undefined +>true : true + + foo(n: string): number | string; +>foo : { (n: "str", opt?: true): string; (n: string): number | string; } +>n : string + } + + interface Alpha { + foo(n: "str", opt?: boolean): string; +>foo : (n: "str", opt?: boolean) => string +>n : "str" +>opt : boolean | undefined + } + + declare let alphaBeta: Alpha | Beta; +>alphaBeta : Alpha | Beta + + const result: string = alphaBeta.foo("str"); +>result : string +>alphaBeta.foo("str") : string +>alphaBeta.foo : { (n: "str", opt?: true): string; (n: string): number | string; } | ((n: "str", opt?: boolean) => string) +>alphaBeta : Alpha | Beta +>foo : { (n: "str", opt?: true): string; (n: string): number | string; } | ((n: "str", opt?: boolean) => string) +>"str" : "str" +} + diff --git a/tsc/testdata/tests/cases/compiler/unionOverloadSignatureOrder.ts b/tsc/testdata/tests/cases/compiler/unionOverloadSignatureOrder.ts new file mode 100644 index 0000000000000..956605abb8b1e --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/unionOverloadSignatureOrder.ts @@ -0,0 +1,73 @@ +// @strict: true + +namespace Unprimed { + interface Alpha { + foo(n: "str", opt?: boolean): string; + } + + interface Beta { + foo(n: "str", opt?: true): string; + foo(n: string): number | string; + } + + declare let alphaBeta: Alpha | Beta; + declare let betaAlpha: Beta | Alpha; + + const alphaBetaResult: string = alphaBeta.foo("str"); + const betaAlphaResult: string = betaAlpha.foo("str"); +} + +namespace Primed { + interface Alpha { + foo(n: "str", opt?: boolean): string; + } + + type B = Beta["foo"]; + + interface Beta { + foo(n: "str", opt?: true): string; + foo(n: string): number | string; + } + + declare let alphaBeta: Alpha | Beta; + declare let betaAlpha: Beta | Alpha; + + const alphaBetaResult: string = alphaBeta.foo("str"); + const betaAlphaResult: string = betaAlpha.foo("str"); +} + +namespace MultipleOverloads { + interface Alpha { + foo(type: "num", opts?: unknown): number; + foo(type: "str", opts?: unknown): string; + foo(type: string, opts?: unknown): number | string; + } + + interface Beta { + foo(type: "num", opts?: { a?: string }): number; + foo(type: "str", opts?: { b?: string }): string; + foo(type: "num" | "str", opts?: unknown): number | string; + } + + declare let beta: Beta; + beta.foo("str"); + + declare let alphaBeta: Alpha | Beta; + const result: string = alphaBeta.foo("str"); + alphaBeta.foo("other"); + alphaBeta.foo("str", false); +} + +namespace ReversedDeclarations { + interface Beta { + foo(n: "str", opt?: true): string; + foo(n: string): number | string; + } + + interface Alpha { + foo(n: "str", opt?: boolean): string; + } + + declare let alphaBeta: Alpha | Beta; + const result: string = alphaBeta.foo("str"); +}