Skip to content

Restricted generic ArrayLike parameter is deduced as never[] for empty array argument #11082

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
zenmumbler opened this issue Sep 23, 2016 · 2 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@zenmumbler
Copy link

TypeScript Version: 2.0.3

Code

interface MutableArrayLike<T> {
    readonly length: number;
    [n: number]: T;
}

type ArrayOfNumber = MutableArrayLike<number>;
type ArrayOfConstNumber = ArrayLike<number>; // has readonly subindex

interface vec3 {
    // the `out` array is modified and then returned as the function result
    subtract<T extends ArrayOfNumber>(out: T, a: ArrayOfConstNumber, b: ArrayOfConstNumber): T;
}

// later..
const result = vec3.subtract([], vA, vB);

Expected behavior:
Param out and the result are of type number[] or some looser type.

Actual behavior:
Param out and the result are of type never[]

Comments
strictNullChecks is on.

I realise that the compiler gets no help from an empty array parameter to deduce the type of its contents, but I was hoping my restricting of type T would either make it force the the type or throw an error. Making it a never[] seems a bit useless though I can intuit some of the reasoning of the compiler.

The interface works like this as the vec3 interface (from gl-matrix) deals with simple arrays or typed arrays so I typed everything to at least force numbers in there, but I was hoping that I could get it to set the result type to the type of the argument that I pass into the out param, because that is the value that is returned to facilitate easier chaining.

This may be a design limitation but I can always hope.

@ahejlsberg
Copy link
Member

ahejlsberg commented Oct 12, 2016

We infer never[] from the empty array literal. That is the most specific type possible and it is a subtype of the ArrayOfNumber constraint, so it seems entirely reasonable. It looks to me like your intent is to return some array-like type, but always with an element type of number. I can't think of any way to express that other than overloads:

interface vec3 {
    // the `out` array is modified and then returned as the function result
    subtract(out: number[], a: ArrayOfConstNumber, b: ArrayOfConstNumber): number[];
    subtract(out: ArrayOfNumber, a: ArrayOfConstNumber, b: ArrayOfConstNumber): ArrayOfNumber;
}

@ahejlsberg ahejlsberg added the Working as Intended The behavior described is the intended behavior; this is not a bug label Oct 12, 2016
@zenmumbler
Copy link
Author

Thanks for the feedback, I had not even considered using an overload in this case. I will try it out.

@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

3 participants