How to collect validation errors and custom errors in pipe

I have a pipe in which I want to add errors to the arkerrors array. But when there is an validation error, then only the validation error is outputted.
const pipedType = type({foo: 'string', bar: 'number'}).pipe((t, ctx) => {
if (t.foo === 'foo') {
ctx.error({
data: 'foo',
expected: 'bar',
message: 'baz',
code: 'predicate',
path: ['foo']
});
return ctx.errors;
}
return t;
});
const pipedType = type({foo: 'string', bar: 'number'}).pipe((t, ctx) => {
if (t.foo === 'foo') {
ctx.error({
data: 'foo',
expected: 'bar',
message: 'baz',
code: 'predicate',
path: ['foo']
});
return ctx.errors;
}
return t;
});
When I have now the following type, only the validation error is shown:
const foo = {
foo: 'foo',
bar: 'bar',
};
const foo = {
foo: 'foo',
bar: 'bar',
};
But I want that both errors are returned, so that I can return all collected errors.
2 Replies
TizzySaurus
TizzySaurus3mo ago
If type validation fails then the pipe doesn't run You'd probably need to do something like
const foo = type({foo: 'string', bar: 'number'}); // defined outside pipe so that it's only created the once
const pipedType = type('unknown').pipe((t, ctx) => {
// Get initial errors
const fooParseResult = foo(t);
const initialErrors = fooParseResult instanceof type.errors ? fooParseResult : [];

// Get extra errors
if (t.foo === 'foo') {
ctx.error({...});
}

// Return result
if (initialErrors.length > 0 || ctx.hasErrors()) {
return [...ctx.errors, ...initialErrors];
}
return t;
});
const foo = type({foo: 'string', bar: 'number'}); // defined outside pipe so that it's only created the once
const pipedType = type('unknown').pipe((t, ctx) => {
// Get initial errors
const fooParseResult = foo(t);
const initialErrors = fooParseResult instanceof type.errors ? fooParseResult : [];

// Get extra errors
if (t.foo === 'foo') {
ctx.error({...});
}

// Return result
if (initialErrors.length > 0 || ctx.hasErrors()) {
return [...ctx.errors, ...initialErrors];
}
return t;
});
(untested) I'm not sure returning errors is actually a "valid" thing though
floratmin
floratminOP3mo ago
Ok, I figured it out, thank you.
export function isRecord<T extends Record<string, any>>(obj: unknown): obj is Partial<T> {
if (typeof obj !== 'object' || obj === null) {
return false;
}
if (Array.isArray(obj)) {
return false;
}
return Object.getOwnPropertySymbols(obj).length <= 0;
}

const foo = type({foo: 'string', bar: 'number'});
const pipedType = type('unknown').pipe((t: unknown, ctx: Traversal) => {
const parseResult = foo(t);
if (parseResult instanceof ArkErrors) {
parseResult.forEach((arkError) => {
ctx.errors.add(arkError);
});
}
if (isRecord<typeof foo.infer>(t)) {
if (t.foo === 'foo') {
ctx.error({
data: 'foo',
expected: 'bar',
message: 'baz',
code: 'predicate',
path: ['foo']
});
}
return parseResult;
}
return t as typeof foo.infer;
});
export function isRecord<T extends Record<string, any>>(obj: unknown): obj is Partial<T> {
if (typeof obj !== 'object' || obj === null) {
return false;
}
if (Array.isArray(obj)) {
return false;
}
return Object.getOwnPropertySymbols(obj).length <= 0;
}

const foo = type({foo: 'string', bar: 'number'});
const pipedType = type('unknown').pipe((t: unknown, ctx: Traversal) => {
const parseResult = foo(t);
if (parseResult instanceof ArkErrors) {
parseResult.forEach((arkError) => {
ctx.errors.add(arkError);
});
}
if (isRecord<typeof foo.infer>(t)) {
if (t.foo === 'foo') {
ctx.error({
data: 'foo',
expected: 'bar',
message: 'baz',
code: 'predicate',
path: ['foo']
});
}
return parseResult;
}
return t as typeof foo.infer;
});
But it pretty much breaks down and makes it unusable for real world scenarios. You have to set standard values for each missing property and check when there is an ArkErrors the validity of each property and set them also to standard values if you need them in your business logic, which defeats the whole purpose of using ArkType from the beginning.

Did you find this page helpful?