question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

String `.endsWith` & `.startsWith` could perhaps be typed more strongly

See original GitHub issue

If the passed value was a literal, we could have a generic in ZodString that will include a prefix / suffix.

Use case: At the moment, I am using the code below to validate that a value is a specific ID format that has a constant prefix

export function id<P extends IdPrefixes>(prefix: P) {
	return z
		.string()
		.refine((value): value is `${P}_${string}` => pika.validate(value, prefix));
}

Imagine if this could be done with just .startsWith and .endsWith — ZodString could then have a single generic of the output, which would default to just a string and can be made more specific with these two methods.

CleanShot 2022-12-23 at 14 02 47@2x

Should note that I am not sure if this is a good idea or not, but I wanted to just throw the idea out either way — it’s a use case I have very frequently and always use .refine to solve.

Issue Analytics

  • State:open
  • Created 9 months ago
  • Reactions:2
  • Comments:8 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
tachibanayuicommented, Dec 25, 2022

One way would be to add an overload to these methods (almost like I did on my PR for ZodRequired).

We could leave the current implementation at the top of the overloads so the users will not feel any difference. This type of “exact” inference would be turned off by default.

Then, as a second overload, we add a definition that forces the user to pass true in one of the properties of the options object, turning the inference on.

Something like this:

startsWith(prefix: string, options?: { message?: string; exact?: never }): ZodString
startsWith<Start extends string>(prefix: Start, options: { message?: string; exact: true }): ZodString<Start, End>
startsWith(prefix: string, options?: { message?: string; exact?: true }): ZodString {
  // no change in implementation, the `exact` is solely for turning the inference on.
}

I think this is a breaking change because the second argument is message?: string | {message?: string }. It should be:

startsWith(prefix: string, options?: string | { message?: string; exact?: never }): ZodString
startsWith<Start extends string>(prefix: Start, options: { message?: string; exact: true }): ZodString<Start, End>
startsWith(prefix: string, options?: string | { message?: string; exact?: true }): ZodString {
  // no change in implementation, the `exact` is solely for turning the inference on.
}

IMO, I prefer creating a separate method for template literals because it looks cleaner when chaining methods:

const schemaUrl = z
  .string()
  .startsWith("https://", {message: "Protocol must be https!", exact: true})
  .endsWith("__schema.json", {exact: true})
  .max(255);

const schemaUrl = z
  .string()
  .startsWithLiteral("https://", "Protocol must be https!")
  .endsWithLiteral("__schema.json")
  .max(255);
0reactions
santosmarco-cariboucommented, Dec 26, 2022

Yeah, I like the idea of a ZodTemplate (as in “template string”) as well.

You pass an array of components (mainly ZodLiterals but we can extend it to receive other types as well) to it (or even raw values), and the inference results in a template string.

image

But that’s a bit complex to handle.

But anyway, just wanted to share this idea too. Back to our ZodString, the new methods in ZodString make sense to me. I agree with it and can volunteer to fix my PR if that works for people.

I don’t like the idea of a z.ExactString, though, because we would have another Zod class that does the exact same validation. That’s some repetition there. Every time we add a new method to ZodString we will need to update ExactString as well.

Read more comments on GitHub >

github_iconTop Results From Across the Web

startsWith() and endsWith() functions in PHP - Stack Overflow
How can I write two functions that would take a string and return if it starts with the specified character/string or ends with...
Read more >
EndsWith and StartsWith functions in Power Apps
The EndsWith function tests whether one text string ends with another. ... In many apps, you can type one or more characters into...
Read more >
a built-in startswith($string, $prefix) function #16200 - GitHub
Currently Perl has no good way to check whether a string starts with another string. ... string, and it would probably be really...
Read more >
Issue 37490: poor documentation for .startswith, .endswith
The documentation is reasonably clear regarding the first parameter, which can be a string or a tuple of strings to match at the...
Read more >
Python Startswith and Endswith: Step-By-Step Guide
The Python startswith() function checks if a string starts with a specified substring. Python endswith() checks if a string ends with a ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found