Z
Zod8mo ago
k9

k9 - Hello! I'm getting up to speed. The Comple...

Hello! I'm getting up to speed. The Complex Schema Validation section of zod-tutorial talks about how to preresent what would be a union type in a schema. That doesn't quite do what I'm looking for I have defined types with a string template type e.g.
export type PlayerId = `p${string}`;
export type GameId = `g${string}`;
export type SpectatorId = `s${string}`;
export type PlayerId = `p${string}`;
export type GameId = `g${string}`;
export type SpectatorId = `s${string}`;
which has been a useful way to ensure we don't send the wrong IDs throughout our ecosystem. Those IDs come through JSON schemas I would like to validate with Zod. I can represent validations (there's already methods that ensure the strings are of their type, e.g.
export function isGameId(object: any): object is GameId {
return object?.charAt?.(0) === 'g';
}
export function isGameId(object: any): object is GameId {
return object?.charAt?.(0) === 'g';
}
So, erm, so GameId is everywhere in the codebase, so I have to be careful about refactoring the API. But how can I define a type that a) only accepts a string and b) only if it matches type GameId and c) z.infer() can describe it as type GameId?
Solution:
Should just be the following: ``ts type GameId = g${string}`; const isGameId = (value: unknown): value is GameId => {...
Jump to solution
5 Replies
Solution
Sikari
Sikari8mo ago
Should just be the following:
type GameId = `g${string}`;

const isGameId = (value: unknown): value is GameId => {
return typeof value === "string" && value.startsWith("g");
};

const schema = z.string().refine(isGameId);
const result = schema.parse("g123");
// ^? `g${string}`
type GameId = `g${string}`;

const isGameId = (value: unknown): value is GameId => {
return typeof value === "string" && value.startsWith("g");
};

const schema = z.string().refine(isGameId);
const result = schema.parse("g123");
// ^? `g${string}`
Sikari
Sikari8mo ago
Depending on if you consider just g valid, you might want to also have a min length on the string, something along the lines of: z.string().min(2).refine(isGameId) to make sure you have a string that has g and at least one character after. And if your is function is just for Zod, you can get rid of the string check as well.
const isGameId = (str: string): str is GameId => str.startsWith("g");
const isGameId = (str: string): str is GameId => str.startsWith("g");
Scott Trinh
Scott Trinh8mo ago
There is also z.custom which is mentioned in the docs for precisely this use case: https://zod.dev/?id=custom-schemas
GitHub
TypeScript-first schema validation with static type inference
TypeScript-first schema validation with static type inference
Scott Trinh
Scott Trinh8mo ago
const GameId = z.custom<GameId>(isGameId);
const GameId = z.custom<GameId>(isGameId);
https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgLzgXzgMyhEcBEyEAJvgNwBQFMAnmAKZwDiAhiPQJLFwC8cABgHMAJAgDOMKMAB2gtP0oUAxhGkS4wMa3ZdecABQA3FgBsArvQBccM9IDW0iAHdpASmvHzjTczaduPAB8iBRwcFD0MGZQ0nC0DBCYcJ4WvDx8+BJSsvhwAGR5yaYWAHQSLLBiAOrAMAAW+viC+K6UaIoqavDa-nrIJUpmErgAPD1cgfqa48StyqrqEWJmJvB8MyVgFWL0jYIAjABMAMwtlAD052FhAHoA-EA
TS Playground - An online editor for exploring TypeScript and JavaS...
The Playground lets you write TypeScript or JavaScript online in a safe and sharable way.
k9
k97mo ago
Fantastic, wow, thank you!
Want results from more Discord servers?
Add your server