chore: DRY the types
This commit is contained in:
+1
-1
@@ -41,7 +41,7 @@ export default defineConfig([
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
varsIgnorePattern: "^_",
|
||||
varsIgnorePattern: "^_[^_]",
|
||||
reportUsedIgnorePattern: true,
|
||||
},
|
||||
],
|
||||
|
||||
@@ -7,8 +7,6 @@ export interface Identity extends HKT {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
export const never = undefined as never;
|
||||
|
||||
export type MaxDepth = 20;
|
||||
|
||||
export class AssertionError extends Error {
|
||||
public constructor(msg?: string) {
|
||||
super(msg);
|
||||
|
||||
+2
-85
@@ -2,6 +2,7 @@ import { makeFluent } from "../base";
|
||||
import type { HKT } from "../base/hkt";
|
||||
import { Mixin, type Input, type Return } from "../base/mixin";
|
||||
import { assert, assertType, type HidePrototype } from "../internal";
|
||||
import type { MaxDepth, At } from "../utility";
|
||||
|
||||
type IterArgs<T extends readonly unknown[] = unknown[]> = [
|
||||
element: T[number],
|
||||
@@ -9,11 +10,7 @@ type IterArgs<T extends readonly unknown[] = unknown[]> = [
|
||||
array: Readonly<T>,
|
||||
];
|
||||
|
||||
type MaxDepth = 20;
|
||||
|
||||
type Unordered<T extends readonly unknown[]> = T extends unknown[]
|
||||
? T[number][]
|
||||
: readonly T[number][];
|
||||
type Unordered<T extends readonly unknown[]> = T[number][];
|
||||
|
||||
type Map<
|
||||
T extends readonly unknown[],
|
||||
@@ -38,54 +35,6 @@ type Reverse<
|
||||
? TOut
|
||||
: T[number][];
|
||||
|
||||
namespace At {
|
||||
export type Dec<N extends number> = [
|
||||
-1,
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
][N];
|
||||
|
||||
export type Select<
|
||||
T extends readonly unknown[],
|
||||
Skip extends number,
|
||||
> = Skip extends 0
|
||||
? T extends readonly [...unknown[], infer T]
|
||||
? T
|
||||
: undefined
|
||||
: T extends readonly [...infer TRest, unknown]
|
||||
? Select<TRest, Dec<Skip>>
|
||||
: undefined;
|
||||
}
|
||||
|
||||
type At<
|
||||
T extends readonly unknown[],
|
||||
K extends keyof T & number,
|
||||
> = number extends T["length"]
|
||||
? T[K] | undefined
|
||||
: `${K}` extends `-${infer N extends number}`
|
||||
? At.Select<T, At.Dec<N>>
|
||||
: T[K];
|
||||
|
||||
type Repeat<
|
||||
T extends readonly unknown[],
|
||||
N extends number,
|
||||
@@ -97,38 +46,6 @@ type Repeat<
|
||||
? T[number][]
|
||||
: Repeat<T, N, [...Acc, null], [...TOut, ...T]>;
|
||||
|
||||
namespace Flat {
|
||||
type Inc<
|
||||
N extends number,
|
||||
Acc extends unknown[] = [],
|
||||
> = Acc["length"] extends N
|
||||
? [...Acc, null]["length"]
|
||||
: Inc<N, [...Acc, null]>;
|
||||
|
||||
export type Leaves<
|
||||
T,
|
||||
Depth extends number = 0,
|
||||
> = Depth extends MaxDepth
|
||||
? T
|
||||
: T extends readonly unknown[]
|
||||
? Leaves<T[number], Inc<Depth>>
|
||||
: T;
|
||||
|
||||
export type Rebuild<
|
||||
T extends readonly unknown[],
|
||||
Depth extends number = 0,
|
||||
> = Depth extends MaxDepth
|
||||
? T
|
||||
: T extends readonly [infer H, ...infer R]
|
||||
? H extends readonly unknown[]
|
||||
? [...Rebuild<H, Inc<Depth>>, ...Rebuild<R, Depth>]
|
||||
: [H, ...Rebuild<R, Depth>]
|
||||
: [];
|
||||
}
|
||||
|
||||
export type Flat<T extends readonly unknown[]> =
|
||||
number extends T["length"] ? Flat.Leaves<T>[] : Flat.Rebuild<T>;
|
||||
|
||||
function isArray(v: unknown): v is readonly unknown[] {
|
||||
return typeof v === "object" && globalThis.Array.isArray(v);
|
||||
}
|
||||
|
||||
+2
-13
@@ -6,21 +6,10 @@ import {
|
||||
type Props,
|
||||
type Return,
|
||||
} from "../base/mixin";
|
||||
import { assertType, type MaxDepth } from "../internal";
|
||||
import { assertType } from "../internal";
|
||||
import type { Inc } from "../utility";
|
||||
import { applySwizzle, type Swizzle } from "./math/swizzle";
|
||||
|
||||
type Vec<
|
||||
T,
|
||||
N extends number,
|
||||
TOut extends T[] = [],
|
||||
> = TOut["length"] extends N
|
||||
? TOut
|
||||
: TOut["length"] extends MaxDepth
|
||||
? T[]
|
||||
: Vec<T, N, [...TOut, T]>;
|
||||
|
||||
type Inc<N extends number> = [...Vec<null, N>, null]["length"];
|
||||
|
||||
type Sign<T extends number> = T extends 0
|
||||
? 0
|
||||
: `${T}` extends `-${number}`
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
import { makeFluent } from "../../base";
|
||||
import type { Props, Return } from "../../base/mixin";
|
||||
import { type MaxDepth } from "../../internal";
|
||||
import { Math } from "../math";
|
||||
import type { Vec, Dec, Inc as __Inc } from "../../utility";
|
||||
|
||||
type Axis = typeof axis;
|
||||
type Vec<
|
||||
T,
|
||||
N extends number,
|
||||
TOut extends T[] = [],
|
||||
> = TOut["length"] extends N
|
||||
? TOut
|
||||
: TOut["length"] extends MaxDepth
|
||||
? T[]
|
||||
: Vec<T, N, [...TOut, T]>;
|
||||
|
||||
type Inc<N extends number | undefined> = N extends number
|
||||
? [...Vec<null, N>, null]["length"]
|
||||
? __Inc<N>
|
||||
: 0;
|
||||
type Dec<N extends number> =
|
||||
Vec<null, N> extends [...infer Rest extends null[], null]
|
||||
? Rest["length"]
|
||||
: -1;
|
||||
|
||||
type Next<
|
||||
N extends number,
|
||||
@@ -52,13 +39,8 @@ type Key<
|
||||
type IsAscending<
|
||||
State extends (number | undefined)[],
|
||||
Prev extends number | undefined = undefined,
|
||||
> = State extends readonly [
|
||||
infer Current extends number,
|
||||
...infer Rest extends number[],
|
||||
]
|
||||
? Current extends Inc<Prev>
|
||||
? IsAscending<Rest, Inc<Prev>>
|
||||
: false
|
||||
> = State extends readonly [Inc<Prev>, ...infer Rest extends number[]]
|
||||
? IsAscending<Rest, Inc<Prev>>
|
||||
: State extends readonly []
|
||||
? true
|
||||
: false;
|
||||
|
||||
+252
@@ -0,0 +1,252 @@
|
||||
export type MaxDepth = 50;
|
||||
|
||||
export type Pretty<T> = { [K in keyof T]: T[K] };
|
||||
export type Constrain<T, U> = T extends U ? T : never;
|
||||
|
||||
namespace Vec {
|
||||
// prettier-ignore
|
||||
type Lookup<T, N extends number> = N extends 0
|
||||
? []
|
||||
: N extends 1
|
||||
? [T]
|
||||
: N extends 2
|
||||
? [T, T]
|
||||
: N extends 3
|
||||
? [T, T, T]
|
||||
: N extends 4
|
||||
? [T, T, T, T]
|
||||
: N extends 5
|
||||
? [T, T, T, T, T]
|
||||
: N extends 6
|
||||
? [T, T, T, T, T, T]
|
||||
: N extends 7
|
||||
? [T, T, T, T, T, T, T]
|
||||
: N extends 8
|
||||
? [T, T, T, T, T, T, T, T]
|
||||
: N extends 9
|
||||
? [T, T, T, T, T, T, T, T, T]
|
||||
: N extends 10
|
||||
? [T, T, T, T, T, T, T, T, T, T]
|
||||
: N extends 11
|
||||
? [T, T, T, T, T, T, T, T, T, T, T]
|
||||
: N extends 12
|
||||
? [T, T, T, T, T, T, T, T, T, T, T, T]
|
||||
: N extends 13
|
||||
? [T, T, T, T, T, T, T, T, T, T, T, T, T]
|
||||
: N extends 14
|
||||
? [T, T, T, T, T, T, T, T, T, T, T, T, T, T]
|
||||
: N extends 15
|
||||
? [T, T, T, T, T, T, T, T, T, T, T, T, T, T, T]
|
||||
: N extends 16
|
||||
? [T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T]
|
||||
: N extends 17
|
||||
? [T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T]
|
||||
: N extends 18
|
||||
? [T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T]
|
||||
: N extends 19
|
||||
? [T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T]
|
||||
: N extends 20
|
||||
? [T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T]
|
||||
: [T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T];
|
||||
|
||||
export type Recursive<
|
||||
T,
|
||||
N extends number,
|
||||
TOut extends T[] = Lookup<T, N>,
|
||||
TAcc extends never[] = [],
|
||||
> = TOut["length"] extends N
|
||||
? TOut
|
||||
: TAcc["length"] extends MaxDepth
|
||||
? T[]
|
||||
: Recursive<T, N, [...TOut, T], [...TAcc, never]>;
|
||||
}
|
||||
export type Vec<
|
||||
T,
|
||||
N extends number,
|
||||
Readonly extends boolean = false,
|
||||
> = number extends N
|
||||
? Readonly extends true
|
||||
? readonly T[]
|
||||
: T[]
|
||||
: `${N}` extends `${infer U extends number}${`.${number}` | ""}`
|
||||
? `${N}` extends `-${number}`
|
||||
? T[]
|
||||
: Vec.Recursive<T, U> extends infer V
|
||||
? Readonly extends true
|
||||
? { readonly [K in keyof V]: V[K] }
|
||||
: V
|
||||
: never
|
||||
: T[];
|
||||
|
||||
export type Inc<N extends number> = Constrain<
|
||||
number extends N ? number : [...Vec<never, N>, never]["length"],
|
||||
number
|
||||
>;
|
||||
|
||||
export type Dec<N extends number> = N extends 0
|
||||
? -1
|
||||
: `${N}` extends `-${infer U extends number}`
|
||||
? `-${Inc<U>}` extends `${infer O extends number}`
|
||||
? O
|
||||
: never
|
||||
: `${N}` extends `${number}`
|
||||
? Vec<never, N> extends [never, ...infer Rest]
|
||||
? Rest["length"]
|
||||
: number
|
||||
: number;
|
||||
|
||||
namespace At {
|
||||
export type FindBack<
|
||||
T extends readonly unknown[],
|
||||
N extends number,
|
||||
TAcc extends never[] = [],
|
||||
> = T extends readonly [...infer Rest, infer Last]
|
||||
? TAcc["length"] extends N
|
||||
? Last
|
||||
: TAcc["length"] extends MaxDepth
|
||||
? Rest[number]
|
||||
: FindBack<Rest, N, [...TAcc, never]>
|
||||
: T extends readonly []
|
||||
? undefined
|
||||
: never;
|
||||
|
||||
export type Sequence<
|
||||
T extends readonly unknown[],
|
||||
N extends readonly number[],
|
||||
Fallback extends T[number][],
|
||||
TOut extends T[number][] = [],
|
||||
> = TOut["length"] extends MaxDepth
|
||||
? Fallback
|
||||
: N extends readonly [
|
||||
infer Current extends number,
|
||||
...infer Rest extends number[],
|
||||
]
|
||||
? Sequence<T, Rest, Fallback, [...TOut, At<T, Current>]>
|
||||
: N extends readonly []
|
||||
? TOut
|
||||
: never;
|
||||
}
|
||||
export type At<
|
||||
T extends readonly unknown[],
|
||||
N extends number | readonly number[],
|
||||
> = N extends readonly number[]
|
||||
? number extends N["length"]
|
||||
? (T[number] | undefined)[]
|
||||
: At.Sequence<T, N, Vec<T[number], N["length"]>>
|
||||
: N extends number
|
||||
? N extends `${number}.${number}`
|
||||
? undefined
|
||||
: number extends T["length"]
|
||||
? T[number] | undefined
|
||||
: `${N}` extends `-${infer U extends number}`
|
||||
? At.FindBack<T, Dec<U>>
|
||||
: T[N]
|
||||
: never;
|
||||
|
||||
namespace Flat {
|
||||
export type Simple<
|
||||
T,
|
||||
Depth extends number = 0,
|
||||
> = Depth extends MaxDepth
|
||||
? T
|
||||
: T extends readonly unknown[]
|
||||
? Simple<T[number], Inc<Depth>>
|
||||
: T;
|
||||
|
||||
export type Flatten<
|
||||
T extends readonly unknown[],
|
||||
TOrig extends readonly unknown[] = T,
|
||||
TOut extends unknown[] = [],
|
||||
> = TOut["length"] extends MaxDepth
|
||||
? Flat.Simple<TOrig>[]
|
||||
: T extends readonly [infer Current, ...infer Rest]
|
||||
? Current extends readonly unknown[]
|
||||
? number extends Current["length"]
|
||||
? Flatten<Rest, TOrig, [...TOut, ...Current]>
|
||||
: Flatten<
|
||||
Rest,
|
||||
TOrig,
|
||||
[...TOut, ...Flat<Current>]
|
||||
>
|
||||
: Flatten<Rest, TOrig, [...TOut, Current]>
|
||||
: T extends readonly []
|
||||
? TOut
|
||||
: never;
|
||||
export type Flat<
|
||||
T extends readonly unknown[],
|
||||
TOrig extends readonly unknown[] = T,
|
||||
> = number extends T["length"]
|
||||
? Flat.Simple<T>[]
|
||||
: Flat.Flatten<T, TOrig>;
|
||||
}
|
||||
export type Flat<T extends readonly unknown[]> = Flat.Flat<T>;
|
||||
|
||||
if (import.meta.vitest) {
|
||||
const { test, expectTypeOf } = import.meta.vitest;
|
||||
|
||||
test("Vec<T, N>", () => {
|
||||
expectTypeOf<Vec<never, 0>>().toEqualTypeOf<[]>();
|
||||
|
||||
expectTypeOf<Vec<number, 4>>().toEqualTypeOf<
|
||||
[number, number, number, number]
|
||||
>();
|
||||
expectTypeOf<Vec<number, 4, true>>().toEqualTypeOf<
|
||||
readonly [number, number, number, number]
|
||||
>();
|
||||
|
||||
expectTypeOf<Vec<number, typeof Infinity>>().toEqualTypeOf<
|
||||
number[]
|
||||
>();
|
||||
expectTypeOf<Vec<number, number>>().toEqualTypeOf<number[]>();
|
||||
});
|
||||
|
||||
test("Inc<N>", () => {
|
||||
expectTypeOf<Inc<0>>().toEqualTypeOf<1>();
|
||||
expectTypeOf<Inc<50>>().toEqualTypeOf<51>();
|
||||
|
||||
expectTypeOf<Inc<-5>>().toEqualTypeOf<number>();
|
||||
expectTypeOf<Inc<typeof Infinity>>().toEqualTypeOf<number>();
|
||||
expectTypeOf<Inc<number>>().toEqualTypeOf<number>();
|
||||
});
|
||||
|
||||
test("Dec<N>", () => {
|
||||
expectTypeOf<Dec<5>>().toEqualTypeOf<4>();
|
||||
expectTypeOf<Dec<0>>().toEqualTypeOf<-1>();
|
||||
expectTypeOf<Dec<-4>>().toEqualTypeOf<-5>();
|
||||
|
||||
expectTypeOf<Dec<typeof Infinity>>().toEqualTypeOf<number>();
|
||||
expectTypeOf<Dec<number>>().toEqualTypeOf<number>();
|
||||
});
|
||||
|
||||
test("At<T, N>", () => {
|
||||
type Array = [0, 1, 2, 3, 4, 5];
|
||||
|
||||
expectTypeOf<At<Array, 0>>().toEqualTypeOf<Array[0]>();
|
||||
expectTypeOf<At<Array, -1>>().toEqualTypeOf<Array[5]>();
|
||||
|
||||
expectTypeOf<At<Array, 10>>().toEqualTypeOf<undefined>();
|
||||
expectTypeOf<At<Array, -10>>().toEqualTypeOf<undefined>();
|
||||
expectTypeOf<At<number[], 0>>().toEqualTypeOf<
|
||||
number | undefined
|
||||
>();
|
||||
|
||||
expectTypeOf<At<Array, [0, -1]>>().toEqualTypeOf<[0, 5]>();
|
||||
expectTypeOf<At<Readonly<Array>, [0]>>().toEqualTypeOf<[0]>();
|
||||
});
|
||||
|
||||
test("Flat<T>", () => {
|
||||
type Array = [0, [1, 2], [[3]]];
|
||||
|
||||
expectTypeOf<Flat<Array>>().toEqualTypeOf<[0, 1, 2, 3]>();
|
||||
expectTypeOf<Flat<number[]>>().toEqualTypeOf<number[]>();
|
||||
|
||||
expectTypeOf<Flat<[...Array, boolean[]]>>().toEqualTypeOf<
|
||||
[0, 1, 2, 3, ...boolean[]]
|
||||
>();
|
||||
|
||||
expectTypeOf<Flat<number[][][]>>().toEqualTypeOf<number[]>();
|
||||
expectTypeOf<
|
||||
Flat<((number[] | number)[] | number)[]>
|
||||
>().toEqualTypeOf<number[]>();
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user