Skip to content

Commit

Permalink
Support for the tacit usage of external handlers for Match.tag and …
Browse files Browse the repository at this point in the history
…`Match.tagStartsWith` functions (#3121)

Co-authored-by: maksim.khramtsov <[email protected]>
  • Loading branch information
KhraksMamtsov and maksim.khramtsov committed Jul 1, 2024
1 parent 5c0ceb0 commit 33735b1
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 16 deletions.
17 changes: 17 additions & 0 deletions .changeset/lovely-monkeys-compete.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
"effect": patch
---

Support for the tacit usage of external handlers for `Match.tag` and `Match.tagStartsWith` functions

```ts
type Value = { _tag: "A"; a: string } | { _tag: "B"; b: number }
const handlerA = (_: { _tag: "A"; a: number }) => _.a

// $ExpectType string | number
pipe(
M.type<Value>(),
M.tag("A", handlerA), // <-- no type issue
M.orElse((_) => _.b)
)(value)
```
25 changes: 25 additions & 0 deletions packages/effect/dtslint/Match.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as M from "effect/Match"

type Value = { _tag: "A"; a: number } | { _tag: "B"; b: number }
const value = { _tag: "A", a: 123 } as Value
const handlerA = (_: { _tag: "A"; a: number }) => _.a.toString()

// -------------------------------------------------------------------------------------
// valueTags
Expand Down Expand Up @@ -139,3 +140,27 @@ pipe(
C: () => false
})
)(value)

// -------------------------------------------------------------------------------------
// tag
// -------------------------------------------------------------------------------------

// tacit usage of external handler
// $ExpectType string | number
pipe(
M.type<Value>(),
M.tag("A", handlerA),
M.orElse((_) => _.b)
)(value)

// -------------------------------------------------------------------------------------
// tagStartsWith
// -------------------------------------------------------------------------------------

// tacit usage of external handler
// $ExpectType string | number
pipe(
M.type<Value>(),
M.tagStartsWith("A", handlerA),
M.orElse((_) => _.b)
)(value)
32 changes: 16 additions & 16 deletions packages/effect/src/Match.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import * as internal from "./internal/matcher.js"
import type * as Option from "./Option.js"
import type { Pipeable } from "./Pipeable.js"
import * as Predicate from "./Predicate.js"
import type { Contravariant, Covariant, UnionToIntersection } from "./Types.js"
import type * as T from "./Types.js"
import type { Unify } from "./Unify.js"

/**
Expand Down Expand Up @@ -36,11 +36,11 @@ export type Matcher<Input, Filters, RemainingApplied, Result, Provided, Return =
export interface TypeMatcher<in Input, out Filters, out Remaining, out Result, out Return = any> extends Pipeable {
readonly _tag: "TypeMatcher"
readonly [MatcherTypeId]: {
readonly _input: Contravariant<Input>
readonly _filters: Covariant<Filters>
readonly _remaining: Covariant<Remaining>
readonly _result: Covariant<Result>
readonly _return: Covariant<Return>
readonly _input: T.Contravariant<Input>
readonly _filters: T.Covariant<Filters>
readonly _remaining: T.Covariant<Remaining>
readonly _result: T.Covariant<Result>
readonly _return: T.Covariant<Return>
}
readonly cases: ReadonlyArray<Case>
add<I, R, RA, A>(_case: Case): TypeMatcher<I, R, RA, A>
Expand All @@ -55,10 +55,10 @@ export interface ValueMatcher<in Input, Filters, out Remaining, out Result, Prov
{
readonly _tag: "ValueMatcher"
readonly [MatcherTypeId]: {
readonly _input: Contravariant<Input>
readonly _filters: Covariant<Filters>
readonly _result: Covariant<Result>
readonly _return: Covariant<Return>
readonly _input: T.Contravariant<Input>
readonly _filters: T.Covariant<Filters>
readonly _result: T.Covariant<Result>
readonly _return: T.Covariant<Return>
}
readonly provided: Provided
readonly value: Either.Either<Provided, Remaining>
Expand Down Expand Up @@ -196,15 +196,15 @@ export const whenAnd: <
R,
const P extends ReadonlyArray<Types.PatternPrimitive<R> | Types.PatternBase<R>>,
Ret,
Fn extends (_: Types.WhenMatch<R, UnionToIntersection<P[number]>>) => Ret
Fn extends (_: Types.WhenMatch<R, T.UnionToIntersection<P[number]>>) => Ret
>(
...args: [...patterns: P, f: Fn]
) => <I, F, A, Pr>(
self: Matcher<I, F, R, A, Pr, Ret>
) => Matcher<
I,
Types.AddWithout<F, Types.PForExclude<UnionToIntersection<P[number]>>>,
Types.ApplyFilters<I, Types.AddWithout<F, Types.PForExclude<UnionToIntersection<P[number]>>>>,
Types.AddWithout<F, Types.PForExclude<T.UnionToIntersection<P[number]>>>,
Types.ApplyFilters<I, Types.AddWithout<F, Types.PForExclude<T.UnionToIntersection<P[number]>>>>,
A | ReturnType<Fn>,
Pr
> = internal.whenAnd
Expand Down Expand Up @@ -297,7 +297,7 @@ export const discriminatorsExhaustive: <D extends string>(
* @since 1.0.0
*/
export const tag: <R, P extends Types.Tags<"_tag", R> & string, Ret, B extends Ret>(
...pattern: [first: P, ...values: Array<P>, f: (_: Extract<R, Record<"_tag", P>>) => B]
...pattern: [first: P, ...values: Array<P>, f: (_: Extract<T.NoInfer<R>, Record<"_tag", P>>) => B]
) => <I, F, A, Pr>(
self: Matcher<I, F, R, A, Pr, Ret>
) => Matcher<
Expand All @@ -315,7 +315,7 @@ export const tag: <R, P extends Types.Tags<"_tag", R> & string, Ret, B extends R
*/
export const tagStartsWith: <R, P extends string, Ret, B extends Ret>(
pattern: P,
f: (_: Extract<R, Record<"_tag", `${P}${string}`>>) => B
f: (_: Extract<T.NoInfer<R>, Record<"_tag", `${P}${string}`>>) => B
) => <I, F, A, Pr>(
self: Matcher<I, F, R, A, Pr, Ret>
) => Matcher<
Expand Down Expand Up @@ -692,7 +692,7 @@ export declare namespace Types {
/**
* @since 1.0.0
*/
export type ArrayToIntersection<A extends ReadonlyArray<any>> = UnionToIntersection<
export type ArrayToIntersection<A extends ReadonlyArray<any>> = T.UnionToIntersection<
A[number]
>

Expand Down

0 comments on commit 33735b1

Please sign in to comment.