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
31 changes: 31 additions & 0 deletions tsc/internal/checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -21509,6 +21509,37 @@ func (c *Checker) getUnionSignatures(signatureLists [][]*Signature) []*Signature
}
result = results
}
isMoreSpecific := func(a, b *Signature) bool {
if len(a.typeParameters) != 0 || len(b.typeParameters) != 0 || c.getParameterCount(a) != c.getParameterCount(b) || c.getMinArgumentCount(a) != c.getMinArgumentCount(b) || c.hasEffectiveRestParameter(a) != c.hasEffectiveRestParameter(b) {
return false
}
aThis := c.getThisTypeOfSignature(a)
bThis := c.getThisTypeOfSignature(b)
if aThis != bThis && (aThis == nil || bThis == nil || c.compareTypesIdentical(aThis, bThis) == TernaryFalse) {
return false
}
aMoreSpecific := true
bMoreSpecific := true
for i := range c.getParameterCount(a) {
aMoreSpecific = aMoreSpecific && c.compareTypesSubtypeOf(c.getTypeAtPosition(a, i), c.getTypeAtPosition(b, i)) != TernaryFalse
bMoreSpecific = bMoreSpecific && c.compareTypesSubtypeOf(c.getTypeAtPosition(b, i), c.getTypeAtPosition(a, i)) != TernaryFalse
}
return aMoreSpecific && !bMoreSpecific
}
for i := 1; i < len(result); i++ {
insertionIndex := i
for j := range i {
if isMoreSpecific(result[i], result[j]) {
insertionIndex = j
break
}
}
if insertionIndex != i {
signature := result[i]
copy(result[insertionIndex+1:i+1], result[insertionIndex:i])
result[insertionIndex] = signature
}
}
return result
}

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