Skip to content

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

Description

@pelotom

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

Activity

  1. RyanCavanaugh commented on Oct 1, 2018

    @RyanCavanaugh
    Member

    Anders Hejlsberg (@ahejlsberg) bug? feature request?

  2. ahejlsberg commented on Oct 9, 2018

    @ahejlsberg
    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.

  3. added
    Design LimitationConstraints of the existing architecture prevent this from being fixed
    and removed
    Needs InvestigationThis issue needs a team member to investigate its status.
    on Oct 9, 2018
  4. jcalz commented on Jun 3, 2019

    @jcalz
    Contributor

    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

Metadata

Metadata

Labels

Design LimitationConstraints of the existing architecture prevent this from being fixed

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions