Skip to content

Commit

Permalink
feat: ArrayPlus.Entries<A>
Browse files Browse the repository at this point in the history
  • Loading branch information
unional committed May 14, 2023
1 parent d2997de commit 09495be
Show file tree
Hide file tree
Showing 9 changed files with 142 additions and 18 deletions.
5 changes: 5 additions & 0 deletions .changeset/popular-kids-arrive.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'type-plus': minor
---

Add `ArrayPlus.Entries<A>`.
8 changes: 7 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
"tersify",
"typelevel",
"typepark",
"unpartial"
"unpartial",
"unshift"
],
"eslint.enable": true,
"files.watcherExclude": {
Expand Down Expand Up @@ -61,5 +62,10 @@
],
"markdown.extension.toc.orderedList": true,
"markdownlint.ignore": ".markdownlintignore",
"tsimporter.filesToExclude": [
"**/cjs",
"**/esm",
"**/tslib"
],
"typescript.tsdk": "node_modules/typescript/lib"
}
13 changes: 0 additions & 13 deletions ts/array/array.ts → ts/array/array.at.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,3 @@ export type At<A extends unknown[], N extends number, Fail = never> = IndexAt<A,
? TupleType<A, IsStrictNumber<I, A[I] | undefined, A[I]>, A[I] | undefined>
: Fail
: never

/**
* Concats two arrays or tuples.
*
* alias of: `[...A, ...B]`
*
* @alias ArrayPlus.Concat
*
* ```ts
* type R = Concat<[1], [2, 3]> // [1, 2, 3]
* ```
*/
export type Concat<A extends unknown[], B extends unknown[]> = [...A, ...B]
12 changes: 12 additions & 0 deletions ts/array/array.concat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* Concats two arrays or tuples.
*
* alias of: `[...A, ...B]`
*
* @alias ArrayPlus.Concat
*
* ```ts
* type R = Concat<[1], [2, 3]> // [1, 2, 3]
* ```
*/
export type Concat<A extends unknown[], B extends unknown[]> = [...A, ...B]
24 changes: 24 additions & 0 deletions ts/array/array.entries.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { it, test } from '@jest/globals'
import { testType, type ArrayPlus } from '../index.js'

test('behavior of array.entries()', () => {
const array = [1, 2, '3']
const entries = array.entries()
testType.equal<typeof entries, IterableIterator<[number, string | number]>>(true)
})

test('behavior of tuple.entries()', () => {
const tuple = [1, 2, '3'] as const
const entries = tuple.entries()
testType.equal<typeof entries, IterableIterator<[number, 1 | 2 | '3']>>(true)
})

it('gets Array<[number, T]> for array', () => {
testType.equal<ArrayPlus.Entries<string[]>, Array<[number, string]>>(true)
testType.equal<ArrayPlus.Entries<Array<string | number>>, Array<[number, string | number]>>(true)
})

it('returns [[0, T1], [1, T2],...[n, Tn]] for tuple', () => {
testType.equal<ArrayPlus.Entries<[]>, []>(true)
testType.equal<ArrayPlus.Entries<[1, 2, 3]>, [[0, 1], [1, 2], [2, 3]]>(true)
})
24 changes: 24 additions & 0 deletions ts/array/array.entries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { IsTuple } from '../tuple/tuple_type.js'
/**
* Returns an array of key-value pairs for every entry in the array or tuple.
*
* Note that this is not the same as `Array.entries(A)`,
* which returns an iterable interator.
*
* @example
* ```ts
* ArrayPlus.Entries<Array<string | number>> // Array<[number, string | number]>
* ArrayPlus.Entries<[1, 2, 3]> // [[0, 1], [1, 2], [2, 3]]
* ```
*/
export type Entries<A extends unknown[]> = IsTuple<
A,
Device<A, []>,
A extends Array<infer T> ? Array<[number, T]> : never
>

type Device<A extends unknown[], R extends unknown[]> = A['length'] extends 0
? R
: A extends [...infer F, infer N]
? Device<F, [[F['length'], N], ...R]>
: never
4 changes: 3 additions & 1 deletion ts/array/array_plus.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
export type { At, Concat } from './array.js'
export type { At } from './array.at.js'
export type { Concat } from './array.concat.js'
export type { Entries } from './array.entries.js'
export type { IndexAt, IsIndexOutOfBound } from './array_index.js'
66 changes: 64 additions & 2 deletions ts/array/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ as *tuples* is a subset of array.
For *tuple* specific types and type utilities,
please check [`TuplePlus`](../tuple/readme.md#TuplePlus).
### [`ArrayPlus.At`](./array.ts#L17)
### [`ArrayPlus.At`](./array.at.ts#L18)
> `ArrayPlus.At<A, N, Fail = never>`
Expand Down Expand Up @@ -61,7 +61,7 @@ If the `N` is out of bound,
or `N` is not a valid index,
`ArrayPlus.At` will return the `Fail` case, which defaults to `never`.
### [`ArrayPlus.Concat`](./array.ts#L35)
### [`ArrayPlus.Concat`](./array.concat.ts#L12)
> `ArrayPlus.Concat<A, B>`
Expand All @@ -72,6 +72,68 @@ It is added for completeness.
You are encouraged to use `[...A, ...B]` directly.
### [`ArrayPlus.Entries`](./array.entries.ts#L14)
> `ArrayPlus.Entries<A>`
Returns an array of key-value pairs for every entry in the array or tuple.
Note that this is not the same as `Array.entries(A)`,
which returns an iterable interator.
```ts
ArrayPlus.Entries<Array<string | number>> // Array<[number, string | number]>
ArrayPlus.Entries<[1, 2, 3]> // [[0, 1], [1, 2], [2, 3]]
```
## Builtin array methods
JavaScript has many builtin array methods.
We will try to bring them to the type-level.
Not all methods can be implemented in the type-level,
or in the same way.
For example, type-level does not support higher-level generics,
i.e. it is not possible to pass in a generic type and "invoke" it.
Therefore, methods like `map` and `reduce()` cannot be implemented generically.
They have to be implemented separately for each specific use case,
or with reduced capability.
They are exposed under the `ArrayPlus` namespace,
while some common ones are exposed at top-level.
Here are the list of array methods and their corresponding type-level functions, if availableL
- ✅ `at`: [`ArrayPlus.At`](#arrayplusat)
- ✅ `concat`: [`Concat`](#arrayplusconcat)
- 🚧 `copyWithin`: `CopyWithin<A, Target, Start, End>`
- 🚧 ⬇️ `entries`: `Array<T> => Array<[number, T]>`, `Tuple<...T> => [[0, T1], [1, T2], ...[n, Tn]]`\
(this is not the same as `array.entries()` which returns `IterableIterator<[number, T]>`)
- 🚧 `every`: `Every<A, Criteria, Then = A, Else = never>`
- 🚧 `fill`: `Fill<A, V, Start, End>`
- 🚧 `find`: `Find<A, Criteria> => V | never`
- 🚧 `findIndex`: `FindIndex<A, Criteria> => number | number literal | never`
- 🚧 `flat`: `Flat<A>`
- 🚧 `flatMap`: `Flat<A, Criteria, R>`
- 🚧 `includes`:
- 🚧 `join`:
- 🚧 `keys`:
- 🚧 `map`: `Map<A, Criteria, R>`
- 🚧 `pop`: `Pop<A>`
- 🚧 `push`: `Push<A>`
- 🚧 `reduce`:
- 🚧 `reduceRight`:
- 🚧 `reverse`:
- 🚧 `shift`:
- 🚧 `slice`:
- 🚧 `some`:
- 🚧 `sort`:
- 🚧 `splice`:
- 🚧 `unshift`:
- 🚧 `values`:
## References
- [handbook]
Expand Down
4 changes: 3 additions & 1 deletion ts/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
export { required, requiredDeep, unpartial } from 'unpartial'
export type { IsAnyOrNever } from './any/any_or_never.js'
export type { AnyType, IsAny, IsNotAny, NotAnyType } from './any/any_type.js'
export type { At, Concat } from './array/array.js'
export type { At } from './array/array.at.js'
export type { Concat } from './array/array.concat.js'
export * as ArrayPlus from './array/array_plus.js'
export type { ArrayType, IsArray, IsNotArray, NotArrayType } from './array/array_type.js'
export * from './array/index.js'
Expand Down Expand Up @@ -101,3 +102,4 @@ export type { UnionKeys } from './union_keys.js'
export type { IsNotUnknown, IsUnknown, NotUnknownType, UnknownType } from './unknown/unknown_type.js'
export * from './utils/index.js'
export type { IsNotVoid, IsVoid, NotVoidType, VoidType } from './void/void_type.js'

0 comments on commit 09495be

Please sign in to comment.