Skip to content

Commit

Permalink
feat: added NumericSort<T> utility
Browse files Browse the repository at this point in the history
  • Loading branch information
yankeeinlondon committed Sep 16, 2024
1 parent 9c86e29 commit fe40722
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 0 deletions.
64 changes: 64 additions & 0 deletions src/types/lists/NumericSort.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { AsNumericArray } from "./AsNumericArray"

type Iterator<n, iterator extends any[] = []> =
iterator['length'] extends n
? iterator
: Iterator<n, [any, ...iterator]>

type Drop1<xs extends any[]> =
xs extends [any, ...infer tail] ? tail : []

type LessThanOrEqual<a extends any[], b extends any[]> =
[a, b] extends [[], [any, ...any]]
? true
: [a, b] extends [[any,...any], []]
? false
: [a, b] extends [[], []]
? true
: LessThanOrEqual<Drop1<a>, Drop1<b>>

type GreaterThan<a extends any[], b extends any[]> =
[a, b] extends [[], [any, ...any]]
? false
: [a, b] extends [[any,...any], []]
? true
: [a, b] extends [[], []]
? false
: GreaterThan<Drop1<a>, Drop1<b>>


type FilterLessThanOrEqual<value, xs extends any[], output extends any[] = []> =
xs extends [infer head, ...infer tail]
? LessThanOrEqual<Iterator<value>, Iterator<head>> extends true
? [...output, head, ...FilterLessThanOrEqual<value, tail, output>]
: [...output, ...FilterLessThanOrEqual<value, tail, output>]
: []

type FilterGreaterThan<value, xs extends any[], output extends any[] = []> =
xs extends [infer head, ...infer tail]
? GreaterThan<Iterator<value>, Iterator<head>> extends true
? [...output, head, ...FilterGreaterThan<value, tail, output>]
: [...output, ...FilterGreaterThan<value, tail, output>]
: []


type _Sort<
TValues extends number[],
TReverse extends boolean = false
> =
TValues extends [infer head, ...infer tail]
? TReverse extends true
? [...NumericSort<FilterLessThanOrEqual<head, tail>, TReverse>, head, ...NumericSort<FilterGreaterThan<head, tail>, TReverse>]
: [...NumericSort<FilterGreaterThan<head, tail>, TReverse>, head, ...NumericSort<FilterLessThanOrEqual<head, tail>, TReverse>]
: []


/**
* **NumericSort**`<TValues, [TReverse]>`
*
* Sorts the values in a tuple numerically
*/
export type NumericSort<
TValues extends any[],
TReverse extends boolean = false
> = _Sort<AsNumericArray<TValues>,TReverse>
55 changes: 55 additions & 0 deletions tests/lists/NumericSort.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Equal, Expect } from "@type-challenges/utils";
import { NumericSort } from "src/types/index";
import { describe, it } from "vitest";

// Note: while type tests clearly fail visible inspection, they pass from Vitest
// standpoint so always be sure to run `tsc --noEmit` over your test files to
// gain validation that no new type vulnerabilities have cropped up.

describe("Sort<TValues,[TReverse]>", () => {

it("happy path", () => {
type S1 = NumericSort<[2,3,4,1]>;
type S2 = NumericSort<[22,33,44,11,11]>;
type S3 = NumericSort<[1,2,3,4]>;

type SR1 = NumericSort<[2,3,4,1], true>;
type SR2 = NumericSort<[22,33,44,11,11], true>;
type SR3 = NumericSort<[1,2,3,4], true>;



// @ts-ignore
type cases = [
Expect<Equal<S1, [1,2,3,4]>>,
Expect<Equal<S2, [11,11,22,33,44]>>,
Expect<Equal<S3, [1,2,3,4]>>,

Expect<Equal<SR1, [4,3,2,1]>>,
Expect<Equal<SR2, [44,33,22,11,11]>>,
Expect<Equal<SR3, [4,3,2,1]>>,
];
});

it("with string literals", () => {
type S1 = NumericSort<[`2`,`3`,`4`,1]>;
type S2 = NumericSort<[22,`33`,44,11,11]>;
type S3 = NumericSort<[1,2,3,`4`]>;

type SR1 = NumericSort<[`2`,`3`,`4`,`1`], true>;
type SR2 = NumericSort<[22,33,44,`11`,11], true>;
type SR3 = NumericSort<[1,`2`,`3`,4], true>;

// @ts-ignore
type cases = [
Expect<Equal<S1, [1,2,3,4]>>,
Expect<Equal<S2, [11,11,22,33,44]>>,
Expect<Equal<S3, [1,2,3,4]>>,

Expect<Equal<SR1, [4,3,2,1]>>,
Expect<Equal<SR2, [44,33,22,11,11]>>,
Expect<Equal<SR3, [4,3,2,1]>>,
];
});

});

0 comments on commit fe40722

Please sign in to comment.