-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore: TypeScript Enhancements for Zod Types #4013
base: main
Are you sure you want to change the base?
Conversation
…e `_addCheck` for `trim`/`toLowerCase`/`toUpperCase` - Updated ZodString to be generic over its output type, enabling propagation of case transformations. - Introduced `inferCase` helper type so that `includes`, `startsWith`, and `endsWith` methods accept values matching the current output case. - Updated `toLowerCase` and `toUpperCase` to return `Lowercase<Output>` and `Uppercase<Output>`, respectively, using `_addCheck`. - Made the `length` method generic, returning `Output & { length: StringLenght }`. - Updated tests to validate the correct behavior.
…`.length` method - Implement tuple-based type inference for fixed-length arrays - Enforce TypeScript limitations with a maximum inferred tuple length of 100 - Preserve simple array types for generic number inputs - Updated Arrays documentation
…pe narrowing inside `_parse` method
WalkthroughThe changes enhance the documentation, tests, and type safety for array length validation and string manipulation in the Zod library. The README sections have been split and clarified, detailing how Changes
Sequence Diagram(s)sequenceDiagram
participant C as Client
participant Z as ZodType::_parse
participant A as _assertParsedDataType
C->>Z: Provide input data for parsing
Z->>A: Invoke _assertParsedDataType(input)
A-->>Z: Confirm input type and return
Z->>C: Return validated, parsed output
Poem
✨ Finishing Touches
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
✅ Deploy Preview for guileless-rolypoly-866f8a ready!Built without sensitive environment variables
To edit notification comments on pull requests, go to your Netlify site configuration. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (7)
deno/lib/README.md (1)
1638-1644
: Grammar and Clarity Improvement in the.length()
SectionPlease update the phrase "a exact‑length array" to "an exact‑length array" to ensure correct English usage. The code example and description otherwise clearly demonstrate the intended tuple transformation behavior.
-To enforce a exact-length array, use `.length()`. +To enforce an exact-length array, use `.length()`.🧰 Tools
🪛 LanguageTool
[misspelling] ~1640-~1640: Use “an” instead of ‘a’ if the following word starts with a vowel sound, e.g. ‘an article’, ‘an hour’.
Context: ...y!", }); ``` ###.length
To enforce a exact-length array, use `.length()`. Th...(EN_A_VS_AN)
README.md (3)
1638-1646
: Grammar Enhancement in the.length
SectionThe documentation currently reads “To enforce a exact-length array, use
.length()
.” For proper grammar, “exact” should be preceded by an rather than a.-To enforce a exact-length array, use `.length()`. +To enforce an exact-length array, use `.length()`.🧰 Tools
🪛 LanguageTool
[misspelling] ~1640-~1640: Use “an” instead of ‘a’ if the following word starts with a vowel sound, e.g. ‘an article’, ‘an hour’.
Context: ...y!", }); ``` ###.length
To enforce a exact-length array, use `.length()`. Th...(EN_A_VS_AN)
1667-1684
: Typo Correction in the TypeScript Limitations SectionThere appears to be a typo in the sentence: “If a generic
number
is passed to.lenght()
, Zod will validate the length but lose the tuple inference…”
It should be spelled as.length()
.-If a generic `number` is passed to `.lenght()`, Zod will validate the length but lose the tuple inference, resulting in a simple array: +If a generic `number` is passed to `.length()`, Zod will validate the length but lose the tuple inference, resulting in a simple array:🧰 Tools
🪛 LanguageTool
[typographical] ~1684-~1684: It is considered good style to insert a comma after introductory phrases with dates or proper nouns.
Context: ...-Infinitycannot be checked because in TypeScript they are of type
number`.
## T...(IN_NNP_COMMA)
1680-1685
: Punctuation Improvement in Listing Special NumbersFor clarity and consistency, consider adding a comma in the list of special numeric values. For example, change “
NaN
,Infinity
and-Infinity
” to “NaN
,Infinity
, and-Infinity
”.- > ⚠️ `NaN`, `Infinity` and `-Infinity` cannot be checked because in TypeScript they are of type `number`. + > ⚠️ `NaN`, `Infinity`, and `-Infinity` cannot be checked because in TypeScript they are of type `number`.🧰 Tools
🪛 LanguageTool
[typographical] ~1684-~1684: It is considered good style to insert a comma after introductory phrases with dates or proper nouns.
Context: ...-Infinitycannot be checked because in TypeScript they are of type
number`.
## T...(IN_NNP_COMMA)
src/types.ts (1)
1112-1112
: Returning value as any
Casting toany
can reduce type safety. Consider maintaining stronger typing to avoid losing type information.deno/lib/types.ts (2)
1112-1112
: Remove theas any
to strengthen type safety.
While this works, it's safer to avoidany
if possible.Apply this diff to remove the unnecessary cast:
- return { status: status.value, value: input.data } as any; + return { status: status.value, value: input.data };
2354-2354
: Consider adjusting the naming of “atleastone”.
Renaming to “atLeastOne” may improve clarity and consistency within codebases.Suggested update:
-export type ArrayCardinality = "many" | "atleastone" | "exact"; +export type ArrayCardinality = "many" | "atLeastOne" | "exact";
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
README.md
(1 hunks)deno/lib/README.md
(1 hunks)deno/lib/__tests__/string.test.ts
(2 hunks)deno/lib/helpers/util.ts
(2 hunks)deno/lib/types.ts
(51 hunks)src/__tests__/string.test.ts
(2 hunks)src/helpers/util.ts
(2 hunks)src/types.ts
(51 hunks)
🧰 Additional context used
🪛 LanguageTool
deno/lib/README.md
[misspelling] ~1640-~1640: Use “an” instead of ‘a’ if the following word starts with a vowel sound, e.g. ‘an article’, ‘an hour’.
Context: ...y!", }); ``` ### .length
To enforce a exact-length array, use `.length()`. Th...
(EN_A_VS_AN)
[typographical] ~1684-~1684: It is considered good style to insert a comma after introductory phrases with dates or proper nouns.
Context: ...-Infinitycannot be checked because in TypeScript they are of type
number`.
## T...
(IN_NNP_COMMA)
README.md
[misspelling] ~1640-~1640: Use “an” instead of ‘a’ if the following word starts with a vowel sound, e.g. ‘an article’, ‘an hour’.
Context: ...y!", }); ``` ### .length
To enforce a exact-length array, use `.length()`. Th...
(EN_A_VS_AN)
[typographical] ~1684-~1684: It is considered good style to insert a comma after introductory phrases with dates or proper nouns.
Context: ...-Infinitycannot be checked because in TypeScript they are of type
number`.
## T...
(IN_NNP_COMMA)
🔇 Additional comments (74)
deno/lib/README.md (1)
1647-1657
: Documentation Clarity for.min()
/.max()
The updated section clearly explains that the
.min()
and.max()
methods enforce length constraints without altering the inferred type. The provided examples are concise and helpful. No further modifications are needed here.src/__tests__/string.test.ts (3)
41-47
: Well-structured tests for string length validation.The new test case thoroughly validates the behavior of the string length validators (
min
,max
, andlength
), ensuring that they enforce the correct constraints. This corresponds well to the TypeScript enhancements mentioned in the PR objectives.
576-595
: Excellent test coverage for case transformation type safety.The updated tests for
toLowerCase()
properly validate the TypeScript enhancements for case-sensitive methods. The tests check both the transformation behavior and the type-safety improvements:
- Basic case transformation is verified
- Method ordering is tested (e.g.,
toLowerCase().startsWith("a")
vsstartsWith("A").toLowerCase()
)- Type errors are correctly expected when case doesn't match the output type
This implementation directly supports the PR objective of improving generic case inference and ensuring that methods like
startsWith
,endsWith
, andincludes
accept values that match the output case.
597-617
: Comprehensive test pattern for uppercase transformation.The
toUpperCase()
tests mirror the structure of the lowercase tests, creating a thorough and consistent test suite. These tests properly validate that:
- Uppercase transformations work correctly
- Method chaining order is respected
- Type errors occur when case-sensitive methods are called with the wrong case
The symmetrical implementation between lowercase and uppercase tests is a good practice for ensuring consistent behavior across similar functionality.
deno/lib/__tests__/string.test.ts (3)
42-48
: Good addition of comprehensive length validation tests!These tests properly validate that string length validators behave as expected:
minFive
correctly accepts strings of exactly 5 characters or longermaxFive
correctly accepts strings of exactly 5 characters or shorterjustFive
correctly enforces strings to be exactly 5 characters
577-595
: Enhanced case transformation tests with proper type-safety checks.The test has been improved to:
- Make the code more maintainable by using a variable for the transformed string
- Verify correct string conversion with
toLowerCase()
- Test method chaining behavior where transformations are applied in the correct order
- Validate type-safety with appropriate error cases
598-617
: Good symmetrical testing for uppercase transformations.This mirrors the lowercase tests with the same quality improvements:
- Variable assignment for better readability
- Clear test cases for the
toUpperCase()
transformation- Proper validation of method ordering in chains
- Type-safety checks that verify incompatible case operations throw errors
src/helpers/util.ts (4)
20-22
: Well-designed type constraint for non-negative numbers.The
NonNegative<T>
type elegantly uses template literal types to check for negative numbers, resolving tonever
when negative orT
when not, providing strong guarantees for numeric parameters.
24-24
: Clean digit union type definition.The
digit
type creates a reusable union of all single-digit numbers, which improves readability when used in other type expressions.
26-38
: Sophisticated recursive type for exact-length arrays.The
ExactArray<T, N, R>
type is well-structured with:
- Special handling for non-literal numbers (
number extends N
)- Rejection of negative lengths
- Optimization for small arrays (up to 100) with recursive building
- Fallback to a simpler constraint for larger arrays
This type powers the
.length()
array validation method to produce exact tuple types.
95-99
: Useful string case inference type.The
inferCase<T>
type elegantly detects whether a string type is lowercase, uppercase, or mixed case, enabling type-safe operations with case-sensitive string methods like.startsWith()
,.endsWith()
, and.includes()
.deno/lib/helpers/util.ts (4)
20-22
: Well-designed type constraint for non-negative numbers.The
NonNegative<T>
type elegantly uses template literal types to check for negative numbers, providing type-level guarantees for numeric parameters.
24-24
: Clean digit union type definition.Simple but effective definition of digits as a union of literal numbers from 0 to 9.
26-38
: Sophisticated recursive type for exact-length arrays.The
ExactArray<T, N, R>
type is well-designed with appropriate special cases:
- Fallback to
T[]
for non-literal numbers- Rejection of negative numbers
- Recursive construction for reasonable lengths (single/double digit and 100)
- Simple constraint for larger numbers
This type supports strong typing for the array length validation feature.
95-99
: Useful string case inference type.The
inferCase<T>
type intelligently determines the case characteristic of a string type, enabling type-safe operations with case-sensitive string methods, improving the developer experience when using string validators.src/types.ts (17)
191-217
: Nice introduction of typed assertion method
This newly introduced_assertParsedDataType
method is well-documented and provides a clear way to narrow input data types in TypeScript. It's a no-op at runtime, so there's minimal overhead.
800-804
: Additional generic type parameter for ZodString
AllowingOutput extends string
enables more advanced transformations while preserving type safety.
820-820
: Runtime no-op for type assertion
Calling_assertParsedDataType<string>(input)
here ensures correct type-narrowing, consistent with the new generic approach.
978-978
: Includes check
Utilizinginput.data.includes(check.value, check.position)
is correct; no issues found.
992-992
: startsWith check
Straightforward usage ofstartsWith
; no immediate concerns.
1002-1002
: endsWith check
Straightforward usage ofendsWith
; no immediate concerns.
1127-1128
: Generic check addition
The<CheckOutput extends string = Output>
approach for_addCheck
helps preserve type information for custom checks.
1254-1257
: Improved includes signature
Acceptingvalue: util.inferCase<Output>
enforces consistent case inference for string includes.
1266-1266
: startsWith with typed value
Usingutil.inferCase<Output>
for thevalue
parameter supports advanced type safety for string transformations.
1274-1274
: endsWith with typed value
Retaining the consistent approach fromstartsWith
andincludes
; looks good.
1298-1302
: Typed string length
ReturningOutput & { length: StringLength }
is an elegant way to carry length-specific type info through the chain.
1317-1317
: Trim check
Defining a check withkind: "trim"
is a clean extension and aligns with the new pattern.
1321-1321
: toLowerCase
InferringLowercase<Output>
for advanced transformations; no issues identified.
1325-1325
: toUpperCase
Similarly inferringUppercase<Output>
provides symmetrical handling for uppercase transformations.
1460-1460
: Type assertion in ZodNumber
Consistently ensures correct type after parsing a number.
1744-1744
: Type assertion in ZodBigInt
Aligns with the existing pattern of calling_assertParsedDataType
after validating the parsed type.
3894-3900
: Enhanced parse path for Map
Separating key and value paths (e.g.,[index, "key"]
,[index, "value"]
) improves error messaging forZodMap
.deno/lib/types.ts (42)
191-217
: Introduce_assertParsedDataType
: Great addition for type narrowing.
This utility method clarifies the intended type post-checks and improves readability. Ensure it's always invoked after confirming the data's type to avoid incorrect narrowing.
800-804
: RefiningZodString
with a generic output type.
Leveraging generics for the string output type more accurately handles transformations and advanced checks.
820-820
: Confirming_assertParsedDataType<string>
after string check.
You validateparsedType
before asserting, which is consistent and safe for narrowing.
978-978
:includes
check introduced.
UsingString.prototype.includes
is clear and aligns with ES2015+ features.
992-992
:startsWith
check introduced.
The addition is straightforward and follows the same pattern asincludes
.
1002-1002
:endsWith
check introduced.
Aligns with the existing pattern for string validation methods.
1127-1128
: Generic_addCheck
for string output improvements.
Cleverly allows the output type to adjust based on transformations or checks.
1254-1257
:includes
now inferring case.
This is a neat way to ensure consistency with transformed string types.
1266-1266
:startsWith
inferring output case.
This extension elegantly supports generic string transformations.
1274-1274
:endsWith
inferring output case.
Continues the consistent approach of tailoring checks to the string’s transformation.
1298-1302
: Genericlength
method for string schemas.
Tying the length requirement into the output type is an excellent way to reflect exact lengths in the type system.
1317-1317
:trim
check for string schemas.
Straightforward approach to strip whitespace in place. Ensure users are aware of the in-place data modification.
1321-1321
:toLowerCase
returningLowercase<Output>
.
Accurately reflects the lowered case in the output type.
1325-1325
:toUpperCase
returningUppercase<Output>
.
Parallel approach totoLowerCase
, preserving type correctness.
2466-2469
: Genericmin
method for arrays.
Strongly typed approach to constraining minimum length is well-implemented.
2476-2479
: Genericmax
method for arrays.
Matches themin
pattern, maintaining consistent constraints.
2486-2489
: Exactlength
for arrays.
Helps define strictly sized arrays, a nice feature for robust schemas.
2496-2496
:nonempty
for arrays.
Convenient helper for quickly ensuring at least one element is present.
2515-2519
: New array type aliases:ZodNonEmptyArray
andZodExactArray
.
These aliases neatly capture specific cardinalities for array validations.
3160-3160
: Ensuring union type correctness via_assertParsedDataType
.
Called after validating each subtype. This is consistent with the pattern used.
3362-3362
: Ensuring discriminated union type correctness.
This explicit assertion aligns with the prior type checks on the discriminator field.
3535-3535
: Intersection type assertion.
Methodically placed after verifying left and right schemas in_parse
logic.
3663-3663
: Tuple type assertion.
Similarly consistent with the pattern of asserting post-parse.
3788-3788
: Object schema assertion.
Maintaining uniform usage of_assertParsedDataType
across Zod data structures.
3888-3888
: Map type assertion.
Checks the parse context thoroughly before finalizing.
3893-3899
: Parsing key-value pairs forZodMap
.
Nicely splits out key and value parsing with distinct lazy paths for clarity.
3985-3985
: Set type assertion.
Consistent with the rest of the library’s design, ensuring type correctness.
4029-4031
: Mapping set elements with spread and_parse
.
Effective approach for iterating sets while preserving the parse context for each element.
4124-4124
: Function type assertion.
Permits refined type inference after verifying the input is a function.
4303-4303
: Lazy type assertion.
Ensures the lazily-evaluated schema is properly validated at runtime.
4343-4343
: Literal type assertion.
Straightforward check, verifying exact literal match and refining the type.
4434-4434
: Enum type assertion.
Helpful for guaranteeing the input matches one of the enumerated string options.
4621-4621
: Promise type assertion.
Checks that data is a genuinePromise
, then awaits it to validate the resolved value.
4629-4629
: Parsing a promise via.then
chain.
Implementation is clean, returning a validated async result.
4705-4705
: Effects type assertion.
Ensures that the data meets the underlying schema’s checks before applying transformations or refinements.
4883-4883
: Optional type assertion.
Appropriately short-circuits when data isundefined
before continuing validation.
4928-4928
: Nullable type assertion.
Likewise short-circuits fornull
, closely paralleling the optional logic.
5033-5033
: Catch type assertion.
Separates the context to avoid polluting the main parse flow with errors, then reasserts type correctness.
5118-5118
: NaN type assertion.
A specialized check distinguishingNaN
from typical numeric values.
5155-5155
: Branded type assertion.
Useful for combining a standard schema with brand metadata at the type level.
5190-5190
: Pipeline type assertion.
Ensures the data from the “in” side is valid before passing to the “out” schema, with consistent usage of_assertParsedDataType
.
5286-5286
: Readonly type assertion.
Completes the final step by freezing the data after successful validation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (5)
deno/lib/README.md (1)
1638-1645
: Documentation Clarity & Grammar for.length()
MethodThe new section for the
.length()
method is very clear: it explains that using.length()
converts an array schema into a tuple type of exactly the specified length. The provided code snippet neatly demonstrates how a 5‑item array becomes a tuple with an enforced length of 5.Suggestion: Change “a exact‑length array” to “an exact‑length array” to improve grammatical correctness (since “exact” starts with a vowel sound).
-To enforce a exact-length array, use `.length()`. +To enforce an exact-length array, use `.length()`.🧰 Tools
🪛 LanguageTool
[misspelling] ~1640-~1640: Use “an” instead of ‘a’ if the following word starts with a vowel sound, e.g. ‘an article’, ‘an hour’.
Context: ...y!", }); ``` ###.length
To enforce a exact-length array, use `.length()`. Th...(EN_A_VS_AN)
README.md (1)
1683-1684
: Minor Stylistic Suggestion for Special Numeric ValuesThe warning that
NaN
,Infinity
, and-Infinity
cannot be checked is valuable. For clarity and style, consider adding a comma after “Infinity” to improve readability:-> ⚠️ `NaN`, `Infinity` and `-Infinity` cannot be checked because in TypeScript they are of type `number`. +> ⚠️ `NaN`, `Infinity`, and `-Infinity` cannot be checked because in TypeScript they are of type `number`.🧰 Tools
🪛 LanguageTool
[typographical] ~1684-~1684: It is considered good style to insert a comma after introductory phrases with dates or proper nouns.
Context: ...-Infinitycannot be checked because in TypeScript they are of type
number`.
## T...(IN_NNP_COMMA)
deno/lib/types.ts (3)
4550-4551
: Double _assertParsedDataType call is redundantThere are two consecutive calls to _assertParsedDataType with different parameters (input and ctx).
Since you're already calling the method with input on line 4550, the second call with ctx on line 4551 is redundant and could be removed:
- this._assertParsedDataType(input); - this._assertParsedDataType(ctx); + this._assertParsedDataType(input);
4567-4567
: Consider consistent return styleThe ZodNativeEnum._parse method returns OK(input.data) directly while most other implementations define the value in a variable first.
For consistency with other parsers, consider using the same style as most other implementations:
- return OK(input.data); + return { status: "valid", value: input.data };
4629-4629
: Arrow function unnecessary wrapping parameterThe arrow function in ZodPromise._parse unnecessarily wraps the
promisified.then
parameter.The arrow function syntax could be simplified:
- promisified.then((data) => { + promisified.then(data => {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
README.md
(1 hunks)deno/lib/README.md
(1 hunks)deno/lib/types.ts
(51 hunks)src/types.ts
(51 hunks)
🧰 Additional context used
🪛 LanguageTool
deno/lib/README.md
[misspelling] ~1640-~1640: Use “an” instead of ‘a’ if the following word starts with a vowel sound, e.g. ‘an article’, ‘an hour’.
Context: ...y!", }); ``` ### .length
To enforce a exact-length array, use `.length()`. Th...
(EN_A_VS_AN)
[typographical] ~1684-~1684: It is considered good style to insert a comma after introductory phrases with dates or proper nouns.
Context: ...-Infinitycannot be checked because in TypeScript they are of type
number`.
## T...
(IN_NNP_COMMA)
README.md
[misspelling] ~1640-~1640: Use “an” instead of ‘a’ if the following word starts with a vowel sound, e.g. ‘an article’, ‘an hour’.
Context: ...y!", }); ``` ### .length
To enforce a exact-length array, use `.length()`. Th...
(EN_A_VS_AN)
[typographical] ~1684-~1684: It is considered good style to insert a comma after introductory phrases with dates or proper nouns.
Context: ...-Infinitycannot be checked because in TypeScript they are of type
number`.
## T...
(IN_NNP_COMMA)
🔇 Additional comments (42)
deno/lib/README.md (2)
1647-1654
: .min() and .max() Documentation ReviewThe documentation for the
.min()
and.max()
methods is concise and clear. It shows how to constrain arrays to have at least or at most a given number of items without changing the inferred type, which contrasts nicely with the tuple effect of.length()
.
1658-1685
: TypeScript Limitations Section – Excellent Detail with Minor ObservationsThis new “TypeScript Limitations” section is very useful. It clearly explains:
- How passing a literal (e.g. 101) results in a tuple type, while a generic number argument loses tuple inference.
- That negative numbers are disallowed for
.length()
,.min()
, and.max()
to avoid runtime errors.- The note on
NaN
,Infinity
, and-Infinity
is also valuable for setting the developer’s expectations.The examples are well chosen and readable. One minor suggestion: if desired, you might consider a very brief summary statement at the end of this section to reiterate the safe usage practices—though it is optional given the thoroughness already present.
🧰 Tools
🪛 LanguageTool
[typographical] ~1684-~1684: It is considered good style to insert a comma after introductory phrases with dates or proper nouns.
Context: ...-Infinitycannot be checked because in TypeScript they are of type
number`.
## T...(IN_NNP_COMMA)
README.md (5)
1638-1645
: Improve Article Usage & Clarity in.length()
SectionThe documentation for the
.length()
method is very clear and the code snippet nicely illustrates that using.length(5)
enforces an exact tuple type. However, note that the phrase “a exact‐length array” should use “an” rather than “a” since “exact” begins with a vowel sound.-To enforce a exact-length array, use `.length()`. +To enforce an exact-length array, use `.length()`.[refactor_suggestion_nitpick]
🧰 Tools
🪛 LanguageTool
[misspelling] ~1640-~1640: Use “an” instead of ‘a’ if the following word starts with a vowel sound, e.g. ‘an article’, ‘an hour’.
Context: ...y!", }); ``` ###.length
To enforce a exact-length array, use `.length()`. Th...(EN_A_VS_AN)
1647-1651
: Clear Explanation for.min/.max
MethodsThe new “.min/.max” section clearly distinguishes these methods from
.length()
by explicitly noting that they do not alter the inferred type. The provided code snippets are concise and easy to follow.
1658-1665
: Detailed Explanation of Tuple Inference LimitsThe TypeScript Limitations section effectively explains that for
.length()
, the maximum inferred tuple length is capped at 100 and demonstrates what happens when a larger number is passed. This is very useful for users familiar with TypeScript’s limitations.
1668-1673
: Document Behavior When Using Generic Numbers for.length()
The explanation making users aware that passing a generic
number
to.length()
results in a simple array (losing tuple inference) is clear and helpful. Consider emphasizing this edge case so developers know to use explicit literals when tuple types are desired.
1675-1680
: Clarify Disallowing Negative ValuesThe note and code example demonstrating that negative numbers are disallowed (with an appropriate TypeScript error) provide useful safety information. This addition will help prevent potential runtime errors.
deno/lib/types.ts (14)
191-216
: Excellent addition of type assertion helper!This protected method provides a clean way to narrow input/context data types after validations. The no-op implementation properly preserves runtime performance while providing valuable TypeScript type narrowing.
This is a sophisticated TypeScript technique that leverages TypeScript's type assertion capabilities without adding runtime overhead. It will help prevent type errors in downstream code that uses the parsed values.
800-804
: Great enhancement with generic ZodString class!Making
ZodString
generic over its output type is a significant improvement that allows for better type inference with string transformations.This change enables the type system to track string case transformations and length constraints, which will improve developer experience when chaining string operations.
805-821
: Proper implementation of _assertParsedDataType in ZodString._parseGood implementation of the new type assertion method to narrow the input data type after validation.
1254-1257
: Improved type safety for string operations with inferCaseUsing
util.inferCase<Output>
instead of juststring
ensures that case transformations are properly typed.This will maintain case information when performing operations like
.includes()
, ensuring that the type system knows about any prior case transformations.
1266-1266
: Type-safe string comparison with inferCaseThe
startsWith
method now correctly uses the inferred case type.
1274-1274
: Type-safe string comparison with inferCaseThe
endsWith
method now correctly uses the inferred case type.
1298-1302
: Enhanced length method with string length constraintThe length method now properly returns a type that includes the exact length constraint.
This will allow TypeScript to know the exact length of the string in the type system, improving type safety.
1317-1318
: Maintain generics with trim operationThe trim operation properly maintains the output type.
1321-1322
: Properly typed case transformationThe toLowerCase method now correctly returns
Lowercase<Output>
instead of just string.This change enables the type system to track the lowercase transformation in the type.
1325-1326
: Properly typed case transformationThe toUpperCase method now correctly returns
Uppercase<Output>
instead of just string.This change enables the type system to track the uppercase transformation in the type.
2354-2358
: Enhanced array cardinality with exact length supportAdding the "exact" cardinality type extends ZodArray's capabilities to handle fixed-length arrays with proper typing.
This change enables the creation of arrays with exact length constraints that will be reflected in the TypeScript types, similar to tuples.
2361-2366
: Type-safe exact array length outputThe arrayOutputType now correctly handles the "exact" cardinality with proper tuple typing.
This ensures that arrays with exact length constraints are properly typed as tuples of that specific length.
2486-2494
: Enhanced array length method with tuple typeThe length method now returns a
ZodExactArray
type with the exact length constraint.This allows for creating exact-length arrays that are typed as tuples in TypeScript, providing better type safety.
2516-2519
: New ZodExactArray type for fixed-length arraysThe new ZodExactArray type provides a clean way to represent arrays with exact length constraints.
This type specialization helps maintain the distinction between regular arrays and fixed-length arrays in the type system.
src/types.ts (21)
191-217
: Improve clarity with usage examples.This block of JSDoc and overload declarations for
_assertParsedDataType
is clear about its purpose of narrowing types at compile time. Consider including a short code snippet in the documentation to illustrate how developers can use it in_parse
methods, which would make it even more intuitive.
800-804
: Generic parameter for ZodString.Introducing
Output extends string = string
to ZodString is a solid enhancement, helping produce refined string types for case transformations and other checks.
820-820
: Asserting input data type in ZodString parse method.Calling
_assertParsedDataType<string>(input)
consistently enforces compile-time type narrowing for string parsing without affecting runtime behavior.
978-978
: Check validity of position when calling .includes.
includes(check.value, check.position)
works as intended, but ensurecheck.position
is an integer and inform users how negative or large positions behave.
992-992
: startsWith usage looks correct.No logical issues spotted. This change properly uses
startsWith(check.value)
.
1002-1002
: endsWith usage looks correct.No logical issues spotted. This change properly uses
endsWith(check.value)
.
1112-1112
: Returning parse result in ZodString.Returning
{ status: status.value, value: input.data }
aligns with the parsing flow.
1127-1128
: Introducing a generic parameter in _addCheck.Allowing
<CheckOutput extends string = Output>
enables fine-grained transformations for future checks without breaking existing usage.
1254-1257
: Refined signature for .includes.Accepting
util.inferCase<Output>
for the search string and an optional position is consistent with the rest of the case-centric API.
1266-1266
: Refined signature for .startsWith.Using
util.inferCase<Output>
for the prefix is consistent with the library’s new case inference design.
1274-1274
: Refined signature for .endsWith.Similarly, adopting
util.inferCase<Output>
for the suffix is consistent and maintains type safety.
1298-1301
: Generic .length method to encode string length.This change helps encode a compile-time string length constraint (
Output & { length: N }
). It’s a neat approach for advanced type inference.
1317-1317
: .trim check addition.Simple addition that calls
_addCheck({ kind: "trim" })
. No functional issues identified.
1321-1321
: .toLowerCase returning Lowercase.This new approach ensures type-level knowledge that the resulting string is lowercase.
1325-1325
: .toUpperCase returning Uppercase.Likewise, returning
Uppercase<Output>
helps advanced type inference for uppercase transformations.
1460-1460
: Type narrowing for ZodNumber.Using
_assertParsedDataType(input)
here is consistent with the new pattern for numeric parsing.
1744-1744
: Type narrowing for ZodBigInt.Similar to ZodNumber, this ensures the parse path is typed as bigint.
1957-1957
: Type narrowing for ZodBoolean.No concerns; consistent usage in boolean parsing.
2191-2191
: Type assertion within ZodNull parse.Ensures the parse path is typed as
null
; consistent with the approach in other type classes.
2211-2211
: Redundant but harmless parse assertion in ZodNull.A second call to
_assertParsedDataType(input)
is benign. If not required, consider removing to avoid confusion, but it won’t harm runtime.
2262-2262
: Type narrowing for ZodUnknown.No issues spotted; consistent with the library’s new pattern.
4ddf845
to
4890cf9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (4)
deno/lib/README.md (1)
1656-1676
: Detailed Explanation of TypeScript Limitations and Negative Value Handling
The "TypeScript Limitations" block is thorough and helpful. It clearly documents the inherent limitations with tuple inference (including the maximum tuple length of 100), the loss of tuple inference when a generic number is passed, and the decision to disallow negative values for.length()
,.min()
, and.max()
. The code examples are well chosen to demonstrate these points.Minor nitpick: While the technical content is excellent, consider reviewing the phrasing for any potential stylistic improvements (for example, ensuring that introductory phrases are punctuated consistently for optimal readability).
README.md (1)
1656-1675
: TypeScript Limitations Section – Informative with Minor Punctuation SuggestionThe "TypeScript Limitations" section effectively documents critical constraints:
- It clearly explains that
.length()
creates a tuple type (up to 100 elements) and that using a generic number parameter results in a simple array.- The examples handling negative values and the resulting TypeScript errors are very useful for users to anticipate potential issues.
Nitpick: In the warning message, consider adding an Oxford comma for clarity. For example:
- > ⚠️ `NaN`, `Infinity` and `-Infinity` cannot be checked because in TypeScript they are of type `number`. + > ⚠️ `NaN`, `Infinity`, and `-Infinity` cannot be checked because in TypeScript they are of type `number`.This minor change improves readability and conforms to common style guidelines.
deno/lib/types.ts (2)
210-217
: Introduce runtime clarifications for type-narrowing.
The_assertParsedDataType
method serves as a no-op assertion for TypeScript but provides no runtime checks. If you require actual runtime validation, consider supplementing this with real checks or clarifying its TS-only usage.
1127-1128
: Cautious generic override in_addCheck
.
InferringCheckOutput
is flexible, but ensure it doesn't inadvertently widen or conflict with the pre-declaredOutput
type.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
README.md
(1 hunks)deno/lib/README.md
(1 hunks)deno/lib/types.ts
(51 hunks)src/types.ts
(51 hunks)
🧰 Additional context used
🪛 LanguageTool
README.md
[typographical] ~1684-~1684: It is considered good style to insert a comma after introductory phrases with dates or proper nouns.
Context: ...-Infinitycannot be checked because in TypeScript they are of type
number`.
## T...
(IN_NNP_COMMA)
deno/lib/README.md
[typographical] ~1684-~1684: It is considered good style to insert a comma after introductory phrases with dates or proper nouns.
Context: ...-Infinitycannot be checked because in TypeScript they are of type
number`.
## T...
(IN_NNP_COMMA)
🔇 Additional comments (50)
deno/lib/README.md (2)
1638-1645
: Clear and Concise Explanation of.length()
The new documentation for the.length()
method is clear and informative. It succinctly explains that using.length()
on an array schema forces the array to have an exact number of items and even shows the resulting inferred tuple type. This example effectively highlights the added type-safety benefit.
1647-1654
: Well-Documented.min()
and.max()
Behavior
The updated section on.min()
and.max()
clearly distinguishes these methods from.length()
and.nonempty()
by noting that their application does not alter the inferred type. The provided code examples are straightforward and serve to illustrate the expected behavior.README.md (2)
1638-1645
: .length Section – Clear Explanation & Concise Code ExampleThe new section explaining the
.length()
method is clear and concise. The text explains that using.length()
enforces an exact-length array and changes the inferred type into a tuple. The code example is well chosen to illustrate this behavior.
1646-1654
: .min/.max Section – Effective and StraightforwardThis section neatly explains how to use
.min()
and.max()
for array length constraints without altering the inferred type. The code snippet is straightforward and demonstrates the intended usage. Overall, it meets the objective of clarifying the behavior of these methods.deno/lib/types.ts (18)
191-191
: Doc comment clarity.
This updated JSDoc header accurately captures the purpose of the new type-narrowing helper.
800-804
: Generic output parameter in ZodString.
Adopting a generic<Output extends string = string>
parameter broadens type inference without breaking existing usage.
820-821
: Type assertion for string inputs.
This confirms thatinput.data
is treated as a string type in TypeScript, though it remains a no-op at runtime.
978-978
: Safe usage ofincludes
.
No issues spotted. The precedential type assertion averts potential type errors inincludes()
.
992-992
: Safe usage ofstartsWith
.
CallingstartsWith
is straightforward here; no further concerns.
1002-1002
: Safe usage ofendsWith
.
This mirrors the logic ofstartsWith
without evident concerns.
1112-1112
: Return statement correctness.
Returning both parse status and the unmodifiedinput.data
looks consistent with the parsing flow.
1254-1257
: Case inference in.includes()
.
Acceptingutil.inferCase<Output>
for the value parameter enhances type safety and alignment with transformations.
1266-1266
: Case inference in.startsWith()
.
Matches the.includes()
approach for type-sound case handling.
1282-1282
: Case inference in.endsWith()
.
Seamless continuation of the new pattern for advanced type inference.
1298-1302
: Parametric.length()
.
This generic returns an intersection type (Output & { length: StringLength }
) for more precise type inference, which is a neat approach.
1317-1317
: Trim check.
Performing a.trim()
with an added check is straightforward and consistent.
1321-1321
: Type-narrowing fortoLowerCase()
.
This properly narrows the string output toLowercase<Output>
.
1325-1325
: Type-narrowing fortoUpperCase()
.
Similarly extends type inference toUppercase<Output>
.
1744-1744
: Repeated_assertParsedDataType
usage.
No further concerns beyond earlier comments on this no-op TS assertion.
1957-1957
: Repeated_assertParsedDataType
usage.
No further concerns beyond earlier comments on this no-op TS assertion.
2211-2211
: Repeated_assertParsedDataType
usage.
No further concerns beyond earlier comments on this no-op TS assertion.
2262-2262
: Repeated_assertParsedDataType
usage.
No further concerns beyond earlier comments on this no-op TS assertion.src/types.ts (28)
191-217
: Well-documented type-narrowing utility
This new_assertParsedDataType
method introduction and its accompanying doc comment thoroughly explain its purpose for narrowing input data types fromany
. The overloads forParseInput
andParseContext
look consistent.
800-805
: Generic output type for ZodString
AllowingZodString
to be generic overOutput extends string
is a valuable enhancement for typed string transformations (e.g., case conversions). This approach cleanly aligns with the PR’s objectives.
820-820
: Proper usage of_assertParsedDataType
Ensuring the call to_assertParsedDataType<string>(input)
after verifyingparsedType === ZodParsedType.string
solidifies type correctness at the TS level.
978-978
: Verify string containment
The newincludes
check logically usesinput.data.includes(check.value, check.position)
. SinceZodParsedType.string
is already enforced, this is safe.
992-992
: Starts-with validation
The updated startsWith check properly usesinput.data.startsWith(check.value)
. Looks good.
1002-1002
: Ends-with validation
Similar to the startsWith approach, this is a straightforward endsWith validation.
1112-1112
: Returning final string result
Returning{ status: status.value, value: input.data }
ensures the parse result is correctly propagated as valid output.
1127-1128
: Chaining checks with type refinement
The_addCheck<CheckOutput extends string = Output>
method returns a newZodString<CheckOutput>
, allowing the schema to refine the inferred output type.
1254-1257
: Enhanced.includes()
signature
Acceptingvalue: util.inferCase<Output>
helps maintain consistent casing in includes checks.
1266-1266
: Enhanced.startsWith()
signature
ExpandingstartsWith
to acceptutil.inferCase<Output>
further strengthens type correctness.
1274-1274
: Enhanced.endsWith()
signature
Similarly,endsWith
now infers the correct case from the genericOutput
.
1298-1302
: Typed.length()
method
This implementation captures the exact length at the type level, returningOutput & { length: StringLength }
. It’s a powerful approach for structural string constraints.
1317-1317
: Trim check
The simple trim check is logically placed and well-structured.
1321-1321
: Lowercase transform
toLowerCase()
returningLowercase<Output>
ensures strong TypeScript guarantees post-transformation.
1325-1325
: Uppercase transform
toUpperCase()
returningUppercase<Output>
consistently mirrors thetoLowerCase()
approach.
2354-2357
: Introduction of "exact" array cardinality
The new"exact"
option inArrayCardinality
and relatedExactArrayLength
type paves the way for perfectly sized arrays.
2360-2361
: Additional parameters inarrayOutputType
Extending array output types with generics for cardinality and exact length matches the new design.
2370-2371
: ZodArray extended generic signature
ZodArray<T, Cardinality, ArrayLength>
elegantly encapsulates advanced array length constraints.
2395-2395
: Ensuring correct array type
this._assertParsedDataType<T[]>(ctx);
helps confirm type-narrowing after verifyingctx.parsedType === ZodParsedType.array
.
2466-2469
: Generic.min()
min<MinLength extends number>
is consistent with the new typed approach for array lengths.
2476-2479
: Generic.max()
Similarly,max<MaxLength extends number>
aligns with typed array constraints.
2486-2489
: Exact.length()
Exposing a specializedZodExactArray
for fixed-length arrays is a clean solution for precise cardinalities.
2496-2496
:.nonempty()
usage
Internally delegating to.min(1)
is a neat, DRY approach.
2515-2519
: Distinct array types
ZodNonEmptyArray
andZodExactArray
provide a clear naming scheme for special cardinalities.
3894-3901
: Key–value pairing with lazy path
Mapping[key, value]
toParseInputLazyPath
for each entry ensures detailed context inZodMap
.
4629-4629
: Promise resolution chain
Wrappingpromisified.then
with the subsequent parse logic is consistent withZodPromise
usage.
5118-5118
: Confirming NaN type
Callingthis._assertParsedDataType(input);
forZodNaN
cements the type guarantee in the parse route.
5286-5286
: Read-only parse
The_assertParsedDataType
usage inZodReadonly
helps ensure the internal type matches expectations before freezing.
This PR introduces several TypeScript improvements that enhance type inference and developer experience without affecting runtime functionality.
Summary of Changes
1.
ZodString
EnhancementsGeneric Case Inference:
ZodString is now generic over its output type, enabling propagation of case transformations.
Case Matching for Methods:
Introduced the
inferCase
helper type so that methods likeincludes
,startsWith
, andendsWith
only accept values that match the current output case.Enhanced Transformations:
Updated
toLowerCase
andtoUpperCase
to returnLowercase<Output>
andUppercase<Output>
, respectively, by reusing the_addCheck
helper.Generic
length
Method:Made the
.length
method generic, returningOutput & { length: StringLength }
.Tests:
Updated tests to validate the correct behavior of these enhancements.
2.
ZodArray
EnhancementsExact Array Cardinality:
Implemented tuple-based type inference for fixed-length arrays using the
.length
method.TypeScript Limitation Enforcement:
Enforced a maximum inferred tuple length of 100. For numbers beyond this limit or for generic number inputs, a simple array type is returned.
Documentation:
Updated the Arrays documentation to reflect these changes.
3.
ZodType
EnhancementsType Narrowing Helper:
Introduced a generic, no-op method
_assertParsedDataType
that forces TypeScript to narrow the type of parsed input data inside the_parse
method.Overloads for Input Types:
Supports overloads for both
ParseInput
andParseContext
, defaulting the generic type parameter to the ZodType output.Documentation:
Added detailed JSDoc comments to clarify the usage, overloads, and behavior of the method.
Impact
These changes are entirely TypeScript enhancements and do not affect runtime functionality. They improve type safety and developer experience when using Zod's API.
Please review the changes and let me know if any adjustments are needed.
Summary by CodeRabbit
Documentation
New Features
Tests