Closed
Description
Bug Report
π Search Terms
mapped tuple type, key, numeric
π Version & Regression Information
- TypeScript 4.1.3
- TypeScript 3.5.1
This behaviour has been around for a very long time, I just never bothered to report it.
β― Playground Link
π» Code
enum E {
A,
B,
C,
}
type TakesE <T extends E> = ["element", T]
type Foo<
ArrT extends E[]
> = {
[k in keyof ArrT] : TakesE<ArrT[k]>
}
type Test = Foo<[E.A, E.B]>
π Actual behavior
ArrT[k]
assignable to E
If k
is a numeric key of ArrT
, then ArrT[k]
is assignable to E
π Expected behavior
ArrT[k]
not assignable to E
Workaround
enum E {
A,
B,
C,
}
type TakesE <T extends E> = ["element", T]
type TakesEHack<T extends unknown> = TakesE<Extract<T, E>>
type Foo<
ArrT extends E[] | string
> = {
[k in keyof ArrT] : TakesEHack<ArrT[k]>
}
type Test = Foo<[E.A, E.B]>
TakesEHack<>
disables type checking at the call site but it's the most generic workaround that has worked for all my personal use cases.
Non-Workarounds
Stuff like the following didn't quite work for all my use cases,
k in keyof ArrT & number
Does not give a mapped tuple type, does not extract each element's type properlyk in Extract<keyof ArrT, number>
Does not give a mapped tuple type, does not extract each element's type properlyTakesE<Extract<ArrT[k], E>>
This triggered complex union errors/infinitely deep type errors (becauseTakesE<E>
is too large in my case)
I suspect Extract<>
doesn't work for my case because it makes TS explore one branch per element of E
.
So, TakesE<Extract<ArrT[k], E>>
becomes a super large union type.
However, in my real use cases, ArrT[k]
is always exactly one element of E
, meaning I never have large unions in practice.