Skip to content

Type inference fails with complex generic tuples #4136

Closed

Description

@Ellisthion

I've been trying to come up with a smarter type def for Angular's $q.all (https://docs.angularjs.org/api/ng/service/$q#all) which takes an array of promises and spits out a promise with an array of results as the value.

For reference, the current DefinitelyTyped implementation is:

    all(promises: IPromise<any>[]): IPromise<any[]>;

I'm attempting to rewrite it with tuples, like so:

    all<T1, T2, T3>([t1, t2, t3]: [IPromise<T1>, IPromise<T2>, IPromise<T3>]): IPromise<[T1, T2, T3]>;
    all<T1, T2>([t1, t2]: [IPromise<T1>, IPromise<T2>]): IPromise<[T1, T2]>;
    all<T1>([t1]: [IPromise<T1>]): IPromise<[T1]>;

Usage:

    // Fails type inference, causes error
    var a = $q.all([$q.when<string>(), $q.when<number>()]);

    // Explicit types work fine
    var b = $q.all<string, number>([$q.when<string>(), $q.when<number>()]);

    // Same generic type works fine
    var c = $q.all([$q.when<string>(), $q.when<string>()]);

Full example on Typescript playground: http://goo.gl/UOKBp7

Attempting to use this with multiple different implicit generic types (example a) causes this error:

The type argument for type parameter 'T1' cannot be inferred from the usage. Consider specifying the type arguments explicitly. The argument candidate 'string' is not a valid type argument because it is not a supertype of candidate 'number'.

As far as I can tell, the Typescript compiler should (ideally) be able to infer this fine. The error seems wrong: 'number' shouldn't be a candidate for T1 at all.

Activity

  1. ahejlsberg commented on Aug 4, 2015

    @ahejlsberg
    Member

    We currently treat tuple types like any other object type in type inference. Tuples are basically arrays with extra numerically named members for the elements and a union of the tuple types as the array element type. It is this union that messes up type inference: Instead of inferring string for T1 and number for T2, we end up inferring both string and number for both T1 and T2. This also explains why it works when T1 and T2 are the same type.

    It's fairly easy to fix, we just need to special case tuple-to-tuple inference and not dive into the structure of the types as we do now.

  2. locked and limited conversation to collaborators on Jun 19, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

In DiscussionNot yet reached consensusSuggestionAn idea for TypeScript

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions