Skip to content

Commit

Permalink
feat(transform): add filter operator
Browse files Browse the repository at this point in the history
  • Loading branch information
TomokiMiyauci committed Jul 4, 2023
1 parent 957350f commit c7b0d9e
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 4 deletions.
55 changes: 52 additions & 3 deletions operators/transform.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
// Copyright © 2023 Tomoki Miyauchi. All rights reserved. MIT license.
// This module is browser compatible.

import { isSome } from "./query.ts";
import { type Option, Some } from "../spec.ts";
import { isNone } from "../utils.ts";
import { isNone, isSome } from "./query.ts";
import { None, type Option, Some } from "../spec.ts";

/** Maps an `Option<T>` to `Option<U>` by applying a function to a contained value(if `Some`) or returns `None`(if `None`).
*
Expand Down Expand Up @@ -68,3 +67,53 @@ export function mapOrElse<T, U>(

return fn(option.get);
}

/** Returns {@link None} if the {@link option} is {@link None}, otherwise calls predicate with the wrapped value and returns:
* - {@link Some} if predicate returns `true`.
* - {@link None} if predicate returns `false`.
*
* @example
* ```ts
* import { type Option } from "https://deno.land/x/optio/spec.ts";
* import { filter } from "https://deno.land/x/optio/operators/transform.ts";
* import { assertType, IsExact } from "https://deno.land/std/testing/types.ts";
*
* declare const isString: (value: unknown) => value is string;
* declare const option: Option<string | number>;
*
* const opt = filter(option, isString);
* assertType<IsExact<typeof opt, Option<string>>>(true);
* ```
*/
export function filter<T, U extends T = T>(
option: Option<T>,
guard: (value: T) => value is U,
): Option<U>;

/**
* @example
* ```ts
* import { None, Some } from "https://deno.land/x/optio/spec.ts";
* import { filter } from "https://deno.land/x/optio/operators/transform.ts";
* import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
*
* declare const isEven: (value: number) => boolean;
*
* assertEquals(filter(Some.of(0), isEven), Some.of(0));
* assertEquals(filter(Some.of(1), isEven), None);
* assertEquals(filter(None, isEven), None);
* ```
*/
export function filter<T>(
option: Option<T>,
predicate: (value: T) => boolean,
): Option<T>;
export function filter<T>(
option: Option<T>,
predicate: (value: T) => boolean,
): Option<T> {
if (isNone(option)) return option;
if (predicate(option.get)) return option;

return None;
}
37 changes: 36 additions & 1 deletion operators/transform_test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
// Copyright © 2023 Tomoki Miyauchi. All rights reserved. MIT license.

import { map, mapOr, mapOrElse } from "./transform.ts";
import { filter, map, mapOr, mapOrElse } from "./transform.ts";
import { None, Option, Some } from "../spec.ts";
import {
assert,
assertEquals,
assertSpyCallArgs,
assertSpyCalls,
assertType,
describe,
IsExact,
isString,
it,
spy,
} from "../_dev_deps.ts";
Expand Down Expand Up @@ -80,3 +84,34 @@ describe("mapOrElse", () => {
assertSpyCalls(defaultFn, 1);
});
});

describe("filter", () => {
it("should return None if None", () => {
const predicate = spy(() => true);
assertEquals(filter(None, predicate), None);
assertSpyCalls(predicate, 0);
});

it("should return Some if Some and predicate is true", () => {
const predicate = spy(() => true);
const some = Some.of(0);
assert(filter(some, predicate) === some);
assertSpyCalls(predicate, 1);
assertSpyCallArgs(predicate, 0, [0]);
});

it("should return None if Some and predicate is false", () => {
const predicate = spy(() => false);
const some = Some.of(0);
assert(filter(some, predicate) === None);
assertSpyCalls(predicate, 1);
assertSpyCallArgs(predicate, 0, [0]);
});

it("should infer narrowing", () => {
const option: Option<string | number> = Some.of(0);

const opt = filter(option, isString);
assertType<IsExact<typeof opt, Option<string>>>(true);
});
});

0 comments on commit c7b0d9e

Please sign in to comment.