diff --git a/package.json b/package.json index d299811..fce26b8 100644 --- a/package.json +++ b/package.json @@ -34,5 +34,5 @@ "test": "bun test" }, "types": "dist/index.d.ts", - "version": "0.2.0" + "version": "0.3.0" } diff --git a/source/index.test.ts b/source/index.test.ts index 0eed756..27895b2 100644 --- a/source/index.test.ts +++ b/source/index.test.ts @@ -6,9 +6,7 @@ describe('NullishMath static methods', () => { it('correctly implements NullishMath.unwrap()', () => { expect(NullishMath.unwrap(null)).toBe(null) expect(NullishMath.unwrap(undefined)).toBe(null) - // @ts-expect-error not allowed to pass a value that’s always nullish expect(NullishMath.unwrap(nm(null))).toBe(null) - // @ts-expect-error not allowed to pass a value that’s always nullish expect(NullishMath.unwrap(nm(undefined))).toBe(null) expect(NullishMath.unwrap(nm(42))).toBe(42) expect(NullishMath.unwrap(42)).toBe(42) @@ -63,20 +61,15 @@ describe('NullishMath static methods', () => { describe('nm.add()', () => { it('supports null #value', () => { - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(null).add(42).end()).toBe(null) - - // @ts-expect-error not allowed to pass a value that’s always nullish nm(42).add(null).end() }) it('supports a single null parameter', () => { - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(42).add(null).end()).toBe(null) }) it('supports a single undefined parameter', () => { - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(42).add(undefined).end()).toBe(null) }) @@ -89,28 +82,21 @@ describe('nm.add()', () => { }) it('supports a single mixed parameter', () => { - expect( - nm(42) - .add(21 as number | null) - .end(), - ).toBe(63) + expect(nm(42).add(21).end()).toBe(63) }) }) describe('nm.addMany()', () => { it('supports no parameters', () => { expect(nm(42).addMany().end()).toBe(42) - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(null).addMany().end()).toBe(null) }) it('supports multiple null parameters', () => { - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(42).addMany(null, null).end()).toBe(null) }) it('supports multiple undefined parameters', () => { - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(42).addMany(undefined, undefined).end()).toBe(null) }) @@ -127,14 +113,10 @@ describe('nm.addMany()', () => { describe('comparison operators', () => { it('nm.eq()', () => { - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(null).eq(null)).toBe(true) - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(null).eq(undefined)).toBe(true) - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(undefined).eq(null)).toBe(true) - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(undefined).eq(42)).toBe(false) expect(nm(42).eq(undefined)).toBe(false) @@ -144,14 +126,10 @@ describe('comparison operators', () => { }) it('nm.lt()', () => { - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(null).lt(null)).toBe(null) - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(null).lt(undefined)).toBe(null) - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(undefined).lt(null)).toBe(null) - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(undefined).lt(42)).toBe(null) expect(nm(42).lt(undefined)).toBe(null) @@ -161,14 +139,10 @@ describe('comparison operators', () => { }) it('nm.lte()', () => { - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(null).lte(null)).toBe(null) - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(null).lte(undefined)).toBe(null) - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(undefined).lte(null)).toBe(null) - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(undefined).lte(42)).toBe(null) expect(nm(42).lte(undefined)).toBe(null) @@ -178,14 +152,10 @@ describe('comparison operators', () => { }) it('nm.gt()', () => { - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(null).gt(null)).toBe(null) - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(null).gt(undefined)).toBe(null) - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(undefined).gt(null)).toBe(null) - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(undefined).gt(42)).toBe(null) expect(nm(42).gt(undefined)).toBe(null) @@ -195,14 +165,10 @@ describe('comparison operators', () => { }) it('nm.gte()', () => { - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(null).gte(null)).toBe(null) - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(null).gte(undefined)).toBe(null) - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(undefined).gte(null)).toBe(null) - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(undefined).gte(42)).toBe(null) expect(nm(42).gte(undefined)).toBe(null) @@ -214,17 +180,14 @@ describe('comparison operators', () => { describe('nm.subtract()', () => { it('supports null #value', () => { - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(null).subtract(42).end()).toBe(null) }) it('supports a single null parameter', () => { - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(42).subtract(null).end()).toBe(null) }) it('supports a single undefined parameter', () => { - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(42).subtract(undefined).end()).toBe(null) }) @@ -237,28 +200,21 @@ describe('nm.subtract()', () => { }) it('supports a single mixed parameter', () => { - expect( - nm(42) - .subtract(21 as number | null) - .end(), - ).toBe(21) + expect(nm(42).subtract(21).end()).toBe(21) }) }) describe('nm.subtractMany()', () => { it('supports no parameters', () => { expect(nm(42).subtractMany().end()).toBe(42) - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(null).subtractMany().end()).toBe(null) }) it('supports multiple null parameters', () => { - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(42).subtractMany(null, null).end()).toBe(null) }) it('supports multiple undefined parameters', () => { - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(42).subtractMany(undefined, undefined).end()).toBe(null) }) @@ -275,17 +231,14 @@ describe('nm.subtractMany()', () => { describe('nm.multiply()', () => { it('supports null #value', () => { - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(null).multiply(42).end()).toBe(null) }) it('supports a single null parameter', () => { - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(42).multiply(null).end()).toBe(null) }) it('supports a single undefined parameter', () => { - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(42).multiply(undefined).end()).toBe(null) }) @@ -298,28 +251,21 @@ describe('nm.multiply()', () => { }) it('supports a single mixed parameter', () => { - expect( - nm(42) - .multiply(21 as number | null) - .end(), - ).toBe(882) + expect(nm(42).multiply(21).end()).toBe(882) }) }) describe('nm.multiplyMany()', () => { it('supports no parameters', () => { expect(nm(42).multiplyMany().end()).toBe(42) - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(null).multiplyMany().end()).toBe(null) }) it('supports multiple null parameters', () => { - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(42).multiplyMany(null, null).end()).toBe(null) }) it('supports multiple undefined parameters', () => { - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(42).multiplyMany(undefined, undefined).end()).toBe(null) }) @@ -336,17 +282,14 @@ describe('nm.multiplyMany()', () => { describe('nm.divide()', () => { it('supports null #value', () => { - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(null).divide(42).end()).toBe(null) }) it('supports a single null parameter', () => { - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(42).divide(null).end()).toBe(null) }) it('supports a single undefined parameter', () => { - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(42).divide(undefined).end()).toBe(null) }) @@ -359,28 +302,21 @@ describe('nm.divide()', () => { }) it('supports a single mixed parameter', () => { - expect( - nm(42) - .divide(21 as number | null) - .end(), - ).toBe(2) + expect(nm(42).divide(21).end()).toBe(2) }) }) describe('nm.divideMany()', () => { it('supports no parameters', () => { expect(nm(42).divideMany().end()).toBe(42) - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(null).divideMany().end()).toBe(null) }) it('supports multiple null parameters', () => { - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(42).divideMany(null, null).end()).toBe(null) }) it('supports multiple undefined parameters', () => { - // @ts-expect-error not allowed to pass a value that’s always nullish expect(nm(42).divideMany(undefined, undefined).end()).toBe(null) }) diff --git a/source/index.ts b/source/index.ts index 0b8e3f8..10d16e8 100644 --- a/source/index.ts +++ b/source/index.ts @@ -1,30 +1,10 @@ -export type NullishNumber = - | number - | NullishMath - | null - | undefined - -type NotOnlyNullish = [T] extends [null] - ? 'Number cannot always be null' - : [T] extends [undefined] - ? 'Number cannot always be undefined' - : [T] extends [null | undefined] - ? 'Number cannot always be nullish' - : T - -type NotOnlyNullishArray = [T] extends [null[]] - ? 'Number cannot always be null'[] - : [T] extends [undefined[]] - ? 'Number cannot always be undefined'[] - : [T] extends [Array] - ? 'Number cannot always be nullish'[] - : T - -export class NullishMath { +export type NullishNumber = NullishMath | number | null | undefined + +export class NullishMath { readonly #value: number | null - constructor(value: NotOnlyNullish) { - this.#value = NullishMath.unwrap(value as NullishNumber) + constructor(value: NullishNumber) { + this.#value = NullishMath.unwrap(value) } static average = ( @@ -34,7 +14,7 @@ export class NullishMath { } = { treatNullishAsZero: false, }, - ): NullishMath => { + ): NullishMath => { let countValid = 0 let sumValid = 0 @@ -56,9 +36,7 @@ export class NullishMath { return nm(sumValid).divide(countValid) } - static max = ( - numbers: NullishNumber[], - ): NullishMath => { + static max = (numbers: NullishNumber[]): NullishMath => { let max: number | null = null for (const rawNumber of numbers) { @@ -66,16 +44,13 @@ export class NullishMath { if (number === null) continue - if (max === null || number > max) - max = number + if (max === null || number > max) max = number } return nm(max) } - static min = ( - numbers: NullishNumber[], - ): NullishMath => { + static min = (numbers: NullishNumber[]): NullishMath => { let min: number | null = null for (const rawNumber of numbers) { @@ -83,8 +58,7 @@ export class NullishMath { if (number === null) continue - if (min === null || number < min) - min = number + if (min === null || number < min) min = number } return nm(min) @@ -97,26 +71,23 @@ export class NullishMath { return value.end() } - add( - number: NotOnlyNullish, - ): NullishMath { - const n = NullishMath.unwrap(number as NullishNumber) + add(number: NullishNumber): NullishMath { + const n = NullishMath.unwrap(number) - if (this.#value === null || n === null) - return new NullishMath(null as NullishNumber) + if (this.#value === null || n === null) return new NullishMath(null) return new NullishMath(this.#value + n) } - addMany>(...numbers: NotOnlyNullishArray) { + addMany(...numbers: NullishNumber[]) { let result = this.#value - if (result === null) return new NullishMath(null as NullishNumber) + if (result === null) return new NullishMath(null) for (const _n of numbers) { - const n = NullishMath.unwrap(_n as NullishNumber) + const n = NullishMath.unwrap(_n) - if (n === null) return new NullishMath(null as NullishNumber) + if (n === null) return new NullishMath(null) result = result + n } @@ -180,28 +151,23 @@ export class NullishMath { return this.#value !== n } - subtract( - number: NotOnlyNullish, - ): NullishMath { - const n = NullishMath.unwrap(number as NullishNumber) + subtract(number: NullishNumber): NullishMath { + const n = NullishMath.unwrap(number) - if (this.#value === null || n === null) - return new NullishMath(null as NullishNumber) + if (this.#value === null || n === null) return new NullishMath(null) return new NullishMath(this.#value - n) } - subtractMany>( - ...numbers: NotOnlyNullishArray - ) { + subtractMany(...numbers: NullishNumber[]) { let result = this.#value - if (result === null) return new NullishMath(null as NullishNumber) + if (result === null) return new NullishMath(null) for (const _n of numbers) { - const n = NullishMath.unwrap(_n as NullishNumber) + const n = NullishMath.unwrap(_n) - if (n === null) return new NullishMath(null as NullishNumber) + if (n === null) return new NullishMath(null) result = result - n } @@ -209,28 +175,23 @@ export class NullishMath { return new NullishMath(result) } - multiply( - number: NotOnlyNullish, - ): NullishMath { - const n = NullishMath.unwrap(number as NullishNumber) + multiply(number: NullishNumber): NullishMath { + const n = NullishMath.unwrap(number) - if (this.#value === null || n === null) - return new NullishMath(null as NullishNumber) + if (this.#value === null || n === null) return new NullishMath(null) return new NullishMath(this.#value * n) } - multiplyMany>( - ...numbers: NotOnlyNullishArray - ) { + multiplyMany(...numbers: NullishNumber[]) { let result = this.#value - if (result === null) return new NullishMath(null as NullishNumber) + if (result === null) return new NullishMath(null) for (const _n of numbers) { - const n = NullishMath.unwrap(_n as NullishNumber) + const n = NullishMath.unwrap(_n) - if (n === null) return new NullishMath(null as NullishNumber) + if (n === null) return new NullishMath(null) result = result * n } @@ -238,28 +199,23 @@ export class NullishMath { return new NullishMath(result) } - divide( - number: NotOnlyNullish, - ): NullishMath { - const n = NullishMath.unwrap(number as NullishNumber) + divide(number: NullishNumber): NullishMath { + const n = NullishMath.unwrap(number) - if (this.#value === null || n === null) - return new NullishMath(null as NullishNumber) + if (this.#value === null || n === null) return new NullishMath(null) return new NullishMath(this.#value / n) } - divideMany>( - ...numbers: NotOnlyNullishArray - ) { + divideMany(...numbers: NullishNumber[]) { let result = this.#value - if (result === null) return new NullishMath(null as NullishNumber) + if (result === null) return new NullishMath(null) for (const _n of numbers) { - const n = NullishMath.unwrap(_n as NullishNumber) + const n = NullishMath.unwrap(_n) - if (n === null) return new NullishMath(null as NullishNumber) + if (n === null) return new NullishMath(null) result = result / n } @@ -272,6 +228,6 @@ export class NullishMath { } } -export function nm(value: NotOnlyNullish) { +export function nm(value: NullishNumber) { return new NullishMath(value) }