Replies: 1 comment
|
It is probably an artifact that came from effect v3. import * as Record from 'effect/Record'
import * as Schema from 'effect/Schema'
export const NonEmptyRecord = <
K extends Schema.Schema.All,
V extends Schema.Schema.All,
>(
key: K,
value: V,
) =>
Schema.Record({ key, value }).pipe(
Schema.filter(
record =>
!!Record.size(record) || 'Record must contain at least some keys',
),
)
const GitHubSlugStringSchema = Schema.NonEmptyString.pipe(
Schema.filter(s => isGitHubSlug(s) || invalidGitHubSlugMessage),
)I assume it was intended to be used like this, but I agree it might be a silent footgun in some cases and support the idea of writing a bit more code for clarity in this case |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
What happened
Schema.makeFilter/ schemacheckpredicates return aFilterOutput, where a returnedstringis interpreted as a rejection with that string as the error message. That stringarm is a nice, deliberate ergonomic — but because the return type is widened to include
string, a predicate that accidentally produces a string (very easy with&&/||)type-checks fine and silently inverts its meaning.
Minimal repro
The intended predicate was (c) => !c.done (boolean). The && c.title was a mistake, but
nothing at the type level flagged it — the string return is a legal FilterOutput.
Why it's surprising
(e.g. Array.filter). There, (c) => !c.done && c.title is a compile error — string
isn't assignable to boolean. Here, because FilterOutput includes a string arm, the
identical mistake type-checks and silently inverts. The footgun is specifically that the
return type is widened to accept strings.
"return a bare boolean-ish expression" is a natural thing to write — and it's exactly what
breaks here.
Question / idea
The suggested Filter module already models pass/fail explicitly with a tagged Result:
Because you must explicitly call Result.succeed / Result.fail, it's impossible to
accidentally "return a truthy string and have it silently mean reject" — the exact footgun
above can't happen.
Would it make sense for schema checks to accept (or offer) this same Result-returning
shape as an alternative to the overloaded FilterOutput? Sketch:
Not asking to change the default — just whether the safer, already-shipped Result shape
could be usable for schema validation too, since the abstraction clearly exists in v4.
For reference, the current signature:
Version: effect@4.0.0-beta.98
All reactions