Skip to content

Key in mapped type not traversed when there's a something-with-generics extends clause in itΒ #62370

@Holzchopf

Description

@Holzchopf

πŸ”Ž Search Terms

mapped conditional type keyof generic extends ternary

πŸ•— Version & Regression Information

  • This changed between versions 4.0.5 and 4.1.5
    (Because the mapped type wouldn't work prior to 4.1)

⏯ Playground Link

https://www.typescriptlang.org/play/?ts=5.9.2#code/KYDwDg9gTgLgBDAnmYcCyBDMKAmAVCPKDAN2CgGdgcAePAPjgF4BYAKDjgG93POBtANJwAlgDs4Aa2CIIAMzh44GCoqEBdOKBjAxOVRjGI4AfjjCAXOfVWA5DGJlK1W7zgBfduyQo4ACQgnPAALEQoARmZ0LFwCIlJyKloeDmUjAAUoCDArQ0Q3CgdM7KtCqHEAczcIACMAK2KcuFq64ABjGHZ3enYAel64QBRyQHg-5QAbMbgwLJRYEWADKFQxCAB3OAAiBwTnHA2LPoGfVACg0IiolP6+TjzGqy3HROoNgG5Dm7gy+83tpyS3h8bi0fo8dgD3mxrp42N5kCdAuQQmEAEx0RhMaLYahxJ67GgpW4ZGa5IwFIokr4OSrVeo-PBdHpQgaAGXJmnSZqJVABbMIUSoHZkIeH+RFQZEUNEMS5Avh3Slg-4vSHXG7fBV-Z57FUDGFw3ynJHnADM6KimGx+EIeKSBLc8pKaXyqXVjrKNNSIMpACV2tBaNJZAo8AAaOBiACu3Jq5CZ3Q+bK92S5cF5FH5Ygqguux1FZzCpulmKuAxuDqaiq1gKFaopjsru2r0KAA

πŸ’» Code

export type MappedToTraversed<T> =
  {
    [K in keyof T as T[K] extends any ? K : K]: 'traversed'
  }

type HoverThis1 = MappedToTraversed<{
  anyProp: any
  strProp: string
  objProp: object
}>
// βœ”οΈ all properties are now "traversed":
// type HoverThis1 = {
//     anyProp: "traversed";
//     strProp: "traversed";
//     objProp: "traversed";
// }

type HoverThis2<T> = MappedToTraversed<{
  anyProp: any
  strProp: string
  objProp: T
}>
// ❌ objProp is missing:
// type HoverThis2<T> = {
//     anyProp: "traversed";
//     strProp: "traversed";
// }

type HoverThis3<T> = MappedToTraversed<{
  anyProp: any
  strProp: string
  objProp: Record<keyof T, number>
}>
// ❌ objProp is missing:
// type HoverThis3<T> = {
//     anyProp: "traversed";
//     strProp: "traversed";
// }

πŸ™ Actual behavior

The objProp is missing from the HoverThis types when it is somehow using a generic (e.g. when used as property type or key in a Record). Looks like it is not being traversed during mapping at all due to the extends clause, because the ternary as T[K] extends any ? K : K should IMHO always evaluate to K.

πŸ™‚ Expected behavior

objProp should be listed in all HoverThis types.

Additional information about the issue

I think it's due to the extends clause, because if the mapping is simply written as

export type MappedToTraversed<T> =
  {
    [K in keyof T as K]: 'traversed'
  }

objProp is listed in the resulting HoverThis types.

It also fails if

  • the ternary is the other way round, i.e. any extends T[K] ? K : K
  • the ternary checks something that should always be true T[K] extends T[K] ? K : K
  • I try to disable union distribution according to hand book: [T[K]] extends [any] ? K : K

However, if I mess up disabling the union distribution (putting only one side in square brackets), it works..? [T[K]] extends any ? K : K. This feels like an unsafe workaround.

Metadata

Metadata

Assignees

No one assigned

    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