diff --git a/test/max.test.ts b/test/max.test.ts new file mode 100644 index 0000000..7ad5b6e --- /dev/null +++ b/test/max.test.ts @@ -0,0 +1,22 @@ +import { expectError, expectType } from 'tsd'; + +import { max } from '../es'; + +// please note how literals work in this situation +expectType<1 | 2>(max(1, 2)); +// using variables that are type `number` is the more general use-case here +const a: number = 1; +const b: number = 2; +expectType(max(a, b)); +// you can also upcast inline to get the same result +expectType(max(1 as number, 2 as number)); +// now check the other Ord types +expectType(max('a' as string, 'b' as string)); +expectType(max(true as boolean, false as boolean)); +expectType(max(new Date(Date.now() - 1), new Date(Date.now()))); + +// curried +expectType<(b: number) => number>(max(a)); + +// don't allow different types +expectError(max(1, '2')); diff --git a/test/maxBy.test.ts b/test/maxBy.test.ts new file mode 100644 index 0000000..92fc189 --- /dev/null +++ b/test/maxBy.test.ts @@ -0,0 +1,34 @@ +import { expectError, expectType } from 'tsd'; + +import { __, maxBy, prop } from '../es'; + +type Obj = { + str: string; + date: Date; + bool: boolean; +}; + +// please note how literals work in this situation +expectType<1 | 2>(maxBy(Math.abs, 1, 2)); +// using variables that are type `number` is the more general use-case here +const a: number = 1; +const b: number = 2; +expectType(maxBy(Math.abs, a, b)); +// you can also upcast inline to get the same result +expectType(maxBy(Math.abs, 1 as number, 2 as number)); +// now check the other Ord types +expectType(maxBy(prop('str'), {} as Obj, {} as Obj)); +expectType(maxBy(prop('bool'), {} as Obj, {} as Obj)); +expectType(maxBy(prop('date'), {} as Obj, {} as Obj)); + +// Placeholder +// expectType(max(__, a, b)(fn)); +expectType(maxBy(__, 1 as number, 2 as number)(Math.abs)); +// curried +// notice how literals work fine here because `T` is pulled directly from Math.abs +// in the full function typescript will hard union them, but here it cannot +expectType(maxBy(Math.abs)(1)(2)); +expectType(maxBy(Math.abs)(1, 2)); + +// don't allow different types +expectError(maxBy(Math.abs, 1, '2')); diff --git a/test/min.test.ts b/test/min.test.ts new file mode 100644 index 0000000..25ab010 --- /dev/null +++ b/test/min.test.ts @@ -0,0 +1,22 @@ +import { expectError, expectType } from 'tsd'; + +import { min } from '../es'; + +// please note how literals work in this situation +expectType<1 | 2>(min(1, 2)); +// using variables that are type `number` is the more general use-case here +const a: number = 1; +const b: number = 2; +expectType(min(a, b)); +// you can also upcast inline to get the same result +expectType(min(1 as number, 2 as number)); +// now check the other Ord types +expectType(min('a' as string, 'b' as string)); +expectType(min(true as boolean, false as boolean)); +expectType(min(new Date(Date.now() - 1), new Date(Date.now()))); + +// curried +expectType<(b: number) => number>(min(a)); + +// don't allow different types +expectError(min(1, '2')); diff --git a/test/minBy.test.ts b/test/minBy.test.ts new file mode 100644 index 0000000..adc3413 --- /dev/null +++ b/test/minBy.test.ts @@ -0,0 +1,34 @@ +import { expectError, expectType } from 'tsd'; + +import { __, minBy, prop } from '../es'; + +type Obj = { + str: string; + date: Date; + bool: boolean; +}; + +// please note how literals work in this situation +expectType<1 | 2>(minBy(Math.abs, 1, 2)); +// using variables that are type `number` is the more general use-case here +const a: number = 1; +const b: number = 2; +expectType(minBy(Math.abs, a, b)); +// you can also upcast inline to get the same result +expectType(minBy(Math.abs, 1 as number, 2 as number)); +// now check the other Ord types +expectType(minBy(prop('str'), {} as Obj, {} as Obj)); +expectType(minBy(prop('bool'), {} as Obj, {} as Obj)); +expectType(minBy(prop('date'), {} as Obj, {} as Obj)); + +// Placeholder +// expectType(max(__, b)(a)); +expectType(minBy(__, 1 as number, 2 as number)(Math.abs)); +// curried +// notice how literals work fine here because `T` is pulled directly from Math.abs +// in the full function typescript will hard union them, but here it cannot +expectType(minBy(Math.abs)(1)(2)); +expectType(minBy(Math.abs)(1, 2)); + +// don't allow different types +expectError(minBy(Math.abs, 1, '2')); diff --git a/types/maxBy.d.ts b/types/maxBy.d.ts index c24b22b..4a603fd 100644 --- a/types/maxBy.d.ts +++ b/types/maxBy.d.ts @@ -1,6 +1,25 @@ -import * as _ from 'ts-toolbelt'; -import { Ord } from './util/tools'; +import { Placeholder, Ord } from './util/tools'; -export function maxBy(keyFn: (a: T) => Ord): _.F.Curry<(a: T, b: T) => T>; -export function maxBy(keyFn: (a: T) => Ord, a: T): (b: T) => T; -export function maxBy(keyFn: (a: T) => Ord, a: T, b: T): T; +// Commutative means we can simplify the overloads for handlings placeholders +// maxBy(fn) +export function maxBy(fn: (a: T) => Ord): { + // maxBy(fn)(a)(b) + (a: T): (b: T) => T; + // maxBy(fn)(a, b) + (a: T, b: T): T; +}; +// maxBy(__, a) +export function maxBy(__: Placeholder, a: T): { + // maxBy(__, a)(fn)(b) + (fn: (a: T) => Ord): (b: T) => T; + // maxBy(__, a)(__, b)(fn) + (__: Placeholder, b: T): (fn: (a: T) => Ord) => T; + // maxBy(__, a)(fn, b) + (fn: (a: T) => Ord, b: T): T; +}; +// maxBy(fn, a)(b) +export function maxBy(fn: (a: T) => Ord, a: T): (b: T) => T; +// maxBy(__, a, b)(fn) +export function maxBy(__: Placeholder, a: T, b: T): (fn: (a: T) => Ord) => T; +// maxBy(fn, a, b) +export function maxBy(fn: (a: T) => Ord, a: T, b: T): T; diff --git a/types/minBy.d.ts b/types/minBy.d.ts index 7df94ee..aac7b5f 100644 --- a/types/minBy.d.ts +++ b/types/minBy.d.ts @@ -1,6 +1,25 @@ -import * as _ from 'ts-toolbelt'; -import { Ord } from './util/tools'; +import { Placeholder, Ord } from './util/tools'; -export function minBy(keyFn: (a: T) => Ord): _.F.Curry<(a: T, b: T) => T>; -export function minBy(keyFn: (a: T) => Ord, a: T): (b: T) => T; -export function minBy(keyFn: (a: T) => Ord, a: T, b: T): T; +// Commutative means we can simplify the overloads for handlings placeholders +// minBy(fn) +export function minBy(fn: (a: T) => Ord): { + // minBy(fn)(a)(b) + (a: T): (b: T) => T; + // minBy(fn)(a, b) + (a: T, b: T): T; +}; +// minBy(__, a) +export function minBy(__: Placeholder, a: T): { + // minBy(__, a)(fn)(b) + (fn: (a: T) => Ord): (b: T) => T; + // minBy(__, a)(__, b)(fn) + (__: Placeholder, b: T): (fn: (a: T) => Ord) => T; + // minBy(__, a)(fn, b) + (fn: (a: T) => Ord, b: T): T; +}; +// minBy(fn, a)(b) +export function minBy(fn: (a: T) => Ord, a: T): (b: T) => T; +// minBy(__, a, b)(fn) +export function minBy(__: Placeholder, a: T, b: T): (fn: (a: T) => Ord) => T; +// minBy(fn, a, b) +export function minBy(fn: (a: T) => Ord, a: T, b: T): T;