arktypeio / arktype

TypeScript's 1:1 validator, optimized from editor to runtime
https://arktype.io/
MIT License
3.89k stars 58 forks source link

Type operations don't preserve metadata #832

Closed smolattack closed 5 months ago

smolattack commented 1 year ago

Report a bug

🔎 Search Terms

custom error

🧩 Context

🧑‍💻 Repro

import { type, scope } from "arktype"

const emailValidations = scope({
    hasADomain: type(["string", "=>", (s) => s.includes("@")], {
        mustBe: "a valid email with a domain"
    }),
    domainIsValid: type(["string", "=>", (s) => s.endsWith(".com")], {
        mustBe: "a valid domain"
    }),
    all: "hasADomain&domainIsValid"
}).compile()

export const emailValidator = emailValidations.all

export const { data, problems } = emailValidator(
    "should give a list of defined errors"
)

console.log(problems?.summary ?? data)

console shows

'should give a list of defined errors' must be...
• valid
• valid

But I expect it to show

'should give a list of defined errors' must be...
• a valid email with a domain
• a valid domain

https://stackblitz.com/edit/arktype-bug-2d9kpj?devToolsHeight=33&file=demo.ts

ssalbdivad commented 1 year ago

Integrating external concerns like custom error messages with a type system is a really tricky problem, and the solution I came up with for alpha really missed the mark. I'd recommend adding the problems directly like this:

import { type, scope } from 'arktype';

const emailValidations = scope({
  hasADomain: type([
    'string',
    '=>',
    (s, problems) =>
      s.includes('@') || !problems.mustBe('a valid email with a domain'),
  ]),
  domainIsValid: type([
    'string',
    '=>',
    (s, problems) => s.endsWith('.com') || !problems.mustBe('a valid domain'),
  ]),
  all: 'hasADomain&domainIsValid',
}).compile();

export const email = emailValidations.all;

export const { data, problems } = email('should give a list of defined errors');

console.log(problems?.summary ?? data);

(on StackBlitz)

Aptly, I was actually working on metadata intersections on beta when you logged this issue. I'll update the title and use this issue to track that work getting merged and that when it does, your original definition will work as expected ⛵