Skip to content

Mapped array/tuple types not always working as expectedΒ #43129

Closed as not planned
@trusktr

Description

@trusktr

Bug Report

πŸ”Ž Search Terms

Mapped array types

πŸ•— Version & Regression Information

I noticed now in TS 4.1.2.

⏯ Code and Playground Links

There are two problems.

The following has an error in the mapped type despite that I did it just like in #26063 (as far as I know):

type Constructor<T = object, A extends any[] = any[], Static = {}> = (new (...a: A) => T) & Static

type ElementTypeArrayToInstArray<T extends Constructor[]> = {
	[K in keyof T]: InstanceType<T[K]> // <----------- ERROR
}
type ArrayValues<T extends any[]> = T[keyof T]
type ElementTypes<T extends Constructor[]> = ArrayValues<ElementTypeArrayToInstArray<T>>

type test = ElementTypes<[typeof HTMLAnchorElement, typeof HTMLDivElement]>

Playground link with relevant code

But notice that when you hover on test, it is a union of all the values of the array including values from non-numeric keys, which is unlike the examples in #26063.

There seems to some sort of special casing happening.

I had to specify that I want number keys only in order(unlike #26063) to get rid of the error:

type Constructor<T = object, A extends any[] = any[], Static = {}> = (new (...a: A) => T) & Static

type ElementTypeArrayToInstArray<T extends Constructor[]> = {
	[K in keyof T]: InstanceType<T[number & K]> // <----------- GOOD
}
type ArrayValues<T extends any[]> = T[keyof T]
type ElementTypes<T extends Constructor[]> = ArrayValues<ElementTypeArrayToInstArray<T>>

type test = ElementTypes<[typeof HTMLAnchorElement, typeof HTMLDivElement]>

Playground link with relevant code

But notice that test still contains all the values of all keys, not just array values.

Finally, I had to specify numeric keys for ArrayValues:

type Constructor<T = object, A extends any[] = any[], Static = {}> = (new (...a: A) => T) & Static

type ElementTypeArrayToInstArray<T extends Constructor[]> = {
	[K in keyof T]: InstanceType<T[number & K]>
}
type ArrayValues<T extends any[]> = T[number & keyof T] // <-------- number
type ElementTypes<T extends Constructor[]> = ArrayValues<ElementTypeArrayToInstArray<T>>

type test = ElementTypes<[typeof HTMLAnchorElement, typeof HTMLDivElement]>

Playground link with relevant code

But notice if I use Promise instead of InstanceType, the first issues goes away, although number is still needed in ArrayValues:

type Constructor<T = object, A extends any[] = any[], Static = {}> = (new (...a: A) => T) & Static

type ElementTypeArrayToInstArray<T extends Constructor[]> = {
	[K in keyof T]: Promise<T[K]> // <-------- no number
}
type ArrayValues<T extends any[]> = T[number & keyof T] // <-------- number still needed
type ElementTypes<T extends Constructor[]> = ArrayValues<ElementTypeArrayToInstArray<T>>

type test = ElementTypes<[typeof HTMLAnchorElement, typeof HTMLDivElement]>

Playground link with relevant code

πŸ™ Actual behavior

Does not work like #26063

πŸ™‚ Expected behavior

Works like #26063


There seems to be some sort of special casing going on.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Needs More InfoThe issue still hasn't been fully clarified

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions