Skip to content

Mappable tuples with constraints are unwieldy due to lack of covariance #27351

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
pelotom opened this issue Sep 25, 2018 · 3 comments
Closed
Assignees
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed

Comments

@pelotom
Copy link

pelotom commented Sep 25, 2018

TypeScript Version: 3.1.0-dev.20180925

Search Terms: mappable tuples constraints covariance

I'm trying to make use of the new "mappable tuple and array types" coming in 3.1, and discovered that it's a bit awkward to work with arrays constrained to a particular type.

Code

interface WithFoo<T = any> {
  foo: T;
}

type SelectFoos<A extends WithFoo[]> = { [K in keyof A]: A[K]['foo'] };

Expected behavior:

Should compile.

Actual behavior:

Error: Type '"foo"' cannot be used to index type 'A[K]'..

Notes

It's possible to work around this using a conditional:

type SelectFoos<A extends WithFoo[]> = {
  [K in keyof A]: A[K] extends WithFoo ? A[K]['foo'] : never
};

but it seems like it should just work as is.

Playground Link

@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label Oct 1, 2018
@RyanCavanaugh
Copy link
Member

@ahejlsberg bug? feature request?

@ahejlsberg
Copy link
Member

The issue here is that even though a homomorphic mapped type only maps the element type(s) of the array or tuple, keyof A still includes the non-numeric properties of Array<T> (i.e. "length", "concat", etc.) and therefore A[keyof A] (the constraint of A[K]) is a large and fairly useless union type that can't be indexed with "foo".

We considered having keyof T for an array or tuple type not include non-numeric properties, but it would be a significant breaking change. For example, A["length"] wouldn't work anymore.

Given where we're at, your conditional type workaround seems reasonable.

@ahejlsberg ahejlsberg added Design Limitation Constraints of the existing architecture prevent this from being fixed and removed Needs Investigation This issue needs a team member to investigate its status. labels Oct 9, 2018
@jcalz
Copy link
Contributor

jcalz commented Jun 3, 2019

When mapping over the keys K in a type T constrained to an array type, is it possible to narrow K instead of T or keyof T? Assuming there were a "numericString" type, the suggestion is to treat

type MapArray<T extends {x: string}[]> = {[K in keyof T]: T[K]['x']}

like

type MapArray<T extends {x: string}[]> = {[K in keyof T]: T[K & numericString]['x']

That would possibly give the expected behavior here without pretending that keyof T is limited to the numeric keys, so T['length'] would still exist. Just a passing thought...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed
Projects
None yet
Development

No branches or pull requests

4 participants