Repository navigation
Allow function overloads with a varying parameter to unify, and inductively narrow the parameter when narrowing the return type #12885
Description
Activity
dead-claudia commented
on Dec 13, 2016 AuthorMore actionsYeah...I've picked up a few things on how partial types, readonly types,
_.pluck, among others, were all fixed with two new primitives: index types and mapped types.Oh, and this also would fix these two (among likely others):
- Uninformative error message in Incorrect error message when overloaded function is called with invalid parameter #12313 (it could show all nearby overloads instead)
- A missing overload in Some signatures should use union instead of overloads #5766 redundant with this proposal (similarly, lib.d.ts could really be simplified)
If type unions of functions are similarly unified, this would also fix #10620 (among likely others).
Similar induction with objects would also fix #12448, but that's beyond the scope of this proposal.
RyanCavanaugh commented
on Dec 13, 2016 MemberMore actionsDuplicate #7294 ?
I believe these are two issues. 1. issues like
String.split(#5766), where multiple overloads only differ in type of one parameter, and thus could not be called with a union type argument. and 2. calling signatures on a union type as (#7294).In DefinitelyTyped, we have added a tslint rule to flag these cases as an error (see unifiedSignaturesRule). We could incorporate this into the compiler, and make it an error to have two signatures vary only by the type of one paramter, but this would be a breaking change.
- addedSuggestionAn idea for TypeScriptAn idea for TypeScriptIn DiscussionNot yet reached consensusNot yet reached consensus
on Dec 14, 2016 just to clarify what i meant:
interface AcceptsStringAndNumber { push(a: string): void; push(a: number): void; } interface AcceptsString { push(a: string): void; } interface AcceptsNumber { push(a: number): void; } type AcceptsStringOrNumber = AcceptsString | AcceptsNumber; var value: string | number; var acceptsStringAndNumber: AcceptsStringAndNumber; acceptsStringAndNumber.push(value); // Safe, but not allowed var acceptsStringOrNumber: AcceptsStringOrNumber; acceptsStringOrNumber.push(value); // Unsafe, and not allowed
dead-claudia commented
on Dec 15, 2016 AuthorMore actionsYes, that is the correct understanding of the current state. In particular, I'm proposing the safe one to be unified, not the unsafe one. (This is mod the return type half, which is much more complex)…On Wed, Dec 14, 2016, 18:09 Mohamed Hegazy ***@***.***> wrote: just to clarify what i meant: interface AcceptsStringAndNumber { push(a: string): void; push(a: number): void; } interface AcceptsString { push(a: string): void; } interface AcceptsNumber { push(a: number): void; } type AcceptsStringOrNumber = AcceptsString | AcceptsNumber; var value: string | number; var acceptsStringAndNumber: AcceptsStringAndNumber;acceptsStringAndNumber.push(value); // Safe, but not allowed var acceptsStringOrNumber: AcceptsStringOrNumber;acceptsStringOrNumber.push(value); // Unsafe, and not allowed — You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub <#12885 (comment)>, or mute the thread <https://github.com/notifications/unsubscribe-auth/AERrBKiOF8R0PbxFVio-r3Tar-DoP78aks5rIHc5gaJpZM4LL5ym> .dead-claudia commented
on Dec 27, 2016 AuthorMore actionsTo clarify the return type half and its related inference, it's this:
declare const stringOrNumber: string | number; declare function convert(s: string): string; declare function convert(n: number): number; const result = convert(stringOrNumber); if (typeof result === "string") { // stringOrNumber is type `string` here } else { // stringOrNumber is type `number` here }
related: #6160
dead-claudia commented
on Apr 24, 2017 AuthorMore actionsClosing in favor of #13257, since that is a better thought out, more general superset of this.
- locked and limited conversation to collaborators
on Jun 19, 2018
I don't really know how to word the title for this one or explain it well...but here's what I'm thinking: it would be nice to allow function overloads to unify, provided only one parameter and possibly the return type are different across each overload. Additionally, when narrowing the returned type, it should be able to inductively narrow the overloaded parameter's type accordingly within the same block. To hopefully explain this a little better, here's what I mean:
In this case, if
resultis aFoo,strcan only possibly be a"foo"through induction, and similarlyresultbeing aBarandstrbeing a"bar".With #12883 also, this would also permit assertions to do compile-time type narrowing, without adding any new syntax or special casing of any particular identifier, hence fixing #12825 and #8655 simultaneously while remaining much more flexible:
I know this would likely be really hard to implement, but it would pay off. It helps that
booleanis equivalent totrue | false,"foo"is a subtype ofstring,Eis equivalent toE.A | E.B | E.Cwhereenum E {A, B, C}, etc., so much of the structural narrowing would allow this to apply to several other areas.Note that this would specifically not allow more than one varying type to be unified, because it would be an M⨯N type implication, which would be unrealistic to infer in practice (you would already need
lengthto be similarly guarded in theory):Sorry if I did a really poor job explaining it (I don't really know the correct technical term for this, hence the detailed examples).