-
-
Couldn't load subscription status.
- Fork 2.1k
Description
Describe the problem
Unlike redirect() and error(), the new invalid() function in remote forms does not block the TypeScript control flow analysis, even though it throws internally and has a never return type.
import { form } from '$app/server';
import * as v from 'valibot';
export const testForm = form(
v.object({
test: v.union([v.string(), v.number()])
}),
(input, invalid) => {
if (typeof input.test == "number") invalid(invalid.test("Should not be a number"));
console.log(input.test);
// ^? string | number
if (typeof input.test == "number") throw invalid(invalid.test("Should not be a number"));
console.log(input.test);
// ^? string
return input;
}
);Describe the proposed solution
I feel like this should be mentioned in the docs. It already mentions that it throws a validation error, but without an explicit throw invalid() it won't narrow types.
- Call `invalid(issue1, issue2, ...issueN)` to throw a validation error
- Like `error()` and `redirect()`, it throws an error internally. However, unlike
`error()` and `redirect()`, it must be explicitly thrown to block the TypeScript
control flow analysis. Example: `throw invalid(issue1, issue2, ...issueN)`Alternatives considered
I'm not sure if this is possible to fix.
Currently the code is this:
export type Invalid<Input = any> = ((...issues: Array<string | StandardSchemaV1.Issue>) => never) & InvalidField<Input>;I tried this and got the same result:
export type Invalid<Input = any> = {
(...issues: Array<string | StandardSchemaV1.Issue>): never;
} & InvalidField<Input>;Unlike redirect() and error() which are functions exported directly, invalid() is returned as a callback parameter and I think TS is not treating it the same, even though they have similar declarations:
/**
* ...
* @return {never}
*/
export function redirect(status, location) { ... }
/**
* ...
* @returns {never}
*/
function invalid(...issues) { ... }Importance
nice to have
Additional Information
No response