镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Key in mapped variadic tuple should not be literal after the variadic part #48856

Description

Bug Report

🔎 Search Terms

Variadic tuple mapped type keyof

🕗 Version & Regression Information

  • This is the behavior in every version I tried

⏯ Playground Link

Playground link with relevant code

💻 Code

type Keys<O extends unknown[]> = { [K in keyof O]: K };

type A = Keys<[string, ...string[]]>;
type B = Keys<[string, ...string[], number]>;

🙁 Actual behavior

A and B both have the variadic part typed as ..."1"[], which is wrong. B is further wrong because the number part becomes "2", while in practice it would rarely be "2".

🙂 Expected behavior

A should be ["0", ...number[]]; B should be ["0", ...number[], number]

Activity

  1. ahejlsberg commented on Apr 27, 2022

    @ahejlsberg
    Member

    I don't think this is a bug. Consider:

    type Box<T> = { value: T };
    type Boxified<T> = { [P in keyof T]: Box<T[P]> };
    
    type T0 = Boxified<[number, string, ...boolean[]]>;  // [Box<number>, Box<string>, ...Box<boolean>[]]

    With the proposed change, P would be number instead of "2" for the rest element, which means the resulting rest element would be ...Box<string | number | boolean>[] instead of just ...Box<boolean[]>. Not only is that less correct, it is a breaking change. Effectively, number is a less precise way of expressing "element at index 2 or above", whereas "2" gets much closer. This speaks to the fact that in homomorphic mappings over array and tuple types, the key types are just exemplars and not an exact representation of some specific property.

  2. added
    Working as IntendedThe behavior described is the intended behavior; this is not a bug
    and removed
    BugA bug in TypeScript
    on Apr 27, 2022
  3. Josh-Cena commented on Apr 28, 2022

    @Josh-Cena
    ContributorAuthor

    I also thought about that. The problem is it's really hard to be correct for both the key type itself, and for homomorphic mapped types to continue be homomorphic. However, accessing T[P] and P directly should be two orthogonal actions. In my actual case, I'm doing Entries instead of Keys:

    export type Entries<O extends unknown[]> = { [K in keyof O]: [K, O[K]] };

    In an ideal world, I'd like Entries<[number, string, ...boolean[]]> to be [["0", number], ["1", string], ...[number, boolean][]]. Does that sound reasonable?

    If we have subtracted types, the index should rather by Exclude<number, 0 | 1>, but since we are not there yet, I'd be more happy with number than 2 as the index type.

  4. typescript-bot commented on Apr 30, 2022

    @typescript-bot
    Contributor

    This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

  5. ahejlsberg commented on Jan 11, 2024

    @ahejlsberg
    Member

    Joshua Chen (@Josh-Cena) FWIW, I now agree with your observations and suggested changes. See #57031. Better late than never! 😄

  6. locked as resolved and limited conversation to collaborators on Oct 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Fix AvailableA PR has been opened for this issueWorking as IntendedThe behavior described is the intended behavior; this is not a bug

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions