How can I globally configure a subtypes error

Problem: I want to configure all “string.email” errors to just be “Invalid Email”. I can almost accomplish this, I’m just missing a way to detect the subtype of the pattern at hand. Looking at the ctx object, code is just pattern. The closest thing I could do is match on the description, but that seems brittle. Zod seems to expose a .validation subtype to check on.
const { type } = scope(
{},
{
pattern: {
message: (ctx) => {
// How can I detect here that its an email vs some other pattern?
console.log(ctx)
return "test1"
},
},
}
)

const form = type({
email: "string.email",
})
const out = form({
email: "bla.com",
})

if (out instanceof type.errors) {
console.log(out.message)
}
const { type } = scope(
{},
{
pattern: {
message: (ctx) => {
// How can I detect here that its an email vs some other pattern?
console.log(ctx)
return "test1"
},
},
}
)

const form = type({
email: "string.email",
})
const out = form({
email: "bla.com",
})

if (out instanceof type.errors) {
console.log(out.message)
}
15 Replies
ssalbdivad
ssalbdivad2d ago
Honestly for something like this I'd actually recommend just defining your own version of the email type with the config you want. You could try and parse context to remap each specific regex error that you want to describe, but that seems a bit flaky I'd recommend either:
const email = type("string.email").configure({
message: () => "INVALID EMAIL"
})

// INVALID EMAIL
email("foo")

// reference as needed
const user = type({ email })
const email = type("string.email").configure({
message: () => "INVALID EMAIL"
})

// INVALID EMAIL
email("foo")

// reference as needed
const user = type({ email })
or
import { keywords, scope } from "arktype"

const { type } = scope({
string: scope({
...keywords.string,
email: keywords.string.email.configure({
message: () => "INVALID EMAIL"
})
}).export()
})

// INVALID EMAIL
type("string.email")("foo").toString() //?
import { keywords, scope } from "arktype"

const { type } = scope({
string: scope({
...keywords.string,
email: keywords.string.email.configure({
message: () => "INVALID EMAIL"
})
}).export()
})

// INVALID EMAIL
type("string.email")("foo").toString() //?
It's even easier if you want to call it something not mirroring the base name, e.g. if you just want to use "email":
const { type } = scope({
email: [
"string.email",
"@",
{
message: () => "INVALID EMAIL"
}
]
})

type("email")("foo").toString() //?
const { type } = scope({
email: [
"string.email",
"@",
{
message: () => "INVALID EMAIL"
}
]
})

type("email")("foo").toString() //?
Bobakanoosh
BobakanooshOP2d ago
Huh ok solution 2 seems a little verbose but would accomplish what I’m looking for, since the end goal is to configure this once. solution 1 is definetly a good fallback, though the downside to me is now other developers have to remember to use the custom one vs the native one. Option 3 has the same pitfall, but nice to know that syntax
ssalbdivad
ssalbdivad2d ago
It would be easy to write a simple wrapper to do this for lots of different keywords though I didn't consider people would be invested in using the original string.email, but I could add config options for builtin keywords directly I guess that would be very easy e.g. to just have a keywords option on the config and allow you to pass whatever options you want to apply when parsing it
ssalbdivad
ssalbdivad2d ago
GitHub
Add global keywords config option · Issue #1280 · arktypeio/arkty...
Could be used like: import { configure } from "arktype/config" configure({ keywords: { string: { email: { message: () => "INVALID EMAIL" } } } }) As opposed to: import { keyw...
Bobakanoosh
BobakanooshOP2d ago
Yeah I mean my goal is to make sure the other engineers on my team have a seamless experience adopting Arktype, so everything I can do to reduce friction the better.
ssalbdivad
ssalbdivad2d ago
(but even now exetrnally this should be quite easy) As in, writing a wrapper that makes what I did in 2 less verbose. you still would be the only one actually applying that config once globally
Bobakanoosh
BobakanooshOP2d ago
Def agree a wrapper would help it as well. Regarding that ticket, what are your thoughts on Zods approach of exposing the “subtype” on the error instead? By doing that, it would keep the library simpler by not adding another new concept if that makes sense then you could just say if(err.code === “pattern” && err.subtype === “email”) within the already existing configuration system Not sure how complex that would be to add to the error object
ssalbdivad
ssalbdivad2d ago
Zods approach
not adding another new concept
Idk if those two things are compatible 😛
Bobakanoosh
BobakanooshOP2d ago
Sure yeah they both add new things But “the Zod way” is adding a new thing in the same “code path” that already exists for configuration
ssalbdivad
ssalbdivad2d ago
I think this is worse IMO. What would be the advantage of creating an error "subtype" for every internal keyword I might want to add rather than just letting you configure the keyword directly? it also means you'd be writing a bunch of if statements instead of just passing the config exactly where you need The keywords and configs "already exist" in a much more direct way A concept of builtin "subtypes" overlaps almost entirely with keywords but just gives it a different name This example from this issue:
import { configure } from "arktype/config"

configure({
keywords: {
"string.email": { message: () => "INVALID EMAIL" }
}
})
import { configure } from "arktype/config"

configure({
keywords: {
"string.email": { message: () => "INVALID EMAIL" }
}
})
Seems pretty much ideal, no?
Bobakanoosh
BobakanooshOP2d ago
Yeah fair that does seem very ideal
ssalbdivad
ssalbdivad2d ago
I just think stuff that people are used to using is always initially going to feel more intuitive/better haha But yeah here I feel like this is the clear solution
Bobakanoosh
BobakanooshOP2d ago
that’s true yeah awesome Will watch that ticket and use the helper method in the meantime
ssalbdivad
ssalbdivad2d ago
I will add this next release, already have everything needed to type all the flattened keywords and apply the configs So probably in the next couple days
Bobakanoosh
BobakanooshOP2d ago
Awesome thanks again!!

Did you find this page helpful?