Skip to content

Commit

Permalink
Merge pull request #81 from ahrjarrett/@ahrjarrett/v0.40.10
Browse files Browse the repository at this point in the history
feat: adds `Widen`
  • Loading branch information
ahrjarrett authored Apr 15, 2024
2 parents 678d91f + 66a6800 commit cf6ba46
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/khaki-squids-deliver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"any-ts": patch
---

feat: adds `Widen` type + ambient namespace
2 changes: 2 additions & 0 deletions src/exports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,5 @@ export {
Focus,
type FocusConstructor
} from "./lens/focus"

export type { Widen } from "./widen/exports"
2 changes: 1 addition & 1 deletion src/function/function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ export {
}

type return_<type> = [type] extends [(...args: any) => infer out] ? out : never
type arguments_<type> = [type] extends [(...args: infer arguments) => any] ? arguments : never
type arguments_<type> = [type] extends [(...args: infer arguments) => any] ? arguments : never
1 change: 1 addition & 0 deletions src/widen/exports.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type { Widen } from "./widen"
128 changes: 128 additions & 0 deletions src/widen/widen.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import type { Widen } from "./widen"
import type { expect, assert } from "../test/exports"

declare namespace Spec {

type __Widen__ = [
// ^?
expect<assert.equal<
Widen<[1, [2, [3, [4, [5, [6]]]]]], 0>,
[1, [2, [3, [4, [5, [6]]]]]]
>>,

expect<assert.equal<
Widen<[1, [2, [3, [4, [5, [6]]]]]], 1>,
[number, [2, [3, [4, [5, [6]]]]]]
>>,

expect<assert.equal<
Widen<[1, [2, [3, [4, [5, [6]]]]]], 2>,
[number, [number, [3, [4, [5, [6]]]]]]
>>,

expect<assert.equal<
Widen<[1, [2, [3, [4, [5, [6]]]]]], 3>,
[number, [number, [number, [4, [5, [6]]]]]]
>>,

expect<assert.equal<
Widen<[1, [2, [3, [4, [5, [6]]]]]], 4>,
[number, [number, [number, [number, [5, [6]]]]]]
>>,

expect<assert.equal<
Widen<[1, [2, [3, [4, [5, [6]]]]]], 5>,
[number, [number, [number, [number, [number, [6]]]]]]
>>,

expect<assert.equal<
Widen<[1, [2, [3, [4, [5, [6]]]]]], 6>,
[number, [number, [number, [number, [number, [number]]]]]]
>>,

expect<assert.equal<
Widen<{ abc: 1, def: { ghi: 2, jkl: { mno: 3, pqr: { stu: 4, vwx: { yz: 5 } } } } }, 0>,
{ abc: 1, def: { ghi: 2, jkl: { mno: 3, pqr: { stu: 4, vwx: { yz: 5 } } } } }
>>,

expect<assert.equal<
Widen<{ abc: 1, def: { ghi: 2, jkl: { mno: 3, pqr: { stu: 4, vwx: { yz: 5 } } } } }, 1>,
{ abc: number, def: { ghi: 2, jkl: { mno: 3, pqr: { stu: 4, vwx: { yz: 5 } } } } }
>>,

expect<assert.equal<
Widen<{ abc: 1, def: { ghi: 2, jkl: { mno: 3, pqr: { stu: 4, vwx: { yz: 5 } } } } }, 2>,
{ abc: number, def: { ghi: number, jkl: { mno: 3, pqr: { stu: 4, vwx: { yz: 5 } } } } }
>>,

expect<assert.equal<
Widen<{ abc: 1, def: { ghi: 2, jkl: { mno: 3, pqr: { stu: 4, vwx: { yz: 5 } } } } }, 3>,
{ abc: number, def: { ghi: number, jkl: { mno: number, pqr: { stu: 4, vwx: { yz: 5 } } } } }
>>,

expect<assert.equal<
Widen<{ abc: 1, def: { ghi: 2, jkl: { mno: 3, pqr: { stu: 4, vwx: { yz: 5 } } } } }, 4>,
{ abc: number, def: { ghi: number, jkl: { mno: number, pqr: { stu: number, vwx: { yz: 5 } } } } }
>>,

expect<assert.equal<
Widen<{ abc: 1, def: { ghi: 2, jkl: { mno: 3, pqr: { stu: 4, vwx: { yz: 5 } } } } }, 5>,
{ abc: number, def: { ghi: number, jkl: { mno: number, pqr: { stu: number, vwx: { yz: number } } } } }
>>,

expect<assert.equal<
Widen<{ abc: [1, def: { ghi: [2, jkl: { mno: [3, pqr: { stu: [4, vwx: { yz: [5] }] }] }] }] }, 0>,
{ abc: [1, { ghi: [2, { mno: [3, pqr: { stu: [4, vwx: { yz: [5] }] }] }] }] }
>>,

expect<assert.equal<
Widen<{ abc: [1, def: { ghi: [2, jkl: { mno: [3, pqr: { stu: [4, vwx: { yz: [5] }] }] }] }] }, 1>,
{ abc: [1, { ghi: [2, { mno: [3, pqr: { stu: [4, vwx: { yz: [5] }] }] }] }] }
>>,

expect<assert.equal<
Widen<{ abc: [1, def: { ghi: [2, jkl: { mno: [3, pqr: { stu: [4, vwx: { yz: [5] }] }] }] }] }, 2>,
{ abc: [number, { ghi: [2, { mno: [3, pqr: { stu: [4, vwx: { yz: [5] }] }] }] }] }
>>,

expect<assert.equal<
Widen<{ abc: [1, def: { ghi: [2, jkl: { mno: [3, pqr: { stu: [4, vwx: { yz: [5] }] }] }] }] }, 3>,
{ abc: [number, { ghi: [2, { mno: [3, pqr: { stu: [4, vwx: { yz: [5] }] }] }] }] }
>>,

expect<assert.equal<
Widen<{ abc: [1, def: { ghi: [2, jkl: { mno: [3, pqr: { stu: [4, vwx: { yz: [5] }] }] }] }] }, 4>,
{ abc: [number, { ghi: [number, { mno: [3, pqr: { stu: [4, vwx: { yz: [5] }] }] }] }] }
>>,

expect<assert.equal<
Widen<{ abc: [1, def: { ghi: [2, jkl: { mno: [3, pqr: { stu: [4, vwx: { yz: [5] }] }] }] }] }, 5>,
{ abc: [number, { ghi: [number, { mno: [3, pqr: { stu: [4, vwx: { yz: [5] }] }] }] }] }
>>,

expect<assert.equal<
Widen<{ abc: [1, def: { ghi: [2, jkl: { mno: [3, pqr: { stu: [4, vwx: { yz: [5] }] }] }] }] }, 6>,
{ abc: [number, { ghi: [number, { mno: [number, pqr: { stu: [4, vwx: { yz: [5] }] }] }] }] }
>>,

expect<assert.equal<
Widen<{ abc: [1, def: { ghi: [2, jkl: { mno: [3, pqr: { stu: [4, vwx: { yz: [5] }] }] }] }] }, 7>,
{ abc: [number, { ghi: [number, { mno: [number, pqr: { stu: [4, vwx: { yz: [5] }] }] }] }] }
>>,

expect<assert.equal<
Widen<{ abc: [1, def: { ghi: [2, jkl: { mno: [3, pqr: { stu: [4, vwx: { yz: [5] }] }] }] }] }, 8>,
{ abc: [number, { ghi: [number, { mno: [number, pqr: { stu: [number, vwx: { yz: [5] }] }] }] }] }
>>,

expect<assert.equal<
Widen<{ abc: [1, def: { ghi: [2, jkl: { mno: [3, pqr: { stu: [4, vwx: { yz: [5] }] }] }] }] }, 9>,
{ abc: [number, { ghi: [number, { mno: [number, pqr: { stu: [number, vwx: { yz: [5] }] }] }] }] }
>>,

expect<assert.equal<
Widen<{ abc: [1, def: { ghi: [2, jkl: { mno: [3, pqr: { stu: [4, vwx: { yz: [5] }] }] }] }] }, 10>,
{ abc: [number, { ghi: [number, { mno: [number, pqr: { stu: [number, vwx: { yz: [number] }] }] }] }] }
>>,
]
}
55 changes: 55 additions & 0 deletions src/widen/widen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import type { any } from "../any/exports"
import type { nonempty } from "../empty"

/**
* {@link Widen `Widen`} is a type constructor that accepts a tree and an optional max depth
* (default to `2`), and constructs a new tree with the same overall structure.
*
* Until it hits its max depth, any leaf it encounters is widened to the least upper bound of
* its respective domain.
*
* For example:
*
* - given `{ abc: ["def", "ghi"] }`, {@link Widen `Widen`} returns `{ abc: [string, string] }`;
* - given `[{ abc: 123 }, { def: 456 }]`, {@link Widen `Widen`} returns `[{ abc: number }, { def: number }]`
*
* @example
* import type { Widen } from "any-ts"
*
* type StateTuple<S> = readonly [state: S, setState: S | ((s: S) => S)]
* declare function useState<const state>(initialState: Widen<state, 3>): StateTuple<Widen<state, 3>>
*
* const [state] = useState([
* { user: { first: "Caril Ann", last: "Fugate", email: "[email protected]" } },
* { user: { first: "Charles", last: "Starkweather", email: "[email protected]" } }
* ])
*
* state
* // ^? [{ user: { first: string, last: string, email: string } }, { user: { first: string, last: string, email: string } }]
*/
export type Widen<type, maxDepth extends number = 2> = Widen.tree<type, maxDepth>

export declare namespace Widen {
type leaf<type> = type extends { valueOf(): infer target } ? target : type
type tree<type, maxDepth extends number> = internal.widen<type, [], maxDepth>
}

declare namespace internal {
type widen<type, depth extends void[], maxDepth extends number>
= type extends any.primitive ? Widen.leaf<type>
: [depth[`length`], maxDepth] extends [maxDepth, depth[`length`]] ? type
: type extends any.array ? internal.widenAll<type, [], depth, maxDepth>
: { -readonly [k in keyof type]: internal.widen<type[k], [...depth, void], maxDepth> }

type widenAll<
xs extends any.array,
acc extends any.array,
depth extends void[],
maxDepth extends number,
> = [depth[`length`], maxDepth] extends [maxDepth, depth[`length`]] ? xs
: xs extends nonempty.array<infer head, infer tail>
? internal.widen<head, [...depth, void], maxDepth> extends infer x
? widenAll<tail, [...acc, x], depth, maxDepth>
: never
: acc
}

0 comments on commit cf6ba46

Please sign in to comment.