ump.check()
check() is the main evaluation API. It is pure, synchronous, and side-effect free.
Signature
Section titled âSignatureâump.check( values: InputValues, conditions?: C, prev?: InputValues,): AvailabilityMap<F>values accepts any Record<string, unknown> â pass your form state, store snapshot, or any object directly. Umpire only reads keys that match declared field names; extra keys are silently ignored. This means you donât need to transform or filter your state before calling check().
What about typos? If you pass { emai: 'alex@example.com' } when the field is named email, umpire wonât error â it just sees email as empty. But the result will tell you: any rule that depends on email being satisfied (like requires('confirmPassword', 'email')) will report it as disabled with its reason. The availability map always uses the field names you declared, so the mismatch is visible in the output.
Return Shape
Section titled âReturn Shapeâtype FieldStatus = { enabled: boolean satisfied: boolean fair: boolean required: boolean reason: string | null reasons: string[] valid?: boolean error?: string}
type AvailabilityMap<F extends Record<string, FieldDef>> = { [K in keyof F]: FieldStatus}Semantics
Section titled âSemanticsâenabledis the combined result of every availability rule (enabledWhen,requires,disables,oneOf) targeting the field.satisfiedis whether the current value is non-empty under that fieldâsisEmptystrategy.fairisfalsewhen afairWhenpredicate returnsfalseon a non-empty value. Alwaystruewhen the field has no value.fairWhenonly runs when the field is enabled.requiredis suppressed tofalsewhen the field is disabled, even if the field definition saysrequired: true.reasonis the first failure in declaration order â from either an availability rule or afairWhenrule.reasonsincludes every failure in declaration order.
Conditions
Section titled âConditionsâUse conditions for external data that affects availability but is not itself a field value.
const availability = signupUmp.check(values, { plan: 'business' })Typical conditions inputs:
- plan tier
- captcha token
- feature flags
- loaded palette metadata
prev is mainly for oneOf() branch resolution.
When multiple branches are satisfied at once, Umpire can use the previous values snapshot to determine which branch became active most recently.
const prev = { everyHour: [9, 17] }const next = { everyHour: [9, 17], startTime: '09:00' }
ump.check(next, undefined, prev)Without prev, ambiguous oneOf() situations fall back to the first satisfied branch and emit a development warning.
Example
Section titled âExampleâconst result = loginUmp.check( { email: 'not-an-email', password: '' }, { captchaToken: 'cf-turnstile-xxxx' },)
result.submit// {// enabled: false,// required: false,// reason: 'Enter a valid email address',// reasons: ['Enter a valid email address', 'Enter a password'],// }Required Suppression
Section titled âRequired SuppressionâDisabled fields never stay required.
const result = signupUmp.check( { companyName: 'Acme' }, { plan: 'personal' },)
result.companyName.required// falseThat behavior keeps validation layers from flagging disabled fields as missing.
When to also use play()
Section titled âWhen to also use play()âcheck() tells you the current state of every field. That is exactly what you need for validation: walk the availability map, skip disabled fields, collect anything that is enabled but unsatisfied or foul.
What check() cannot tell you is whether a previously valid selection became stale because something else changed. Consider a scheduler where the user picks a timezone, then enables a âuse local timezoneâ option. The timezone field is now disabled â but it still holds "America/New_York". check() will correctly report it as disabled. It wonât tell you that the value sitting there is now orphaned and should be cleared.
That is the job play() was designed for. It takes two snapshots â the state before the change and the state after â and returns a list of fields whose values became stale in the transition. You apply those recommendations however your state layer works; play() never mutates anything.
Most patch handlers need one or the other:
- If youâre validating before saving,
check()is sufficient. - If a user action just changed which fields are active and you want to auto-reset the ones that fell out, reach for
play().
The case where you genuinely need both in the same handler is uncommon. A field switch that disables something stale calls for play(). A form submission that checks completeness calls for check(). They are rarely the same moment.