Skip to content

Commit

Permalink
feature: Better Option type annotations
Browse files Browse the repository at this point in the history
add more conditionals return types for Option<never>
  • Loading branch information
mathroc committed Sep 26, 2024
1 parent e0d930b commit 7de4309
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 16 deletions.
51 changes: 35 additions & 16 deletions src/Option.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ interface Option extends \IteratorAggregate
* self::assertFalse($x->isSome());
* ```
*
* @return (T is never ? false : bool)
* @phpstan-return bool
* @psalm-assert-if-true Option\Some $this
* @psalm-assert-if-false Option\None $this
*/
Expand All @@ -90,6 +92,8 @@ public function isSome(): bool;
* self::assertTrue($x->isNone());
* ```
*
* @return (T is never ? true : bool)
* @phpstan-return bool
* @psalm-assert-if-true Option\None $this
* @psalm-assert-if-false Option\Some $this
*/
Expand All @@ -115,6 +119,8 @@ public function isNone(): bool;
* ```
*
* @param callable(T):bool $predicate
* @return (T is never ? false : bool)
* @phpstan-return bool
* @psalm-assert-if-true Option\Some $this
*/
public function isSomeAnd(callable $predicate): bool;
Expand Down Expand Up @@ -247,7 +253,8 @@ public function inspect(callable $callback): self;
*
* @template U
* @param Option<U> $right
* @return Option<U>
* @return (T is never ? Option\None : Option<U>)
* @phpstan-return Option<U>
*/
public function and(Option $right): Option;

Expand All @@ -270,7 +277,8 @@ public function and(Option $right): Option;
*
* @template U
* @param callable(T):Option<U> $right
* @return Option<U>
* @return (T is never ? Option\None : Option<U>)
* @phpstan-return Option<U>
*/
public function andThen(callable $right): Option;

Expand Down Expand Up @@ -301,9 +309,9 @@ public function andThen(callable $right): Option;
* self::assertSame($x->or($y), Option\none());
* ```
*
* @param Option<T> $right
* @return Option<T>
* @psalm-assert-if-false Option\None $this
* @template U
* @param Option<U> $right
* @return Option<T|U>
*/
public function or(Option $right): Option;

Expand Down Expand Up @@ -336,7 +344,7 @@ public function or(Option $right): Option;
public function orElse(callable $right): Option;

/**
* Returns the option if it is `Some`, otherwise returns `$right`.
* Returns the some option if exactly one is a `Some`, return `None` otherwise.
*
* # Examples
*
Expand All @@ -359,8 +367,9 @@ public function orElse(callable $right): Option;
* self::assertSame($x->xor($y), Option\none());
* ```
*
* @param Option<T> $right
* @return Option<T>
* @template U
* @param Option<U> $right
* @return Option<T|U>
*/
public function xor(Option $right): Option;

Expand All @@ -380,6 +389,8 @@ public function xor(Option $right): Option;
* ```
*
* @psalm-assert-if-true Option\Some $this
* @return (T is never ? false : bool)
* @phpstan-return bool
*/
public function contains(mixed $value, bool $strict = true): bool;

Expand Down Expand Up @@ -416,7 +427,8 @@ public function filter(callable $predicate): Option;
*
* @template U
* @param callable(T):U $callback
* @return Option<U>
* @return (T is never ? Option\None : Option<U>)
* @phpstan-return Option<U>
*/
public function map(callable $callback): Option;

Expand All @@ -435,9 +447,11 @@ public function map(callable $callback): Option;
* ```
*
* @template U
* @template V
* @param callable(T):U $callback
* @param U $default
* @return U
* @param V $default
* @return (T is never ? V : U)
* @phpstan-return U|V
*/
public function mapOr(callable $callback, mixed $default): mixed;

Expand All @@ -457,9 +471,11 @@ public function mapOr(callable $callback, mixed $default): mixed;
* ```
*
* @template U
* @template V
* @param callable(T):U $callback
* @param callable():U $default
* @return U
* @param callable():V $default
* @return (T is never ? V : U)
* @phpstan-return U|V
*/
public function mapOrElse(callable $callback, callable $default): mixed;

Expand All @@ -482,7 +498,8 @@ public function mapOrElse(callable $callback, callable $default): mixed;
*
* @template U
* @param Option<U> $option
* @return Option<array{T, U}>
* @return (T is never ? Option\None : (U is never ? Option\None : Option<array{T, U}>))
* @phpstan-return Option<array{T, U}>
*/
public function zip(Option $option): Option;

Expand All @@ -500,7 +517,8 @@ public function zip(Option $option): Option;
*
* @template E
* @param E $err
* @return Result<T, E>
* @return (T is never ? Result\Err<E> : Result<T,E>)
* @phpstan-return Result<T,E>
*/
#[ExamplesSetup(IgnoreUnusedResults::class)]
public function okOr(mixed $err): Result;
Expand All @@ -519,7 +537,8 @@ public function okOr(mixed $err): Result;
*
* @template E
* @param callable():E $err
* @return Result<T, E>
* @phpstan-return Result<T,E>
* @return (T is never ? Result\Err<E> : Result<T,E>)
*/
#[ExamplesSetup(IgnoreUnusedResults::class)]
public function okOrElse(callable $err): Result;
Expand Down
14 changes: 14 additions & 0 deletions src/Option/None.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,25 @@ public function map(callable $callback): Option
return $this;
}

/**
* @template U
* @template V
* @param callable(never):U $callback
* @param V $default
* @return V
*/
public function mapOr(callable $callback, mixed $default): mixed
{
return $default;
}

/**
* @template U
* @template V
* @param callable(never):U $callback
* @param callable():V $default
* @return V
*/
public function mapOrElse(callable $callback, callable $default): mixed
{
return $default();
Expand Down
36 changes: 36 additions & 0 deletions src/Option/Some.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ public function isNone(): bool
return false;
}

/**
* @param callable(T):bool $predicate
* @return bool
*/
public function isSomeAnd(callable $predicate): bool
{
return $predicate($this->value);
Expand Down Expand Up @@ -82,11 +86,21 @@ public function inspect(callable $callback): self
return $this;
}

/**
* @template U
* @param Option<U> $right
* @return Option<U>
*/
public function and(Option $right): Option
{
return $right;
}

/**
* @template U
* @param callable(T):Option<U> $right
* @return Option<U>
*/
public function andThen(callable $right): Option
{
return $right($this->value);
Expand Down Expand Up @@ -115,6 +129,9 @@ public function xor(Option $right): Option
: Option\none();
}

/**
* @return bool
*/
public function contains(mixed $value, bool $strict = true): bool
{
return $strict
Expand All @@ -130,16 +147,35 @@ public function filter(callable $predicate): Option
: Option\none();
}

/**
* @template U
* @param callable(T):U $callback
* @return Option<U>
*/
public function map(callable $callback): Option
{
return Option\some($callback($this->value));
}

/**
* @template U
* @template V
* @param callable(T):U $callback
* @param V $default
* @return U
*/
public function mapOr(callable $callback, mixed $default): mixed
{
return $callback($this->value);
}

/**
* @template U
* @template V
* @param callable(T):U $callback
* @param callable():V $default
* @return U
*/
public function mapOrElse(callable $callback, callable $default): mixed
{
return $callback($this->value);
Expand Down

0 comments on commit 7de4309

Please sign in to comment.