From a30a1db5cc7f616de4024420e631d60405907297 Mon Sep 17 00:00:00 2001 From: uri Date: Wed, 8 Jan 2025 16:41:14 +0200 Subject: [PATCH] smart-filter --- src/composition.ts | 2 +- src/filter.test.ts | 4 ++++ src/filter.ts | 14 +++++++++----- src/juxt.ts | 5 ++--- src/map.ts | 1 - src/mapping.ts | 21 +++++++-------------- 6 files changed, 23 insertions(+), 24 deletions(-) diff --git a/src/composition.ts b/src/composition.ts index 4f874e4..884308e 100644 --- a/src/composition.ts +++ b/src/composition.ts @@ -1,5 +1,5 @@ import { reverse } from "./array.ts"; -import { ComposeMany } from "./composeTyping.ts"; +import type { ComposeMany } from "./composeTyping.ts"; import { not } from "./operator.ts"; import { isPromise } from "./promise.ts"; import { reduce } from "./reduce.ts"; diff --git a/src/filter.test.ts b/src/filter.test.ts index 6b9fdd4..7e932ce 100644 --- a/src/filter.test.ts +++ b/src/filter.test.ts @@ -19,12 +19,16 @@ Deno.test("async filter", async () => { }); const _nums: number[] = remove((x: number) => x > 0)([1, 2, 3]); + // @ts-expect-error should preserve typing information const _strings: string[] = remove((x: number) => x > 0)([1, 2, 3]); + const _strings_promise: Promise = remove((x: number) => Promise.resolve(x > 0) )([1, 2, 3]); +const _predicateTyping: 1[] = filter((x: number) => x == 1)([1, 2, 3]); + Deno.test("async filter", async () => { assertEquals( await remove((arg: number) => wrapPromise(arg % 2 === 0))([ diff --git a/src/filter.ts b/src/filter.ts index 51cc4d4..e2ff458 100644 --- a/src/filter.ts +++ b/src/filter.ts @@ -1,14 +1,18 @@ -import type { Func, IsAsync, ParamOf } from "./typing.ts"; -import { complement, pipe } from "./composition.ts"; import { head, second } from "./array.ts"; - -import { map } from "./map.ts"; +import { complement, pipe } from "./composition.ts"; import { pairRight } from "./juxt.ts"; +import { map } from "./map.ts"; import { isPromise } from "./promise.ts"; +import type { Func, IsAsync, ParamOf } from "./typing.ts"; + +type ConstrainedTyping = F extends + ((value: ParamOf) => value is infer S) ? S[] + : ParamOf[]; export const filter = (f: F): ( _: ParamOf[], -) => true extends IsAsync ? Promise[]> : ParamOf[] => +) => true extends IsAsync ? Promise> + : ConstrainedTyping => // @ts-expect-error typing head is hard. pipe( map(pairRight(f)), diff --git a/src/juxt.ts b/src/juxt.ts index 2a2f745..2c2aae1 100644 --- a/src/juxt.ts +++ b/src/juxt.ts @@ -1,5 +1,7 @@ import { allmap, anymap, concat, zip } from "./array.ts"; import { identity, pipe } from "./composition.ts"; +import { isPromise } from "./promise.ts"; +import { map } from "./map.ts"; import type { AnyAsync, Func, @@ -8,9 +10,6 @@ import type { Union, } from "./typing.ts"; -import { map } from "./map.ts"; -import { isPromise } from "./index.ts"; - type Results = { [i in keyof Functions]: ReturnTypeUnwrapped; }; diff --git a/src/map.ts b/src/map.ts index d8d0688..a21da59 100644 --- a/src/map.ts +++ b/src/map.ts @@ -1,5 +1,4 @@ import type { IsAsync, Unary, UnaryFnUntyped } from "./typing.ts"; - import { errorBoundry, pipe } from "./composition.ts"; import { reduce } from "./reduce.ts"; import { isPromise } from "./promise.ts"; diff --git a/src/mapping.ts b/src/mapping.ts index 9747b31..8d64c97 100644 --- a/src/mapping.ts +++ b/src/mapping.ts @@ -1,5 +1,10 @@ +import { head, second, wrapArray } from "./array.ts"; +import { applyTo, identity, pipe } from "./composition.ts"; +import { filter } from "./filter.ts"; +import { stack } from "./juxt.ts"; +import { map } from "./map.ts"; +import { reduce } from "./reduce.ts"; import type { - AsyncFunction, ElementOf, Func, IsAsync, @@ -8,13 +13,6 @@ import type { ReturnTypeUnwrapped, Unary, } from "./typing.ts"; -import { applyTo, identity, pipe } from "./composition.ts"; -import { head, second, wrapArray } from "./array.ts"; - -import { filter } from "./filter.ts"; -import { map } from "./map.ts"; -import { reduce } from "./reduce.ts"; -import { stack } from "./juxt.ts"; export const wrapObject = (key: string) => (value: V) => ({ [key]: value }); @@ -115,12 +113,7 @@ const onEntries = < export const entryMap = pipe(map, onEntries); -export const entryFilter = < - Function extends ( - // deno-lint-ignore no-explicit-any - ((kv: [any, any]) => any) - ), ->(f: Function) => onEntries(filter(f)); +export const entryFilter = pipe(filter, onEntries); type RecordKey = string | number | symbol; type EntryMap<