Repository navigation
Using 'Key in keyof ArrayType' always returns an Array regardles of the value manipulation applied #40069
Description
TypeScript Version: 4.0.0-beta (same behaviour in version 3.5.1 v3.5.1-Play Ground)
Search Terms:
"key in keyof Array", "keyof Array"
Expected behavior:
using key in ArrayType has the same behaviour as on any object (returning an array type only if the relevant properties are unchanged)
Actual behavior:
using key in ArrayType performs actions on touple entries but the returned type allways includes all default Array properties
Extention note:
Not the point of this issue and i know there are other issues around this topic. it's just a note,
but how about possibly adding tupple functionality for ArrayLike-, Map- and Set-types? They have all the basic qualities of a tupple, and it would be awesome to use them in a similar fashion (especially inference of Map.prototype.get/set and [Symbol.iterator] inference of tupples)
Related Issues:
#39726
#34780
type-fest/issues/119 (external library, but about this this behaviour and includes adHoc fix)
Code
type Arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
type Arr2 = (0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9)[]
type WhoopMyArray_Faulty<Base extends ArrayLike<any>, Condition> = {
[Key in keyof Base]:
Base[Key] extends Condition
? 'Whoop it'
: Base[Key] extends Base[number] ? Base[Key] : never
}
// action is performed on array elements but return type is still a proper array
type WhoopedArray = WhoopMyArray_Faulty<Arr, 7 | 5 | 2>
type WhoopedArrayKeys = WhoopMyArray_Faulty<Arr, 7 | 5 | 2>[keyof Arr]
// related side note, but not the main pont
// no action performed. in line with 1st example, expected: (0 | 1 | 'Whoop it' | 3 | 4 | 'Whoop it' | 6 | 'Whoop it' | 8 | 9)[]
type WhoopedArray2 = WhoopMyArray_Faulty<Arr2, 7 | 5 | 2>
type WhoopedArray2Keys = WhoopMyArray_Faulty<Arr, 7 | 5 | 2>[keyof Arr]infered types:
type WhoopedArray = [0, 1, "Whoop it", 3, 4, "Whoop it", 6, "Whoop it", 8, 9]
type WhoopedArrayKeys = 0 | "Whoop it" | 1 | 3 | 4 | 6 | 8 | 9 | 10 | (() => string) | (() => string)
| (() => 0 | "Whoop it" | 1 | 3 | 4 | 6 | 8 | 9 | undefined) | ((...items: (0 | "Whoop it" | 1 | 3 | 4 | 6 | 8 | 9)[]) => number)
| { ...; } | ... 22 more ... | (() => IterableIterator<...>)
type WhoopedArray2 = (0 | 7 | 5 | 2 | 1 | 3 | 4 | 6 | 8 | 9)[]
type WhoopedArray2Keys = 0 | "Whoop it" | 1 | 3 | 4 | 6 | 8 | 9 | 10 | (() => string) | (() => string)
| (() => 0 | "Whoop it" | 1 | 3 | 4 | 6 | 8 | 9 | undefined) | ((...items: (0 | "Whoop it" | 1 | 3 | 4 | 6 | 8 | 9)[]) => number)
| { ...; } | ... 22 more ... | (() => IterableIterator<...>)Output
"use strict";Compiler Options
{
"compilerOptions": {
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"noImplicitThis": true,
"noImplicitReturns": true,
"useDefineForClassFields": true,
"alwaysStrict": true,
"allowUnusedLabels": true,
"noEmitHelpers": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"preserveConstEnums": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"moduleResolution": 2,
"target": "Latest",
"module": "ESNext"
}
}Playground Link: Provided
Activity
jcalz commentedon Aug 16, 2020
This working as intended. Mapped arrays/tuples stay arrays/tuples as of TypeScript 3.1. See #26063.
KilianKilmister commentedon Aug 16, 2020
I would argue that mapping its method & length keys to
nevermakes the resulting object non-homomorphic. It also causes generics that acceptobject-types act unpredictable and in no way type-safe.While it does work in accordance of the mentiond PR, this should then be considered a design oversight.
ForReference: Playground Link
yume-chan commentedon Aug 25, 2020
A mapped type will not touch
lengthand methods keys for an array type, for exampleThe problem is you can't do
Arr[keyof Arr]to get its "values", you can useArr[number], so yourValuesshould beKilianKilmister commentedon Oct 26, 2020
Simon Chan (@yume-chan) completly missed this response, so my apologies for the late reply
Sure, this is easy when you expect an array, but if you just expect any generic object, this will really suprise you, see the example in my comment. Arrays have to be explicitly filtered out and handled differently (which i started doing after i ran into this).
But this also has become much less of an issue with some of the awedome new features #40336