Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion tsc/internal/checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -21449,6 +21449,10 @@ func (c *Checker) isReadonlyArraySymbol(symbol *ast.Symbol) bool {
// type is the union of the constituent return types.
func (c *Checker) getUnionSignatures(signatureLists [][]*Signature) []*Signature {
var result []*Signature
var priorities [][]int
orderedSignatureLists := core.Map(signatureLists, func(signatures []*Signature) []*Signature {
return c.reorderCandidates(signatures, SignatureFlagsNone)
})
var indexWithLengthOverOne int
var countLengthOverOne int
for i := range signatureLists {
Expand Down Expand Up @@ -21483,7 +21487,28 @@ func (c *Checker) getUnionSignatures(signatureLists [][]*Signature) []*Signature
s = c.createUnionSignature(signature, unionSignatures)
s.thisParameter = thisParameter
}
result = append(result, s)
priority := core.Map(orderedSignatureLists, func(signatures []*Signature) int {
return core.FindIndex(signatures, func(signature *Signature) bool {
return slices.Contains(unionSignatures, signature)
})
})
// A union candidate has precedence when its matching overloads occur no
// later in any constituent and earlier in at least one.
index := core.FindIndex(priorities, func(previous []int) bool {
earlier := false
for i, position := range priority {
if position < 0 || previous[i] < 0 || position > previous[i] {
return false
}
earlier = earlier || position < previous[i]
}
return earlier
})
if index < 0 {
index = len(result)
}
result = slices.Insert(result, index, s)
priorities = slices.Insert(priorities, index, priority)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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");
}

Original file line number Diff line number Diff line change
@@ -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 = {}));
Loading