Skip to content

Commit 3af38fb

Browse files
add ZodNumber.safe() & ZodNumber.isSafe. (#1753)
* implement `ZodNumber.safe()`. * implement `ZodNumber.isSafe`. * test `ZodNumber.safe()` & `ZodNumber.isSafe`. * add `ZodNumber.safe()` to README.md. * test `ZodNumer.isSafe`. * Remove isSafe --------- Co-authored-by: Colin McDonnell <[email protected]>
1 parent e71cc52 commit 3af38fb

File tree

6 files changed

+48
-2
lines changed

6 files changed

+48
-2
lines changed

Diff for: README.md

+1
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,7 @@ z.number().nonpositive(); // <= 0
721721
z.number().multipleOf(5); // Evenly divisible by 5. Alias .step(5)
722722

723723
z.number().finite(); // value must be finite, not Infinity or -Infinity
724+
z.number().safe(); // value must be between Number.MIN_SAFE_INTEGER and Number.MAX_SAFE_INTEGER
724725
```
725726

726727
Optionally, you can pass in a second argument to provide a custom error message.

Diff for: deno/lib/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,7 @@ z.number().nonpositive(); // <= 0
721721
z.number().multipleOf(5); // Evenly divisible by 5. Alias .step(5)
722722

723723
z.number().finite(); // value must be finite, not Infinity or -Infinity
724+
z.number().safe(); // value must be between Number.MIN_SAFE_INTEGER and Number.MAX_SAFE_INTEGER
724725
```
725726

726727
Optionally, you can pass in a second argument to provide a custom error message.

Diff for: deno/lib/__tests__/number.test.ts

+9
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const nonnegative = z.number().nonnegative();
1818
const multipleOfFive = z.number().multipleOf(5);
1919
const multipleOfNegativeFive = z.number().multipleOf(-5);
2020
const finite = z.number().finite();
21+
const safe = z.number().safe();
2122
const stepPointOne = z.number().step(0.1);
2223
const stepPointZeroZeroZeroOne = z.number().step(0.0001);
2324
const stepSixPointFour = z.number().step(6.4);
@@ -58,6 +59,8 @@ test("passing validations", () => {
5859
multipleOfNegativeFive.parse(-15);
5960
multipleOfNegativeFive.parse(15);
6061
finite.parse(123);
62+
safe.parse(Number.MIN_SAFE_INTEGER);
63+
safe.parse(Number.MAX_SAFE_INTEGER);
6164
stepPointOne.parse(6);
6265
stepPointOne.parse(6.1);
6366
stepPointOne.parse(6.1);
@@ -85,6 +88,8 @@ test("failing validations", () => {
8588
expect(() => multipleOfNegativeFive.parse(7.5)).toThrow();
8689
expect(() => finite.parse(Infinity)).toThrow();
8790
expect(() => finite.parse(-Infinity)).toThrow();
91+
expect(() => safe.parse(Number.MIN_SAFE_INTEGER - 1)).toThrow();
92+
expect(() => safe.parse(Number.MAX_SAFE_INTEGER + 1)).toThrow();
8893

8994
expect(() => stepPointOne.parse(6.11)).toThrow();
9095
expect(() => stepPointOne.parse(6.1000000001)).toThrow();
@@ -111,6 +116,7 @@ test("min max getters", () => {
111116
expect(minFive.min(10).minValue).toEqual(10);
112117
expect(positive.minValue).toEqual(0);
113118
expect(nonnegative.minValue).toEqual(0);
119+
expect(safe.minValue).toEqual(Number.MIN_SAFE_INTEGER);
114120

115121
expect(z.number().maxValue).toBeNull;
116122
expect(gtFive.maxValue).toBeNull;
@@ -127,6 +133,7 @@ test("min max getters", () => {
127133
expect(maxFive.max(1).maxValue).toEqual(1);
128134
expect(negative.maxValue).toEqual(0);
129135
expect(nonpositive.maxValue).toEqual(0);
136+
expect(safe.maxValue).toEqual(Number.MAX_SAFE_INTEGER);
130137
});
131138

132139
test("int getter", () => {
@@ -143,6 +150,7 @@ test("int getter", () => {
143150
expect(maxFive.isInt).toEqual(false);
144151
expect(negative.isInt).toEqual(false);
145152
expect(nonpositive.isInt).toEqual(false);
153+
expect(safe.isInt).toEqual(false);
146154

147155
expect(intNum.isInt).toEqual(true);
148156
expect(multipleOfFive.isInt).toEqual(true);
@@ -165,4 +173,5 @@ test("finite getter", () => {
165173
expect(intNum.isFinite).toEqual(true);
166174
expect(multipleOfFive.isFinite).toEqual(true);
167175
expect(z.number().min(5).max(10).isFinite).toEqual(true);
176+
expect(safe.isFinite).toEqual(true);
168177
});

Diff for: deno/lib/types.ts

+14-1
Original file line numberDiff line numberDiff line change
@@ -1211,6 +1211,7 @@ export class ZodNumber extends ZodType<number, ZodNumberDef> {
12111211
message: errorUtil.toString(message),
12121212
});
12131213
}
1214+
step = this.multipleOf;
12141215

12151216
finite(message?: errorUtil.ErrMessage) {
12161217
return this._addCheck({
@@ -1219,7 +1220,19 @@ export class ZodNumber extends ZodType<number, ZodNumberDef> {
12191220
});
12201221
}
12211222

1222-
step = this.multipleOf;
1223+
safe(message?: errorUtil.ErrMessage) {
1224+
return this._addCheck({
1225+
kind: "min",
1226+
inclusive: true,
1227+
value: Number.MIN_SAFE_INTEGER,
1228+
message: errorUtil.toString(message),
1229+
})._addCheck({
1230+
kind: "max",
1231+
inclusive: true,
1232+
value: Number.MAX_SAFE_INTEGER,
1233+
message: errorUtil.toString(message),
1234+
});
1235+
}
12231236

12241237
get minValue() {
12251238
let min: number | null = null;

Diff for: src/__tests__/number.test.ts

+9
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const nonnegative = z.number().nonnegative();
1717
const multipleOfFive = z.number().multipleOf(5);
1818
const multipleOfNegativeFive = z.number().multipleOf(-5);
1919
const finite = z.number().finite();
20+
const safe = z.number().safe();
2021
const stepPointOne = z.number().step(0.1);
2122
const stepPointZeroZeroZeroOne = z.number().step(0.0001);
2223
const stepSixPointFour = z.number().step(6.4);
@@ -57,6 +58,8 @@ test("passing validations", () => {
5758
multipleOfNegativeFive.parse(-15);
5859
multipleOfNegativeFive.parse(15);
5960
finite.parse(123);
61+
safe.parse(Number.MIN_SAFE_INTEGER);
62+
safe.parse(Number.MAX_SAFE_INTEGER);
6063
stepPointOne.parse(6);
6164
stepPointOne.parse(6.1);
6265
stepPointOne.parse(6.1);
@@ -84,6 +87,8 @@ test("failing validations", () => {
8487
expect(() => multipleOfNegativeFive.parse(7.5)).toThrow();
8588
expect(() => finite.parse(Infinity)).toThrow();
8689
expect(() => finite.parse(-Infinity)).toThrow();
90+
expect(() => safe.parse(Number.MIN_SAFE_INTEGER - 1)).toThrow();
91+
expect(() => safe.parse(Number.MAX_SAFE_INTEGER + 1)).toThrow();
8792

8893
expect(() => stepPointOne.parse(6.11)).toThrow();
8994
expect(() => stepPointOne.parse(6.1000000001)).toThrow();
@@ -110,6 +115,7 @@ test("min max getters", () => {
110115
expect(minFive.min(10).minValue).toEqual(10);
111116
expect(positive.minValue).toEqual(0);
112117
expect(nonnegative.minValue).toEqual(0);
118+
expect(safe.minValue).toEqual(Number.MIN_SAFE_INTEGER);
113119

114120
expect(z.number().maxValue).toBeNull;
115121
expect(gtFive.maxValue).toBeNull;
@@ -126,6 +132,7 @@ test("min max getters", () => {
126132
expect(maxFive.max(1).maxValue).toEqual(1);
127133
expect(negative.maxValue).toEqual(0);
128134
expect(nonpositive.maxValue).toEqual(0);
135+
expect(safe.maxValue).toEqual(Number.MAX_SAFE_INTEGER);
129136
});
130137

131138
test("int getter", () => {
@@ -142,6 +149,7 @@ test("int getter", () => {
142149
expect(maxFive.isInt).toEqual(false);
143150
expect(negative.isInt).toEqual(false);
144151
expect(nonpositive.isInt).toEqual(false);
152+
expect(safe.isInt).toEqual(false);
145153

146154
expect(intNum.isInt).toEqual(true);
147155
expect(multipleOfFive.isInt).toEqual(true);
@@ -164,4 +172,5 @@ test("finite getter", () => {
164172
expect(intNum.isFinite).toEqual(true);
165173
expect(multipleOfFive.isFinite).toEqual(true);
166174
expect(z.number().min(5).max(10).isFinite).toEqual(true);
175+
expect(safe.isFinite).toEqual(true);
167176
});

Diff for: src/types.ts

+14-1
Original file line numberDiff line numberDiff line change
@@ -1211,6 +1211,7 @@ export class ZodNumber extends ZodType<number, ZodNumberDef> {
12111211
message: errorUtil.toString(message),
12121212
});
12131213
}
1214+
step = this.multipleOf;
12141215

12151216
finite(message?: errorUtil.ErrMessage) {
12161217
return this._addCheck({
@@ -1219,7 +1220,19 @@ export class ZodNumber extends ZodType<number, ZodNumberDef> {
12191220
});
12201221
}
12211222

1222-
step = this.multipleOf;
1223+
safe(message?: errorUtil.ErrMessage) {
1224+
return this._addCheck({
1225+
kind: "min",
1226+
inclusive: true,
1227+
value: Number.MIN_SAFE_INTEGER,
1228+
message: errorUtil.toString(message),
1229+
})._addCheck({
1230+
kind: "max",
1231+
inclusive: true,
1232+
value: Number.MAX_SAFE_INTEGER,
1233+
message: errorUtil.toString(message),
1234+
});
1235+
}
12231236

12241237
get minValue() {
12251238
let min: number | null = null;

0 commit comments

Comments
 (0)